diff options
44 files changed, 585 insertions, 436 deletions
diff --git a/.travis.yml b/.travis.yml index 5550de12d6..03ab9d2613 100644 --- a/.travis.yml +++ b/.travis.yml @@ -112,7 +112,7 @@ jobs: FILE_ENV="./ci/test/00_setup_env_native_qt5.sh" - stage: test - name: 'x86_64 Linux [GOAL: install] [focal] [depends, sanitizers: thread (TSan), no wallet, no gui]' + name: 'x86_64 Linux [GOAL: install] [focal] [depends, sanitizers: thread (TSan), no gui]' # Not enough memory on travis machines, so feature_block is excluded for now env: >- TEST_RUNNER_EXTRA="--exclude feature_block" diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh index f51cbf8f3c..43ee219ef9 100644 --- a/ci/test/00_setup_env_native_fuzz.sh +++ b/ci/test/00_setup_env_native_fuzz.sh @@ -14,4 +14,4 @@ export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false export RUN_FUZZ_TESTS=true export GOAL="install" -export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined --enable-c++17 CC=clang CXX=clang++" +export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=clang CXX=clang++" diff --git a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh index fb4c27c36f..c27d525003 100644 --- a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh +++ b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh @@ -15,4 +15,4 @@ export RUN_FUNCTIONAL_TESTS=false export RUN_FUZZ_TESTS=true export FUZZ_TESTS_CONFIG="--valgrind" export GOAL="install" -export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer --enable-c++17 CC=clang CXX=clang++" +export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer CC=clang CXX=clang++" diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh index 99cf9cd182..87b9d9da95 100644 --- a/ci/test/00_setup_env_native_tsan.sh +++ b/ci/test/00_setup_env_native_tsan.sh @@ -11,4 +11,4 @@ export DOCKER_NAME_TAG=ubuntu:20.04 export PACKAGES="clang llvm libc++abi-dev libc++-dev python3-zmq" export DEP_OPTS="CC=clang CXX='clang++ -stdlib=libc++'" export GOAL="install" -export BITCOIN_CONFIG="--enable-zmq --disable-wallet --with-gui=no CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=thread CC=clang CXX='clang++ -stdlib=libc++'" +export BITCOIN_CONFIG="--enable-zmq --with-gui=no CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=thread CC=clang CXX='clang++ -stdlib=libc++'" diff --git a/configure.ac b/configure.ac index f2f053dabc..0e263a473f 100644 --- a/configure.ac +++ b/configure.ac @@ -69,7 +69,7 @@ AC_ARG_ENABLE([c++17], [use_cxx17=no]) dnl Require C++11 or C++17 compiler (no GNU extensions) -if test "x$use_cxx17" = xyes; then +if test "x$use_cxx17" = xyes -o "x$enable_fuzz" = xyes ; then AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory]) else AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory]) @@ -391,6 +391,7 @@ if test "x$enable_werror" = "xyes"; then dnl https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78010 AX_CHECK_COMPILE_FLAG([-Werror=suggest-override],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=suggest-override"],,[[$CXXFLAG_WERROR]], [AC_LANG_SOURCE([[struct A { virtual void f(); }; struct B : A { void f() final; };]])]) + AX_CHECK_COMPILE_FLAG([-Werror=unreachable-code-loop-increment],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=unreachable-code-loop-increment"],,[[$CXXFLAG_WERROR]]) fi if test "x$CXXFLAGS_overridden" = "xno"; then @@ -410,6 +411,7 @@ if test "x$CXXFLAGS_overridden" = "xno"; then AX_CHECK_COMPILE_FLAG([-Wsign-compare],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wsign-compare"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wsuggest-override],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wsuggest-override"],,[[$CXXFLAG_WERROR]], [AC_LANG_SOURCE([[struct A { virtual void f(); }; struct B : A { void f() final; };]])]) + AX_CHECK_COMPILE_FLAG([-Wunreachable-code-loop-increment],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wunreachable-code-loop-increment"],,[[$CXXFLAG_WERROR]]) dnl Some compilers (gcc) ignore unknown -Wno-* options, but warn about all dnl unknown options if any other warning is produced. Test the -Wfoo case, and diff --git a/doc/fuzzing.md b/doc/fuzzing.md index 16852bb970..419b1db44e 100644 --- a/doc/fuzzing.md +++ b/doc/fuzzing.md @@ -8,7 +8,7 @@ To quickly get started fuzzing Bitcoin Core using [libFuzzer](https://llvm.org/d $ git clone https://github.com/bitcoin/bitcoin $ cd bitcoin/ $ ./autogen.sh -$ CC=clang CXX=clang++ ./configure --enable-fuzz --with-sanitizers=address,fuzzer,undefined --enable-c++17 +$ CC=clang CXX=clang++ ./configure --enable-fuzz --with-sanitizers=address,fuzzer,undefined # macOS users: If you have problem with this step then make sure to read "macOS hints for # libFuzzer" on https://github.com/bitcoin/bitcoin/blob/master/doc/fuzzing.md#macos-hints-for-libfuzzer $ make @@ -103,7 +103,7 @@ You may also need to take care of giving the correct path for `clang` and Full configure that was tested on macOS Catalina with `brew` installed `llvm`: ```sh -./configure --enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=/usr/local/opt/llvm/bin/clang CXX=/usr/local/opt/llvm/bin/clang++ --disable-asm --enable-c++17 +./configure --enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=/usr/local/opt/llvm/bin/clang CXX=/usr/local/opt/llvm/bin/clang++ --disable-asm ``` Read the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html) for more information. This [libFuzzer tutorial](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md) might also be of interest. @@ -121,7 +121,7 @@ $ git clone https://github.com/google/afl $ make -C afl/ $ make -C afl/llvm_mode/ $ ./autogen.sh -$ CC=$(pwd)/afl/afl-clang-fast CXX=$(pwd)/afl/afl-clang-fast++ ./configure --enable-fuzz --enable-c++17 +$ CC=$(pwd)/afl/afl-clang-fast CXX=$(pwd)/afl/afl-clang-fast++ ./configure --enable-fuzz $ make # For macOS you may need to ignore x86 compilation checks when running "make". If so, # try compiling using: AFL_NO_X86=1 make @@ -148,7 +148,7 @@ $ git clone https://github.com/google/honggfuzz $ cd honggfuzz/ $ make $ cd .. -$ CC=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang CXX=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang++ ./configure --enable-fuzz --with-sanitizers=address,undefined --enable-c++17 +$ CC=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang CXX=$(pwd)/honggfuzz/hfuzz_cc/hfuzz-clang++ ./configure --enable-fuzz --with-sanitizers=address,undefined $ make $ mkdir -p inputs/ $ honggfuzz/honggfuzz -i inputs/ -- src/test/fuzz/process_message diff --git a/doc/reduce-traffic.md b/doc/reduce-traffic.md index e39e43df7a..ce77a00dd5 100644 --- a/doc/reduce-traffic.md +++ b/doc/reduce-traffic.md @@ -23,7 +23,7 @@ longer serving historic blocks (blocks older than one week). Keep in mind that new nodes require other nodes that are willing to serve historic blocks. -Whitelisted peers will never be disconnected, although their traffic counts for +Peers with the `noban` permission will never be disconnected, although their traffic counts for calculating the target. ## 2. Disable "listening" (`-listen=0`) diff --git a/src/Makefile.am b/src/Makefile.am index 2b004691fd..7a280a67a7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -241,6 +241,7 @@ BITCOIN_CORE_H = \ versionbitsinfo.h \ walletinitinterface.h \ wallet/coincontrol.h \ + wallet/context.h \ wallet/crypter.h \ wallet/db.h \ wallet/feebumper.h \ @@ -350,6 +351,7 @@ libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ interfaces/wallet.cpp \ wallet/coincontrol.cpp \ + wallet/context.cpp \ wallet/crypter.cpp \ wallet/db.cpp \ wallet/feebumper.cpp \ diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index 4626395ef0..59d1888fff 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -9,8 +9,6 @@ #include <util/translation.h> #include <validation.h> -#include <boost/thread.hpp> - constexpr char DB_BEST_BLOCK = 'B'; constexpr char DB_TXINDEX = 't'; constexpr char DB_TXINDEX_BLOCK = 'T'; @@ -150,7 +148,6 @@ bool TxIndex::DB::MigrateData(CBlockTreeDB& block_tree_db, const CBlockLocator& bool interrupted = false; std::unique_ptr<CDBIterator> cursor(block_tree_db.NewIterator()); for (cursor->Seek(begin_key); cursor->Valid(); cursor->Next()) { - boost::this_thread::interruption_point(); if (ShutdownRequested()) { interrupted = true; break; diff --git a/src/init.cpp b/src/init.cpp index 7b5330e31e..4c5c0051ca 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -71,11 +71,9 @@ #include <sys/stat.h> #endif -#include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/replace.hpp> -#include <boost/algorithm/string/split.hpp> #include <boost/signals2/signal.hpp> -#include <boost/thread.hpp> +#include <boost/thread/thread.hpp> #if ENABLE_ZMQ #include <zmq/zmqabstractnotifier.h> @@ -444,7 +442,7 @@ void SetupServerArgs(NodeContext& node) gArgs.AddArg("-maxreceivebuffer=<n>", strprintf("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); gArgs.AddArg("-maxsendbuffer=<n>", strprintf("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); gArgs.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)", DEFAULT_MAX_TIME_ADJUSTMENT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - gArgs.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + gArgs.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target (in MiB per 24h). Limit does not apply to peers with 'noban' permission. 0 = no limit (default: %d)", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); gArgs.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor hidden services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); gArgs.AddArg("-onlynet=<net>", "Make outgoing connections only through network <net> (ipv4, ipv6 or onion). Incoming connections are not affected by this option. This option can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); gArgs.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -957,17 +955,27 @@ bool AppInitParameterInteraction() // also see: InitParameterInteraction() - // Warn if network-specific options (-addnode, -connect, etc) are + // Error if network-specific options (-addnode, -connect, etc) are // specified in default section of config file, but not overridden // on the command line or in this network's section of the config file. std::string network = gArgs.GetChainName(); + bilingual_str errors; for (const auto& arg : gArgs.GetUnsuitableSectionOnlyArgs()) { - return InitError(strprintf(_("Config setting for %s only applied on %s network when in [%s] section."), arg, network, network)); + errors += strprintf(_("Config setting for %s only applied on %s network when in [%s] section.") + Untranslated("\n"), arg, network, network); + } + + if (!errors.empty()) { + return InitError(errors); } // Warn if unrecognized section name are present in the config file. + bilingual_str warnings; for (const auto& section : gArgs.GetUnrecognizedSections()) { - InitWarning(strprintf(Untranslated("%s:%i ") + _("Section [%s] is not recognized."), section.m_file, section.m_line, section.m_name)); + warnings += strprintf(Untranslated("%s:%i ") + _("Section [%s] is not recognized.") + Untranslated("\n"), section.m_file, section.m_line, section.m_name); + } + + if (!warnings.empty()) { + InitWarning(warnings); } if (!fs::is_directory(GetBlocksDir())) { diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index cec75030ad..397403d308 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -9,13 +9,16 @@ #include <interfaces/handler.h> #include <policy/fees.h> #include <primitives/transaction.h> +#include <rpc/server.h> #include <script/standard.h> #include <support/allocators/secure.h> #include <sync.h> #include <ui_interface.h> #include <uint256.h> #include <util/check.h> +#include <util/ref.h> #include <util/system.h> +#include <wallet/context.h> #include <wallet/feebumper.h> #include <wallet/fees.h> #include <wallet/ismine.h> @@ -481,16 +484,21 @@ class WalletClientImpl : public ChainClient { public: WalletClientImpl(Chain& chain, std::vector<std::string> wallet_filenames) - : m_chain(chain), m_wallet_filenames(std::move(wallet_filenames)) + : m_wallet_filenames(std::move(wallet_filenames)) { + m_context.chain = &chain; } void registerRpcs() override { - g_rpc_chain = &m_chain; - return RegisterWalletRPCCommands(m_chain, m_rpc_handlers); + for (const CRPCCommand& command : GetWalletRPCCommands()) { + m_rpc_commands.emplace_back(command.category, command.name, [this, &command](const JSONRPCRequest& request, UniValue& result, bool last_handler) { + return command.actor({request, m_context}, result, last_handler); + }, command.argNames, command.unique_id); + m_rpc_handlers.emplace_back(m_context.chain->handleRpc(m_rpc_commands.back())); + } } - bool verify() override { return VerifyWallets(m_chain, m_wallet_filenames); } - bool load() override { return LoadWallets(m_chain, m_wallet_filenames); } + bool verify() override { return VerifyWallets(*m_context.chain, m_wallet_filenames); } + bool load() override { return LoadWallets(*m_context.chain, m_wallet_filenames); } void start(CScheduler& scheduler) override { return StartWallets(scheduler); } void flush() override { return FlushWallets(); } void stop() override { return StopWallets(); } @@ -505,9 +513,10 @@ public: } ~WalletClientImpl() override { UnloadWallets(); } - Chain& m_chain; + WalletContext m_context; std::vector<std::string> m_wallet_filenames; std::vector<std::unique_ptr<Handler>> m_rpc_handlers; + std::list<CRPCCommand> m_rpc_commands; }; } // namespace diff --git a/src/net.cpp b/src/net.cpp index 2ccb89248f..f3b7e8dab1 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2639,7 +2639,7 @@ void CConnman::RecordBytesSent(uint64_t bytes) nMaxOutboundTotalBytesSentInCycle = 0; } - // TODO, exclude whitebind peers + // TODO, exclude peers with noban permission nMaxOutboundTotalBytesSentInCycle += bytes; } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 404b33a977..d48745aef2 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -441,32 +441,32 @@ static CNodeState *State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return &it->second; } -static void UpdatePreferredDownload(CNode* node, CNodeState* state) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { nPreferredDownload -= state->fPreferredDownload; // Whether this node should be marked as a preferred download node. - state->fPreferredDownload = (!node->fInbound || node->HasPermission(PF_NOBAN)) && !node->fOneShot && !node->fClient; + state->fPreferredDownload = (!node.fInbound || node.HasPermission(PF_NOBAN)) && !node.fOneShot && !node.fClient; nPreferredDownload += state->fPreferredDownload; } -static void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime) +static void PushNodeVersion(CNode& pnode, CConnman* connman, int64_t nTime) { // Note that pnode->GetLocalServices() is a reflection of the local // services we were offering when the CNode object was created for this // peer. - ServiceFlags nLocalNodeServices = pnode->GetLocalServices(); - uint64_t nonce = pnode->GetLocalNonce(); - int nNodeStartingHeight = pnode->GetMyStartingHeight(); - NodeId nodeid = pnode->GetId(); - CAddress addr = pnode->addr; + ServiceFlags nLocalNodeServices = pnode.GetLocalServices(); + uint64_t nonce = pnode.GetLocalNonce(); + int nNodeStartingHeight = pnode.GetMyStartingHeight(); + NodeId nodeid = pnode.GetId(); + CAddress addr = pnode.addr; CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); CAddress addrMe = CAddress(CService(), nLocalNodeServices); - connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, - nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes && pnode->m_tx_relay != nullptr)); + connman->PushMessage(&pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, + nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes && pnode.m_tx_relay != nullptr)); if (fLogIPs) { LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid); @@ -799,9 +799,9 @@ void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) // Returns true for outbound peers, excluding manual connections, feelers, and // one-shots. -static bool IsOutboundDisconnectionCandidate(const CNode *node) +static bool IsOutboundDisconnectionCandidate(const CNode& node) { - return !(node->fInbound || node->m_manual_connection || node->fFeeler || node->fOneShot); + return !(node.fInbound || node.m_manual_connection || node.fFeeler || node.fOneShot); } void PeerLogicValidation::InitializeNode(CNode *pnode) { @@ -813,7 +813,7 @@ void PeerLogicValidation::InitializeNode(CNode *pnode) { mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName), pnode->fInbound, pnode->m_manual_connection)); } if(!pnode->fInbound) - PushNodeVersion(pnode, connman, GetTime()); + PushNodeVersion(*pnode, connman, GetTime()); } void PeerLogicValidation::ReattemptInitialBroadcast(CScheduler& scheduler) const @@ -1462,7 +1462,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman& connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); } -void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, const CInv& inv, CConnman* connman) +void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, const CInv& inv, CConnman* connman) { bool send = false; std::shared_ptr<const CBlock> a_recent_block; @@ -1504,28 +1504,30 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c if (pindex) { send = BlockRequestAllowed(pindex, consensusParams); if (!send) { - LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); + LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom.GetId()); } } - const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); + const CNetMsgMaker msgMaker(pfrom.GetSendVersion()); // disconnect node in case we have reached the outbound limit for serving historical blocks - // never disconnect whitelisted nodes - if (send && connman->OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->HasPermission(PF_NOBAN)) - { - LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); + if (send && + connman->OutboundTargetReached(true) && + (((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) && + !pfrom.HasPermission(PF_NOBAN) // never disconnect nodes with the noban permission + ) { + LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId()); //disconnect node - pfrom->fDisconnect = true; + pfrom.fDisconnect = true; send = false; } // Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold - if (send && !pfrom->HasPermission(PF_NOBAN) && ( - (((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (::ChainActive().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) ) + if (send && !pfrom.HasPermission(PF_NOBAN) && ( + (((pfrom.GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom.GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (::ChainActive().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) ) )) { - LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId()); + LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom.GetId()); //disconnect node and prevent it from stalling (would otherwise wait for the missing block) - pfrom->fDisconnect = true; + pfrom.fDisconnect = true; send = false; } // Pruned nodes may have deleted the block, so check whether @@ -1542,7 +1544,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c if (!ReadRawBlockFromDisk(block_data, pindex, chainparams.MessageStart())) { assert(!"cannot load block from disk"); } - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, MakeSpan(block_data))); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, MakeSpan(block_data))); // Don't set pblock as we've sent the block } else { // Send block from disk @@ -1553,22 +1555,22 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c } if (pblock) { if (inv.type == MSG_BLOCK) - connman->PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock)); + connman->PushMessage(&pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock)); else if (inv.type == MSG_WITNESS_BLOCK) - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock)); else if (inv.type == MSG_FILTERED_BLOCK) { bool sendMerkleBlock = false; CMerkleBlock merkleBlock; - if (pfrom->m_tx_relay != nullptr) { - LOCK(pfrom->m_tx_relay->cs_filter); - if (pfrom->m_tx_relay->pfilter) { + if (pfrom.m_tx_relay != nullptr) { + LOCK(pfrom.m_tx_relay->cs_filter); + if (pfrom.m_tx_relay->pfilter) { sendMerkleBlock = true; - merkleBlock = CMerkleBlock(*pblock, *pfrom->m_tx_relay->pfilter); + merkleBlock = CMerkleBlock(*pblock, *pfrom.m_tx_relay->pfilter); } } if (sendMerkleBlock) { - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock)); // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see // This avoids hurting performance by pointlessly requiring a round-trip // Note that there is currently no way for a node to request any single transactions we didn't send here - @@ -1577,7 +1579,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c // however we MUST always provide at least what the remote peer needs typedef std::pair<unsigned int, uint256> PairType; for (PairType& pair : merkleBlock.vMatchedTxn) - connman->PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first])); + connman->PushMessage(&pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first])); } // else // no response @@ -1588,44 +1590,44 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c // they won't have a useful mempool to match against a compact block, // and we don't feel like constructing the object for them, so // instead we respond with the full, non-compact block. - bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness; + bool fPeerWantsWitness = State(pfrom.GetId())->fWantsCmpctWitness; int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; if (CanDirectFetch(consensusParams) && pindex->nHeight >= ::ChainActive().Height() - MAX_CMPCTBLOCK_DEPTH) { if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) { - connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block)); + connman->PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block)); } else { CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness); - connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); + connman->PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); } } else { - connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock)); + connman->PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock)); } } } // Trigger the peer node to send a getblocks request for the next batch of inventory - if (inv.hash == pfrom->hashContinue) + if (inv.hash == pfrom.hashContinue) { // Bypass PushInventory, this must send even if redundant, // and we want it right after the last block so they don't // wait for other stuff first. std::vector<CInv> vInv; vInv.push_back(CInv(MSG_BLOCK, ::ChainActive().Tip()->GetBlockHash())); - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv)); - pfrom->hashContinue.SetNull(); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv)); + pfrom.hashContinue.SetNull(); } } } //! Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). -CTransactionRef static FindTxForGetData(CNode* peer, const uint256& txid, const std::chrono::seconds mempool_req, const std::chrono::seconds longlived_mempool_time) LOCKS_EXCLUDED(cs_main) +CTransactionRef static FindTxForGetData(CNode& peer, const uint256& txid, const std::chrono::seconds mempool_req, const std::chrono::seconds longlived_mempool_time) LOCKS_EXCLUDED(cs_main) { // Check if the requested transaction is so recent that we're just // about to announce it to the peer; if so, they certainly shouldn't // know we already have it. { - LOCK(peer->m_tx_relay->cs_tx_inventory); - if (peer->m_tx_relay->setInventoryTxToSend.count(txid)) return {}; + LOCK(peer.m_tx_relay->cs_tx_inventory); + if (peer.m_tx_relay->setInventoryTxToSend.count(txid)) return {}; } { @@ -1648,32 +1650,32 @@ CTransactionRef static FindTxForGetData(CNode* peer, const uint256& txid, const return {}; } -void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnman* connman, CTxMemPool& mempool, const std::atomic<bool>& interruptMsgProc) LOCKS_EXCLUDED(cs_main) +void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnman* connman, CTxMemPool& mempool, const std::atomic<bool>& interruptMsgProc) LOCKS_EXCLUDED(cs_main) { AssertLockNotHeld(cs_main); - std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin(); + std::deque<CInv>::iterator it = pfrom.vRecvGetData.begin(); std::vector<CInv> vNotFound; - const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); + const CNetMsgMaker msgMaker(pfrom.GetSendVersion()); // mempool entries added before this time have likely expired from mapRelay const std::chrono::seconds longlived_mempool_time = GetTime<std::chrono::seconds>() - RELAY_TX_CACHE_TIME; // Get last mempool request time - const std::chrono::seconds mempool_req = pfrom->m_tx_relay != nullptr ? pfrom->m_tx_relay->m_last_mempool_req.load() + const std::chrono::seconds mempool_req = pfrom.m_tx_relay != nullptr ? pfrom.m_tx_relay->m_last_mempool_req.load() : std::chrono::seconds::min(); // Process as many TX items from the front of the getdata queue as // possible, since they're common and it's efficient to batch process // them. - while (it != pfrom->vRecvGetData.end() && (it->type == MSG_TX || it->type == MSG_WITNESS_TX)) { + while (it != pfrom.vRecvGetData.end() && (it->type == MSG_TX || it->type == MSG_WITNESS_TX)) { if (interruptMsgProc) return; // The send buffer provides backpressure. If there's no space in // the buffer, pause processing until the next call. - if (pfrom->fPauseSend) break; + if (pfrom.fPauseSend) break; const CInv &inv = *it++; - if (pfrom->m_tx_relay == nullptr) { + if (pfrom.m_tx_relay == nullptr) { // Ignore GETDATA requests for transactions from blocks-only peers. continue; } @@ -1681,7 +1683,7 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm CTransactionRef tx = FindTxForGetData(pfrom, inv.hash, mempool_req, longlived_mempool_time); if (tx) { int nSendFlags = (inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0); - connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *tx)); + connman->PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *tx)); mempool.RemoveUnbroadcastTx(inv.hash); } else { vNotFound.push_back(inv); @@ -1690,7 +1692,7 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm // Only process one BLOCK item per call, since they're uncommon and can be // expensive to process. - if (it != pfrom->vRecvGetData.end() && !pfrom->fPauseSend) { + if (it != pfrom.vRecvGetData.end() && !pfrom.fPauseSend) { const CInv &inv = *it++; if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK) { ProcessGetBlockData(pfrom, chainparams, inv, connman); @@ -1699,7 +1701,7 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm // and continue processing the queue on the next call. } - pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it); + pfrom.vRecvGetData.erase(pfrom.vRecvGetData.begin(), it); if (!vNotFound.empty()) { // Let the peer know that we didn't find what it asked for, so it doesn't @@ -1716,37 +1718,37 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm // In normal operation, we often send NOTFOUND messages for parents of // transactions that we relay; if a peer is missing a parent, they may // assume we have them and request the parents from us. - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound)); } } -static uint32_t GetFetchFlags(CNode* pfrom) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { +static uint32_t GetFetchFlags(const CNode& pfrom) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { uint32_t nFetchFlags = 0; - if ((pfrom->GetLocalServices() & NODE_WITNESS) && State(pfrom->GetId())->fHaveWitness) { + if ((pfrom.GetLocalServices() & NODE_WITNESS) && State(pfrom.GetId())->fHaveWitness) { nFetchFlags |= MSG_WITNESS_FLAG; } return nFetchFlags; } -inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman* connman) { +inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode& pfrom, CConnman* connman) { BlockTransactions resp(req); for (size_t i = 0; i < req.indexes.size(); i++) { if (req.indexes[i] >= block.vtx.size()) { LOCK(cs_main); - Misbehaving(pfrom->GetId(), 100, strprintf("Peer %d sent us a getblocktxn with out-of-bounds tx indices", pfrom->GetId())); + Misbehaving(pfrom.GetId(), 100, strprintf("Peer %d sent us a getblocktxn with out-of-bounds tx indices", pfrom.GetId())); return; } resp.txn[i] = block.vtx[req.indexes[i]]; } LOCK(cs_main); - const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); - int nSendFlags = State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; - connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp)); + const CNetMsgMaker msgMaker(pfrom.GetSendVersion()); + int nSendFlags = State(pfrom.GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; + connman->PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp)); } -bool static ProcessHeadersMessage(CNode* pfrom, CConnman* connman, ChainstateManager& chainman, CTxMemPool& mempool, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool via_compact_block) +bool static ProcessHeadersMessage(CNode& pfrom, CConnman* connman, ChainstateManager& chainman, CTxMemPool& mempool, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool via_compact_block) { - const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); + const CNetMsgMaker msgMaker(pfrom.GetSendVersion()); size_t nCount = headers.size(); if (nCount == 0) { @@ -1758,7 +1760,7 @@ bool static ProcessHeadersMessage(CNode* pfrom, CConnman* connman, ChainstateMan const CBlockIndex *pindexLast = nullptr; { LOCK(cs_main); - CNodeState *nodestate = State(pfrom->GetId()); + CNodeState *nodestate = State(pfrom.GetId()); // If this looks like it could be a block announcement (nCount < // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that @@ -1770,19 +1772,19 @@ bool static ProcessHeadersMessage(CNode* pfrom, CConnman* connman, ChainstateMan // nUnconnectingHeaders gets reset back to 0. if (!LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) { nodestate->nUnconnectingHeaders++; - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256())); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256())); LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", headers[0].GetHash().ToString(), headers[0].hashPrevBlock.ToString(), pindexBestHeader->nHeight, - pfrom->GetId(), nodestate->nUnconnectingHeaders); + pfrom.GetId(), nodestate->nUnconnectingHeaders); // Set hashLastUnknownBlock for this peer, so that if we // eventually get the headers - even from a different peer - // we can use this peer to download. - UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash()); + UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash()); if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) { - Misbehaving(pfrom->GetId(), 20); + Misbehaving(pfrom.GetId(), 20); } return true; } @@ -1790,7 +1792,7 @@ bool static ProcessHeadersMessage(CNode* pfrom, CConnman* connman, ChainstateMan uint256 hashLastBlock; for (const CBlockHeader& header : headers) { if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) { - Misbehaving(pfrom->GetId(), 20, "non-continuous headers sequence"); + Misbehaving(pfrom.GetId(), 20, "non-continuous headers sequence"); return false; } hashLastBlock = header.GetHash(); @@ -1806,21 +1808,21 @@ bool static ProcessHeadersMessage(CNode* pfrom, CConnman* connman, ChainstateMan BlockValidationState state; if (!chainman.ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) { if (state.IsInvalid()) { - MaybePunishNodeForBlock(pfrom->GetId(), state, via_compact_block, "invalid header received"); + MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received"); return false; } } { LOCK(cs_main); - CNodeState *nodestate = State(pfrom->GetId()); + CNodeState *nodestate = State(pfrom.GetId()); if (nodestate->nUnconnectingHeaders > 0) { - LogPrint(BCLog::NET, "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->GetId(), nodestate->nUnconnectingHeaders); + LogPrint(BCLog::NET, "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom.GetId(), nodestate->nUnconnectingHeaders); } nodestate->nUnconnectingHeaders = 0; assert(pindexLast); - UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); + UpdateBlockAvailability(pfrom.GetId(), pindexLast->GetBlockHash()); // From here, pindexBestKnownBlock should be guaranteed to be non-null, // because it is set in UpdateBlockAvailability. Some nullptr checks @@ -1834,8 +1836,8 @@ bool static ProcessHeadersMessage(CNode* pfrom, CConnman* connman, ChainstateMan // Headers message had its maximum size; the peer may have more headers. // TODO: optimize: if pindexLast is an ancestor of ::ChainActive().Tip or pindexBestHeader, continue // from there instead. - LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight); - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexLast), uint256())); + LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom.GetId(), pfrom.nStartingHeight); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexLast), uint256())); } bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); @@ -1848,7 +1850,7 @@ bool static ProcessHeadersMessage(CNode* pfrom, CConnman* connman, ChainstateMan while (pindexWalk && !::ChainActive().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && !mapBlocksInFlight.count(pindexWalk->GetBlockHash()) && - (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) { + (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom.GetId())->fHaveWitness)) { // We don't have this block, and it's not yet in flight. vToFetch.push_back(pindexWalk); } @@ -1872,9 +1874,9 @@ bool static ProcessHeadersMessage(CNode* pfrom, CConnman* connman, ChainstateMan } uint32_t nFetchFlags = GetFetchFlags(pfrom); vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash())); - MarkBlockAsInFlight(mempool, pfrom->GetId(), pindex->GetBlockHash(), pindex); + MarkBlockAsInFlight(mempool, pfrom.GetId(), pindex->GetBlockHash(), pindex); LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", - pindex->GetBlockHash().ToString(), pfrom->GetId()); + pindex->GetBlockHash().ToString(), pfrom.GetId()); } if (vGetData.size() > 1) { LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n", @@ -1885,7 +1887,7 @@ bool static ProcessHeadersMessage(CNode* pfrom, CConnman* connman, ChainstateMan // In any case, we want to download using a compact block, not a regular one vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); } - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData)); } } } @@ -1904,19 +1906,19 @@ bool static ProcessHeadersMessage(CNode* pfrom, CConnman* connman, ChainstateMan // nMinimumChainWork, even if a peer has a chain past our tip, // as an anti-DoS measure. if (IsOutboundDisconnectionCandidate(pfrom)) { - LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom->GetId()); - pfrom->fDisconnect = true; + LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom.GetId()); + pfrom.fDisconnect = true; } } } - if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr && pfrom->m_tx_relay != nullptr) { + if (!pfrom.fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr && pfrom.m_tx_relay != nullptr) { // If this is an outbound full-relay peer, check to see if we should protect // it from the bad/lagging chain logic. // Note that block-relay-only peers are already implicitly protected, so we // only consider setting m_protect for the full-relay peers. if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= ::ChainActive().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) { - LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom->GetId()); + LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom.GetId()); nodestate->m_chain_sync.m_protect = true; ++g_outbound_peers_with_protect_from_disconnect; } @@ -2203,9 +2205,9 @@ static void ProcessGetCFCheckPt(CNode& pfrom, CDataStream& vRecv, const CChainPa connman.PushMessage(&pfrom, std::move(msg)); } -bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, ChainstateManager& chainman, CTxMemPool& mempool, CConnman* connman, BanMan* banman, const std::atomic<bool>& interruptMsgProc) +bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, ChainstateManager& chainman, CTxMemPool& mempool, CConnman* connman, BanMan* banman, const std::atomic<bool>& interruptMsgProc) { - LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(msg_type), vRecv.size(), pfrom->GetId()); + LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(msg_type), vRecv.size(), pfrom.GetId()); if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0) { LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n"); @@ -2213,26 +2215,26 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec } - if (!(pfrom->GetLocalServices() & NODE_BLOOM) && + if (!(pfrom.GetLocalServices() & NODE_BLOOM) && (msg_type == NetMsgType::FILTERLOAD || msg_type == NetMsgType::FILTERADD)) { - if (pfrom->nVersion >= NO_BLOOM_VERSION) { + if (pfrom.nVersion >= NO_BLOOM_VERSION) { LOCK(cs_main); - Misbehaving(pfrom->GetId(), 100); + Misbehaving(pfrom.GetId(), 100); return false; } else { - pfrom->fDisconnect = true; + pfrom.fDisconnect = true; return false; } } if (msg_type == NetMsgType::VERSION) { // Each connection can only send one version message - if (pfrom->nVersion != 0) + if (pfrom.nVersion != 0) { LOCK(cs_main); - Misbehaving(pfrom->GetId(), 1); + Misbehaving(pfrom.GetId(), 1); return false; } @@ -2251,21 +2253,21 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec vRecv >> nVersion >> nServiceInt >> nTime >> addrMe; nSendVersion = std::min(nVersion, PROTOCOL_VERSION); nServices = ServiceFlags(nServiceInt); - if (!pfrom->fInbound) + if (!pfrom.fInbound) { - connman->SetServices(pfrom->addr, nServices); + connman->SetServices(pfrom.addr, nServices); } - if (!pfrom->fInbound && !pfrom->fFeeler && !pfrom->m_manual_connection && !HasAllDesirableServiceFlags(nServices)) + if (!pfrom.fInbound && !pfrom.fFeeler && !pfrom.m_manual_connection && !HasAllDesirableServiceFlags(nServices)) { - LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->GetId(), nServices, GetDesirableServiceFlags(nServices)); - pfrom->fDisconnect = true; + LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom.GetId(), nServices, GetDesirableServiceFlags(nServices)); + pfrom.fDisconnect = true; return false; } if (nVersion < MIN_PEER_PROTO_VERSION) { // disconnect from peers older than this proto version - LogPrint(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion); - pfrom->fDisconnect = true; + LogPrint(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom.GetId(), nVersion); + pfrom.fDisconnect = true; return false; } @@ -2282,145 +2284,145 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec if (!vRecv.empty()) vRecv >> fRelay; // Disconnect if we connected to ourself - if (pfrom->fInbound && !connman->CheckIncomingNonce(nNonce)) + if (pfrom.fInbound && !connman->CheckIncomingNonce(nNonce)) { - LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString()); - pfrom->fDisconnect = true; + LogPrintf("connected to self at %s, disconnecting\n", pfrom.addr.ToString()); + pfrom.fDisconnect = true; return true; } - if (pfrom->fInbound && addrMe.IsRoutable()) + if (pfrom.fInbound && addrMe.IsRoutable()) { SeenLocal(addrMe); } // Be shy and don't send version until we hear - if (pfrom->fInbound) + if (pfrom.fInbound) PushNodeVersion(pfrom, connman, GetAdjustedTime()); - connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK)); + connman->PushMessage(&pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK)); - pfrom->nServices = nServices; - pfrom->SetAddrLocal(addrMe); + pfrom.nServices = nServices; + pfrom.SetAddrLocal(addrMe); { - LOCK(pfrom->cs_SubVer); - pfrom->cleanSubVer = cleanSubVer; + LOCK(pfrom.cs_SubVer); + pfrom.cleanSubVer = cleanSubVer; } - pfrom->nStartingHeight = nStartingHeight; + pfrom.nStartingHeight = nStartingHeight; // set nodes not relaying blocks and tx and not serving (parts) of the historical blockchain as "clients" - pfrom->fClient = (!(nServices & NODE_NETWORK) && !(nServices & NODE_NETWORK_LIMITED)); + pfrom.fClient = (!(nServices & NODE_NETWORK) && !(nServices & NODE_NETWORK_LIMITED)); // set nodes not capable of serving the complete blockchain history as "limited nodes" - pfrom->m_limited_node = (!(nServices & NODE_NETWORK) && (nServices & NODE_NETWORK_LIMITED)); + pfrom.m_limited_node = (!(nServices & NODE_NETWORK) && (nServices & NODE_NETWORK_LIMITED)); - if (pfrom->m_tx_relay != nullptr) { - LOCK(pfrom->m_tx_relay->cs_filter); - pfrom->m_tx_relay->fRelayTxes = fRelay; // set to true after we get the first filter* message + if (pfrom.m_tx_relay != nullptr) { + LOCK(pfrom.m_tx_relay->cs_filter); + pfrom.m_tx_relay->fRelayTxes = fRelay; // set to true after we get the first filter* message } // Change version - pfrom->SetSendVersion(nSendVersion); - pfrom->nVersion = nVersion; + pfrom.SetSendVersion(nSendVersion); + pfrom.nVersion = nVersion; if((nServices & NODE_WITNESS)) { LOCK(cs_main); - State(pfrom->GetId())->fHaveWitness = true; + State(pfrom.GetId())->fHaveWitness = true; } // Potentially mark this peer as a preferred download peer. { LOCK(cs_main); - UpdatePreferredDownload(pfrom, State(pfrom->GetId())); + UpdatePreferredDownload(pfrom, State(pfrom.GetId())); } - if (!pfrom->fInbound && pfrom->IsAddrRelayPeer()) + if (!pfrom.fInbound && pfrom.IsAddrRelayPeer()) { // Advertise our address if (fListen && !::ChainstateActive().IsInitialBlockDownload()) { - CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices()); + CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices()); FastRandomContext insecure_rand; if (addr.IsRoutable()) { LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString()); - pfrom->PushAddress(addr, insecure_rand); - } else if (IsPeerAddrLocalGood(pfrom)) { + pfrom.PushAddress(addr, insecure_rand); + } else if (IsPeerAddrLocalGood(&pfrom)) { addr.SetIP(addrMe); LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString()); - pfrom->PushAddress(addr, insecure_rand); + pfrom.PushAddress(addr, insecure_rand); } } // Get recent addresses - if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman->GetAddressCount() < 1000) + if (pfrom.fOneShot || pfrom.nVersion >= CADDR_TIME_VERSION || connman->GetAddressCount() < 1000) { - connman->PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR)); - pfrom->fGetAddr = true; + connman->PushMessage(&pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR)); + pfrom.fGetAddr = true; } - connman->MarkAddressGood(pfrom->addr); + connman->MarkAddressGood(pfrom.addr); } std::string remoteAddr; if (fLogIPs) - remoteAddr = ", peeraddr=" + pfrom->addr.ToString(); + remoteAddr = ", peeraddr=" + pfrom.addr.ToString(); LogPrint(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n", - cleanSubVer, pfrom->nVersion, - pfrom->nStartingHeight, addrMe.ToString(), pfrom->GetId(), + cleanSubVer, pfrom.nVersion, + pfrom.nStartingHeight, addrMe.ToString(), pfrom.GetId(), remoteAddr); int64_t nTimeOffset = nTime - GetTime(); - pfrom->nTimeOffset = nTimeOffset; - AddTimeData(pfrom->addr, nTimeOffset); + pfrom.nTimeOffset = nTimeOffset; + AddTimeData(pfrom.addr, nTimeOffset); // If the peer is old enough to have the old alert system, send it the final alert. - if (pfrom->nVersion <= 70012) { + if (pfrom.nVersion <= 70012) { CDataStream finalAlert(ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"), SER_NETWORK, PROTOCOL_VERSION); - connman->PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert)); + connman->PushMessage(&pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert)); } // Feeler connections exist only to verify if address is online. - if (pfrom->fFeeler) { - assert(pfrom->fInbound == false); - pfrom->fDisconnect = true; + if (pfrom.fFeeler) { + assert(pfrom.fInbound == false); + pfrom.fDisconnect = true; } return true; } - if (pfrom->nVersion == 0) { + if (pfrom.nVersion == 0) { // Must have a version message before anything else LOCK(cs_main); - Misbehaving(pfrom->GetId(), 1); + Misbehaving(pfrom.GetId(), 1); return false; } // At this point, the outgoing message serialization version can't change. - const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); + const CNetMsgMaker msgMaker(pfrom.GetSendVersion()); if (msg_type == NetMsgType::VERACK) { - pfrom->SetRecvVersion(std::min(pfrom->nVersion.load(), PROTOCOL_VERSION)); + pfrom.SetRecvVersion(std::min(pfrom.nVersion.load(), PROTOCOL_VERSION)); - if (!pfrom->fInbound) { + if (!pfrom.fInbound) { // Mark this node as currently connected, so we update its timestamp later. LOCK(cs_main); - State(pfrom->GetId())->fCurrentlyConnected = true; + State(pfrom.GetId())->fCurrentlyConnected = true; LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s (%s)\n", - pfrom->nVersion.load(), pfrom->nStartingHeight, - pfrom->GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom->addr.ToString()) : ""), - pfrom->m_tx_relay == nullptr ? "block-relay" : "full-relay"); + pfrom.nVersion.load(), pfrom.nStartingHeight, + pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToString()) : ""), + pfrom.m_tx_relay == nullptr ? "block-relay" : "full-relay"); } - if (pfrom->nVersion >= SENDHEADERS_VERSION) { + if (pfrom.nVersion >= SENDHEADERS_VERSION) { // Tell our peer we prefer to receive headers rather than inv's // We send this to non-NODE NETWORK peers as well, because even // non-NODE NETWORK peers can announce blocks (such as pruning // nodes) - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDHEADERS)); } - if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) { + if (pfrom.nVersion >= SHORT_IDS_BLOCKS_VERSION) { // Tell our peer we are willing to provide version 1 or 2 cmpctblocks // However, we do not request new block announcements using // cmpctblock messages. @@ -2428,19 +2430,19 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // they may wish to request compact blocks from us bool fAnnounceUsingCMPCTBLOCK = false; uint64_t nCMPCTBLOCKVersion = 2; - if (pfrom->GetLocalServices() & NODE_WITNESS) - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + if (pfrom.GetLocalServices() & NODE_WITNESS) + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); nCMPCTBLOCKVersion = 1; - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); } - pfrom->fSuccessfullyConnected = true; + pfrom.fSuccessfullyConnected = true; return true; } - if (!pfrom->fSuccessfullyConnected) { + if (!pfrom.fSuccessfullyConnected) { // Must have a verack message before anything else LOCK(cs_main); - Misbehaving(pfrom->GetId(), 1); + Misbehaving(pfrom.GetId(), 1); return false; } @@ -2449,15 +2451,15 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec vRecv >> vAddr; // Don't want addr from older versions unless seeding - if (pfrom->nVersion < CADDR_TIME_VERSION && connman->GetAddressCount() > 1000) + if (pfrom.nVersion < CADDR_TIME_VERSION && connman->GetAddressCount() > 1000) return true; - if (!pfrom->IsAddrRelayPeer()) { + if (!pfrom.IsAddrRelayPeer()) { return true; } if (vAddr.size() > 1000) { LOCK(cs_main); - Misbehaving(pfrom->GetId(), 20, strprintf("message addr size() = %u", vAddr.size())); + Misbehaving(pfrom.GetId(), 20, strprintf("message addr size() = %u", vAddr.size())); return false; } @@ -2478,10 +2480,10 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) addr.nTime = nNow - 5 * 24 * 60 * 60; - pfrom->AddAddressKnown(addr); + pfrom.AddAddressKnown(addr); if (banman->IsBanned(addr)) continue; // Do not process banned addresses beyond remembering we received them bool fReachable = IsReachable(addr); - if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) + if (addr.nTime > nSince && !pfrom.fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) { // Relay to a limited number of other nodes RelayAddress(addr, fReachable, *connman); @@ -2490,17 +2492,17 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec if (fReachable) vAddrOk.push_back(addr); } - connman->AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60); + connman->AddNewAddresses(vAddrOk, pfrom.addr, 2 * 60 * 60); if (vAddr.size() < 1000) - pfrom->fGetAddr = false; - if (pfrom->fOneShot) - pfrom->fDisconnect = true; + pfrom.fGetAddr = false; + if (pfrom.fOneShot) + pfrom.fDisconnect = true; return true; } if (msg_type == NetMsgType::SENDHEADERS) { LOCK(cs_main); - State(pfrom->GetId())->fPreferHeaders = true; + State(pfrom.GetId())->fPreferHeaders = true; return true; } @@ -2508,20 +2510,20 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec bool fAnnounceUsingCMPCTBLOCK = false; uint64_t nCMPCTBLOCKVersion = 0; vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion; - if (nCMPCTBLOCKVersion == 1 || ((pfrom->GetLocalServices() & NODE_WITNESS) && nCMPCTBLOCKVersion == 2)) { + if (nCMPCTBLOCKVersion == 1 || ((pfrom.GetLocalServices() & NODE_WITNESS) && nCMPCTBLOCKVersion == 2)) { LOCK(cs_main); // fProvidesHeaderAndIDs is used to "lock in" version of compact blocks we send (fWantsCmpctWitness) - if (!State(pfrom->GetId())->fProvidesHeaderAndIDs) { - State(pfrom->GetId())->fProvidesHeaderAndIDs = true; - State(pfrom->GetId())->fWantsCmpctWitness = nCMPCTBLOCKVersion == 2; + if (!State(pfrom.GetId())->fProvidesHeaderAndIDs) { + State(pfrom.GetId())->fProvidesHeaderAndIDs = true; + State(pfrom.GetId())->fWantsCmpctWitness = nCMPCTBLOCKVersion == 2; } - if (State(pfrom->GetId())->fWantsCmpctWitness == (nCMPCTBLOCKVersion == 2)) // ignore later version announces - State(pfrom->GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK; - if (!State(pfrom->GetId())->fSupportsDesiredCmpctVersion) { - if (pfrom->GetLocalServices() & NODE_WITNESS) - State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2); + if (State(pfrom.GetId())->fWantsCmpctWitness == (nCMPCTBLOCKVersion == 2)) // ignore later version announces + State(pfrom.GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK; + if (!State(pfrom.GetId())->fSupportsDesiredCmpctVersion) { + if (pfrom.GetLocalServices() & NODE_WITNESS) + State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2); else - State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1); + State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1); } } return true; @@ -2533,16 +2535,16 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec if (vInv.size() > MAX_INV_SZ) { LOCK(cs_main); - Misbehaving(pfrom->GetId(), 20, strprintf("message inv size() = %u", vInv.size())); + Misbehaving(pfrom.GetId(), 20, strprintf("message inv size() = %u", vInv.size())); return false; } // We won't accept tx inv's if we're in blocks-only mode, or this is a // block-relay-only peer - bool fBlocksOnly = !g_relay_txes || (pfrom->m_tx_relay == nullptr); + bool fBlocksOnly = !g_relay_txes || (pfrom.m_tx_relay == nullptr); // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true - if (pfrom->HasPermission(PF_RELAY)) + if (pfrom.HasPermission(PF_RELAY)) fBlocksOnly = false; LOCK(cs_main); @@ -2557,14 +2559,14 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec return true; bool fAlreadyHave = AlreadyHave(inv, mempool); - LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->GetId()); + LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId()); if (inv.type == MSG_TX) { inv.type |= nFetchFlags; } if (inv.type == MSG_BLOCK) { - UpdateBlockAvailability(pfrom->GetId(), inv.hash); + UpdateBlockAvailability(pfrom.GetId(), inv.hash); if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) { // Headers-first is the primary method of announcement on // the network. If a node fell back to sending blocks by inv, @@ -2574,20 +2576,20 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec best_block = &inv.hash; } } else { - pfrom->AddInventoryKnown(inv); + pfrom.AddInventoryKnown(inv); if (fBlocksOnly) { - LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom->GetId()); - pfrom->fDisconnect = true; + LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId()); + pfrom.fDisconnect = true; return true; } else if (!fAlreadyHave && !fImporting && !fReindex && !::ChainstateActive().IsInitialBlockDownload()) { - RequestTx(State(pfrom->GetId()), inv.hash, current_time); + RequestTx(State(pfrom.GetId()), inv.hash, current_time); } } } if (best_block != nullptr) { - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), *best_block)); - LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom->GetId()); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), *best_block)); + LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom.GetId()); } return true; @@ -2599,17 +2601,17 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec if (vInv.size() > MAX_INV_SZ) { LOCK(cs_main); - Misbehaving(pfrom->GetId(), 20, strprintf("message getdata size() = %u", vInv.size())); + Misbehaving(pfrom.GetId(), 20, strprintf("message getdata size() = %u", vInv.size())); return false; } - LogPrint(BCLog::NET, "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom->GetId()); + LogPrint(BCLog::NET, "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom.GetId()); if (vInv.size() > 0) { - LogPrint(BCLog::NET, "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->GetId()); + LogPrint(BCLog::NET, "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom.GetId()); } - pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); + pfrom.vRecvGetData.insert(pfrom.vRecvGetData.end(), vInv.begin(), vInv.end()); ProcessGetData(pfrom, chainparams, connman, mempool, interruptMsgProc); return true; } @@ -2620,8 +2622,8 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec vRecv >> locator >> hashStop; if (locator.vHave.size() > MAX_LOCATOR_SZ) { - LogPrint(BCLog::NET, "getblocks locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom->GetId()); - pfrom->fDisconnect = true; + LogPrint(BCLog::NET, "getblocks locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.GetId()); + pfrom.fDisconnect = true; return true; } @@ -2653,7 +2655,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec if (pindex) pindex = ::ChainActive().Next(pindex); int nLimit = 500; - LogPrint(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom->GetId()); + LogPrint(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom.GetId()); for (; pindex; pindex = ::ChainActive().Next(pindex)) { if (pindex->GetBlockHash() == hashStop) @@ -2669,13 +2671,13 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); break; } - pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); + pfrom.PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); if (--nLimit <= 0) { // When this block is requested, we'll send an inv that'll // trigger the peer to getblocks the next batch of inventory. LogPrint(BCLog::NET, " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); - pfrom->hashContinue = pindex->GetBlockHash(); + pfrom.hashContinue = pindex->GetBlockHash(); break; } } @@ -2702,7 +2704,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec const CBlockIndex* pindex = LookupBlockIndex(req.blockhash); if (!pindex || !(pindex->nStatus & BLOCK_HAVE_DATA)) { - LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom->GetId()); + LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom.GetId()); return true; } @@ -2714,11 +2716,11 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // might maliciously send lots of getblocktxn requests to trigger // expensive disk reads, because it will require the peer to // actually receive all the data read from disk over the network. - LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block > %i deep\n", pfrom->GetId(), MAX_BLOCKTXN_DEPTH); + LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block > %i deep\n", pfrom.GetId(), MAX_BLOCKTXN_DEPTH); CInv inv; - inv.type = State(pfrom->GetId())->fWantsCmpctWitness ? MSG_WITNESS_BLOCK : MSG_BLOCK; + inv.type = State(pfrom.GetId())->fWantsCmpctWitness ? MSG_WITNESS_BLOCK : MSG_BLOCK; inv.hash = req.blockhash; - pfrom->vRecvGetData.push_back(inv); + pfrom.vRecvGetData.push_back(inv); // The message processing loop will go around again (without pausing) and we'll respond then (without cs_main) return true; } @@ -2737,18 +2739,18 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec vRecv >> locator >> hashStop; if (locator.vHave.size() > MAX_LOCATOR_SZ) { - LogPrint(BCLog::NET, "getheaders locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom->GetId()); - pfrom->fDisconnect = true; + LogPrint(BCLog::NET, "getheaders locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.GetId()); + pfrom.fDisconnect = true; return true; } LOCK(cs_main); - if (::ChainstateActive().IsInitialBlockDownload() && !pfrom->HasPermission(PF_NOBAN)) { - LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->GetId()); + if (::ChainstateActive().IsInitialBlockDownload() && !pfrom.HasPermission(PF_NOBAN)) { + LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom.GetId()); return true; } - CNodeState *nodestate = State(pfrom->GetId()); + CNodeState *nodestate = State(pfrom.GetId()); const CBlockIndex* pindex = nullptr; if (locator.IsNull()) { @@ -2759,7 +2761,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec } if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) { - LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom->GetId()); + LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom.GetId()); return true; } } @@ -2774,7 +2776,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end std::vector<CBlock> vHeaders; int nLimit = MAX_HEADERS_RESULTS; - LogPrint(BCLog::NET, "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom->GetId()); + LogPrint(BCLog::NET, "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom.GetId()); for (; pindex; pindex = ::ChainActive().Next(pindex)) { vHeaders.push_back(pindex->GetBlockHeader()); @@ -2794,7 +2796,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // will re-announce the new block via headers (or compact blocks again) // in the SendMessages logic. nodestate->pindexBestHeaderSent = pindex ? pindex : ::ChainActive().Tip(); - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); return true; } @@ -2802,10 +2804,10 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // Stop processing the transaction early if // 1) We are in blocks only mode and peer has no relay permission // 2) This peer is a block-relay-only peer - if ((!g_relay_txes && !pfrom->HasPermission(PF_RELAY)) || (pfrom->m_tx_relay == nullptr)) + if ((!g_relay_txes && !pfrom.HasPermission(PF_RELAY)) || (pfrom.m_tx_relay == nullptr)) { - LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom->GetId()); - pfrom->fDisconnect = true; + LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom.GetId()); + pfrom.fDisconnect = true; return true; } @@ -2814,13 +2816,13 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec const CTransaction& tx = *ptx; CInv inv(MSG_TX, tx.GetHash()); - pfrom->AddInventoryKnown(inv); + pfrom.AddInventoryKnown(inv); LOCK2(cs_main, g_cs_orphans); TxValidationState state; - CNodeState* nodestate = State(pfrom->GetId()); + CNodeState* nodestate = State(pfrom.GetId()); nodestate->m_tx_download.m_tx_announced.erase(inv.hash); nodestate->m_tx_download.m_tx_in_flight.erase(inv.hash); EraseTxRequest(inv.hash); @@ -2835,20 +2837,20 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(inv.hash, i)); if (it_by_prev != mapOrphanTransactionsByPrev.end()) { for (const auto& elem : it_by_prev->second) { - pfrom->orphan_work_set.insert(elem->first); + pfrom.orphan_work_set.insert(elem->first); } } } - pfrom->nLastTXTime = GetTime(); + pfrom.nLastTXTime = GetTime(); LogPrint(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n", - pfrom->GetId(), + pfrom.GetId(), tx.GetHash().ToString(), mempool.size(), mempool.DynamicMemoryUsage() / 1000); // Recursively process any orphan transactions that depended on this one - ProcessOrphanTx(connman, mempool, pfrom->orphan_work_set, lRemovedTxn); + ProcessOrphanTx(connman, mempool, pfrom.orphan_work_set, lRemovedTxn); } else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { @@ -2865,10 +2867,10 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec for (const CTxIn& txin : tx.vin) { CInv _inv(MSG_TX | nFetchFlags, txin.prevout.hash); - pfrom->AddInventoryKnown(_inv); - if (!AlreadyHave(_inv, mempool)) RequestTx(State(pfrom->GetId()), _inv.hash, current_time); + pfrom.AddInventoryKnown(_inv); + if (!AlreadyHave(_inv, mempool)) RequestTx(State(pfrom.GetId()), _inv.hash, current_time); } - AddOrphanTx(ptx, pfrom->GetId()); + AddOrphanTx(ptx, pfrom.GetId()); // DoS prevention: do not allow mapOrphanTransactions to grow unbounded (see CVE-2012-3789) unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, gArgs.GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); @@ -2896,15 +2898,15 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec AddToCompactExtraTransactions(ptx); } - if (pfrom->HasPermission(PF_FORCERELAY)) { + if (pfrom.HasPermission(PF_FORCERELAY)) { // Always relay transactions received from whitelisted peers, even // if they were already in the mempool, // allowing the node to function as a gateway for // nodes hidden behind it. if (!mempool.exists(tx.GetHash())) { - LogPrintf("Not relaying non-mempool transaction %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->GetId()); + LogPrintf("Not relaying non-mempool transaction %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom.GetId()); } else { - LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->GetId()); + LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom.GetId()); RelayTransaction(tx.GetHash(), *connman); } } @@ -2933,9 +2935,9 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec if (state.IsInvalid()) { LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(), - pfrom->GetId(), + pfrom.GetId(), state.ToString()); - MaybePunishNodeForTx(pfrom->GetId(), state); + MaybePunishNodeForTx(pfrom.GetId(), state); } return true; } @@ -2944,7 +2946,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec { // Ignore cmpctblock received while importing if (fImporting || fReindex) { - LogPrint(BCLog::NET, "Unexpected cmpctblock message received from peer %d\n", pfrom->GetId()); + LogPrint(BCLog::NET, "Unexpected cmpctblock message received from peer %d\n", pfrom.GetId()); return true; } @@ -2959,7 +2961,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) { // Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers if (!::ChainstateActive().IsInitialBlockDownload()) - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256())); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256())); return true; } @@ -2972,7 +2974,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec BlockValidationState state; if (!chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) { if (state.IsInvalid()) { - MaybePunishNodeForBlock(pfrom->GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock"); + MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock"); return true; } } @@ -2997,9 +2999,9 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec LOCK2(cs_main, g_cs_orphans); // If AcceptBlockHeader returned true, it set pindex assert(pindex); - UpdateBlockAvailability(pfrom->GetId(), pindex->GetBlockHash()); + UpdateBlockAvailability(pfrom.GetId(), pindex->GetBlockHash()); - CNodeState *nodestate = State(pfrom->GetId()); + CNodeState *nodestate = State(pfrom.GetId()); // If this was a new header with more work than our tip, update the // peer's last block announcement time @@ -3020,7 +3022,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // so we just grab the block via normal getdata std::vector<CInv> vInv(1); vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash()); - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); } return true; } @@ -3039,9 +3041,9 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // possibilities in compact block processing... if (pindex->nHeight <= ::ChainActive().Height() + 2) { if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) || - (fAlreadyInFlight && blockInFlightIt->second.first == pfrom->GetId())) { + (fAlreadyInFlight && blockInFlightIt->second.first == pfrom.GetId())) { std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr; - if (!MarkBlockAsInFlight(mempool, pfrom->GetId(), pindex->GetBlockHash(), pindex, &queuedBlockIt)) { + if (!MarkBlockAsInFlight(mempool, pfrom.GetId(), pindex->GetBlockHash(), pindex, &queuedBlockIt)) { if (!(*queuedBlockIt)->partialBlock) (*queuedBlockIt)->partialBlock.reset(new PartiallyDownloadedBlock(&mempool)); else { @@ -3055,13 +3057,13 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact); if (status == READ_STATUS_INVALID) { MarkBlockAsReceived(pindex->GetBlockHash()); // Reset in-flight state in case of whitelist - Misbehaving(pfrom->GetId(), 100, strprintf("Peer %d sent us invalid compact block\n", pfrom->GetId())); + Misbehaving(pfrom.GetId(), 100, strprintf("Peer %d sent us invalid compact block\n", pfrom.GetId())); return true; } else if (status == READ_STATUS_FAILED) { // Duplicate txindexes, the block is now in-flight, so just request it std::vector<CInv> vInv(1); vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash()); - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); return true; } @@ -3078,7 +3080,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec fProcessBLOCKTXN = true; } else { req.blockhash = pindex->GetBlockHash(); - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req)); } } else { // This block is either already in flight from a different @@ -3104,7 +3106,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // mempool will probably be useless - request the block normally std::vector<CInv> vInv(1); vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash()); - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv)); return true; } else { // If this was an announce-cmpctblock, we want the same treatment as a header message @@ -3130,7 +3132,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // block that is in flight from some other peer. { LOCK(cs_main); - mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom->GetId(), false)); + mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom.GetId(), false)); } bool fNewBlock = false; // Setting fForceProcessing to true means that we bypass some of @@ -3144,7 +3146,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // reconstructed compact blocks as having been requested. chainman.ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock); if (fNewBlock) { - pfrom->nLastBlockTime = GetTime(); + pfrom.nLastBlockTime = GetTime(); } else { LOCK(cs_main); mapBlockSource.erase(pblock->GetHash()); @@ -3165,7 +3167,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec { // Ignore blocktxn received while importing if (fImporting || fReindex) { - LogPrint(BCLog::NET, "Unexpected blocktxn message received from peer %d\n", pfrom->GetId()); + LogPrint(BCLog::NET, "Unexpected blocktxn message received from peer %d\n", pfrom.GetId()); return true; } @@ -3179,8 +3181,8 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator it = mapBlocksInFlight.find(resp.blockhash); if (it == mapBlocksInFlight.end() || !it->second.second->partialBlock || - it->second.first != pfrom->GetId()) { - LogPrint(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom->GetId()); + it->second.first != pfrom.GetId()) { + LogPrint(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId()); return true; } @@ -3188,13 +3190,13 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn); if (status == READ_STATUS_INVALID) { MarkBlockAsReceived(resp.blockhash); // Reset in-flight state in case of whitelist - Misbehaving(pfrom->GetId(), 100, strprintf("Peer %d sent us invalid compact block/non-matching block transactions\n", pfrom->GetId())); + Misbehaving(pfrom.GetId(), 100, strprintf("Peer %d sent us invalid compact block/non-matching block transactions\n", pfrom.GetId())); return true; } else if (status == READ_STATUS_FAILED) { // Might have collided, fall back to getdata now :( std::vector<CInv> invs; invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom), resp.blockhash)); - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs)); } else { // Block is either okay, or possibly we received // READ_STATUS_CHECKBLOCK_FAILED. @@ -3221,7 +3223,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // BIP 152 permits peers to relay compact blocks after validating // the header only; we should not punish peers if the block turns // out to be invalid. - mapBlockSource.emplace(resp.blockhash, std::make_pair(pfrom->GetId(), false)); + mapBlockSource.emplace(resp.blockhash, std::make_pair(pfrom.GetId(), false)); } } // Don't hold cs_main when we call into ProcessNewBlock if (fBlockRead) { @@ -3234,7 +3236,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // in compact block optimistic reconstruction handling. chainman.ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock); if (fNewBlock) { - pfrom->nLastBlockTime = GetTime(); + pfrom.nLastBlockTime = GetTime(); } else { LOCK(cs_main); mapBlockSource.erase(pblock->GetHash()); @@ -3247,7 +3249,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec { // Ignore headers received while importing if (fImporting || fReindex) { - LogPrint(BCLog::NET, "Unexpected headers message received from peer %d\n", pfrom->GetId()); + LogPrint(BCLog::NET, "Unexpected headers message received from peer %d\n", pfrom.GetId()); return true; } @@ -3257,7 +3259,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec unsigned int nCount = ReadCompactSize(vRecv); if (nCount > MAX_HEADERS_RESULTS) { LOCK(cs_main); - Misbehaving(pfrom->GetId(), 20, strprintf("headers message size = %u", nCount)); + Misbehaving(pfrom.GetId(), 20, strprintf("headers message size = %u", nCount)); return false; } headers.resize(nCount); @@ -3273,14 +3275,14 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec { // Ignore block received while importing if (fImporting || fReindex) { - LogPrint(BCLog::NET, "Unexpected block message received from peer %d\n", pfrom->GetId()); + LogPrint(BCLog::NET, "Unexpected block message received from peer %d\n", pfrom.GetId()); return true; } std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); vRecv >> *pblock; - LogPrint(BCLog::NET, "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom->GetId()); + LogPrint(BCLog::NET, "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom.GetId()); bool forceProcessing = false; const uint256 hash(pblock->GetHash()); @@ -3292,12 +3294,12 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // mapBlockSource is only used for punishing peers and setting // which peers send us compact blocks, so the race between here and // cs_main in ProcessNewBlock is fine. - mapBlockSource.emplace(hash, std::make_pair(pfrom->GetId(), true)); + mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true)); } bool fNewBlock = false; chainman.ProcessNewBlock(chainparams, pblock, forceProcessing, &fNewBlock); if (fNewBlock) { - pfrom->nLastBlockTime = GetTime(); + pfrom.nLastBlockTime = GetTime(); } else { LOCK(cs_main); mapBlockSource.erase(pblock->GetHash()); @@ -3311,64 +3313,64 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // to users' AddrMan and later request them by sending getaddr messages. // Making nodes which are behind NAT and can only make outgoing connections ignore // the getaddr message mitigates the attack. - if (!pfrom->fInbound) { - LogPrint(BCLog::NET, "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom->GetId()); + if (!pfrom.fInbound) { + LogPrint(BCLog::NET, "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom.GetId()); return true; } - if (!pfrom->IsAddrRelayPeer()) { - LogPrint(BCLog::NET, "Ignoring \"getaddr\" from block-relay-only connection. peer=%d\n", pfrom->GetId()); + if (!pfrom.IsAddrRelayPeer()) { + LogPrint(BCLog::NET, "Ignoring \"getaddr\" from block-relay-only connection. peer=%d\n", pfrom.GetId()); return true; } // Only send one GetAddr response per connection to reduce resource waste // and discourage addr stamping of INV announcements. - if (pfrom->fSentAddr) { - LogPrint(BCLog::NET, "Ignoring repeated \"getaddr\". peer=%d\n", pfrom->GetId()); + if (pfrom.fSentAddr) { + LogPrint(BCLog::NET, "Ignoring repeated \"getaddr\". peer=%d\n", pfrom.GetId()); return true; } - pfrom->fSentAddr = true; + pfrom.fSentAddr = true; - pfrom->vAddrToSend.clear(); + pfrom.vAddrToSend.clear(); std::vector<CAddress> vAddr = connman->GetAddresses(); FastRandomContext insecure_rand; for (const CAddress &addr : vAddr) { if (!banman->IsBanned(addr)) { - pfrom->PushAddress(addr, insecure_rand); + pfrom.PushAddress(addr, insecure_rand); } } return true; } if (msg_type == NetMsgType::MEMPOOL) { - if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->HasPermission(PF_MEMPOOL)) + if (!(pfrom.GetLocalServices() & NODE_BLOOM) && !pfrom.HasPermission(PF_MEMPOOL)) { - if (!pfrom->HasPermission(PF_NOBAN)) + if (!pfrom.HasPermission(PF_NOBAN)) { - LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId()); - pfrom->fDisconnect = true; + LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom.GetId()); + pfrom.fDisconnect = true; } return true; } - if (connman->OutboundTargetReached(false) && !pfrom->HasPermission(PF_MEMPOOL)) + if (connman->OutboundTargetReached(false) && !pfrom.HasPermission(PF_MEMPOOL)) { - if (!pfrom->HasPermission(PF_NOBAN)) + if (!pfrom.HasPermission(PF_NOBAN)) { - LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId()); - pfrom->fDisconnect = true; + LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom.GetId()); + pfrom.fDisconnect = true; } return true; } - if (pfrom->m_tx_relay != nullptr) { - LOCK(pfrom->m_tx_relay->cs_tx_inventory); - pfrom->m_tx_relay->fSendMempool = true; + if (pfrom.m_tx_relay != nullptr) { + LOCK(pfrom.m_tx_relay->cs_tx_inventory); + pfrom.m_tx_relay->fSendMempool = true; } return true; } if (msg_type == NetMsgType::PING) { - if (pfrom->nVersion > BIP0031_VERSION) + if (pfrom.nVersion > BIP0031_VERSION) { uint64_t nonce = 0; vRecv >> nonce; @@ -3383,7 +3385,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec // it, if the remote node sends a ping once per second and this node takes 5 // seconds to respond to each, the 5th ping the remote sends would appear to // return very quickly. - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce)); + connman->PushMessage(&pfrom, msgMaker.Make(NetMsgType::PONG, nonce)); } return true; } @@ -3399,15 +3401,15 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec vRecv >> nonce; // Only process pong message if there is an outstanding ping (old ping without nonce should never pong) - if (pfrom->nPingNonceSent != 0) { - if (nonce == pfrom->nPingNonceSent) { + if (pfrom.nPingNonceSent != 0) { + if (nonce == pfrom.nPingNonceSent) { // Matching pong received, this ping is no longer outstanding bPingFinished = true; - int64_t pingUsecTime = pingUsecEnd - pfrom->nPingUsecStart; + int64_t pingUsecTime = pingUsecEnd - pfrom.nPingUsecStart; if (pingUsecTime > 0) { // Successful ping time measurement, replace previous - pfrom->nPingUsecTime = pingUsecTime; - pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime.load(), pingUsecTime); + pfrom.nPingUsecTime = pingUsecTime; + pfrom.nMinPingUsecTime = std::min(pfrom.nMinPingUsecTime.load(), pingUsecTime); } else { // This should never happen sProblem = "Timing mishap"; @@ -3432,14 +3434,14 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec if (!(sProblem.empty())) { LogPrint(BCLog::NET, "pong peer=%d: %s, %x expected, %x received, %u bytes\n", - pfrom->GetId(), + pfrom.GetId(), sProblem, - pfrom->nPingNonceSent, + pfrom.nPingNonceSent, nonce, nAvail); } if (bPingFinished) { - pfrom->nPingNonceSent = 0; + pfrom.nPingNonceSent = 0; } return true; } @@ -3452,13 +3454,13 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec { // There is no excuse for sending a too-large filter LOCK(cs_main); - Misbehaving(pfrom->GetId(), 100); + Misbehaving(pfrom.GetId(), 100); } - else if (pfrom->m_tx_relay != nullptr) + else if (pfrom.m_tx_relay != nullptr) { - LOCK(pfrom->m_tx_relay->cs_filter); - pfrom->m_tx_relay->pfilter.reset(new CBloomFilter(filter)); - pfrom->m_tx_relay->fRelayTxes = true; + LOCK(pfrom.m_tx_relay->cs_filter); + pfrom.m_tx_relay->pfilter.reset(new CBloomFilter(filter)); + pfrom.m_tx_relay->fRelayTxes = true; } return true; } @@ -3472,30 +3474,30 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec bool bad = false; if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) { bad = true; - } else if (pfrom->m_tx_relay != nullptr) { - LOCK(pfrom->m_tx_relay->cs_filter); - if (pfrom->m_tx_relay->pfilter) { - pfrom->m_tx_relay->pfilter->insert(vData); + } else if (pfrom.m_tx_relay != nullptr) { + LOCK(pfrom.m_tx_relay->cs_filter); + if (pfrom.m_tx_relay->pfilter) { + pfrom.m_tx_relay->pfilter->insert(vData); } else { bad = true; } } if (bad) { LOCK(cs_main); - Misbehaving(pfrom->GetId(), 100); + Misbehaving(pfrom.GetId(), 100); } return true; } if (msg_type == NetMsgType::FILTERCLEAR) { - if (pfrom->m_tx_relay == nullptr) { + if (pfrom.m_tx_relay == nullptr) { return true; } - LOCK(pfrom->m_tx_relay->cs_filter); - if (pfrom->GetLocalServices() & NODE_BLOOM) { - pfrom->m_tx_relay->pfilter = nullptr; + LOCK(pfrom.m_tx_relay->cs_filter); + if (pfrom.GetLocalServices() & NODE_BLOOM) { + pfrom.m_tx_relay->pfilter = nullptr; } - pfrom->m_tx_relay->fRelayTxes = true; + pfrom.m_tx_relay->fRelayTxes = true; return true; } @@ -3503,34 +3505,34 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec CAmount newFeeFilter = 0; vRecv >> newFeeFilter; if (MoneyRange(newFeeFilter)) { - if (pfrom->m_tx_relay != nullptr) { - LOCK(pfrom->m_tx_relay->cs_feeFilter); - pfrom->m_tx_relay->minFeeFilter = newFeeFilter; + if (pfrom.m_tx_relay != nullptr) { + LOCK(pfrom.m_tx_relay->cs_feeFilter); + pfrom.m_tx_relay->minFeeFilter = newFeeFilter; } - LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->GetId()); + LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom.GetId()); } return true; } if (msg_type == NetMsgType::GETCFILTERS) { - ProcessGetCFilters(*pfrom, vRecv, chainparams, *connman); + ProcessGetCFilters(pfrom, vRecv, chainparams, *connman); return true; } if (msg_type == NetMsgType::GETCFHEADERS) { - ProcessGetCFHeaders(*pfrom, vRecv, chainparams, *connman); + ProcessGetCFHeaders(pfrom, vRecv, chainparams, *connman); return true; } if (msg_type == NetMsgType::GETCFCHECKPT) { - ProcessGetCFCheckPt(*pfrom, vRecv, chainparams, *connman); + ProcessGetCFCheckPt(pfrom, vRecv, chainparams, *connman); return true; } if (msg_type == NetMsgType::NOTFOUND) { // Remove the NOTFOUND transactions from the peer LOCK(cs_main); - CNodeState *state = State(pfrom->GetId()); + CNodeState *state = State(pfrom.GetId()); std::vector<CInv> vInv; vRecv >> vInv; if (vInv.size() <= MAX_PEER_TX_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER) { @@ -3553,31 +3555,31 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec } // Ignore unknown commands for extensibility - LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom->GetId()); + LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom.GetId()); return true; } -bool PeerLogicValidation::CheckIfBanned(CNode* pnode) +bool PeerLogicValidation::CheckIfBanned(CNode& pnode) { AssertLockHeld(cs_main); - CNodeState &state = *State(pnode->GetId()); + CNodeState &state = *State(pnode.GetId()); if (state.fShouldBan) { state.fShouldBan = false; - if (pnode->HasPermission(PF_NOBAN)) - LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode->addr.ToString()); - else if (pnode->m_manual_connection) - LogPrintf("Warning: not punishing manually-connected peer %s!\n", pnode->addr.ToString()); - else if (pnode->addr.IsLocal()) { + if (pnode.HasPermission(PF_NOBAN)) + LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode.addr.ToString()); + else if (pnode.m_manual_connection) + LogPrintf("Warning: not punishing manually-connected peer %s!\n", pnode.addr.ToString()); + else if (pnode.addr.IsLocal()) { // Disconnect but don't ban _this_ local node - LogPrintf("Warning: disconnecting but not banning local peer %s!\n", pnode->addr.ToString()); - pnode->fDisconnect = true; + LogPrintf("Warning: disconnecting but not banning local peer %s!\n", pnode.addr.ToString()); + pnode.fDisconnect = true; } else { // Disconnect and ban all nodes sharing the address if (m_banman) { - m_banman->Ban(pnode->addr, BanReasonNodeMisbehaving); + m_banman->Ban(pnode.addr, BanReasonNodeMisbehaving); } - connman->DisconnectNode(pnode->addr); + connman->DisconnectNode(pnode.addr); } return true; } @@ -3598,7 +3600,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter bool fMoreWork = false; if (!pfrom->vRecvGetData.empty()) - ProcessGetData(pfrom, chainparams, connman, m_mempool, interruptMsgProc); + ProcessGetData(*pfrom, chainparams, connman, m_mempool, interruptMsgProc); if (!pfrom->orphan_work_set.empty()) { std::list<CTransactionRef> removed_txn; @@ -3666,7 +3668,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter bool fRet = false; try { - fRet = ProcessMessage(pfrom, msg_type, vRecv, msg.m_time, chainparams, m_chainman, m_mempool, connman, m_banman, interruptMsgProc); + fRet = ProcessMessage(*pfrom, msg_type, vRecv, msg.m_time, chainparams, m_chainman, m_mempool, connman, m_banman, interruptMsgProc); if (interruptMsgProc) return false; if (!pfrom->vRecvGetData.empty()) @@ -3682,17 +3684,17 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter } LOCK(cs_main); - CheckIfBanned(pfrom); + CheckIfBanned(*pfrom); return fMoreWork; } -void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds) +void PeerLogicValidation::ConsiderEviction(CNode& pto, int64_t time_in_seconds) { AssertLockHeld(cs_main); - CNodeState &state = *State(pto->GetId()); - const CNetMsgMaker msgMaker(pto->GetSendVersion()); + CNodeState &state = *State(pto.GetId()); + const CNetMsgMaker msgMaker(pto.GetSendVersion()); if (!state.m_chain_sync.m_protect && IsOutboundDisconnectionCandidate(pto) && state.fSyncStarted) { // This is an outbound peer subject to disconnection if they don't @@ -3721,12 +3723,12 @@ void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds) // message to give the peer a chance to update us. if (state.m_chain_sync.m_sent_getheaders) { // They've run out of time to catch up! - LogPrintf("Disconnecting outbound peer %d for old chain, best known block = %s\n", pto->GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>"); - pto->fDisconnect = true; + LogPrintf("Disconnecting outbound peer %d for old chain, best known block = %s\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>"); + pto.fDisconnect = true; } else { assert(state.m_chain_sync.m_work_header); - LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto->GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString()); - connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(state.m_chain_sync.m_work_header->pprev), uint256())); + LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString()); + connman->PushMessage(&pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(state.m_chain_sync.m_work_header->pprev), uint256())); state.m_chain_sync.m_sent_getheaders = true; constexpr int64_t HEADERS_RESPONSE_TIME = 120; // 2 minutes // Bump the timeout to allow a response, which could clear the timeout @@ -3756,7 +3758,7 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds) AssertLockHeld(cs_main); // Ignore non-outbound peers, or nodes marked for disconnect already - if (!IsOutboundDisconnectionCandidate(pnode) || pnode->fDisconnect) return; + if (!IsOutboundDisconnectionCandidate(*pnode) || pnode->fDisconnect) return; CNodeState *state = State(pnode->GetId()); if (state == nullptr) return; // shouldn't be possible, but just in case // Don't evict our protected peers @@ -3885,7 +3887,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto) if (!lockMain) return true; - if (CheckIfBanned(pto)) return true; + if (CheckIfBanned(*pto)) return true; CNodeState &state = *State(pto->GetId()); @@ -4296,7 +4298,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto) // Check that outbound peers have reasonable chains // GetTime() is used by this anti-DoS logic so we can test this using mocktime - ConsiderEviction(pto, GetTime()); + ConsiderEviction(*pto, GetTime()); // // Message: getdata (blocks) @@ -4307,7 +4309,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto) NodeId staller = -1; FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams); for (const CBlockIndex *pindex : vToDownload) { - uint32_t nFetchFlags = GetFetchFlags(pto); + uint32_t nFetchFlags = GetFetchFlags(*pto); vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash())); MarkBlockAsInFlight(m_mempool, pto->GetId(), pindex->GetBlockHash(), pindex); LogPrint(BCLog::NET, "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), @@ -4351,7 +4353,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto) // Erase this entry from tx_process_time (it may be added back for // processing at a later time, see below) tx_process_time.erase(tx_process_time.begin()); - CInv inv(MSG_TX | GetFetchFlags(pto), txid); + CInv inv(MSG_TX | GetFetchFlags(*pto), txid); if (!AlreadyHave(inv, m_mempool)) { // If this transaction was last requested more than 1 minute ago, // then request. diff --git a/src/net_processing.h b/src/net_processing.h index ec758c7537..19beca0cc4 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -31,7 +31,7 @@ private: ChainstateManager& m_chainman; CTxMemPool& m_mempool; - bool CheckIfBanned(CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool CheckIfBanned(CNode& pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main); public: PeerLogicValidation(CConnman* connman, BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool); @@ -74,7 +74,7 @@ public: bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing); /** Consider evicting an outbound peer based on the amount of time they've been behind our tip */ - void ConsiderEviction(CNode *pto, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + void ConsiderEviction(CNode& pto, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound */ void CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams); /** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */ diff --git a/src/protocol.cpp b/src/protocol.cpp index 83a24b9d95..2dfe4bee74 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -5,8 +5,8 @@ #include <protocol.h> -#include <util/system.h> #include <util/strencodings.h> +#include <util/system.h> #ifndef WIN32 # include <arpa/inet.h> @@ -220,11 +220,7 @@ static std::string serviceFlagToStr(size_t bit) std::ostringstream stream; stream.imbue(std::locale::classic()); stream << "UNKNOWN["; - if (bit < 8) { - stream << service_flag; - } else { - stream << "2^" << bit; - } + stream << "2^" << bit; stream << "]"; return stream.str(); } diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 6192013e5f..195d80d47c 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -350,6 +350,9 @@ void BitcoinGUI::createActions() m_create_wallet_action->setEnabled(false); m_create_wallet_action->setStatusTip(tr("Create a new wallet")); + m_close_all_wallets_action = new QAction(tr("Close All Wallets..."), this); + m_close_all_wallets_action->setStatusTip(tr("Close all wallets")); + showHelpMessageAction = new QAction(tr("&Command-line options"), this); showHelpMessageAction->setMenuRole(QAction::NoRole); showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(PACKAGE_NAME)); @@ -421,7 +424,9 @@ void BitcoinGUI::createActions() connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater); activity->create(); }); - + connect(m_close_all_wallets_action, &QAction::triggered, [this] { + m_wallet_controller->closeAllWallets(this); + }); connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::setPrivacy); } #endif // ENABLE_WALLET @@ -447,6 +452,7 @@ void BitcoinGUI::createMenuBar() file->addAction(m_create_wallet_action); file->addAction(m_open_wallet_action); file->addAction(m_close_wallet_action); + file->addAction(m_close_all_wallets_action); file->addSeparator(); file->addAction(openAction); file->addAction(backupWalletAction); @@ -727,6 +733,7 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) usedReceivingAddressesAction->setEnabled(enabled); openAction->setEnabled(enabled); m_close_wallet_action->setEnabled(enabled); + m_close_all_wallets_action->setEnabled(enabled); } void BitcoinGUI::createTrayIcon() diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index c0198dd168..b009e279b6 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -155,6 +155,7 @@ private: QAction* m_open_wallet_action{nullptr}; QMenu* m_open_wallet_menu{nullptr}; QAction* m_close_wallet_action{nullptr}; + QAction* m_close_all_wallets_action{nullptr}; QAction* m_wallet_selector_label_action = nullptr; QAction* m_wallet_selector_action = nullptr; QAction* m_mask_values_action{nullptr}; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index f15921c5bc..c1d358f7f6 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -116,9 +116,23 @@ int ClientModel::getNumBlocks() const uint256 ClientModel::getBestBlockHash() { + uint256 tip{WITH_LOCK(m_cached_tip_mutex, return m_cached_tip_blocks)}; + + if (!tip.IsNull()) { + return tip; + } + + // Lock order must be: first `cs_main`, then `m_cached_tip_mutex`. + // The following will lock `cs_main` (and release it), so we must not + // own `m_cached_tip_mutex` here. + tip = m_node.getBestBlockHash(); + LOCK(m_cached_tip_mutex); + // We checked that `m_cached_tip_blocks` is not null above, but then we + // released the mutex `m_cached_tip_mutex`, so it could have changed in the + // meantime. Thus, check again. if (m_cached_tip_blocks.IsNull()) { - m_cached_tip_blocks = m_node.getBestBlockHash(); + m_cached_tip_blocks = tip; } return m_cached_tip_blocks; } diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index 20f2ef5b5f..f1438e3439 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -92,6 +92,23 @@ void WalletController::closeWallet(WalletModel* wallet_model, QWidget* parent) removeAndDeleteWallet(wallet_model); } +void WalletController::closeAllWallets(QWidget* parent) +{ + QMessageBox::StandardButton button = QMessageBox::question(parent, tr("Close all wallets"), + tr("Are you sure you wish to close all wallets?"), + QMessageBox::Yes|QMessageBox::Cancel, + QMessageBox::Yes); + if (button != QMessageBox::Yes) return; + + QMutexLocker locker(&m_mutex); + for (WalletModel* wallet_model : m_wallets) { + wallet_model->wallet().remove(); + Q_EMIT walletRemoved(wallet_model); + delete wallet_model; + } + m_wallets.clear(); +} + WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet) { QMutexLocker locker(&m_mutex); diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h index 24dd83adf7..f7e366878d 100644 --- a/src/qt/walletcontroller.h +++ b/src/qt/walletcontroller.h @@ -62,6 +62,7 @@ public: std::map<std::string, bool> listWalletDir() const; void closeWallet(WalletModel* wallet_model, QWidget* parent = nullptr); + void closeAllWallets(QWidget* parent = nullptr); Q_SIGNALS: void walletAdded(WalletModel* wallet_model); diff --git a/src/rpc/request.h b/src/rpc/request.h index 02ec5393a7..4761e9e371 100644 --- a/src/rpc/request.h +++ b/src/rpc/request.h @@ -41,6 +41,16 @@ public: const util::Ref& context; JSONRPCRequest(const util::Ref& context) : id(NullUniValue), params(NullUniValue), fHelp(false), context(context) {} + + //! Initializes request information from another request object and the + //! given context. The implementation should be updated if any members are + //! added or removed above. + JSONRPCRequest(const JSONRPCRequest& other, const util::Ref& context) + : id(other.id), strMethod(other.strMethod), params(other.params), fHelp(other.fHelp), URI(other.URI), + authUser(other.authUser), peerAddr(other.peerAddr), context(context) + { + } + void parse(const UniValue& valRequest); }; diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index 3c54d5bee4..aaecab1ef2 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -11,7 +11,7 @@ #include <util/system.h> #include <cuckoocache.h> -#include <boost/thread.hpp> +#include <boost/thread/shared_mutex.hpp> namespace { /** diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp index 35750b2ebc..8348810ac1 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -10,7 +10,7 @@ #include <util/time.h> #include <boost/test/unit_test.hpp> -#include <boost/thread.hpp> +#include <boost/thread/thread.hpp> #include <atomic> #include <condition_variable> diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index c51ee3cf29..211a84b5f2 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -30,7 +30,7 @@ #include <string> #include <vector> -bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, ChainstateManager& chainman, CTxMemPool& mempool, CConnman* connman, BanMan* banman, const std::atomic<bool>& interruptMsgProc); +bool ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, ChainstateManager& chainman, CTxMemPool& mempool, CConnman* connman, BanMan* banman, const std::atomic<bool>& interruptMsgProc); namespace { @@ -77,7 +77,7 @@ void test_one_input(const std::vector<uint8_t>& buffer) connman.AddTestNode(p2p_node); g_setup->m_node.peer_logic->InitializeNode(&p2p_node); try { - (void)ProcessMessage(&p2p_node, random_message_type, random_bytes_data_stream, GetTimeMillis(), Params(), *g_setup->m_node.chainman, *g_setup->m_node.mempool, g_setup->m_node.connman.get(), g_setup->m_node.banman.get(), std::atomic<bool>{false}); + (void)ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream, GetTimeMillis(), Params(), *g_setup->m_node.chainman, *g_setup->m_node.mempool, g_setup->m_node.connman.get(), g_setup->m_node.banman.get(), std::atomic<bool>{false}); } catch (const std::ios_base::failure&) { } SyncWithValidationInterfaceQueue(); diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index 1395a7f38c..fcee6a9b9d 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -7,7 +7,7 @@ #include <util/time.h> #include <boost/test/unit_test.hpp> -#include <boost/thread.hpp> +#include <boost/thread/thread.hpp> #include <mutex> diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index 2477f9ad06..d5cda8a95b 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -17,7 +17,7 @@ #include <type_traits> -#include <boost/thread.hpp> +#include <boost/thread/thread.hpp> /** This is connected to the logger. Can be used to redirect logs to any other log */ extern const std::function<void(const std::string&)> G_TEST_LOG_FUN; diff --git a/src/txdb.cpp b/src/txdb.cpp index 129697f0e7..6f652c1375 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -16,8 +16,6 @@ #include <stdint.h> -#include <boost/thread.hpp> - static const char DB_COIN = 'C'; static const char DB_COINS = 'c'; static const char DB_BLOCK_FILES = 'f'; @@ -242,7 +240,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, // Load m_block_index while (pcursor->Valid()) { - boost::this_thread::interruption_point(); if (ShutdownRequested()) return false; std::pair<char, uint256> key; if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) { @@ -354,7 +351,6 @@ bool CCoinsViewDB::Upgrade() { std::pair<unsigned char, uint256> key; std::pair<unsigned char, uint256> prev_key = {DB_COINS, uint256()}; while (pcursor->Valid()) { - boost::this_thread::interruption_point(); if (ShutdownRequested()) { break; } diff --git a/src/util/translation.h b/src/util/translation.h index 268bcf30a7..695d6dac96 100644 --- a/src/util/translation.h +++ b/src/util/translation.h @@ -23,6 +23,11 @@ struct bilingual_str { translated += rhs.translated; return *this; } + + bool empty() const + { + return original.empty(); + } }; inline bilingual_str operator+(bilingual_str lhs, const bilingual_str& rhs) diff --git a/src/validation.cpp b/src/validation.cpp index c8eec1faa9..c7a1423536 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -50,7 +50,6 @@ #include <string> #include <boost/algorithm/string/replace.hpp> -#include <boost/thread.hpp> #if defined(NDEBUG) # error "Bitcoin cannot be compiled without assertions." @@ -1778,19 +1777,24 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; } -void static FlushBlockFile(bool fFinalize = false) +static void FlushUndoFile(int block_file, bool finalize = false) { - LOCK(cs_LastBlockFile); + FlatFilePos undo_pos_old(block_file, vinfoBlockFile[block_file].nUndoSize); + if (!UndoFileSeq().Flush(undo_pos_old, finalize)) { + AbortNode("Flushing undo file to disk failed. This is likely the result of an I/O error."); + } +} +static void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false) +{ + LOCK(cs_LastBlockFile); FlatFilePos block_pos_old(nLastBlockFile, vinfoBlockFile[nLastBlockFile].nSize); - FlatFilePos undo_pos_old(nLastBlockFile, vinfoBlockFile[nLastBlockFile].nUndoSize); - - bool status = true; - status &= BlockFileSeq().Flush(block_pos_old, fFinalize); - status &= UndoFileSeq().Flush(undo_pos_old, fFinalize); - if (!status) { + if (!BlockFileSeq().Flush(block_pos_old, fFinalize)) { AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error."); } + // we do not always flush the undo file, as the chain tip may be lagging behind the incoming blocks, + // e.g. during IBD or a sync after a node going offline + if (!fFinalize || finalize_undo) FlushUndoFile(nLastBlockFile, finalize_undo); } static bool FindUndoPos(BlockValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize); @@ -1804,6 +1808,14 @@ static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationSt return error("ConnectBlock(): FindUndoPos failed"); if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) return AbortNode(state, "Failed to write undo data"); + // rev files are written in block height order, whereas blk files are written as blocks come in (often out of order) + // we want to flush the rev (undo) file once we've written the last block, which is indicated by the last height + // in the block file info as below; note that this does not catch the case where the undo writes are keeping up + // with the block writes (usually when a synced up node is getting newly mined blocks) -- this case is caught in + // the FindBlockPos function + if (_pos.nFile < nLastBlockFile && static_cast<uint32_t>(pindex->nHeight) == vinfoBlockFile[_pos.nFile].nHeightLast) { + FlushUndoFile(_pos.nFile, true); + } // update nUndoPos in block index pindex->nUndoPos = _pos.nPos; @@ -2867,8 +2879,6 @@ bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainPar CBlockIndex *pindexNewTip = nullptr; int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT); do { - boost::this_thread::interruption_point(); - // Block until the validation queue drains. This should largely // never happen in normal operation, however may happen during // reindex, causing memory blowup if we run too far ahead. @@ -2937,8 +2947,7 @@ bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainPar // never shutdown before connecting the genesis block during LoadChainTip(). Previously this // caused an assert() failure during shutdown in such cases as the UTXO DB flushing checks // that the best block hash is non-null. - if (ShutdownRequested()) - break; + if (ShutdownRequested()) break; } while (pindexNewTip != pindexMostWork); CheckBlockIndex(chainparams.GetConsensus()); @@ -3256,8 +3265,13 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n vinfoBlockFile.resize(nFile + 1); } + bool finalize_undo = false; if (!fKnown) { while (vinfoBlockFile[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { + // when the undo file is keeping up with the block file, we want to flush it explicitly + // when it is lagging behind (more blocks arrive than are being connected), we let the + // undo block write case handle it + finalize_undo = (vinfoBlockFile[nFile].nHeightLast == (unsigned int)ChainActive().Tip()->nHeight); nFile++; if (vinfoBlockFile.size() <= nFile) { vinfoBlockFile.resize(nFile + 1); @@ -3271,7 +3285,7 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n if (!fKnown) { LogPrintf("Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString()); } - FlushBlockFile(!fKnown); + FlushBlockFile(!fKnown, finalize_undo); nLastBlockFile = nFile; } @@ -4280,7 +4294,6 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int reportDone = 0; LogPrintf("[0%%]..."); /* Continued */ for (pindex = ::ChainActive().Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { - boost::this_thread::interruption_point(); const int percentageDone = std::max(1, std::min(99, (int)(((double)(::ChainActive().Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); if (reportDone < percentageDone/10) { // report every 10% step @@ -4326,8 +4339,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, nGoodTransactions += block.vtx.size(); } } - if (ShutdownRequested()) - return true; + if (ShutdownRequested()) return true; } if (pindexFailure) return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", ::ChainActive().Height() - pindexFailure->nHeight + 1, nGoodTransactions); @@ -4338,7 +4350,6 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, // check level 4: try reconnecting blocks if (nCheckLevel >= 4) { while (pindex != ::ChainActive().Tip()) { - boost::this_thread::interruption_point(); const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(::ChainActive().Height() - pindex->nHeight)) / (double)nCheckDepth * 50))); if (reportDone < percentageDone/10) { // report every 10% step @@ -4352,6 +4363,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); if (!::ChainstateActive().ConnectBlock(block, state, pindex, coins, chainparams)) return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString()); + if (ShutdownRequested()) return true; } } diff --git a/src/wallet/context.cpp b/src/wallet/context.cpp new file mode 100644 index 0000000000..09b2f30467 --- /dev/null +++ b/src/wallet/context.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <wallet/context.h> + +WalletContext::WalletContext() {} +WalletContext::~WalletContext() {} diff --git a/src/wallet/context.h b/src/wallet/context.h new file mode 100644 index 0000000000..3c8fdd1c59 --- /dev/null +++ b/src/wallet/context.h @@ -0,0 +1,32 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_WALLET_CONTEXT_H +#define BITCOIN_WALLET_CONTEXT_H + +namespace interfaces { +class Chain; +} // namespace interfaces + +//! WalletContext struct containing references to state shared between CWallet +//! instances, like the reference to the chain interface, and the list of opened +//! wallets. +//! +//! Future shared state can be added here as an alternative to adding global +//! variables. +//! +//! The struct isn't intended to have any member functions. It should just be a +//! collection of state pointers that doesn't pull in dependencies or implement +//! behavior. +struct WalletContext { + interfaces::Chain* chain{nullptr}; + + //! Declare default constructor and destructor that are not inline, so code + //! instantiating the WalletContext struct doesn't need to #include class + //! definitions for smart pointer and container members. + WalletContext(); + ~WalletContext(); +}; + +#endif // BITCOIN_WALLET_CONTEXT_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2a9ac189ea..ae2b19e923 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -21,12 +21,14 @@ #include <util/fees.h> #include <util/message.h> // For MessageSign() #include <util/moneystr.h> +#include <util/ref.h> #include <util/string.h> #include <util/system.h> #include <util/translation.h> #include <util/url.h> #include <util/vector.h> #include <wallet/coincontrol.h> +#include <wallet/context.h> #include <wallet/feebumper.h> #include <wallet/rpcwallet.h> #include <wallet/wallet.h> @@ -121,6 +123,14 @@ void EnsureWalletIsUnlocked(const CWallet* pwallet) } } +WalletContext& EnsureWalletContext(const util::Ref& context) +{ + if (!context.Has<WalletContext>()) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found"); + } + return context.Get<WalletContext>(); +} + // also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create) { @@ -2584,6 +2594,7 @@ static UniValue loadwallet(const JSONRPCRequest& request) }, }.Check(request); + WalletContext& context = EnsureWalletContext(request.context); WalletLocation location(request.params[0].get_str()); if (!location.Exists()) { @@ -2598,7 +2609,7 @@ static UniValue loadwallet(const JSONRPCRequest& request) bilingual_str error; std::vector<bilingual_str> warnings; - std::shared_ptr<CWallet> const wallet = LoadWallet(*g_rpc_chain, location, error, warnings); + std::shared_ptr<CWallet> const wallet = LoadWallet(*context.chain, location, error, warnings); if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error.original); UniValue obj(UniValue::VOBJ); @@ -2702,6 +2713,7 @@ static UniValue createwallet(const JSONRPCRequest& request) }, }.Check(request); + WalletContext& context = EnsureWalletContext(request.context); uint64_t flags = 0; if (!request.params[1].isNull() && request.params[1].get_bool()) { flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; @@ -2731,7 +2743,7 @@ static UniValue createwallet(const JSONRPCRequest& request) bilingual_str error; std::shared_ptr<CWallet> wallet; - WalletCreationStatus status = CreateWallet(*g_rpc_chain, passphrase, flags, request.params[0].get_str(), error, warnings, wallet); + WalletCreationStatus status = CreateWallet(*context.chain, passphrase, flags, request.params[0].get_str(), error, warnings, wallet); switch (status) { case WalletCreationStatus::CREATION_FAILED: throw JSONRPCError(RPC_WALLET_ERROR, error.original); @@ -4263,7 +4275,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request); UniValue importmulti(const JSONRPCRequest& request); UniValue importdescriptors(const JSONRPCRequest& request); -void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique_ptr<interfaces::Handler>>& handlers) +Span<const CRPCCommand> GetWalletRPCCommands() { // clang-format off static const CRPCCommand commands[] = @@ -4329,9 +4341,5 @@ static const CRPCCommand commands[] = { "wallet", "walletprocesspsbt", &walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} }, }; // clang-format on - - for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - handlers.emplace_back(chain.handleRpc(commands[vcidx])); + return MakeSpan(commands); } - -interfaces::Chain* g_rpc_chain = nullptr; diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h index 8c149d455b..d00221a04c 100644 --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -5,30 +5,22 @@ #ifndef BITCOIN_WALLET_RPCWALLET_H #define BITCOIN_WALLET_RPCWALLET_H +#include <span.h> + #include <memory> #include <string> #include <vector> -class CRPCTable; +class CRPCCommand; class CWallet; class JSONRPCRequest; class LegacyScriptPubKeyMan; class UniValue; -struct PartiallySignedTransaction; class CTransaction; +struct PartiallySignedTransaction; +struct WalletContext; -namespace interfaces { -class Chain; -class Handler; -} - -//! Pointer to chain interface that needs to be declared as a global to be -//! accessible loadwallet and createwallet methods. Due to limitations of the -//! RPC framework, there's currently no direct way to pass in state to RPC -//! methods without globals. -extern interfaces::Chain* g_rpc_chain; - -void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique_ptr<interfaces::Handler>>& handlers); +Span<const CRPCCommand> GetWalletRPCCommands(); /** * Figures out what wallet, if any, to use for a JSONRPCRequest. @@ -40,6 +32,7 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques void EnsureWalletIsUnlocked(const CWallet*); bool EnsureWalletIsAvailable(const CWallet*, bool avoidException); +WalletContext& EnsureWalletContext(const util::Ref& context); LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false); UniValue getaddressinfo(const JSONRPCRequest& request); diff --git a/test/README.md b/test/README.md index 0210907878..b036a66f67 100644 --- a/test/README.md +++ b/test/README.md @@ -261,6 +261,7 @@ Use the `-v` option for verbose output. | Lint test | Dependency | Version [used by CI](../ci/lint/04_install.sh) | Installation |-----------|:----------:|:-------------------------------------------:|-------------- | [`lint-python.sh`](lint/lint-python.sh) | [flake8](https://gitlab.com/pycqa/flake8) | [3.7.8](https://github.com/bitcoin/bitcoin/pull/15257) | `pip3 install flake8==3.7.8` +| [`lint-python.sh`](lint/lint-python.sh) | [mypy](https://github.com/python/mypy) | [0.700](https://github.com/bitcoin/bitcoin/pull/18210) | `pip3 install mypy==0.700` | [`lint-shell.sh`](lint/lint-shell.sh) | [ShellCheck](https://github.com/koalaman/shellcheck) | [0.6.0](https://github.com/bitcoin/bitcoin/pull/15166) | [details...](https://github.com/koalaman/shellcheck#installing) | [`lint-shell.sh`](lint/lint-shell.sh) | [yq](https://github.com/kislyuk/yq) | default | `pip3 install yq` | [`lint-spelling.sh`](lint/lint-spelling.sh) | [codespell](https://github.com/codespell-project/codespell) | [1.15.0](https://github.com/bitcoin/bitcoin/pull/16186) | `pip3 install codespell==1.15.0` diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index 1a7c656274..a4dc455d57 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -71,7 +71,7 @@ class ConfArgsTest(BitcoinTestFramework): with open(inc_conf_file2_path, 'w', encoding='utf-8') as conf: conf.write('[testnet]\n') self.restart_node(0) - self.nodes[0].stop_node(expected_stderr='Warning: ' + inc_conf_file_path + ':1 Section [testnot] is not recognized.' + os.linesep + 'Warning: ' + inc_conf_file2_path + ':1 Section [testnet] is not recognized.') + self.nodes[0].stop_node(expected_stderr='Warning: ' + inc_conf_file_path + ':1 Section [testnot] is not recognized.' + os.linesep + inc_conf_file2_path + ':1 Section [testnet] is not recognized.') with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('') # clear diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index 9579a1715d..7eabf86cad 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -138,8 +138,7 @@ class MaxUploadTest(BitcoinTestFramework): self.nodes[0].disconnect_p2ps() self.log.info("Restarting node 0 with noban permission and 1MB maxuploadtarget") - self.stop_node(0) - self.start_node(0, ["-whitelist=noban@127.0.0.1", "-maxuploadtarget=1"]) + self.restart_node(0, ["-whitelist=noban@127.0.0.1", "-maxuploadtarget=1"]) # Reconnect to self.nodes[0] self.nodes[0].add_p2p_connection(TestP2PConn()) @@ -152,9 +151,9 @@ class MaxUploadTest(BitcoinTestFramework): getdata_request.inv = [CInv(MSG_BLOCK, big_old_block)] self.nodes[0].p2p.send_and_ping(getdata_request) - assert_equal(len(self.nodes[0].getpeerinfo()), 1) #node is still connected because of the whitelist + assert_equal(len(self.nodes[0].getpeerinfo()), 1) #node is still connected because of the noban permission - self.log.info("Peer still connected after trying to download old block (whitelisted)") + self.log.info("Peer still connected after trying to download old block (noban permission)") if __name__ == '__main__': MaxUploadTest().main() diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index 1bda167c87..86d7c78d63 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -29,8 +29,6 @@ from test_framework.util import ( assert_raises_rpc_error, connect_nodes, ) -from test_framework.script import CScriptNum - def assert_template(node, block, expect, rehash=True): if rehash: @@ -91,12 +89,6 @@ class MiningTest(BitcoinTestFramework): coinbase_tx.rehash() # round-trip the encoded bip34 block height commitment - assert_equal(CScriptNum.decode(coinbase_tx.vin[0].scriptSig), next_height) - # round-trip negative and multi-byte CScriptNums to catch python regression - assert_equal(CScriptNum.decode(CScriptNum.encode(CScriptNum(1500))), 1500) - assert_equal(CScriptNum.decode(CScriptNum.encode(CScriptNum(-1500))), -1500) - assert_equal(CScriptNum.decode(CScriptNum.encode(CScriptNum(-1))), -1) - block = CBlock() block.nVersion = tmpl["version"] block.hashPrevBlock = int(tmpl["previousblockhash"], 16) diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index 376bb35f07..58d8c4abe1 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -28,6 +28,7 @@ from test_framework.messages import ( NODE_WITNESS, ) + def assert_net_servicesnames(servicesflag, servicenames): """Utility that checks if all flags are correctly decoded in `getpeerinfo` and `getnetworkinfo`. @@ -40,6 +41,7 @@ def assert_net_servicesnames(servicesflag, servicenames): servicesflag_generated |= getattr(test_framework.messages, 'NODE_' + servicename) assert servicesflag_generated == servicesflag + class NetTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True @@ -57,6 +59,7 @@ class NetTest(BitcoinTestFramework): self._test_getnetworkinfo() self._test_getaddednodeinfo() self._test_getpeerinfo() + self.test_service_flags() self._test_getnodeaddresses() def _test_connection_count(self): @@ -139,6 +142,11 @@ class NetTest(BitcoinTestFramework): for info in peer_info: assert_net_servicesnames(int(info[0]["services"], 0x10), info[0]["servicesnames"]) + def test_service_flags(self): + self.nodes[0].add_p2p_connection(P2PInterface(), services=(1 << 4) | (1 << 63)) + assert_equal(['UNKNOWN[2^4]', 'UNKNOWN[2^63]'], self.nodes[0].getpeerinfo()[-1]['servicesnames']) + self.nodes[0].disconnect_p2ps() + def _test_getnodeaddresses(self): self.nodes[0].add_p2p_connection(P2PInterface()) @@ -174,5 +182,6 @@ class NetTest(BitcoinTestFramework): node_addresses = self.nodes[0].getnodeaddresses(LARGE_REQUEST_COUNT) assert_greater_than(LARGE_REQUEST_COUNT, len(node_addresses)) + if __name__ == '__main__': NetTest().main() diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index d741b00ba0..afc1995009 100644 --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -4,6 +4,8 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Utilities for manipulating blocks and transactions.""" +import unittest + from .address import ( key_to_p2sh_p2wpkh, key_to_p2wpkh, @@ -217,3 +219,9 @@ def send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=Tru tx_to_witness = ToHex(tx) return node.sendrawtransaction(tx_to_witness) + +class TestFrameworkBlockTools(unittest.TestCase): + def test_create_coinbase(self): + height = 20 + coinbase_tx = create_coinbase(height=height) + assert_equal(CScriptNum.decode(coinbase_tx.vin[0].scriptSig), height) diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index bc1b5b26fc..cc5f8307d3 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -732,3 +732,9 @@ class TestFrameworkScript(unittest.TestCase): self.assertEqual(bn2vch(0xFFFFFFFF), bytes([0xFF, 0xFF, 0xFF, 0xFF, 0x00])) self.assertEqual(bn2vch(123456789), bytes([0x15, 0xCD, 0x5B, 0x07])) self.assertEqual(bn2vch(-54321), bytes([0x31, 0xD4, 0x80])) + + def test_cscriptnum_encoding(self): + # round-trip negative and multi-byte CScriptNums + values = [0, 1, -1, -2, 127, 128, -255, 256, (1 << 15) - 1, -(1 << 16), (1 << 24) - 1, (1 << 31), 1 - (1 << 32), 1 << 40, 1500, -1500] + for value in values: + self.assertEqual(CScriptNum.decode(CScriptNum.encode(CScriptNum(value))), value) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 1517407700..0ea65c68b8 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -68,6 +68,7 @@ TEST_EXIT_SKIPPED = 77 TEST_FRAMEWORK_MODULES = [ "address", + "blocktools", "script", ] diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh index bd9c8337ac..5404565b94 100755 --- a/test/lint/lint-includes.sh +++ b/test/lint/lint-includes.sh @@ -67,9 +67,9 @@ EXPECTED_BOOST_INCLUDES=( boost/signals2/last_value.hpp boost/signals2/signal.hpp boost/test/unit_test.hpp - boost/thread.hpp boost/thread/condition_variable.hpp boost/thread/mutex.hpp + boost/thread/shared_mutex.hpp boost/thread/thread.hpp boost/variant.hpp boost/variant/apply_visitor.hpp diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh index b9aa6c799b..decea38c4f 100755 --- a/test/lint/lint-python.sh +++ b/test/lint/lint-python.sh @@ -90,12 +90,20 @@ elif PYTHONWARNINGS="ignore" flake8 --version | grep -q "Python 2"; then exit 0 fi -PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=","; echo "${enabled[*]}") $( +EXIT_CODE=0 + +if ! PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=","; echo "${enabled[*]}") $( if [[ $# == 0 ]]; then git ls-files "*.py" else echo "$@" fi -) +); then + EXIT_CODE=1 +fi + +if ! mypy --ignore-missing-imports $(git ls-files "test/functional/*.py"); then + EXIT_CODE=1 +fi -mypy --ignore-missing-imports $(git ls-files "test/functional/*.py")
\ No newline at end of file +exit $EXIT_CODE diff --git a/test/sanitizer_suppressions/tsan b/test/sanitizer_suppressions/tsan index f71599d92f..fd2e1a329c 100644 --- a/test/sanitizer_suppressions/tsan +++ b/test/sanitizer_suppressions/tsan @@ -12,17 +12,22 @@ mutex:CConnman::ThreadOpenAddedConnections mutex:CConnman::SocketHandler mutex:UpdateTip mutex:PeerLogicValidation::UpdatedBlockTip +mutex:g_best_block_mutex # race (TODO fix) race:CConnman::WakeMessageHandler race:CConnman::ThreadMessageHandler race:fHaveGenesis race:ProcessNewBlock race:ThreadImport +race:WalletBatch::WriteHDChain race:zmq::* race:bitcoin-qt # deadlock (TODO fix) deadlock:CConnman::ForNode +deadlock:CConnman::GetNodeStats +deadlock:CChainState::ConnectTip deadlock:UpdateTip +deadlock:wallet_tests::CreateWalletFromFile # WalletBatch (unidentified deadlock) deadlock:WalletBatch |