elements/src/protocol.cpp
furszy 9f36e591c5
net: move state dependent peer services flags
No behavior change. Just an intermediate refactoring.

By relocating the peer desirable services flags into the peer
manager, we allow the connections acceptance process to handle
post-IBD potential stalling scenarios.

In the follow-up commit(s), the desirable service flags will be
dynamically adjusted to detect post-IBD stalling scenarios (such
as a +48-hour inactive node that must prefer full node connections
instead of limited peer connections because they cannot provide
historical blocks). Additionally, this encapsulation enable us
to customize the connections decision-making process based on
new user's configurations in the future.
2024-01-15 10:28:20 -03:00

219 lines
6.4 KiB
C++

// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <protocol.h>
#include <common/system.h>
#include <atomic>
static std::atomic<bool> g_initial_block_download_completed(false);
namespace NetMsgType {
const char* VERSION = "version";
const char* VERACK = "verack";
const char* ADDR = "addr";
const char* ADDRV2 = "addrv2";
const char* SENDADDRV2 = "sendaddrv2";
const char* INV = "inv";
const char* GETDATA = "getdata";
const char* MERKLEBLOCK = "merkleblock";
const char* GETBLOCKS = "getblocks";
const char* GETHEADERS = "getheaders";
const char* TX = "tx";
const char* HEADERS = "headers";
const char* BLOCK = "block";
const char* GETADDR = "getaddr";
const char* MEMPOOL = "mempool";
const char* PING = "ping";
const char* PONG = "pong";
const char* NOTFOUND = "notfound";
const char* FILTERLOAD = "filterload";
const char* FILTERADD = "filteradd";
const char* FILTERCLEAR = "filterclear";
const char* SENDHEADERS = "sendheaders";
const char* FEEFILTER = "feefilter";
const char* SENDCMPCT = "sendcmpct";
const char* CMPCTBLOCK = "cmpctblock";
const char* GETBLOCKTXN = "getblocktxn";
const char* BLOCKTXN = "blocktxn";
const char* GETCFILTERS = "getcfilters";
const char* CFILTER = "cfilter";
const char* GETCFHEADERS = "getcfheaders";
const char* CFHEADERS = "cfheaders";
const char* GETCFCHECKPT = "getcfcheckpt";
const char* CFCHECKPT = "cfcheckpt";
const char* WTXIDRELAY = "wtxidrelay";
const char* SENDTXRCNCL = "sendtxrcncl";
} // namespace NetMsgType
/** All known message types. Keep this in the same order as the list of
* messages above and in protocol.h.
*/
const static std::vector<std::string> g_all_net_message_types{
NetMsgType::VERSION,
NetMsgType::VERACK,
NetMsgType::ADDR,
NetMsgType::ADDRV2,
NetMsgType::SENDADDRV2,
NetMsgType::INV,
NetMsgType::GETDATA,
NetMsgType::MERKLEBLOCK,
NetMsgType::GETBLOCKS,
NetMsgType::GETHEADERS,
NetMsgType::TX,
NetMsgType::HEADERS,
NetMsgType::BLOCK,
NetMsgType::GETADDR,
NetMsgType::MEMPOOL,
NetMsgType::PING,
NetMsgType::PONG,
NetMsgType::NOTFOUND,
NetMsgType::FILTERLOAD,
NetMsgType::FILTERADD,
NetMsgType::FILTERCLEAR,
NetMsgType::SENDHEADERS,
NetMsgType::FEEFILTER,
NetMsgType::SENDCMPCT,
NetMsgType::CMPCTBLOCK,
NetMsgType::GETBLOCKTXN,
NetMsgType::BLOCKTXN,
NetMsgType::GETCFILTERS,
NetMsgType::CFILTER,
NetMsgType::GETCFHEADERS,
NetMsgType::CFHEADERS,
NetMsgType::GETCFCHECKPT,
NetMsgType::CFCHECKPT,
NetMsgType::WTXIDRELAY,
NetMsgType::SENDTXRCNCL,
};
CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn)
: pchMessageStart{pchMessageStartIn}
{
// Copy the command name
size_t i = 0;
for (; i < COMMAND_SIZE && pszCommand[i] != 0; ++i) pchCommand[i] = pszCommand[i];
assert(pszCommand[i] == 0); // Assert that the command name passed in is not longer than COMMAND_SIZE
nMessageSize = nMessageSizeIn;
}
std::string CMessageHeader::GetCommand() const
{
return std::string(pchCommand, pchCommand + strnlen(pchCommand, COMMAND_SIZE));
}
bool CMessageHeader::IsCommandValid() const
{
// Check the command string for errors
for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; ++p1) {
if (*p1 == 0) {
// Must be all zeros after the first zero
for (; p1 < pchCommand + COMMAND_SIZE; ++p1) {
if (*p1 != 0) {
return false;
}
}
} else if (*p1 < ' ' || *p1 > 0x7E) {
return false;
}
}
return true;
}
void SetServiceFlagsIBDCache(bool state) {
g_initial_block_download_completed = state;
}
bool GetServicesFlagsIBDCache() { return g_initial_block_download_completed; }
CInv::CInv()
{
type = 0;
hash.SetNull();
}
CInv::CInv(uint32_t typeIn, const uint256& hashIn) : type(typeIn), hash(hashIn) {}
bool operator<(const CInv& a, const CInv& b)
{
return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
}
std::string CInv::GetCommand() const
{
std::string cmd;
if (type & MSG_WITNESS_FLAG)
cmd.append("witness-");
int masked = type & MSG_TYPE_MASK;
switch (masked)
{
case MSG_TX: return cmd.append(NetMsgType::TX);
// WTX is not a message type, just an inv type
case MSG_WTX: return cmd.append("wtx");
case MSG_BLOCK: return cmd.append(NetMsgType::BLOCK);
case MSG_FILTERED_BLOCK: return cmd.append(NetMsgType::MERKLEBLOCK);
case MSG_CMPCT_BLOCK: return cmd.append(NetMsgType::CMPCTBLOCK);
default:
throw std::out_of_range(strprintf("CInv::GetCommand(): type=%d unknown type", type));
}
}
std::string CInv::ToString() const
{
try {
return strprintf("%s %s", GetCommand(), hash.ToString());
} catch(const std::out_of_range &) {
return strprintf("0x%08x %s", type, hash.ToString());
}
}
const std::vector<std::string> &getAllNetMessageTypes()
{
return g_all_net_message_types;
}
/**
* Convert a service flag (NODE_*) to a human readable string.
* It supports unknown service flags which will be returned as "UNKNOWN[...]".
* @param[in] bit the service flag is calculated as (1 << bit)
*/
static std::string serviceFlagToStr(size_t bit)
{
const uint64_t service_flag = 1ULL << bit;
switch ((ServiceFlags)service_flag) {
case NODE_NONE: abort(); // impossible
case NODE_NETWORK: return "NETWORK";
case NODE_BLOOM: return "BLOOM";
case NODE_WITNESS: return "WITNESS";
case NODE_COMPACT_FILTERS: return "COMPACT_FILTERS";
case NODE_NETWORK_LIMITED: return "NETWORK_LIMITED";
case NODE_P2P_V2: return "P2P_V2";
// Not using default, so we get warned when a case is missing
}
return strprintf("UNKNOWN[2^%u]", bit);
}
std::vector<std::string> serviceFlagsToStr(uint64_t flags)
{
std::vector<std::string> str_flags;
for (size_t i = 0; i < sizeof(flags) * 8; ++i) {
if (flags & (1ULL << i)) {
str_flags.emplace_back(serviceFlagToStr(i));
}
}
return str_flags;
}
GenTxid ToGenTxid(const CInv& inv)
{
assert(inv.IsGenTxMsg());
return inv.IsMsgWtx() ? GenTxid::Wtxid(inv.hash) : GenTxid::Txid(inv.hash);
}