diff options
142 files changed, 859 insertions, 438 deletions
diff --git a/configure.ac b/configure.ac index 0b96e15b9e..4d84aacce1 100644 --- a/configure.ac +++ b/configure.ac @@ -733,6 +733,10 @@ fi AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h]) +AC_CHECK_DECLS([getifaddrs, freeifaddrs],,, + [#include <sys/types.h> + #include <ifaddrs.h>] +) AC_CHECK_DECLS([strnlen]) # Check for daemon(3), unrelated to --with-daemon (although used by it) diff --git a/depends/Makefile b/depends/Makefile index da81c4c7ee..50cc77ddeb 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -15,7 +15,7 @@ HOST ?= $(BUILD) PATCHES_PATH = $(BASEDIR)/patches BASEDIR = $(CURDIR) HASH_LENGTH:=11 -DOWNLOAD_CONNECT_TIMEOUT:=10 +DOWNLOAD_CONNECT_TIMEOUT:=30 DOWNLOAD_RETRIES:=3 HOST_ID_SALT ?= salt BUILD_ID_SALT ?= salt diff --git a/src/Makefile.am b/src/Makefile.am index 3701ee8f3c..159812e847 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -228,6 +228,8 @@ libbitcoin_server_a_SOURCES = \ httpserver.cpp \ index/base.cpp \ index/txindex.cpp \ + interfaces/handler.cpp \ + interfaces/node.cpp \ init.cpp \ dbwrapper.cpp \ merkleblock.cpp \ @@ -260,6 +262,10 @@ libbitcoin_server_a_SOURCES = \ 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) @@ -410,8 +416,6 @@ libbitcoin_util_a_SOURCES = \ compat/glibcxx_sanity.cpp \ compat/strnlen.cpp \ fs.cpp \ - interfaces/handler.cpp \ - interfaces/node.cpp \ logging.cpp \ random.cpp \ rpc/protocol.cpp \ diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index b17ff3507d..4c57965bec 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -162,7 +162,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c break; } - LogPrint(BCLog::CMPCTBLOCK, "Initialized PartiallyDownloadedBlock for block %s using a cmpctblock of size %lu\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock, SER_NETWORK, PROTOCOL_VERSION)); + LogPrint(BCLog::CMPCTBLOCK, "Initialized PartiallyDownloadedBlock for block %s using a cmpctblock of size %lu\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock, PROTOCOL_VERSION)); return READ_STATUS_OK; } diff --git a/src/coins.cpp b/src/coins.cpp index da1036acfb..f125b483bb 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -244,7 +244,7 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const return true; } -static const size_t MIN_TRANSACTION_OUTPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); +static const size_t MIN_TRANSACTION_OUTPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxOut(), PROTOCOL_VERSION); static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_OUTPUT_WEIGHT; const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid) diff --git a/src/coins.h b/src/coins.h index 41a422f485..3867a37b39 100644 --- a/src/coins.h +++ b/src/coins.h @@ -285,8 +285,8 @@ public: * Note that lightweight clients may not know anything besides the hash of previous transactions, * so may not be able to calculate this. * - * @param[in] tx transaction for which we are checking input total - * @return Sum of value of all inputs (scriptSigs) + * @param[in] tx transaction for which we are checking input total + * @return Sum of value of all inputs (scriptSigs) */ CAmount GetValueIn(const CTransaction& tx) const; diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index be73d0a2f9..0628ec1d47 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -164,7 +164,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe if (tx.vout.empty()) return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty"); // Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability) - if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT) + if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT) return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize"); // Check for negative or overflow output values diff --git a/src/consensus/validation.h b/src/consensus/validation.h index 008eda69b2..f2e2c3585a 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -95,16 +95,16 @@ public: // weight = (stripped_size * 3) + total_size. static inline int64_t GetTransactionWeight(const CTransaction& tx) { - return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + return ::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(tx, PROTOCOL_VERSION); } static inline int64_t GetBlockWeight(const CBlock& block) { - return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION); + return ::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, PROTOCOL_VERSION); } static inline int64_t GetTransactionInputWeight(const CTxIn& txin) { // scriptWitness size is added here because witnesses and txins are split up in segwit serialization. - return ::GetSerializeSize(txin, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(txin, SER_NETWORK, PROTOCOL_VERSION) + ::GetSerializeSize(txin.scriptWitness.stack, SER_NETWORK, PROTOCOL_VERSION); + return ::GetSerializeSize(txin, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(txin, PROTOCOL_VERSION) + ::GetSerializeSize(txin.scriptWitness.stack, PROTOCOL_VERSION); } #endif // BITCOIN_CONSENSUS_VALIDATION_H diff --git a/src/core_write.cpp b/src/core_write.cpp index 55dcb1661d..b86490716f 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -181,7 +181,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, entry.pushKV("txid", tx.GetHash().GetHex()); entry.pushKV("hash", tx.GetWitnessHash().GetHex()); entry.pushKV("version", tx.nVersion); - entry.pushKV("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)); + entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION)); entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR); entry.pushKV("weight", GetTransactionWeight(tx)); entry.pushKV("locktime", (int64_t)tx.nLockTime); diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp new file mode 100644 index 0000000000..3714187a96 --- /dev/null +++ b/src/dummywallet.cpp @@ -0,0 +1,51 @@ +// Copyright (c) 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. + +#include <stdio.h> +#include <util.h> +#include <walletinitinterface.h> + +class CWallet; + +class DummyWalletInit : public WalletInitInterface { +public: + + bool HasWalletSupport() const override {return false;} + void AddWalletOptions() const override; + bool ParameterInteraction() const override {return true;} + void RegisterRPC(CRPCTable &) const override {} + bool Verify() const override {return true;} + bool Open() const override {LogPrintf("No wallet support compiled in!\n"); return true;} + void Start(CScheduler& scheduler) const override {} + void Flush() const override {} + void Stop() const override {} + void Close() const override {} +}; + +void DummyWalletInit::AddWalletOptions() const +{ + std::vector<std::string> opts = {"-addresstype", "-changetype", "-disablewallet", "-discardfee=<amt>", "-fallbackfee=<amt>", + "-keypool=<n>", "-mintxfee=<amt>", "-paytxfee=<amt>", "-rescan", "-salvagewallet", "-spendzeroconfchange", "-txconfirmtarget=<n>", + "-upgradewallet", "-wallet=<path>", "-walletbroadcast", "-walletdir=<dir>", "-walletnotify=<cmd>", "-walletrbf", "-zapwallettxes=<mode>", + "-dblogsize=<n>", "-flushwallet", "-privdb", "-walletrejectlongchains"}; + gArgs.AddHiddenArgs(opts); +} + +const WalletInitInterface& g_wallet_init_interface = DummyWalletInit(); + +std::vector<std::shared_ptr<CWallet>> GetWallets() +{ + throw std::logic_error("Wallet function called in non-wallet build."); +} + +namespace interfaces { + +class Wallet; + +std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) +{ + throw std::logic_error("Wallet function called in non-wallet build."); +} + +} // namespace interfaces diff --git a/src/fs.cpp b/src/fs.cpp index 1a221788b8..df79b5e3df 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -11,7 +11,12 @@ namespace fsbridge { FILE *fopen(const fs::path& p, const char *mode) { +#ifndef WIN32 return ::fopen(p.string().c_str(), mode); +#else + std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> utf8_cvt; + return ::_wfopen(p.wstring().c_str(), utf8_cvt.from_bytes(mode).c_str()); +#endif } #ifndef WIN32 diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 38f6e79643..43d8c4cbbf 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -14,6 +14,7 @@ #include <util.h> #include <utilstrencodings.h> #include <ui_interface.h> +#include <walletinitinterface.h> #include <crypto/hmac_sha256.h> #include <stdio.h> @@ -240,10 +241,9 @@ bool StartHTTPRPC() return false; RegisterHTTPHandler("/", true, HTTPReq_JSONRPC); -#ifdef ENABLE_WALLET - // ifdef can be removed once we switch to better endpoint support and API versioning - RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC); -#endif + if (g_wallet_init_interface.HasWalletSupport()) { + RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC); + } struct event_base* eventBase = EventBase(); assert(eventBase); httpRPCTimerInterface = MakeUnique<HTTPRPCTimerInterface>(eventBase); @@ -260,9 +260,9 @@ void StopHTTPRPC() { LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n"); UnregisterHTTPHandler("/", true); -#ifdef ENABLE_WALLET - UnregisterHTTPHandler("/wallet/", false); -#endif + if (g_wallet_init_interface.HasWalletSupport()) { + UnregisterHTTPHandler("/wallet/", false); + } if (httpRPCTimerInterface) { RPCUnsetTimerInterface(httpRPCTimerInterface.get()); httpRPCTimerInterface.reset(); diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index c85030e18e..f606c8993c 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -250,7 +250,7 @@ bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex) vPos.reserve(block.vtx.size()); for (const auto& tx : block.vtx) { vPos.emplace_back(tx->GetHash(), pos); - pos.nTxOffset += ::GetSerializeSize(*tx, SER_DISK, CLIENT_VERSION); + pos.nTxOffset += ::GetSerializeSize(*tx, CLIENT_VERSION); } return m_db->WriteTxs(vPos); } diff --git a/src/init.cpp b/src/init.cpp index 86a82ccaf6..45689f7ecd 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -74,33 +74,6 @@ static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; std::unique_ptr<CConnman> g_connman; std::unique_ptr<PeerLogicValidation> peerLogic; -#if !(ENABLE_WALLET) -class DummyWalletInit : public WalletInitInterface { -public: - - void AddWalletOptions() const override; - bool ParameterInteraction() const override {return true;} - void RegisterRPC(CRPCTable &) const override {} - bool Verify() const override {return true;} - bool Open() const override {LogPrintf("No wallet support compiled in!\n"); return true;} - void Start(CScheduler& scheduler) const override {} - void Flush() const override {} - void Stop() const override {} - void Close() const override {} -}; - -void DummyWalletInit::AddWalletOptions() const -{ - std::vector<std::string> opts = {"-addresstype", "-changetype", "-disablewallet", "-discardfee=<amt>", "-fallbackfee=<amt>", - "-keypool=<n>", "-mintxfee=<amt>", "-paytxfee=<amt>", "-rescan", "-salvagewallet", "-spendzeroconfchange", "-txconfirmtarget=<n>", - "-upgradewallet", "-wallet=<path>", "-walletbroadcast", "-walletdir=<dir>", "-walletnotify=<cmd>", "-walletrbf", "-zapwallettxes=<mode>", - "-dblogsize=<n>", "-flushwallet", "-privdb", "-walletrejectlongchains"}; - gArgs.AddHiddenArgs(opts); -} - -const WalletInitInterface& g_wallet_init_interface = DummyWalletInit(); -#endif - #ifdef WIN32 // Win32 LevelDB doesn't use filedescriptors, and the ones used for // accessing block files don't count towards the fd_set size limit @@ -470,7 +443,7 @@ void SetupServerArgs() gArgs.AddArg("-debug=<category>", "Output debugging information (default: -nodebug, supplying <category> is optional). " "If <category> is not supplied or if <category> = 1, output all debugging information. <category> can be: " + ListLogCategories() + ".", false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-debugexclude=<category>", strprintf("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories."), false, OptionsCategory::DEBUG_TEST); - gArgs.AddArg("-help-debug", "Show all debugging options (usage: --help -help-debug)", false, OptionsCategory::DEBUG_TEST); + gArgs.AddArg("-help-debug", "Print help message with debugging options and exit", false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS), false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS), true, OptionsCategory::DEBUG_TEST); diff --git a/src/init.h b/src/init.h index 0c85d3c9dc..c58ba5cfd3 100644 --- a/src/init.h +++ b/src/init.h @@ -13,9 +13,6 @@ class CScheduler; class CWallet; -class WalletInitInterface; -extern const WalletInitInterface& g_wallet_init_interface; - namespace boost { class thread_group; diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index 1da58fe487..d95b41657c 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -32,19 +32,18 @@ #if defined(HAVE_CONFIG_H) #include <config/bitcoin-config.h> #endif -#ifdef ENABLE_WALLET -#include <wallet/fees.h> -#include <wallet/wallet.h> -#define CHECK_WALLET(x) x -#else -#define CHECK_WALLET(x) throw std::logic_error("Wallet function called in non-wallet build.") -#endif #include <atomic> #include <boost/thread/thread.hpp> #include <univalue.h> +class CWallet; +std::vector<std::shared_ptr<CWallet>> GetWallets(); + namespace interfaces { + +class Wallet; + namespace { class NodeImpl : public Node @@ -221,15 +220,11 @@ class NodeImpl : public Node } std::vector<std::unique_ptr<Wallet>> getWallets() override { -#ifdef ENABLE_WALLET std::vector<std::unique_ptr<Wallet>> wallets; for (const std::shared_ptr<CWallet>& wallet : GetWallets()) { wallets.emplace_back(MakeWallet(wallet)); } return wallets; -#else - throw std::logic_error("Node::getWallets() called in non-wallet build."); -#endif } std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override { @@ -249,8 +244,7 @@ class NodeImpl : public Node } std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) override { - CHECK_WALLET( - return MakeHandler(::uiInterface.LoadWallet_connect([fn](std::shared_ptr<CWallet> wallet) { fn(MakeWallet(wallet)); }))); + return MakeHandler(::uiInterface.LoadWallet_connect([fn](std::shared_ptr<CWallet> wallet) { fn(MakeWallet(wallet)); })); } std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override { diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 44240a5726..7aa91f37e1 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -366,8 +366,8 @@ struct WalletTxOut bool is_spent = false; }; -//! Return implementation of Wallet interface. This function will be undefined -//! in builds where ENABLE_WALLET is false. +//! Return implementation of Wallet interface. This function is defined in +//! dummywallet.cpp and throws if the wallet component is not compiled. std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet); } // namespace interfaces diff --git a/src/key.cpp b/src/key.cpp index df452cd330..80d6589a3c 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -89,7 +89,7 @@ static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *ou * will be set to the number of bytes used in the buffer. * key32 must point to a 32-byte raw private key. */ -static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { +static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, bool compressed) { assert(*privkeylen >= CKey::PRIVATE_KEY_SIZE); secp256k1_pubkey pubkey; size_t pubkeylen = 0; @@ -170,7 +170,7 @@ CPrivKey CKey::GetPrivKey() const { size_t privkeylen; privkey.resize(PRIVATE_KEY_SIZE); privkeylen = PRIVATE_KEY_SIZE; - ret = ec_privkey_export_der(secp256k1_context_sign, privkey.data(), &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); + ret = ec_privkey_export_der(secp256k1_context_sign, privkey.data(), &privkeylen, begin(), fCompressed); assert(ret); privkey.resize(privkeylen); return privkey; diff --git a/src/logging.h b/src/logging.h index 6400b131c2..0c8e7f5291 100644 --- a/src/logging.h +++ b/src/logging.h @@ -125,42 +125,31 @@ std::vector<CLogCategoryActive> ListActiveLogCategories(); /** Return true if str parses as a log category and set the flag */ bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str); -/** Get format string from VA_ARGS for error reporting */ -template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; } - -static inline void MarkUsed() {} -template<typename T, typename... Args> static inline void MarkUsed(const T& t, const Args&... args) -{ - (void)t; - MarkUsed(args...); -} - // Be conservative when using LogPrintf/error or other things which // unconditionally log to debug.log! It should not be the case that an inbound // peer can fill up a user's disk with debug.log entries. -#ifdef USE_COVERAGE -#define LogPrintf(...) do { MarkUsed(__VA_ARGS__); } while(0) -#define LogPrint(category, ...) do { MarkUsed(__VA_ARGS__); } while(0) -#else -#define LogPrintf(...) do { \ - if (g_logger->Enabled()) { \ - std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ - try { \ - _log_msg_ = tfm::format(__VA_ARGS__); \ - } catch (tinyformat::format_error &fmterr) { \ - /* Original format string will have newline so don't add one here */ \ - _log_msg_ = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(__VA_ARGS__); \ - } \ - g_logger->LogPrintStr(_log_msg_); \ - } \ -} while(0) - -#define LogPrint(category, ...) do { \ - if (LogAcceptCategory((category))) { \ - LogPrintf(__VA_ARGS__); \ - } \ -} while(0) -#endif +template <typename... Args> +static inline void LogPrintf(const char* fmt, const Args&... args) +{ + if (g_logger->Enabled()) { + std::string log_msg; + try { + log_msg = tfm::format(fmt, args...); + } catch (tinyformat::format_error& fmterr) { + /* Original format string will have newline so don't add one here */ + log_msg = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + fmt; + } + g_logger->LogPrintStr(log_msg); + } +} + +template <typename... Args> +static inline void LogPrint(const BCLog::LogFlags& category, const Args&... args) +{ + if (LogAcceptCategory((category))) { + LogPrintf(args...); + } +} #endif // BITCOIN_LOGGING_H diff --git a/src/net.cpp b/src/net.cpp index c51a1b4a74..f83f39a67d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2167,7 +2167,7 @@ void Discover() } } } -#else +#elif (HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS) // Get local host ip struct ifaddrs* myaddrs; if (getifaddrs(&myaddrs) == 0) diff --git a/src/netbase.cpp b/src/netbase.cpp index 4b63757f3d..093fd0bdb7 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -17,6 +17,8 @@ #ifndef WIN32 #include <fcntl.h> +#else +#include <codecvt> #endif #if !defined(MSG_NOSIGNAL) @@ -649,13 +651,13 @@ bool LookupSubNet(const char* pszName, CSubNet& ret) #ifdef WIN32 std::string NetworkErrorString(int err) { - char buf[256]; + wchar_t buf[256]; buf[0] = 0; - if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, + if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - buf, sizeof(buf), nullptr)) + buf, ARRAYSIZE(buf), nullptr)) { - return strprintf("%s (%d)", buf, err); + return strprintf("%s (%d)", std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err); } else { diff --git a/src/noui.cpp b/src/noui.cpp index 3a1ec2d050..df4bfabb66 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -14,7 +14,7 @@ #include <boost/signals2/connection.hpp> -static bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) +bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) { bool fSecure = style & CClientUIInterface::SECURE; style &= ~CClientUIInterface::SECURE; @@ -41,19 +41,18 @@ static bool noui_ThreadSafeMessageBox(const std::string& message, const std::str return false; } -static bool noui_ThreadSafeQuestion(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style) +bool noui_ThreadSafeQuestion(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style) { return noui_ThreadSafeMessageBox(message, caption, style); } -static void noui_InitMessage(const std::string& message) +void noui_InitMessage(const std::string& message) { LogPrintf("init message: %s\n", message); } void noui_connect() { - // Connect bitcoind signal handlers uiInterface.ThreadSafeMessageBox_connect(noui_ThreadSafeMessageBox); uiInterface.ThreadSafeQuestion_connect(noui_ThreadSafeQuestion); uiInterface.InitMessage_connect(noui_InitMessage); diff --git a/src/noui.h b/src/noui.h index ff16cc9aa8..169c2bbd7f 100644 --- a/src/noui.h +++ b/src/noui.h @@ -5,6 +5,16 @@ #ifndef BITCOIN_NOUI_H #define BITCOIN_NOUI_H -extern void noui_connect(); +#include <string> + +/** Non-GUI handler, which logs and prints messages. */ +bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style); +/** Non-GUI handler, which logs and prints questions. */ +bool noui_ThreadSafeQuestion(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style); +/** Non-GUI handler, which only logs a message. */ +void noui_InitMessage(const std::string& message); + +/** Connect all bitcoind signal handlers */ +void noui_connect(); #endif // BITCOIN_NOUI_H diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 47d6644551..ac1b75edb4 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -34,7 +34,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn) if (txout.scriptPubKey.IsUnspendable()) return 0; - size_t nSize = GetSerializeSize(txout, SER_DISK, 0); + size_t nSize = GetSerializeSize(txout); int witnessversion = 0; std::vector<unsigned char> witnessprogram; diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 59865a5eab..bdb470470e 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -93,7 +93,7 @@ CAmount CTransaction::GetValueOut() const unsigned int CTransaction::GetTotalSize() const { - return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); + return ::GetSerializeSize(*this, PROTOCOL_VERSION); } std::string CTransaction::ToString() const diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index f1d3074c2f..87282a961f 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -28,6 +28,7 @@ #include <interfaces/handler.h> #include <interfaces/node.h> +#include <noui.h> #include <rpc/server.h> #include <ui_interface.h> #include <uint256.h> @@ -71,9 +72,9 @@ Q_DECLARE_METATYPE(bool*) Q_DECLARE_METATYPE(CAmount) Q_DECLARE_METATYPE(uint256) -static void InitMessage(const std::string &message) +static void InitMessage(const std::string& message) { - LogPrintf("init message: %s\n", message); + noui_InitMessage(message); } /** Translate string to current locale using Qt. */ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 632ce0750a..51aff08c42 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -31,6 +31,7 @@ #include <chainparams.h> #include <interfaces/handler.h> #include <interfaces/node.h> +#include <noui.h> #include <ui_interface.h> #include <util.h> @@ -1217,8 +1218,11 @@ void BitcoinGUI::showModalOverlay() modalOverlay->toggleVisibility(); } -static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style) +static bool ThreadSafeMessageBox(BitcoinGUI* gui, const std::string& message, const std::string& caption, unsigned int style) { + // Redundantly log and print message in non-gui fashion + noui_ThreadSafeMessageBox(message, caption, style); + bool modal = (style & CClientUIInterface::MODAL); // The SECURE flag has no effect in the Qt GUI. // bool secure = (style & CClientUIInterface::SECURE); diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index bbf60d96fd..7afe25d25a 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -38,8 +38,6 @@ #include <shlwapi.h> #endif -#include <boost/scoped_array.hpp> - #include <QAbstractItemView> #include <QApplication> #include <QClipboard> @@ -548,40 +546,28 @@ bool SetStartOnSystemStartup(bool fAutoStart) CoInitialize(nullptr); // Get a pointer to the IShellLink interface. - IShellLink* psl = nullptr; + IShellLinkW* psl = nullptr; HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, - CLSCTX_INPROC_SERVER, IID_IShellLink, + CLSCTX_INPROC_SERVER, IID_IShellLinkW, reinterpret_cast<void**>(&psl)); if (SUCCEEDED(hres)) { // Get the current executable path - TCHAR pszExePath[MAX_PATH]; - GetModuleFileName(nullptr, pszExePath, sizeof(pszExePath)); + WCHAR pszExePath[MAX_PATH]; + GetModuleFileNameW(nullptr, pszExePath, ARRAYSIZE(pszExePath)); // Start client minimized QString strArgs = "-min"; // Set -testnet /-regtest options strArgs += QString::fromStdString(strprintf(" -testnet=%d -regtest=%d", gArgs.GetBoolArg("-testnet", false), gArgs.GetBoolArg("-regtest", false))); -#ifdef UNICODE - boost::scoped_array<TCHAR> args(new TCHAR[strArgs.length() + 1]); - // Convert the QString to TCHAR* - strArgs.toWCharArray(args.get()); - // Add missing '\0'-termination to string - args[strArgs.length()] = '\0'; -#endif - // Set the path to the shortcut target psl->SetPath(pszExePath); - PathRemoveFileSpec(pszExePath); + PathRemoveFileSpecW(pszExePath); psl->SetWorkingDirectory(pszExePath); psl->SetShowCmd(SW_SHOWMINNOACTIVE); -#ifndef UNICODE - psl->SetArguments(strArgs.toStdString().c_str()); -#else - psl->SetArguments(args.get()); -#endif + psl->SetArguments(strArgs.toStdWString().c_str()); // Query IShellLink for the IPersistFile interface for // saving the shortcut in persistent storage. @@ -589,11 +575,8 @@ bool SetStartOnSystemStartup(bool fAutoStart) hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&ppf)); if (SUCCEEDED(hres)) { - WCHAR pwsz[MAX_PATH]; - // Ensure that the string is ANSI. - MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH); // Save the link by calling IPersistFile::Save. - hres = ppf->Save(pwsz, TRUE); + hres = ppf->Save(StartupShortcutPath().wstring().c_str(), TRUE); ppf->Release(); psl->Release(); CoUninitialize(); diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index 944bcc8ad0..a989988c45 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -142,7 +142,6 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c if (result != 1) { int error = X509_STORE_CTX_get_error(store_ctx); // For testing payment requests, we allow self signed root certs! - // This option is just shown in the UI options, if -help-debug is enabled. if (!(error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && gArgs.GetBoolArg("-allowselfsignedrootcertificates", DEFAULT_SELFSIGNED_ROOTCERTS))) { throw SSLVerifyError(X509_verify_cert_error_string(error)); } else { diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 6fb04ab005..439427cd7e 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -121,8 +121,8 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx if (chainActive.Contains(blockindex)) confirmations = chainActive.Height() - blockindex->nHeight + 1; result.pushKV("confirmations", confirmations); - result.pushKV("strippedsize", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)); - result.pushKV("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)); + result.pushKV("strippedsize", (int)::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)); + result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION)); result.pushKV("weight", (int)::GetBlockWeight(block)); result.pushKV("height", blockindex->nHeight); result.pushKV("version", block.nVersion); @@ -1831,7 +1831,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) if (loop_outputs) { for (const CTxOut& out : tx->vout) { tx_total_out += out.nValue; - utxo_size_inc += GetSerializeSize(out, SER_NETWORK, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; + utxo_size_inc += GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; } } @@ -1882,7 +1882,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) CTxOut prevoutput = tx_in->vout[in.prevout.n]; tx_total_in += prevoutput.nValue; - utxo_size_inc -= GetSerializeSize(prevoutput, SER_NETWORK, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; + utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; } CAmount txfee = tx_total_in - tx_total_out; @@ -2192,6 +2192,7 @@ UniValue scantxoutset(const JSONRPCRequest& request) return result; } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -2227,6 +2228,7 @@ static const CRPCCommand commands[] = { "hidden", "waitforblockheight", &waitforblockheight, {"height","timeout"} }, { "hidden", "syncwithvalidationinterfacequeue", &syncwithvalidationinterfacequeue, {} }, }; +// clang-format on void RegisterBlockchainRPCCommands(CRPCTable &t) { diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 784d6416cf..f4d44fc809 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -18,6 +18,7 @@ public: std::string paramName; //!< parameter name }; +// clang-format off /** * Specify a (method, idx, name) here if the argument is a non-string RPC * argument and needs to be converted from JSON. @@ -163,6 +164,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "rescanblockchain", 1, "stop_height"}, { "createwallet", 1, "disable_private_keys"}, }; +// clang-format on class CRPCConvertTable { diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 621b86eec8..b1bea85fef 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -750,11 +750,7 @@ static UniValue submitblock(const JSONRPCRequest& request) RegisterValidationInterface(&sc); bool accepted = ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block); UnregisterValidationInterface(&sc); - if (!new_block) { - if (!accepted) { - // TODO Maybe pass down fNewBlock to AcceptBlockHeader, so it is properly set to true in this case? - return "invalid"; - } + if (!new_block && accepted) { return "duplicate"; } if (!sc.found) { @@ -968,6 +964,7 @@ static UniValue estimaterawfee(const JSONRPCRequest& request) return result; } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -986,6 +983,7 @@ static const CRPCCommand commands[] = { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} }, }; +// clang-format on void RegisterMiningRPCCommands(CRPCTable &t) { diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index b7d05cef11..0f3b601414 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -439,6 +439,7 @@ static UniValue echo(const JSONRPCRequest& request) return request.params; } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -454,6 +455,7 @@ static const CRPCCommand commands[] = { "hidden", "echo", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, { "hidden", "echojson", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, }; +// clang-format on void RegisterMiscRPCCommands(CRPCTable &t) { diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 169a452659..099a7cf1da 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -626,6 +626,7 @@ static UniValue setnetworkactive(const JSONRPCRequest& request) return g_connman->GetNetworkActive(); } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -642,6 +643,7 @@ static const CRPCCommand commands[] = { "network", "clearbanned", &clearbanned, {} }, { "network", "setnetworkactive", &setnetworkactive, {"state"} }, }; +// clang-format on void RegisterNetRPCCommands(CRPCTable &t) { diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 6acf383646..798d54f35d 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1695,6 +1695,7 @@ UniValue converttopsbt(const JSONRPCRequest& request) return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -1716,6 +1717,7 @@ static const CRPCCommand commands[] = { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} }, { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} }, }; +// clang-format on void RegisterRawTransactionRPCCommands(CRPCTable &t) { diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 7d7e83fea8..8f3fe31ce8 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -252,6 +252,7 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest) return GetTime() - GetStartupTime(); } +// clang-format off /** * Call Table */ @@ -263,6 +264,7 @@ static const CRPCCommand vRPCCommands[] = { "control", "stop", &stop, {} }, { "control", "uptime", &uptime, {} }, }; +// clang-format on CRPCTable::CRPCTable() { diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index 01cfeb23f1..15e204062f 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -88,7 +88,7 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP CTransaction tx(deserialize, stream); if (nIn >= tx.vin.size()) return set_error(err, bitcoinconsensus_ERR_TX_INDEX); - if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen) + if (GetSerializeSize(tx, PROTOCOL_VERSION) != txToLen) return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH); // Regardless of the verification result, the tx did not error. diff --git a/src/script/sign.h b/src/script/sign.h index 18b7320998..2fc4575e59 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -147,7 +147,7 @@ static constexpr uint8_t PSBT_SEPARATOR = 0x00; template<typename Stream, typename... X> void SerializeToVector(Stream& s, const X&... args) { - WriteCompactSize(s, GetSerializeSizeMany(s, args...)); + WriteCompactSize(s, GetSerializeSizeMany(s.GetVersion(), args...)); SerializeMany(s, args...); } diff --git a/src/serialize.h b/src/serialize.h index 8bd3ef5d76..2d0cfbbbf0 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -901,10 +901,9 @@ class CSizeComputer protected: size_t nSize; - const int nType; const int nVersion; public: - CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {} + explicit CSizeComputer(int nVersionIn) : nSize(0), nVersion(nVersionIn) {} void write(const char *psz, size_t _nSize) { @@ -929,7 +928,6 @@ public: } int GetVersion() const { return nVersion; } - int GetType() const { return nType; } }; template<typename Stream> @@ -980,21 +978,15 @@ inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize) } template <typename T> -size_t GetSerializeSize(const T& t, int nType, int nVersion = 0) +size_t GetSerializeSize(const T& t, int nVersion = 0) { - return (CSizeComputer(nType, nVersion) << t).size(); + return (CSizeComputer(nVersion) << t).size(); } -template <typename S, typename T> -size_t GetSerializeSize(const S& s, const T& t) +template <typename... T> +size_t GetSerializeSizeMany(int nVersion, const T&... t) { - return (CSizeComputer(s.GetType(), s.GetVersion()) << t).size(); -} - -template <typename S, typename... T> -size_t GetSerializeSizeMany(const S& s, const T&... t) -{ - CSizeComputer sc(s.GetType(), s.GetVersion()); + CSizeComputer sc(nVersion); SerializeMany(sc, t...); return sc.size(); } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index eb0e4219d3..3eb8aa14fd 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -139,7 +139,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee uint256 hashFreeTx = tx.GetHash(); mempool.addUnchecked(entry.Fee(0).FromTx(tx)); - size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + size_t freeTxSize = ::GetSerializeSize(tx, PROTOCOL_VERSION); // Calculate a fee on child transaction that will put the package just // below the block min tx fee (assuming 1 child tx of the same size). diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 3a06145861..e754996d2f 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -182,13 +182,13 @@ BOOST_AUTO_TEST_CASE(varints) CDataStream::size_type size = 0; for (int i = 0; i < 100000; i++) { ss << VARINT(i, VarIntMode::NONNEGATIVE_SIGNED); - size += ::GetSerializeSize(VARINT(i, VarIntMode::NONNEGATIVE_SIGNED), 0, 0); + size += ::GetSerializeSize(VARINT(i, VarIntMode::NONNEGATIVE_SIGNED), 0); BOOST_CHECK(size == ss.size()); } for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) { ss << VARINT(i); - size += ::GetSerializeSize(VARINT(i), 0, 0); + size += ::GetSerializeSize(VARINT(i), 0); BOOST_CHECK(size == ss.size()); } diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index f91b633b83..cca5e20296 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -184,8 +184,8 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G BOOST_CHECK(OneL.begin() + 32 == OneL.end()); BOOST_CHECK(MaxL.begin() + 32 == MaxL.end()); BOOST_CHECK(TmpL.begin() + 32 == TmpL.end()); - BOOST_CHECK(GetSerializeSize(R1L, 0, PROTOCOL_VERSION) == 32); - BOOST_CHECK(GetSerializeSize(ZeroL, 0, PROTOCOL_VERSION) == 32); + BOOST_CHECK(GetSerializeSize(R1L, PROTOCOL_VERSION) == 32); + BOOST_CHECK(GetSerializeSize(ZeroL, PROTOCOL_VERSION) == 32); CDataStream ss(0, PROTOCOL_VERSION); ss << R1L; @@ -230,8 +230,8 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G BOOST_CHECK(OneS.begin() + 20 == OneS.end()); BOOST_CHECK(MaxS.begin() + 20 == MaxS.end()); BOOST_CHECK(TmpS.begin() + 20 == TmpS.end()); - BOOST_CHECK(GetSerializeSize(R1S, 0, PROTOCOL_VERSION) == 20); - BOOST_CHECK(GetSerializeSize(ZeroS, 0, PROTOCOL_VERSION) == 20); + BOOST_CHECK(GetSerializeSize(R1S, PROTOCOL_VERSION) == 20); + BOOST_CHECK(GetSerializeSize(ZeroS, PROTOCOL_VERSION) == 20); ss << R1S; BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+20)); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 39434e4bb6..3ad93342c4 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -156,9 +156,9 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntr // GetMemPoolParents() is only valid for entries in the mempool, so we // iterate mapTx to find parents. for (unsigned int i = 0; i < tx.vin.size(); i++) { - txiter piter = mapTx.find(tx.vin[i].prevout.hash); - if (piter != mapTx.end()) { - parentHashes.insert(piter); + boost::optional<txiter> piter = GetIter(tx.vin[i].prevout.hash); + if (piter) { + parentHashes.insert(*piter); if (parentHashes.size() + 1 > limitAncestorCount) { errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount); return false; @@ -364,12 +364,10 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces // Update transaction for any feeDelta created by PrioritiseTransaction // TODO: refactor so that the fee delta is calculated before inserting // into mapTx. - std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(entry.GetTx().GetHash()); - if (pos != mapDeltas.end()) { - const CAmount &delta = pos->second; - if (delta) { + CAmount delta{0}; + ApplyDelta(entry.GetTx().GetHash(), delta); + if (delta) { mapTx.modify(newit, update_fee_delta(delta)); - } } // Update cachedInnerUsage to include contained transaction's usage. @@ -391,11 +389,8 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces // to clean up the mess we're leaving here. // Update ancestors with information about this tx - for (const uint256 &phash : setParentTransactions) { - txiter pit = mapTx.find(phash); - if (pit != mapTx.end()) { + for (const auto& pit : GetIterSet(setParentTransactions)) { UpdateParent(newit, pit, true); - } } UpdateAncestorsOf(true, newit, setAncestors); UpdateEntryForAncestors(newit, setAncestors); @@ -864,6 +859,29 @@ void CTxMemPool::ClearPrioritisation(const uint256 hash) mapDeltas.erase(hash); } +const CTransaction* CTxMemPool::GetConflictTx(const COutPoint& prevout) const +{ + const auto it = mapNextTx.find(prevout); + return it == mapNextTx.end() ? nullptr : it->second; +} + +boost::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const uint256& txid) const +{ + auto it = mapTx.find(txid); + if (it != mapTx.end()) return it; + return boost::optional<txiter>{}; +} + +CTxMemPool::setEntries CTxMemPool::GetIterSet(const std::set<uint256>& hashes) const +{ + CTxMemPool::setEntries ret; + for (const auto& h : hashes) { + const auto mi = GetIter(h); + if (mi) ret.insert(*mi); + } + return ret; +} + bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const { for (unsigned int i = 0; i < tx.vin.size(); i++) diff --git a/src/txmempool.h b/src/txmempool.h index 2163b5eb21..913501fd66 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -566,7 +566,15 @@ public: void ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const; void ClearPrioritisation(const uint256 hash); -public: + /** Get the transaction in the pool that spends the same prevout */ + const CTransaction* GetConflictTx(const COutPoint& prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs); + + /** Returns an iterator to the given hash, if found */ + boost::optional<txiter> GetIter(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs); + + /** Translate a set of hashes into a set of pool iterators to avoid repeated lookups */ + setEntries GetIterSet(const std::set<uint256>& hashes) const EXCLUSIVE_LOCKS_REQUIRED(cs); + /** Remove a set of transactions from the mempool. * If a transaction is in this set, then all in-mempool descendants must * also be in the set, unless this transaction is being removed for being @@ -639,7 +647,7 @@ public: return totalTxSize; } - bool exists(uint256 hash) const + bool exists(const uint256& hash) const { LOCK(cs); return (mapTx.count(hash) != 0); diff --git a/src/undo.h b/src/undo.h index 4a78238944..4ed3dc4ca0 100644 --- a/src/undo.h +++ b/src/undo.h @@ -61,7 +61,7 @@ public: explicit TxInUndoDeserializer(Coin* coin) : txout(coin) {} }; -static const size_t MIN_TRANSACTION_INPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION); +static const size_t MIN_TRANSACTION_INPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxIn(), PROTOCOL_VERSION); static const size_t MAX_INPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_INPUT_WEIGHT; /** Undo information for a CTransaction */ diff --git a/src/util.cpp b/src/util.cpp index 84d8175389..ee8bc94584 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -58,6 +58,7 @@ #ifndef NOMINMAX #define NOMINMAX #endif +#include <codecvt> #include <io.h> /* for _commit */ #include <shlobj.h> @@ -659,7 +660,7 @@ std::string ArgsManager::GetHelpMessage() const bool HelpRequested(const ArgsManager& args) { - return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help"); + return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help") || args.IsArgSet("-help-debug"); } static const int screenWidth = 79; @@ -997,7 +998,7 @@ void CreatePidFile(const fs::path &path, pid_t pid) bool RenameOver(fs::path src, fs::path dest) { #ifdef WIN32 - return MoveFileExA(src.string().c_str(), dest.string().c_str(), + return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(), MOVEFILE_REPLACE_EXISTING) != 0; #else int rc = std::rename(src.string().c_str(), dest.string().c_str()); @@ -1139,14 +1140,14 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { #ifdef WIN32 fs::path GetSpecialFolderPath(int nFolder, bool fCreate) { - char pszPath[MAX_PATH] = ""; + WCHAR pszPath[MAX_PATH] = L""; - if(SHGetSpecialFolderPathA(nullptr, pszPath, nFolder, fCreate)) + if(SHGetSpecialFolderPathW(nullptr, pszPath, nFolder, fCreate)) { return fs::path(pszPath); } - LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n"); + LogPrintf("SHGetSpecialFolderPathW() failed, could not obtain requested path.\n"); return fs::path(""); } #endif @@ -1154,7 +1155,11 @@ fs::path GetSpecialFolderPath(int nFolder, bool fCreate) void runCommand(const std::string& strCommand) { if (strCommand.empty()) return; +#ifndef WIN32 int nErr = ::system(strCommand.c_str()); +#else + int nErr = ::_wsystem(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().from_bytes(strCommand).c_str()); +#endif if (nErr) LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr); } diff --git a/src/validation.cpp b/src/validation.cpp index 7ec0c6a961..947192be0e 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -584,7 +584,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // Do not work on transactions that are too small. // A transaction with 1 segwit input and 1 P2WPHK output has non-witness size of 82 bytes. // Transactions smaller than this are not relayed to reduce unnecessary malloc overhead. - if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) < MIN_STANDARD_TX_NONWITNESS_SIZE) + if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) < MIN_STANDARD_TX_NONWITNESS_SIZE) return state.DoS(0, false, REJECT_NONSTANDARD, "tx-size-small"); // Only accept nLockTime-using transactions that can be mined in the next @@ -602,10 +602,8 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool std::set<uint256> setConflicts; for (const CTxIn &txin : tx.vin) { - auto itConflicting = pool.mapNextTx.find(txin.prevout); - if (itConflicting != pool.mapNextTx.end()) - { - const CTransaction *ptxConflicting = itConflicting->second; + const CTransaction* ptxConflicting = pool.GetConflictTx(txin.prevout); + if (ptxConflicting) { if (!setConflicts.count(ptxConflicting->GetHash())) { // Allow opt-out of transaction replacement by setting @@ -786,16 +784,8 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool CFeeRate newFeeRate(nModifiedFees, nSize); std::set<uint256> setConflictsParents; const int maxDescendantsToVisit = 100; - CTxMemPool::setEntries setIterConflicting; - for (const uint256 &hashConflicting : setConflicts) - { - CTxMemPool::txiter mi = pool.mapTx.find(hashConflicting); - if (mi == pool.mapTx.end()) - continue; - - // Save these to avoid repeated lookups - setIterConflicting.insert(mi); - + const CTxMemPool::setEntries setIterConflicting = pool.GetIterSet(setConflicts); + for (const auto& mi : setIterConflicting) { // Don't allow the replacement to reduce the feerate of the // mempool. // @@ -861,11 +851,12 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // Rather than check the UTXO set - potentially expensive - // it's cheaper to just check if the new input refers to a // tx that's in the mempool. - if (pool.mapTx.find(tx.vin[j].prevout.hash) != pool.mapTx.end()) + if (pool.exists(tx.vin[j].prevout.hash)) { return state.DoS(0, false, REJECT_NONSTANDARD, "replacement-adds-unconfirmed", false, strprintf("replacement %s adds unconfirmed input, idx %d", hash.ToString(), j)); + } } } @@ -1060,7 +1051,7 @@ static bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMes return error("WriteBlockToDisk: OpenBlockFile failed"); // Write index header - unsigned int nSize = GetSerializeSize(fileout, block); + unsigned int nSize = GetSerializeSize(block, fileout.GetVersion()); fileout << messageStart << nSize; // Write block @@ -1470,7 +1461,7 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint return error("%s: OpenUndoFile failed", __func__); // Write index header - unsigned int nSize = GetSerializeSize(fileout, blockundo); + unsigned int nSize = GetSerializeSize(blockundo, fileout.GetVersion()); fileout << messageStart << nSize; // Write undo data @@ -1668,7 +1659,7 @@ static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, CValidationState& // Write undo information to disk if (pindex->GetUndoPos().IsNull()) { CDiskBlockPos _pos; - if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) + if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, CLIENT_VERSION) + 40)) return error("ConnectBlock(): FindUndoPos failed"); if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) return AbortNode(state, "Failed to write undo data"); @@ -3119,7 +3110,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P // checks that use witness data may be performed here. // Size limits - if (block.vtx.empty() || block.vtx.size() * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT) + if (block.vtx.empty() || block.vtx.size() * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT || ::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT) return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed"); // First transaction must be coinbase, the rest must not be @@ -3436,7 +3427,7 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio /** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ static CDiskBlockPos SaveBlockToDisk(const CBlock& block, int nHeight, const CChainParams& chainparams, const CDiskBlockPos* dbp) { - unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); + unsigned int nBlockSize = ::GetSerializeSize(block, CLIENT_VERSION); CDiskBlockPos blockPos; if (dbp != nullptr) blockPos = *dbp; @@ -4142,6 +4133,7 @@ bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view) for (int nHeight = nForkHeight + 1; nHeight <= pindexNew->nHeight; ++nHeight) { const CBlockIndex* pindex = pindexNew->GetAncestor(nHeight); LogPrintf("Rolling forward %s (%i)\n", pindex->GetBlockHash().ToString(), nHeight); + uiInterface.ShowProgress(_("Replaying blocks..."), (int) ((nHeight - nForkHeight) * 100.0 / (pindexNew->nHeight - nForkHeight)) , false); if (!RollforwardBlock(pindex, cache, params)) return false; } diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index b36287ff50..a299a4ee44 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -19,6 +19,9 @@ class WalletInit : public WalletInitInterface { public: + //! Was the wallet component compiled in. + bool HasWalletSupport() const override {return true;} + //! Return the wallets help message. void AddWalletOptions() const override; diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index af36d321d5..c82d0e97d4 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -849,6 +849,9 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con std::vector<unsigned char> vData(ParseHex(output)); script = CScript(vData.begin(), vData.end()); + if (!ExtractDestination(script, dest) && !internal) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set to true for nonstandard scriptPubKey imports."); + } } // Watchonly and private keys @@ -861,11 +864,6 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between internal and label"); } - // Not having Internal + Script - if (!internal && isScript) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set for hex scriptPubKey"); - } - // Keys / PubKeys size check. if (!isP2SH && (keys.size() > 1 || pubKeys.size() > 1)) { // Address / scriptPubKey throw JSONRPCError(RPC_INVALID_PARAMETER, "More than private key given for one address"); @@ -969,21 +967,10 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con CTxDestination pubkey_dest = pubKey.GetID(); // Consistency check. - if (!isScript && !(pubkey_dest == dest)) { + if (!(pubkey_dest == dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } - // Consistency check. - if (isScript) { - CTxDestination destination; - - if (ExtractDestination(script, destination)) { - if (!(destination == pubkey_dest)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); - } - } - } - CScript pubKeyScript = GetScriptForDestination(pubkey_dest); if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) { @@ -1034,21 +1021,10 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con CTxDestination pubkey_dest = pubKey.GetID(); // Consistency check. - if (!isScript && !(pubkey_dest == dest)) { + if (!(pubkey_dest == dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } - // Consistency check. - if (isScript) { - CTxDestination destination; - - if (ExtractDestination(script, destination)) { - if (!(destination == pubkey_dest)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); - } - } - } - CKeyID vchAddress = pubKey.GetID(); pwallet->MarkDirty(); pwallet->SetAddressBook(vchAddress, label, "receive"); @@ -1080,11 +1056,9 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } - if (scriptPubKey.getType() == UniValue::VOBJ) { - // add to address book or update label - if (IsValidDestination(dest)) { - pwallet->SetAddressBook(dest, label, "receive"); - } + // add to address book or update label + if (IsValidDestination(dest)) { + pwallet->SetAddressBook(dest, label, "receive"); } success = true; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e419f8d164..15f3e5947e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4065,6 +4065,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request); UniValue removeprunedfunds(const JSONRPCRequest& request); UniValue importmulti(const JSONRPCRequest& request); +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -4125,6 +4126,7 @@ static const CRPCCommand commands[] = { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} }, { "wallet", "walletprocesspsbt", &walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} }, }; +// clang-format on void RegisterWalletRPCCommands(CRPCTable &t) { diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index a24dc1b5f9..6d1d09d5a5 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -462,14 +462,19 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test) BOOST_CHECK(testWallet.SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, filter_confirmed, GroupCoins(vCoins), setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); + } - // test with many inputs - for (CAmount amt=1500; amt < COIN; amt*=10) { - empty_wallet(); - // Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 bytes per input) - for (uint16_t j = 0; j < 676; j++) - add_coin(amt); + // test with many inputs + for (CAmount amt=1500; amt < COIN; amt*=10) { + empty_wallet(); + // Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 bytes per input) + for (uint16_t j = 0; j < 676; j++) + add_coin(amt); + + // We only create the wallet once to save time, but we still run the coin selection RUN_TESTS times. + for (int i = 0; i < RUN_TESTS; i++) { BOOST_CHECK(testWallet.SelectCoinsMinConf(2000, filter_confirmed, GroupCoins(vCoins), setCoinsRet, nValueRet, coin_selection_params, bnb_used)); + if (amt - 2000 < MIN_CHANGE) { // needs more than one input: uint16_t returnSize = std::ceil((2000.0 + MIN_CHANGE)/amt); @@ -481,14 +486,17 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test) BOOST_CHECK_EQUAL(nValueRet, amt); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); } - } + } + } - // test randomness - { - empty_wallet(); - for (int i2 = 0; i2 < 100; i2++) - add_coin(COIN); + // test randomness + { + empty_wallet(); + for (int i2 = 0; i2 < 100; i2++) + add_coin(COIN); + // Again, we only create the wallet once to save time, but we still run the coin selection RUN_TESTS times. + for (int i = 0; i < RUN_TESTS; i++) { // picking 50 from 100 coins doesn't depend on the shuffle, // but does depend on randomness in the stochastic approximation code BOOST_CHECK(testWallet.SelectCoinsMinConf(50 * COIN, filter_standard, GroupCoins(vCoins), setCoinsRet , nValueRet, coin_selection_params, bnb_used)); @@ -506,17 +514,19 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test) fails++; } BOOST_CHECK_NE(fails, RANDOM_REPEATS); - - // add 75 cents in small change. not enough to make 90 cents, - // then try making 90 cents. there are multiple competing "smallest bigger" coins, - // one of which should be picked at random - add_coin(5 * CENT); - add_coin(10 * CENT); - add_coin(15 * CENT); - add_coin(20 * CENT); - add_coin(25 * CENT); - - fails = 0; + } + + // add 75 cents in small change. not enough to make 90 cents, + // then try making 90 cents. there are multiple competing "smallest bigger" coins, + // one of which should be picked at random + add_coin(5 * CENT); + add_coin(10 * CENT); + add_coin(15 * CENT); + add_coin(20 * CENT); + add_coin(25 * CENT); + + for (int i = 0; i < RUN_TESTS; i++) { + int fails = 0; for (int j = 0; j < RANDOM_REPEATS; j++) { // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time @@ -527,8 +537,9 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test) fails++; } BOOST_CHECK_NE(fails, RANDOM_REPEATS); - } - } + } + } + empty_wallet(); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 690c7936d8..f3d6d0056d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2657,7 +2657,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac scriptChange = GetScriptForDestination(GetDestinationForKey(vchPubKey, change_type)); } CTxOut change_prototype_txout(0, scriptChange); - coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout, SER_DISK, 0); + coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout); CFeeRate discard_rate = GetDiscardRate(*this, ::feeEstimator); @@ -2701,7 +2701,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac } } // Include the fee cost for outputs. Note this is only used for BnB right now - coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, SER_NETWORK, PROTOCOL_VERSION); + coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION); if (IsDust(txout, ::dustRelayFee)) { diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h index e955816162..6f12551273 100644 --- a/src/walletinitinterface.h +++ b/src/walletinitinterface.h @@ -12,6 +12,8 @@ class CRPCTable; class WalletInitInterface { public: + /** Is the wallet component enabled */ + virtual bool HasWalletSupport() const = 0; /** Get wallet help string */ virtual void AddWalletOptions() const = 0; /** Check wallet parameter interaction */ @@ -34,4 +36,6 @@ public: virtual ~WalletInitInterface() {} }; +extern const WalletInitInterface& g_wallet_init_interface; + #endif // BITCOIN_WALLETINITINTERFACE_H diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json index 9f970b4961..dd40a096de 100644 --- a/test/functional/data/rpc_psbt.json +++ b/test/functional/data/rpc_psbt.json @@ -69,14 +69,6 @@ }, { "privkeys" : [ - "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au", - "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE" - ], - "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA", - "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210cwRAIgYxqYn+c4qSrQGYYCMxLBkhT+KAKznly8GsNniAbGksMCIDnbbDh70mdxbf2z1NjaULjoXSEzJrp8faqkwM5B65IjAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgICOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==" - }, - { - "privkeys" : [ "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE" ], "psbt" : "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEBItPf9QUAAAAAGXapFNSO0xELlAFMsRS9Mtb00GbcdCVriKwAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=", diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 3edd760b90..4c9d60b337 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -67,10 +67,11 @@ def custom_function(): # self.log.info("running custom_function") # Oops! Can't run self.log outside the BitcoinTestFramework pass + class ExampleTest(BitcoinTestFramework): # Each functional test is a subclass of the BitcoinTestFramework class. - # Override the set_test_params(), add_options(), setup_chain(), setup_network() + # Override the set_test_params(), skip_test_if_missing_module(), add_options(), setup_chain(), setup_network() # and setup_nodes() methods to customize the test setup as required. def set_test_params(self): @@ -84,6 +85,9 @@ class ExampleTest(BitcoinTestFramework): # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + # Use add_options() to add specific command-line options for your test. # In practice this is not used very much, since the tests are mostly written # to be run in automated environments without command-line options. diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py index 4a9445f503..8466f851ca 100755 --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -25,6 +25,9 @@ class BIP68Test(BitcoinTestFramework): self.num_nodes = 2 self.extra_args = [[], ["-acceptnonstdtxn=0"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"] diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 71c3a396c1..6e36ea5601 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -75,6 +75,9 @@ class FullBlockTest(BitcoinTestFramework): self.setup_clean_chain = True self.extra_args = [[]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): node = self.nodes[0] # convenience reference to the node diff --git a/test/functional/feature_blocksdir.py b/test/functional/feature_blocksdir.py index 784dc2865f..824f0d7e09 100755 --- a/test/functional/feature_blocksdir.py +++ b/test/functional/feature_blocksdir.py @@ -16,6 +16,9 @@ class BlocksdirTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.stop_node(0) shutil.rmtree(self.nodes[0].datadir) diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index 615b0f8a4a..f84b08a199 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -62,6 +62,9 @@ class BIP65Test(BitcoinTestFramework): self.extra_args = [['-whitelist=127.0.0.1', '-par=1']] # Use only one script thread to get the exact reject reason for testing self.setup_clean_chain = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.nodes[0].add_p2p_connection(P2PInterface()) diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index 9be59b32b4..1124119e2b 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -14,6 +14,9 @@ class ConfArgsTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def test_config_file_parser(self): # Assume node is stopped diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index 302cfe4266..df79c4312c 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -145,6 +145,9 @@ class BIP68_112_113Test(BitcoinTestFramework): self.setup_clean_chain = True self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4', '-addresstype=legacy']] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def generate_blocks(self, number, version, test_blocks=None): if test_blocks is None: test_blocks = [] diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py index d612dbe2bc..ae1eacf2d7 100755 --- a/test/functional/feature_dbcrash.py +++ b/test/functional/feature_dbcrash.py @@ -63,6 +63,9 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): self.node3_args = ["-blockmaxweight=4000000"] self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): self.add_nodes(self.num_nodes, extra_args=self.extra_args) self.start_nodes() diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index 6072c5c178..16272877e7 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -49,6 +49,9 @@ class BIP66Test(BitcoinTestFramework): self.extra_args = [['-whitelist=127.0.0.1', '-par=1', '-enablebip61']] # Use only one script thread to get the exact reject reason for testing self.setup_clean_chain = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.nodes[0].add_p2p_connection(P2PInterface()) diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py index 709910f2e4..aaab4279b5 100755 --- a/test/functional/feature_fee_estimation.py +++ b/test/functional/feature_fee_estimation.py @@ -126,6 +126,9 @@ class EstimateFeeTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 3 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): """ We'll setup the network to have 3 nodes that all mine with different parameters. @@ -168,6 +171,11 @@ class EstimateFeeTest(BitcoinTestFramework): newmem.append(utx) self.memutxo = newmem + def import_deterministic_coinbase_privkeys(self): + self.start_nodes() + super().import_deterministic_coinbase_privkeys() + self.stop_nodes() + def run_test(self): self.log.info("This test is time consuming, please be patient") self.log.info("Splitting inputs so we can generate tx's") diff --git a/test/functional/feature_logging.py b/test/functional/feature_logging.py index 8bb7e02695..a74c413440 100755 --- a/test/functional/feature_logging.py +++ b/test/functional/feature_logging.py @@ -15,6 +15,9 @@ class LoggingTest(BitcoinTestFramework): self.num_nodes = 1 self.setup_clean_chain = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def relative_log_path(self, name): return os.path.join(self.nodes[0].datadir, "regtest", name) diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index a81ebb4220..87c318de9a 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -40,6 +40,9 @@ class MaxUploadTest(BitcoinTestFramework): # Cache for utxos, as the listunspent may take a long time later in the test self.utxo_cache = [] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): # Before we connect anything, we first set the time on the node # to be in the past, otherwise things break because the CNode diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py index a1cced0bc7..5d180c2244 100755 --- a/test/functional/feature_minchainwork.py +++ b/test/functional/feature_minchainwork.py @@ -31,6 +31,9 @@ class MinimumChainWorkTest(BitcoinTestFramework): self.extra_args = [[], ["-minimumchainwork=0x65"], ["-minimumchainwork=0x65"]] self.node_min_work = [0, 101, 101] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): # This test relies on the chain setup being: # node0 <- node1 <- node2 diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py index 71e5e493aa..25a7329a0d 100755 --- a/test/functional/feature_notifications.py +++ b/test/functional/feature_notifications.py @@ -13,6 +13,9 @@ class NotificationsTest(BitcoinTestFramework): self.num_nodes = 2 self.setup_clean_chain = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") self.block_filename = os.path.join(self.options.tmpdir, "blocks.txt") diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index 9d1805ec2d..a79cc3d34b 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -44,9 +44,12 @@ class NULLDUMMYTest(BitcoinTestFramework): # normal segwit activation here (and don't use the default always-on behaviour). self.extra_args = [['-whitelist=127.0.0.1', '-vbparams=segwit:0:999999999999', '-addresstype=legacy', "-deprecatedrpc=addwitnessaddress"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.address = self.nodes[0].getnewaddress() - self.ms_address = self.nodes[0].addmultisigaddress(1,[self.address])['address'] + self.ms_address = self.nodes[0].addmultisigaddress(1, [self.address])['address'] self.wit_address = self.nodes[0].addwitnessaddress(self.address) self.wit_ms_address = self.nodes[0].addmultisigaddress(1, [self.address], '', 'p2sh-segwit')['address'] diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py index c8f4b7f8b5..772151dc4b 100755 --- a/test/functional/feature_pruning.py +++ b/test/functional/feature_pruning.py @@ -33,15 +33,20 @@ class PruneTest(BitcoinTestFramework): # Create nodes 0 and 1 to mine. # Create node 2 to test pruning. - self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5", "-limitdescendantcount=100", "-limitdescendantsize=5000", "-limitancestorcount=100", "-limitancestorsize=5000" ] + self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5", "-limitdescendantcount=100", "-limitdescendantsize=5000", "-limitancestorcount=100", "-limitancestorsize=5000"] # Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later) # Create nodes 5 to test wallet in prune mode, but do not connect - self.extra_args = [self.full_node_default_args, - self.full_node_default_args, - ["-maxreceivebuffer=20000", "-prune=550"], - ["-maxreceivebuffer=20000"], - ["-maxreceivebuffer=20000"], - ["-prune=550"]] + self.extra_args = [ + self.full_node_default_args, + self.full_node_default_args, + ["-maxreceivebuffer=20000", "-prune=550"], + ["-maxreceivebuffer=20000"], + ["-maxreceivebuffer=20000"], + ["-prune=550"], + ] + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() def setup_network(self): self.setup_nodes() diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index 7e84ba43b5..ff7c2b23bf 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -61,17 +61,26 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])): return COutPoint(int(txid, 16), 0) -class ReplaceByFeeTest(BitcoinTestFramework): +class ReplaceByFeeTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 - self.extra_args= [["-maxorphantx=1000", - "-whitelist=127.0.0.1", - "-limitancestorcount=50", - "-limitancestorsize=101", - "-limitdescendantcount=200", - "-limitdescendantsize=101"], - ["-mempoolreplacement=0"]] + self.extra_args = [ + [ + "-maxorphantx=1000", + "-whitelist=127.0.0.1", + "-limitancestorcount=50", + "-limitancestorsize=101", + "-limitdescendantcount=200", + "-limitdescendantsize=101", + ], + [ + "-mempoolreplacement=0", + ], + ] + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() def run_test(self): # Leave IBD diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py index f30e1191e3..3727eeaeae 100755 --- a/test/functional/feature_reindex.py +++ b/test/functional/feature_reindex.py @@ -18,6 +18,9 @@ class ReindexTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def reindex(self, justchainstate=False): self.nodes[0].generate(3) blockcount = self.nodes[0].getblockcount() diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index 13d7758e13..2cbfc26e89 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -46,9 +46,30 @@ class SegWitTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 3 # This test tests SegWit both pre and post-activation, so use the normal BIP9 activation. - self.extra_args = [["-rpcserialversion=0", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"], - ["-blockversion=4", "-rpcserialversion=1", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"], - ["-blockversion=536870915", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"]] + self.extra_args = [ + [ + "-rpcserialversion=0", + "-vbparams=segwit:0:999999999999", + "-addresstype=legacy", + "-deprecatedrpc=addwitnessaddress", + ], + [ + "-blockversion=4", + "-rpcserialversion=1", + "-vbparams=segwit:0:999999999999", + "-addresstype=legacy", + "-deprecatedrpc=addwitnessaddress", + ], + [ + "-blockversion=536870915", + "-vbparams=segwit:0:999999999999", + "-addresstype=legacy", + "-deprecatedrpc=addwitnessaddress", + ], + ] + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() def setup_network(self): super().setup_network() diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py index 896c36fa53..cf77720437 100755 --- a/test/functional/feature_versionbits_warning.py +++ b/test/functional/feature_versionbits_warning.py @@ -31,6 +31,9 @@ class VersionBitsWarningTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") # Open and close to create zero-length file diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py index d3b85ce948..f311858bee 100755 --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -12,6 +12,9 @@ class TestBitcoinCli(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): """Main test logic""" diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py index 41a1b4a35d..afa9de580f 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -43,6 +43,9 @@ class RESTTest (BitcoinTestFramework): self.num_nodes = 2 self.extra_args = [["-rest"], []] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def test_rest_request(self, uri, http_method='GET', req_type=ReqType.JSON, body='', status=200, ret_type=RetType.JSON): rest_uri = '/rest' + uri if req_type == ReqType.JSON: diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py index 72de696259..c853ba7e3f 100755 --- a/test/functional/interface_zmq.py +++ b/test/functional/interface_zmq.py @@ -5,15 +5,16 @@ """Test the ZMQ notification interface.""" import struct -from test_framework.test_framework import ( - BitcoinTestFramework, skip_if_no_bitcoind_zmq, skip_if_no_py3_zmq) +from test_framework.test_framework import BitcoinTestFramework from test_framework.messages import CTransaction -from test_framework.util import (assert_equal, - bytes_to_hex_str, - hash256, - ) +from test_framework.util import ( + assert_equal, + bytes_to_hex_str, + hash256, +) from io import BytesIO + class ZMQSubscriber: def __init__(self, socket, topic): self.sequence = 0 @@ -37,9 +38,18 @@ class ZMQTest (BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 + def skip_test_if_missing_module(self): + self.skip_if_no_py3_zmq() + self.skip_if_no_bitcoind_zmq() + self.skip_if_no_wallet() + def setup_nodes(self): - skip_if_no_py3_zmq() - skip_if_no_bitcoind_zmq(self) + # Import keys + self.add_nodes(self.num_nodes) + self.start_nodes() + super().import_deterministic_coinbase_privkeys() + self.stop_nodes() + import zmq # Initialize ZMQ context and socket. @@ -59,10 +69,12 @@ class ZMQTest (BitcoinTestFramework): self.rawblock = ZMQSubscriber(socket, b"rawblock") self.rawtx = ZMQSubscriber(socket, b"rawtx") - self.extra_args = [["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]], []] - self.add_nodes(self.num_nodes, self.extra_args) + self.nodes[0].extra_args = ["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]] self.start_nodes() + def import_deterministic_coinbase_privkeys(self): + pass + def run_test(self): try: self._zmq_test() diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index 44426a0ff7..8847777ba7 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -40,6 +40,9 @@ class MempoolAcceptanceTest(BitcoinTestFramework): '-acceptnonstdtxn=0', # Try to mimic main-net ]] * self.num_nodes + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def check_mempool_result(self, result_expected, *args, **kwargs): """Wrapper to check result of testmempoolaccept on node_0's mempool""" result_test = self.nodes[0].testmempoolaccept(*args, **kwargs) diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py index 55422b67df..c0918893cd 100755 --- a/test/functional/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -15,6 +15,9 @@ class MempoolLimitTest(BitcoinTestFramework): self.num_nodes = 1 self.extra_args = [["-maxmempool=5", "-spendzeroconfchange=0"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): txouts = gen_return_txouts() relayfee = self.nodes[0].getnetworkinfo()['relayfee'] diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py index da254181fe..9336547a6b 100755 --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -18,6 +18,9 @@ class MempoolPackagesTest(BitcoinTestFramework): self.num_nodes = 2 self.extra_args = [["-maxorphantx=1000"], ["-maxorphantx=1000", "-limitancestorcount=5"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + # Build a transaction that spends parent_txid:vout # Return amount sent def chain_transaction(self, node, parent_txid, vout, value, fee, num_outputs): @@ -34,7 +37,7 @@ class MempoolPackagesTest(BitcoinTestFramework): return (txid, send_value) def run_test(self): - ''' Mine some blocks and have them mature. ''' + # Mine some blocks and have them mature. self.nodes[0].generate(101) utxo = self.nodes[0].listunspent(10) txid = utxo[0]['txid'] diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index 6e5f89efb8..b4e9d967fd 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -47,6 +47,9 @@ class MempoolPersistTest(BitcoinTestFramework): self.num_nodes = 3 self.extra_args = [[], ["-persistmempool=0"], []] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): chain_height = self.nodes[0].getblockcount() assert_equal(chain_height, 200) diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py index faa00d56cf..123f0b4c28 100755 --- a/test/functional/mempool_reorg.py +++ b/test/functional/mempool_reorg.py @@ -17,6 +17,9 @@ class MempoolCoinbaseTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + alert_filename = None # Set by setup_network def run_test(self): diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py index 23939f0be5..d035ca907a 100755 --- a/test/functional/mempool_resurrect.py +++ b/test/functional/mempool_resurrect.py @@ -13,6 +13,9 @@ class MempoolCoinbaseTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): node0_address = self.nodes[0].getnewaddress() # Spend block 1/2/3's coinbase transactions diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py index ce3bc3b7e0..854d506f0d 100755 --- a/test/functional/mempool_spend_coinbase.py +++ b/test/functional/mempool_spend_coinbase.py @@ -21,6 +21,9 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): chain_height = self.nodes[0].getblockcount() assert_equal(chain_height, 200) diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index b675cd882f..f95ad31e7c 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -38,9 +38,18 @@ class MiningTest(BitcoinTestFramework): self.num_nodes = 2 self.setup_clean_chain = False + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): node = self.nodes[0] + def assert_submitblock(block, result_str_1, result_str_2=None): + block.solve() + result_str_2 = result_str_2 or 'duplicate-invalid' + assert_equal(result_str_1, node.submitblock(hexdata=b2x(block.serialize()))) + assert_equal(result_str_2, node.submitblock(hexdata=b2x(block.serialize()))) + self.log.info('getmininginfo') mining_info = node.getmininginfo() assert_equal(mining_info['blocks'], 200) @@ -93,6 +102,7 @@ class MiningTest(BitcoinTestFramework): bad_block = copy.deepcopy(block) bad_block.vtx.append(bad_block.vtx[0]) assert_template(node, bad_block, 'bad-txns-duplicate') + assert_submitblock(bad_block, 'bad-txns-duplicate', 'bad-txns-duplicate') self.log.info("getblocktemplate: Test invalid transaction") bad_block = copy.deepcopy(block) @@ -101,12 +111,14 @@ class MiningTest(BitcoinTestFramework): bad_tx.rehash() bad_block.vtx.append(bad_tx) assert_template(node, bad_block, 'bad-txns-inputs-missingorspent') + assert_submitblock(bad_block, 'bad-txns-inputs-missingorspent') self.log.info("getblocktemplate: Test nonfinal transaction") bad_block = copy.deepcopy(block) bad_block.vtx[0].nLockTime = 2 ** 32 - 1 bad_block.vtx[0].rehash() assert_template(node, bad_block, 'bad-txns-nonfinal') + assert_submitblock(bad_block, 'bad-txns-nonfinal') self.log.info("getblocktemplate: Test bad tx count") # The tx count is immediately after the block header @@ -125,24 +137,29 @@ class MiningTest(BitcoinTestFramework): bad_block = copy.deepcopy(block) bad_block.hashMerkleRoot += 1 assert_template(node, bad_block, 'bad-txnmrklroot', False) + assert_submitblock(bad_block, 'bad-txnmrklroot', 'bad-txnmrklroot') self.log.info("getblocktemplate: Test bad timestamps") bad_block = copy.deepcopy(block) bad_block.nTime = 2 ** 31 - 1 assert_template(node, bad_block, 'time-too-new') + assert_submitblock(bad_block, 'time-too-new', 'time-too-new') bad_block.nTime = 0 assert_template(node, bad_block, 'time-too-old') + assert_submitblock(bad_block, 'time-too-old', 'time-too-old') self.log.info("getblocktemplate: Test not best block") bad_block = copy.deepcopy(block) bad_block.hashPrevBlock = 123 assert_template(node, bad_block, 'inconclusive-not-best-prevblk') + assert_submitblock(bad_block, 'prev-blk-not-found', 'prev-blk-not-found') self.log.info('submitheader tests') assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * 80)) assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * 78)) assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata='ff' * 80)) + block.nTime += 1 block.solve() def chain_tip(b_hash, *, status='headers-only', branchlen=1): @@ -161,7 +178,8 @@ class MiningTest(BitcoinTestFramework): node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize())) assert chain_tip(bad_block_root.hash) in node.getchaintips() # Should still reject invalid blocks, even if we have the header: - assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'invalid') + assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot') + assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot') assert chain_tip(bad_block_root.hash) in node.getchaintips() # We know the header for this invalid block, so should just return early without error: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize())) @@ -172,7 +190,8 @@ class MiningTest(BitcoinTestFramework): bad_block_lock.vtx[0].rehash() bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root() bad_block_lock.solve() - assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'invalid') + assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'bad-txns-nonfinal') + assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'duplicate-invalid') # Build a "good" block on top of the submitted bad block bad_block2 = copy.deepcopy(block) bad_block2.hashPrevBlock = bad_block_lock.sha256 @@ -198,6 +217,7 @@ class MiningTest(BitcoinTestFramework): assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize()))) node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize())) + assert_equal(node.submitblock(hexdata=b2x(block.serialize())), 'duplicate') # valid if __name__ == '__main__': diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py index 1259754c5a..9a3c15a4a7 100755 --- a/test/functional/mining_getblocktemplate_longpoll.py +++ b/test/functional/mining_getblocktemplate_longpoll.py @@ -28,6 +28,9 @@ class GetBlockTemplateLPTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.") self.nodes[0].generate(10) @@ -70,4 +73,3 @@ class GetBlockTemplateLPTest(BitcoinTestFramework): if __name__ == '__main__': GetBlockTemplateLPTest().main() - diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py index bb0cc082ab..92590717f3 100755 --- a/test/functional/mining_prioritisetransaction.py +++ b/test/functional/mining_prioritisetransaction.py @@ -16,6 +16,9 @@ class PrioritiseTransactionTest(BitcoinTestFramework): self.num_nodes = 2 self.extra_args = [["-printpriority=1"], ["-printpriority=1"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): # Test `prioritisetransaction` required parameters assert_raises_rpc_error(-1, "prioritisetransaction", self.nodes[0].prioritisetransaction) diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index 5cec5dc6f0..3a5bdf806b 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -102,6 +102,9 @@ class CompactBlocksTest(BitcoinTestFramework): self.extra_args = [["-vbparams=segwit:0:0"], ["-vbparams=segwit:0:999999999999", "-txindex", "-deprecatedrpc=addwitnessaddress"]] self.utxos = [] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def build_block_on_tip(self, node, segwit=False): height = node.getblockcount() tip = node.getbestblockhash() diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py index 3bc7734e75..d589519e45 100755 --- a/test/functional/p2p_feefilter.py +++ b/test/functional/p2p_feefilter.py @@ -42,6 +42,9 @@ class FeeFilterTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): node1 = self.nodes[1] node0 = self.nodes[0] diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py index 4a6ffced93..884fb4b063 100755 --- a/test/functional/p2p_fingerprint.py +++ b/test/functional/p2p_fingerprint.py @@ -30,6 +30,9 @@ class P2PFingerprintTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + # Build a chain of blocks on top of given one def build_chain(self, nblocks, prev_hash, prev_height, prev_median_time): blocks = [] diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py index b3f4d721f9..fd6b84f8b2 100755 --- a/test/functional/p2p_invalid_block.py +++ b/test/functional/p2p_invalid_block.py @@ -24,6 +24,9 @@ class InvalidBlockRequestTest(BitcoinTestFramework): self.setup_clean_chain = True self.extra_args = [["-whitelist=127.0.0.1"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): # Add p2p connection to node0 node = self.nodes[0] # convenience reference to the node diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py index 3b1654f920..4cc43a4fa4 100755 --- a/test/functional/p2p_invalid_locator.py +++ b/test/functional/p2p_invalid_locator.py @@ -15,6 +15,9 @@ class InvalidLocatorTest(BitcoinTestFramework): self.num_nodes = 1 self.setup_clean_chain = False + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): node = self.nodes[0] # convenience reference to the node node.generate(1) # Get node out of IBD diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py index 69d5dd9f9a..2f19b4d933 100755 --- a/test/functional/p2p_invalid_tx.py +++ b/test/functional/p2p_invalid_tx.py @@ -26,6 +26,9 @@ class InvalidTxRequestTest(BitcoinTestFramework): self.num_nodes = 1 self.setup_clean_chain = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def bootstrap_p2p(self, *, num_connections=1): """Add a P2P connection to the node. diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py index dcbf833e7c..05354d17e1 100755 --- a/test/functional/p2p_leak.py +++ b/test/functional/p2p_leak.py @@ -93,6 +93,9 @@ class P2PLeakTest(BitcoinTestFramework): self.num_nodes = 1 self.extra_args = [['-banscore=' + str(banscore)]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): no_version_bannode = self.nodes[0].add_p2p_connection(CNodeNoVersionBan(), send_version=False, wait_for_verack=False) no_version_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVersionIdle(), send_version=False, wait_for_verack=False) diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py index 4740740d42..a16c6a1d47 100755 --- a/test/functional/p2p_node_network_limited.py +++ b/test/functional/p2p_node_network_limited.py @@ -34,6 +34,9 @@ class NodeNetworkLimitedTest(BitcoinTestFramework): self.num_nodes = 3 self.extra_args = [['-prune=550', '-addrmantest'], [], []] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def disconnect_all(self): disconnect_nodes(self.nodes[0], 1) disconnect_nodes(self.nodes[1], 0) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 043fa67f77..de12ab1ed6 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -188,6 +188,9 @@ class SegWitTest(BitcoinTestFramework): # This test tests SegWit both pre and post-activation, so use the normal BIP9 activation. self.extra_args = [["-whitelist=127.0.0.1", "-vbparams=segwit:0:999999999999"], ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0", "-vbparams=segwit:0:999999999999"], ["-whitelist=127.0.0.1", "-vbparams=segwit:0:0"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): self.setup_nodes() connect_nodes(self.nodes[0], 1) diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py index 9cc496d510..9a782c0bb9 100755 --- a/test/functional/p2p_sendheaders.py +++ b/test/functional/p2p_sendheaders.py @@ -208,6 +208,9 @@ class SendHeadersTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 2 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def mine_blocks(self, count): """Mine count blocks and return the new tip.""" diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py index 2e86954aba..232274f59e 100755 --- a/test/functional/p2p_unrequested_blocks.py +++ b/test/functional/p2p_unrequested_blocks.py @@ -66,6 +66,9 @@ class AcceptBlockTest(BitcoinTestFramework): self.num_nodes = 2 self.extra_args = [[], ["-minimumchainwork=0x10"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): # Node0 will be used to test behavior of processing unrequested blocks # from peers which are not whitelisted, while Node1 will be used for diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index d681cdc8ab..00317a2c08 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -47,9 +47,13 @@ from test_framework.mininode import ( class BlockchainTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.extra_args = [['-stopatheight=207', '-prune=1']] + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() def run_test(self): + self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1']) # Set extra args with pruning after rescan is complete + self._test_getblockchaininfo() self._test_getchaintxstats() self._test_gettxoutsetinfo() @@ -169,7 +173,7 @@ class BlockchainTest(BitcoinTestFramework): assert_equal(res['transactions'], 200) assert_equal(res['height'], 200) assert_equal(res['txouts'], 200) - assert_equal(res['bogosize'], 17000), + assert_equal(res['bogosize'], 15000), assert_equal(res['bestblock'], node.getblockhash(200)) size = res['disk_size'] assert size > 6400 diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index f346e1ebfc..3cc35a7b9a 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -12,8 +12,11 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 3 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def get_keys(self): - node0,node1,node2 = self.nodes + node0, node1, node2 = self.nodes self.add = [node1.getnewaddress() for _ in range(self.nkeys)] self.pub = [node1.getaddressinfo(a)["pubkey"] for a in self.add] self.priv = [node1.dumpprivkey(a) for a in self.add] diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index a806de43b4..daa890ab15 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -29,6 +29,9 @@ class RawTransactionsTest(BitcoinTestFramework): self.num_nodes = 4 self.setup_clean_chain = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self, split=False): self.setup_nodes() diff --git a/test/functional/rpc_getchaintips.py b/test/functional/rpc_getchaintips.py index 07929ca0a1..bc19c60dde 100755 --- a/test/functional/rpc_getchaintips.py +++ b/test/functional/rpc_getchaintips.py @@ -17,15 +17,18 @@ class GetChainTipsTest (BitcoinTestFramework): def set_test_params(self): self.num_nodes = 4 - def run_test (self): - tips = self.nodes[0].getchaintips () - assert_equal (len (tips), 1) - assert_equal (tips[0]['branchlen'], 0) - assert_equal (tips[0]['height'], 200) - assert_equal (tips[0]['status'], 'active') + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + tips = self.nodes[0].getchaintips() + assert_equal(len(tips), 1) + assert_equal(tips[0]['branchlen'], 0) + assert_equal(tips[0]['height'], 200) + assert_equal(tips[0]['status'], 'active') # Split the network and build two chains of different lengths. - self.split_network () + self.split_network() self.nodes[0].generate(10) self.nodes[2].generate(20) self.sync_all([self.nodes[:2], self.nodes[2:]]) diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py index ceca40527f..be096af892 100755 --- a/test/functional/rpc_help.py +++ b/test/functional/rpc_help.py @@ -4,9 +4,10 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test RPC help output.""" -from test_framework.test_framework import BitcoinTestFramework, is_zmq_enabled +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error + class HelpRpcTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 @@ -26,12 +27,16 @@ class HelpRpcTest(BitcoinTestFramework): # command titles titles = [line[3:-3] for line in node.help().splitlines() if line.startswith('==')] - components = ['Blockchain', 'Control', 'Generating', 'Mining', 'Network', 'Rawtransactions', 'Util', 'Wallet'] + components = ['Blockchain', 'Control', 'Generating', 'Mining', 'Network', 'Rawtransactions', 'Util'] + + if self.is_wallet_compiled(): + components.append('Wallet') - if is_zmq_enabled(self): + if self.is_zmq_compiled(): components.append('Zmq') assert_equal(titles, components) + if __name__ == '__main__': HelpRpcTest().main() diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py index f40710ef74..84f7cd05fb 100755 --- a/test/functional/rpc_invalidateblock.py +++ b/test/functional/rpc_invalidateblock.py @@ -14,6 +14,9 @@ class InvalidateTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 3 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): self.setup_nodes() diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py index 1e20d1a046..f383b82bb5 100755 --- a/test/functional/rpc_preciousblock.py +++ b/test/functional/rpc_preciousblock.py @@ -38,6 +38,9 @@ class PreciousTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 3 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): self.setup_nodes() diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index a693b7e4bb..54dc871448 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -20,6 +20,9 @@ class PSBTTest(BitcoinTestFramework): self.setup_clean_chain = False self.num_nodes = 3 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): # Create and fund a raw tx for sending 10 BTC psbtx1 = self.nodes[0].walletcreatefundedpsbt([], {self.nodes[2].getnewaddress():10})['psbt'] diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 8169f2b981..d86b546c7d 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -44,6 +44,9 @@ class RawTransactionsTest(BitcoinTestFramework): self.num_nodes = 3 self.extra_args = [["-addresstype=legacy"], ["-addresstype=legacy"], ["-addresstype=legacy"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self, split=False): super().setup_network() connect_nodes_bi(self.nodes, 0, 2) diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py index ceb38e969a..96f9ccdbdb 100755 --- a/test/functional/rpc_scantxoutset.py +++ b/test/functional/rpc_scantxoutset.py @@ -14,6 +14,10 @@ class ScantxoutsetTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.log.info("Mining blocks...") self.nodes[0].generate(110) diff --git a/test/functional/rpc_signmessage.py b/test/functional/rpc_signmessage.py index 449c4075bd..ad0e29b451 100755 --- a/test/functional/rpc_signmessage.py +++ b/test/functional/rpc_signmessage.py @@ -13,6 +13,9 @@ class SignMessagesTest(BitcoinTestFramework): self.num_nodes = 1 self.extra_args = [["-addresstype=legacy"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): message = 'This is just a test message' diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index f6eea1a027..5c07f2ccae 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -14,6 +14,9 @@ class SignRawTransactionsTest(BitcoinTestFramework): self.num_nodes = 1 self.extra_args = [["-deprecatedrpc=signrawtransaction"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def successful_signing_test(self): """Create and sign a valid raw transaction with one input. diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py index f9f8574646..867ba25022 100755 --- a/test/functional/rpc_txoutproof.py +++ b/test/functional/rpc_txoutproof.py @@ -15,6 +15,9 @@ class MerkleBlockTest(BitcoinTestFramework): # Nodes 0/1 are "wallet" nodes, Nodes 2/3 are used for testing self.extra_args = [[], [], [], ["-txindex"]] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): self.setup_nodes() connect_nodes(self.nodes[0], 1) diff --git a/test/functional/rpc_zmq.py b/test/functional/rpc_zmq.py index 6dbc726d5e..bfa6b06f67 100755 --- a/test/functional/rpc_zmq.py +++ b/test/functional/rpc_zmq.py @@ -4,8 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test for the ZMQ RPC methods.""" -from test_framework.test_framework import ( - BitcoinTestFramework, skip_if_no_py3_zmq, skip_if_no_bitcoind_zmq) +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal @@ -17,9 +16,11 @@ class RPCZMQTest(BitcoinTestFramework): self.num_nodes = 1 self.setup_clean_chain = True + def skip_test_if_missing_module(self): + self.skip_if_no_py3_zmq() + self.skip_if_no_bitcoind_zmq() + def run_test(self): - skip_if_no_py3_zmq() - skip_if_no_bitcoind_zmq(self) self._test_getzmqnotifications() def _test_getzmqnotifications(self): diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 0e76b52570..57c985b2a2 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -44,6 +44,13 @@ TEST_EXIT_FAILED = 1 TEST_EXIT_SKIPPED = 77 +class SkipTest(Exception): + """This exception is raised to skip a test""" + + def __init__(self, message): + self.message = message + + class BitcoinTestMetaClass(type): """Metaclass for BitcoinTestFramework. @@ -156,8 +163,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): try: if self.options.usecli and not self.supports_cli: raise SkipTest("--usecli specified but test does not support using CLI") + self.skip_test_if_missing_module() self.setup_chain() self.setup_network() + self.import_deterministic_coinbase_privkeys() self.run_test() success = TestStatus.PASSED except JSONRPCException as e: @@ -220,6 +229,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): """Override this method to add command-line options to the test""" pass + def skip_test_if_missing_module(self): + """Override this method to skip a test if a module is not compiled""" + pass + def setup_chain(self): """Override this method to customize blockchain setup""" self.log.info("Initializing test directory " + self.options.tmpdir) @@ -247,6 +260,19 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.add_nodes(self.num_nodes, extra_args) self.start_nodes() + def import_deterministic_coinbase_privkeys(self): + if self.setup_clean_chain: + return + + for n in self.nodes: + try: + n.getwalletinfo() + except JSONRPCException as e: + assert str(e).startswith('Method not found') + continue + + n.importprivkey(n.get_deterministic_priv_key()[1]) + def run_test(self): """Tests must override this method to define test logic""" raise NotImplementedError @@ -415,7 +441,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): # Create cache directories, run bitcoinds: for i in range(MAX_NODES): datadir = initialize_datadir(self.options.cachedir, i) - args = [self.options.bitcoind, "-datadir=" + datadir] + args = [self.options.bitcoind, "-datadir=" + datadir, '-disablewallet'] if i > 0: args.append("-connect=127.0.0.1:" + str(p2p_port(0))) self.nodes.append(TestNode(i, get_datadir_path(self.options.cachedir, i), extra_conf=["bind=127.0.0.1"], extra_args=[], rpchost=None, timewait=self.rpc_timewait, bitcoind=self.options.bitcoind, bitcoin_cli=self.options.bitcoincli, mocktime=self.mocktime, coverage_dir=None)) @@ -439,7 +465,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): for peer in range(4): for j in range(25): set_node_times(self.nodes, block_time) - self.nodes[peer].generate(1) + self.nodes[peer].generatetoaddress(1, self.nodes[peer].get_deterministic_priv_key()[0]) block_time += 10 * 60 # Must sync before next peer starts generating blocks sync_blocks(self.nodes) @@ -453,8 +479,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): return os.path.join(get_datadir_path(self.options.cachedir, n), "regtest", *paths) for i in range(MAX_NODES): + os.rmdir(cache_path(i, 'wallets')) # Remove empty wallets dir for entry in os.listdir(cache_path(i)): - if entry not in ['wallets', 'chainstate', 'blocks']: + if entry not in ['chainstate', 'blocks']: os.remove(cache_path(i, entry)) for i in range(self.num_nodes): @@ -471,30 +498,45 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): for i in range(self.num_nodes): initialize_datadir(self.options.tmpdir, i) + def skip_if_no_py3_zmq(self): + """Attempt to import the zmq package and skip the test if the import fails.""" + try: + import zmq # noqa + except ImportError: + raise SkipTest("python3-zmq module not available.") + + def skip_if_no_bitcoind_zmq(self): + """Skip the running test if bitcoind has not been compiled with zmq support.""" + if not self.is_zmq_compiled(): + raise SkipTest("bitcoind has not been built with zmq enabled.") + + def skip_if_no_wallet(self): + """Skip the running test if wallet has not been compiled.""" + if not self.is_wallet_compiled(): + raise SkipTest("wallet has not been compiled.") + + def skip_if_no_cli(self): + """Skip the running test if bitcoin-cli has not been compiled.""" + if not self.is_cli_compiled(): + raise SkipTest("bitcoin-cli has not been compiled.") + + def is_cli_compiled(self): + """Checks whether bitcoin-cli was compiled.""" + config = configparser.ConfigParser() + config.read_file(open(self.options.configfile)) -class SkipTest(Exception): - """This exception is raised to skip a test""" - def __init__(self, message): - self.message = message - - -def skip_if_no_py3_zmq(): - """Attempt to import the zmq package and skip the test if the import fails.""" - try: - import zmq # noqa - except ImportError: - raise SkipTest("python3-zmq module not available.") - + return config["components"].getboolean("ENABLE_UTILS") -def skip_if_no_bitcoind_zmq(test_instance): - """Skip the running test if bitcoind has not been compiled with zmq support.""" - if not is_zmq_enabled(test_instance): - raise SkipTest("bitcoind has not been built with zmq enabled.") + def is_wallet_compiled(self): + """Checks whether the wallet module was compiled.""" + config = configparser.ConfigParser() + config.read_file(open(self.options.configfile)) + return config["components"].getboolean("ENABLE_WALLET") -def is_zmq_enabled(test_instance): - """Checks whether zmq is enabled or not.""" - config = configparser.ConfigParser() - config.read_file(open(test_instance.options.configfile)) + def is_zmq_compiled(self): + """Checks whether the zmq module was compiled.""" + config = configparser.ConfigParser() + config.read_file(open(self.options.configfile)) - return config["components"].getboolean("ENABLE_ZMQ") + return config["components"].getboolean("ENABLE_ZMQ") diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index a831fdcd5d..908dda94c5 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -97,6 +97,22 @@ class TestNode(): self.p2ps = [] + def get_deterministic_priv_key(self): + """Return a deterministic priv key in base58, that only depends on the node's index""" + PRIV_KEYS = [ + # adress , privkey + ('mjTkW3DjgyZck4KbiRusZsqTgaYTxdSz6z', 'cVpF924EspNh8KjYsfhgY96mmxvT6DgdWiTYMtMjuM74hJaU5psW'), + ('msX6jQXvxiNhx3Q62PKeLPrhrqZQdSimTg', 'cUxsWyKyZ9MAQTaAhUQWJmBbSvHMwSmuv59KgxQV7oZQU3PXN3KE'), + ('mnonCMyH9TmAsSj3M59DsbH8H63U3RKoFP', 'cTrh7dkEAeJd6b3MRX9bZK8eRmNqVCMH3LSUkE3dSFDyzjU38QxK'), + ('mqJupas8Dt2uestQDvV2NH3RU8uZh2dqQR', 'cVuKKa7gbehEQvVq717hYcbE9Dqmq7KEBKqWgWrYBa2CKKrhtRim'), + ('msYac7Rvd5ywm6pEmkjyxhbCDKqWsVeYws', 'cQDCBuKcjanpXDpCqacNSjYfxeQj8G6CAtH1Dsk3cXyqLNC4RPuh'), + ('n2rnuUnwLgXqf9kk2kjvVm8R5BZK1yxQBi', 'cQakmfPSLSqKHyMFGwAqKHgWUiofJCagVGhiB4KCainaeCSxeyYq'), + ('myzuPxRwsf3vvGzEuzPfK9Nf2RfwauwYe6', 'cQMpDLJwA8DBe9NcQbdoSb1BhmFxVjWD5gRyrLZCtpuF9Zi3a9RK'), + ('mumwTaMtbxEPUswmLBBN3vM9oGRtGBrys8', 'cSXmRKXVcoouhNNVpcNKFfxsTsToY5pvB9DVsFksF1ENunTzRKsy'), + ('mpV7aGShMkJCZgbW7F6iZgrvuPHjZjH9qg', 'cSoXt6tm3pqy43UMabY6eUTmR3eSUYFtB2iNQDGgb3VUnRsQys2k'), + ] + return PRIV_KEYS[self.index] + def _node_msg(self, msg: str) -> str: """Return a modified msg that identifies this node by its index as a debugging aid.""" return "[node %d] %s" % (self.index, msg) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 13c687fd92..37b378e9ca 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -236,8 +236,6 @@ def main(): logging.debug("Temporary test directory at %s" % tmpdir) - enable_wallet = config["components"].getboolean("ENABLE_WALLET") - enable_utils = config["components"].getboolean("ENABLE_UTILS") enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND") if config["environment"]["EXEEXT"] == ".exe" and not args.force: @@ -246,9 +244,9 @@ def main(): print("Tests currently disabled on Windows by default. Use --force option to enable") sys.exit(0) - if not (enable_wallet and enable_utils and enable_bitcoind): - print("No functional tests to run. Wallet, utils, and bitcoind must all be enabled") - print("Rerun `configure` with -enable-wallet, -with-utils and -with-daemon and rerun make") + if not enable_bitcoind: + print("No functional tests to run.") + print("Rerun ./configure with --with-daemon and then make") sys.exit(0) # Build list of tests diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py index 8a57b55ca9..e5ac2c8bd4 100755 --- a/test/functional/wallet_abandonconflict.py +++ b/test/functional/wallet_abandonconflict.py @@ -20,6 +20,9 @@ class AbandonConflictTest(BitcoinTestFramework): self.num_nodes = 2 self.extra_args = [["-minrelaytxfee=0.00001"], []] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.nodes[1].generate(100) sync_blocks(self.nodes) diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py index 30851893b8..0f75045c9d 100755 --- a/test/functional/wallet_address_types.py +++ b/test/functional/wallet_address_types.py @@ -63,6 +63,7 @@ from test_framework.util import ( sync_mempools, ) + class AddressTypeTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 6 @@ -72,9 +73,12 @@ class AddressTypeTest(BitcoinTestFramework): ["-addresstype=p2sh-segwit", "-changetype=bech32"], ["-addresstype=bech32"], ["-changetype=p2sh-segwit"], - [] + [], ] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): self.setup_nodes() diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py index 4ef8f4776b..32ec385fa1 100755 --- a/test/functional/wallet_backup.py +++ b/test/functional/wallet_backup.py @@ -45,6 +45,9 @@ class WalletBackupTest(BitcoinTestFramework): # nodes 1, 2,3 are spenders, let's give them a keypool=100 self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self, split=False): self.setup_nodes() connect_nodes(self.nodes[0], 3) diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index ea0346543a..4079d05491 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -23,6 +23,9 @@ class WalletTest(BitcoinTestFramework): self.num_nodes = 4 self.setup_clean_chain = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): self.add_nodes(4) self.start_node(0) diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index a49590df19..2ea72896bb 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -31,8 +31,14 @@ class BumpFeeTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True - self.extra_args = [["-deprecatedrpc=addwitnessaddress", "-walletrbf={}".format(i), "-mintxfee=0.00002"] - for i in range(self.num_nodes)] + self.extra_args = [[ + "-deprecatedrpc=addwitnessaddress", + "-walletrbf={}".format(i), + "-mintxfee=0.00002", + ] for i in range(self.num_nodes)] + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() def run_test(self): # Encrypt wallet for test_locked_wallet_fails test diff --git a/test/functional/wallet_disableprivatekeys.py b/test/functional/wallet_disableprivatekeys.py index 0ba2cfe9be..34ff525255 100755 --- a/test/functional/wallet_disableprivatekeys.py +++ b/test/functional/wallet_disableprivatekeys.py @@ -17,6 +17,9 @@ class DisablePrivateKeysTest(BitcoinTestFramework): self.num_nodes = 1 self.supports_cli = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): node = self.nodes[0] self.log.info("Test disableprivatekeys creation.") diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py index 63316d9644..db731b2a34 100755 --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -29,50 +29,54 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old): # only read non comment lines if line[0] != "#" and len(line) > 10: # split out some data - key_label, comment = line.split("#") - # key = key_label.split(" ")[0] - keytype = key_label.split(" ")[2] - if len(comment) > 1: - addr_keypath = comment.split(" addr=")[1] - addr = addr_keypath.split(" ")[0] + key_date_label, comment = line.split("#") + key_date_label = key_date_label.split(" ") + # key = key_date_label[0] + date = key_date_label[1] + keytype = key_date_label[2] + if not len(comment) or date.startswith('1970'): + continue + + addr_keypath = comment.split(" addr=")[1] + addr = addr_keypath.split(" ")[0] + keypath = None + if keytype == "inactivehdseed=1": + # ensure the old master is still available + assert (hd_master_addr_old == addr) + elif keytype == "hdseed=1": + # ensure we have generated a new hd master key + assert (hd_master_addr_old != addr) + hd_master_addr_ret = addr + elif keytype == "script=1": + # scripts don't have keypaths keypath = None - if keytype == "inactivehdseed=1": - # ensure the old master is still available - assert(hd_master_addr_old == addr) - elif keytype == "hdseed=1": - # ensure we have generated a new hd master key - assert(hd_master_addr_old != addr) - hd_master_addr_ret = addr - elif keytype == "script=1": - # scripts don't have keypaths - keypath = None - else: - keypath = addr_keypath.rstrip().split("hdkeypath=")[1] - - # count key types - for addrObj in addrs: - if addrObj['address'] == addr.split(",")[0] and addrObj['hdkeypath'] == keypath and keytype == "label=": - # a labeled entry in the wallet should contain both a native address - # and the p2sh-p2wpkh address that was added at wallet setup - if len(addr.split(",")) == 2: - addr_list = addr.split(",") - # the entry should be of the first key in the wallet - assert_equal(addrs[0]['address'], addr_list[0]) - witness_addr_ret = addr_list[1] - found_addr += 1 - break - elif keytype == "change=1": - found_addr_chg += 1 - break - elif keytype == "reserve=1": - found_addr_rsv += 1 - break - - # count scripts - for script_addr in script_addrs: - if script_addr == addr.rstrip() and keytype == "script=1": - found_script_addr += 1 - break + else: + keypath = addr_keypath.rstrip().split("hdkeypath=")[1] + + # count key types + for addrObj in addrs: + if addrObj['address'] == addr.split(",")[0] and addrObj['hdkeypath'] == keypath and keytype == "label=": + # a labeled entry in the wallet should contain both a native address + # and the p2sh-p2wpkh address that was added at wallet setup + if len(addr.split(",")) == 2: + addr_list = addr.split(",") + # the entry should be of the first key in the wallet + assert_equal(addrs[0]['address'], addr_list[0]) + witness_addr_ret = addr_list[1] + found_addr += 1 + break + elif keytype == "change=1": + found_addr_chg += 1 + break + elif keytype == "reserve=1": + found_addr_rsv += 1 + break + + # count scripts + for script_addr in script_addrs: + if script_addr == addr.rstrip() and keytype == "script=1": + found_script_addr += 1 + break return found_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret, witness_addr_ret @@ -83,6 +87,9 @@ class WalletDumpTest(BitcoinTestFramework): self.extra_args = [["-keypool=90", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"]] self.rpc_timeout = 120 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self, split=False): self.add_nodes(self.num_nodes, extra_args=self.extra_args) self.start_nodes() @@ -116,9 +123,9 @@ class WalletDumpTest(BitcoinTestFramework): read_dump(wallet_unenc_dump, addrs, script_addrs, None) assert_equal(found_addr, test_addr_count) # all keys must be in the dump assert_equal(found_script_addr, 2) # all scripts must be in the dump - assert_equal(found_addr_chg, 50) # 50 blocks where mined - assert_equal(found_addr_rsv, 90*2) # 90 keys plus 100% internal keys - assert_equal(witness_addr_ret, witness_addr) # p2sh-p2wsh address added to the first key + assert_equal(found_addr_chg, 0) # 0 blocks where mined + assert_equal(found_addr_rsv, 90 * 2) # 90 keys plus 100% internal keys + assert_equal(witness_addr_ret, witness_addr) # p2sh-p2wsh address added to the first key #encrypt wallet, restart, unlock and dump self.nodes[0].node_encrypt_wallet('test') @@ -132,8 +139,8 @@ class WalletDumpTest(BitcoinTestFramework): read_dump(wallet_enc_dump, addrs, script_addrs, hd_master_addr_unenc) assert_equal(found_addr, test_addr_count) assert_equal(found_script_addr, 2) - assert_equal(found_addr_chg, 90*2 + 50) # old reserve keys are marked as change now - assert_equal(found_addr_rsv, 90*2) + assert_equal(found_addr_chg, 90 * 2) # old reserve keys are marked as change now + assert_equal(found_addr_rsv, 90 * 2) assert_equal(witness_addr_ret, witness_addr) # Overwriting should fail diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py index cec9660259..d8c27b09d9 100755 --- a/test/functional/wallet_encryption.py +++ b/test/functional/wallet_encryption.py @@ -19,6 +19,9 @@ class WalletEncryptionTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): passphrase = "WalletPassphrase" passphrase2 = "SecondWalletPassphrase" diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py index 91dbae8939..0c67982bbe 100755 --- a/test/functional/wallet_fallbackfee.py +++ b/test/functional/wallet_fallbackfee.py @@ -11,6 +11,9 @@ class WalletRBFTest(BitcoinTestFramework): self.num_nodes = 1 self.setup_clean_chain = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.nodes[0].generate(101) diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py index 12dac145bd..9d61483868 100755 --- a/test/functional/wallet_groups.py +++ b/test/functional/wallet_groups.py @@ -23,7 +23,10 @@ class WalletGroupTest(BitcoinTestFramework): self.extra_args = [[], [], ['-avoidpartialspends']] self.rpc_timewait = 120 - def run_test (self): + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): # Mine some coins self.nodes[0].generate(110) diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index 2a5f1934b7..48e71f6c40 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -21,6 +21,9 @@ class WalletHDTest(BitcoinTestFramework): self.num_nodes = 2 self.extra_args = [[], ['-keypool=0']] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): # Make sure can't switch off usehd after wallet creation self.stop_node(1) diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py index 0c6359976a..fab415987e 100755 --- a/test/functional/wallet_import_rescan.py +++ b/test/functional/wallet_import_rescan.py @@ -26,7 +26,7 @@ import collections import enum import itertools -Call = enum.Enum("Call", "single multi") +Call = enum.Enum("Call", "single multiaddress multiscript") Data = enum.Enum("Data", "address pub priv") Rescan = enum.Enum("Rescan", "no yes late_timestamp") @@ -53,11 +53,11 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")): response = self.try_rpc(self.node.importprivkey, privkey=self.key, rescan=rescan) assert_equal(response, None) - elif self.call == Call.multi: + elif self.call in (Call.multiaddress, Call.multiscript): response = self.node.importmulti([{ "scriptPubKey": { "address": self.address["address"] - }, + } if self.call == Call.multiaddress else self.address["scriptPubKey"], "timestamp": timestamp + TIMESTAMP_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0), "pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [], "keys": [self.key] if self.data == Data.priv else [], @@ -109,6 +109,9 @@ class ImportRescanTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 + len(IMPORT_NODES) + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): extra_args = [["-addresstype=legacy"] for _ in range(self.num_nodes)] for i, import_node in enumerate(IMPORT_NODES, 2): @@ -116,17 +119,26 @@ class ImportRescanTest(BitcoinTestFramework): extra_args[i] += ["-prune=1"] self.add_nodes(self.num_nodes, extra_args=extra_args) + + # Import keys + self.start_nodes(extra_args=[[]] * self.num_nodes) + super().import_deterministic_coinbase_privkeys() + self.stop_nodes() + self.start_nodes() for i in range(1, self.num_nodes): connect_nodes(self.nodes[i], 0) + def import_deterministic_coinbase_privkeys(self): + pass + def run_test(self): # Create one transaction on node 0 with a unique amount for # each possible type of wallet import RPC. for i, variant in enumerate(IMPORT_VARIANTS): variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress()) variant.key = self.nodes[1].dumpprivkey(variant.address["address"]) - variant.initial_amount = 10 - (i + 1) / 4.0 + variant.initial_amount = 1 - (i + 1) / 64 variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount) # Generate a block containing the initial transactions, then another @@ -156,7 +168,7 @@ class ImportRescanTest(BitcoinTestFramework): # Create new transactions sending to each address. for i, variant in enumerate(IMPORT_VARIANTS): - variant.sent_amount = 10 - (2 * i + 1) / 8.0 + variant.sent_amount = 1 - (2 * i + 1) / 128 variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount) # Generate a block containing the new transactions. diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index 5f19e1e2c6..f78ff19791 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -3,15 +3,26 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the importmulti RPC.""" + +from test_framework import script from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error +from test_framework.util import ( + assert_equal, + assert_greater_than, + assert_raises_rpc_error, + bytes_to_hex_str, +) + -class ImportMultiTest (BitcoinTestFramework): +class ImportMultiTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 self.extra_args = [["-addresstype=legacy"], ["-addresstype=legacy"]] self.setup_clean_chain = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def setup_network(self): self.setup_nodes() @@ -79,16 +90,17 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(address_assert['ismine'], False) assert_equal(address_assert['timestamp'], timestamp) - # ScriptPubKey + !internal - self.log.info("Should not import a scriptPubKey without internal flag") + # Nonstandard scriptPubKey + !internal + self.log.info("Should not import a nonstandard scriptPubKey without internal flag") + nonstandardScriptPubKey = address['scriptPubKey'] + bytes_to_hex_str(script.CScript([script.OP_NOP])) address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ - "scriptPubKey": address['scriptPubKey'], + "scriptPubKey": nonstandardScriptPubKey, "timestamp": "now", }]) assert_equal(result[0]['success'], False) assert_equal(result[0]['error']['code'], -8) - assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey') + assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.') address_assert = self.nodes[1].getaddressinfo(address['address']) assert_equal(address_assert['iswatchonly'], False) assert_equal(address_assert['ismine'], False) @@ -128,18 +140,18 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(address_assert['ismine'], False) assert_equal(address_assert['timestamp'], timestamp) - # ScriptPubKey + Public key + !internal - self.log.info("Should not import a scriptPubKey without internal and with public key") + # Nonstandard scriptPubKey + Public key + !internal + self.log.info("Should not import a nonstandard scriptPubKey without internal and with public key") address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress()) request = [{ - "scriptPubKey": address['scriptPubKey'], + "scriptPubKey": nonstandardScriptPubKey, "timestamp": "now", "pubkeys": [ address['pubkey'] ] }] result = self.nodes[1].importmulti(request) assert_equal(result[0]['success'], False) assert_equal(result[0]['error']['code'], -8) - assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey') + assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.') address_assert = self.nodes[1].getaddressinfo(address['address']) assert_equal(address_assert['iswatchonly'], False) assert_equal(address_assert['ismine'], False) @@ -207,17 +219,17 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(address_assert['ismine'], True) assert_equal(address_assert['timestamp'], timestamp) - # ScriptPubKey + Private key + !internal - self.log.info("Should not import a scriptPubKey without internal and with private key") + # Nonstandard scriptPubKey + Private key + !internal + self.log.info("Should not import a nonstandard scriptPubKey without internal and with private key") address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ - "scriptPubKey": address['scriptPubKey'], + "scriptPubKey": nonstandardScriptPubKey, "timestamp": "now", "keys": [ self.nodes[0].dumpprivkey(address['address']) ] }]) assert_equal(result[0]['success'], False) assert_equal(result[0]['error']['code'], -8) - assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey') + assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.') address_assert = self.nodes[1].getaddressinfo(address['address']) assert_equal(address_assert['iswatchonly'], False) assert_equal(address_assert['ismine'], False) diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py index 57fc754d35..26b181db33 100755 --- a/test/functional/wallet_importprunedfunds.py +++ b/test/functional/wallet_importprunedfunds.py @@ -16,6 +16,9 @@ class ImportPrunedFundsTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 2 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.log.info("Mining blocks...") self.nodes[0].generate(101) diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py index f52dce04dd..acc336e4d5 100755 --- a/test/functional/wallet_keypool.py +++ b/test/functional/wallet_keypool.py @@ -13,6 +13,9 @@ class KeyPoolTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): nodes = self.nodes addr_before_encrypting = nodes[0].getnewaddress() diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py index f6b88e6225..f1a441c399 100755 --- a/test/functional/wallet_keypool_topup.py +++ b/test/functional/wallet_keypool_topup.py @@ -27,6 +27,9 @@ class KeypoolRestoreTest(BitcoinTestFramework): self.num_nodes = 2 self.extra_args = [[], ['-keypool=100']] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): wallet_path = os.path.join(self.nodes[1].datadir, "regtest", "wallets", "wallet.dat") wallet_backup_path = os.path.join(self.nodes[1].datadir, "wallet.bak") diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py index 01a73d9cef..8d7c77bb96 100755 --- a/test/functional/wallet_labels.py +++ b/test/functional/wallet_labels.py @@ -19,6 +19,9 @@ class WalletLabelsTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): # Check that there's no UTXO on the node node = self.nodes[0] diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py index 09a7c72347..3485c4470f 100755 --- a/test/functional/wallet_listreceivedby.py +++ b/test/functional/wallet_listreceivedby.py @@ -18,6 +18,14 @@ class ReceivedByTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 + def import_deterministic_coinbase_privkeys(self): + assert_equal(0, len(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True))) + super().import_deterministic_coinbase_privkeys() + self.num_cb_reward_addresses = len(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True)) + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): # Generate block to get out of IBD self.nodes[0].generate(1) @@ -64,7 +72,7 @@ class ReceivedByTest(BitcoinTestFramework): assert_raises_rpc_error(-4, "address_filter parameter was invalid", self.nodes[1].listreceivedbyaddress, minconf=0, include_empty=True, include_watchonly=True, address_filter="bamboozling") # Another address receive money res = self.nodes[1].listreceivedbyaddress(0, True, True) - assert_equal(len(res), 2) # Right now 2 entries + assert_equal(len(res), 2 + self.num_cb_reward_addresses) # Right now 2 entries other_addr = self.nodes[1].getnewaddress() txid2 = self.nodes[0].sendtoaddress(other_addr, 0.1) self.nodes[0].generate(1) @@ -81,7 +89,7 @@ class ReceivedByTest(BitcoinTestFramework): assert_equal(len(res), 1) # Should be two entries though without filter res = self.nodes[1].listreceivedbyaddress(0, True, True) - assert_equal(len(res), 3) # Became 3 entries + assert_equal(len(res), 3 + self.num_cb_reward_addresses) # Became 3 entries # Not on random addr other_addr = self.nodes[0].getnewaddress() # note on node[0]! just a random addr diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py index 847b48aa89..53e671cd3b 100755 --- a/test/functional/wallet_listsinceblock.py +++ b/test/functional/wallet_listsinceblock.py @@ -12,6 +12,9 @@ class ListSinceBlockTest (BitcoinTestFramework): self.num_nodes = 4 self.setup_clean_chain = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.nodes[2].generate(101) self.sync_all() diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py index 4dc3ff4b26..5a17395abd 100755 --- a/test/functional/wallet_listtransactions.py +++ b/test/functional/wallet_listtransactions.py @@ -27,6 +27,9 @@ class ListTransactionsTest(BitcoinTestFramework): self.num_nodes = 2 self.enable_mocktime() + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index 0690dcf92d..435821ec48 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -23,6 +23,9 @@ class MultiWalletTest(BitcoinTestFramework): self.num_nodes = 2 self.supports_cli = True + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): node = self.nodes[0] diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py index 8995aa743f..00bf58d709 100755 --- a/test/functional/wallet_resendwallettransactions.py +++ b/test/functional/wallet_resendwallettransactions.py @@ -12,6 +12,9 @@ class ResendWalletTransactionsTest(BitcoinTestFramework): self.num_nodes = 1 self.extra_args = [['--walletbroadcast=false']] + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): # Should raise RPC_WALLET_ERROR (-4) if walletbroadcast is disabled. assert_raises_rpc_error(-4, "Error: Wallet transaction broadcasting is disabled with -walletbroadcast", self.nodes[0].resendwallettransactions) diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py index 4ca4ee14e9..d78c105c17 100755 --- a/test/functional/wallet_txn_clone.py +++ b/test/functional/wallet_txn_clone.py @@ -16,6 +16,9 @@ class TxnMallTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 4 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def add_options(self, parser): parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true", help="Test double-spend of 1-confirmed transaction") diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py index 6811f6ab73..f114d5ab68 100755 --- a/test/functional/wallet_txn_doublespend.py +++ b/test/functional/wallet_txn_doublespend.py @@ -18,6 +18,9 @@ class TxnMallTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 4 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def add_options(self, parser): parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true", help="Test double-spend of 1-confirmed transaction") diff --git a/test/functional/wallet_zapwallettxes.py b/test/functional/wallet_zapwallettxes.py index cbd142d1ee..adebff360a 100755 --- a/test/functional/wallet_zapwallettxes.py +++ b/test/functional/wallet_zapwallettxes.py @@ -26,6 +26,9 @@ class ZapWalletTXesTest (BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 2 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def run_test(self): self.log.info("Mining blocks...") self.nodes[0].generate(1) diff --git a/test/lint/lint-format-strings.py b/test/lint/lint-format-strings.py index 60389176c9..2fb35fd8ca 100755 --- a/test/lint/lint-format-strings.py +++ b/test/lint/lint-format-strings.py @@ -20,6 +20,7 @@ FALSE_POSITIVES = [ ("src/util.cpp", "strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION)"), ("src/wallet/wallet.h", "WalletLogPrintf(std::string fmt, Params... parameters)"), ("src/wallet/wallet.h", "LogPrintf((\"%s \" + fmt).c_str(), GetDisplayName(), parameters...)"), + ("src/logging.h", "LogPrintf(const char* fmt, const Args&... args)"), ] diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh index 346829e24b..a3e7681d45 100755 --- a/test/lint/lint-includes.sh +++ b/test/lint/lint-includes.sh @@ -63,7 +63,6 @@ EXPECTED_BOOST_INCLUDES=( boost/optional.hpp boost/preprocessor/cat.hpp boost/preprocessor/stringize.hpp - boost/scoped_array.hpp boost/signals2/connection.hpp boost/signals2/last_value.hpp boost/signals2/signal.hpp |