bitcoin/src/protocol.cpp
TheCharlatan 7d3b35004b
refactor: Move system from util to common library
Since the kernel library no longer depends on the system file, move it
to the common library instead in accordance to the diagram in
doc/design/libraries.md.
2023-05-20 12:08:13 +02:00

226 lines
6.6 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::string allNetMessageTypes[] = {
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,
};
const static std::vector<std::string> allNetMessageTypesVec(std::begin(allNetMessageTypes), std::end(allNetMessageTypes));
CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn)
{
memcpy(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE);
// 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;
}
ServiceFlags GetDesirableServiceFlags(ServiceFlags services) {
if ((services & NODE_NETWORK_LIMITED) && g_initial_block_download_completed) {
return ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS);
}
return ServiceFlags(NODE_NETWORK | NODE_WITNESS);
}
void SetServiceFlagsIBDCache(bool state) {
g_initial_block_download_completed = state;
}
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 allNetMessageTypesVec;
}
/**
* 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";
// 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);
}