Merge #5983: backport: Merge bitcoin#22138, 21939, bitcoin-core/gui#163, 20373, 22144, 22013, 21719, 20786

18169f4957 Merge #20786: net: [refactor] Prefer integral types in CNodeStats (MarcoFalke)
751c9e66c4 Merge bitcoin/bitcoin#21719: refactor: Add and use EnsureConnman in rpc code (MarcoFalke)
74b20eb309 Merge bitcoin/bitcoin#22013: net: ignore block-relay-only peers when skipping DNS seed (fanquake)
366ca98b39 Merge bitcoin/bitcoin#22144: Randomize message processing peer order (fanquake)
4d20cb7173 Merge #20373: refactor, net: Increase CNode data member encapsulation (MarcoFalke)
b8b3c4c289 Merge bitcoin-core/gui#163: Peer details: replace Direction with Connection Type (MarcoFalke)
00b828c0f5 Merge bitcoin/bitcoin#21939: refactor: Replace memset calls with array initialization (W. J. van der Laan)
7bcc56c9b6 Merge bitcoin/bitcoin#22138: script: fix spelling linter raising spuriously on "invokable" (MarcoFalke)

Pull request description:

  bitcoin backports

Top commit has no ACKs.

Tree-SHA512: 28dd3c672be847a376aaf1683a665b658b132364b4903fa360810dead7f30bd6496c231b6496e55572e09f1908febdba385d863e5e1d714cb784cc4350126be9
This commit is contained in:
pasta 2024-04-23 09:53:17 -05:00
commit 6194e454d7
No known key found for this signature in database
GPG Key ID: 52527BEDABE87984
16 changed files with 201 additions and 171 deletions

View File

@ -286,6 +286,7 @@ BITCOIN_CORE_H = \
rpc/blockchain.h \
rpc/client.h \
rpc/mining.h \
rpc/net.h \
rpc/protocol.h \
rpc/rawtransaction_util.h \
rpc/register.h \

View File

@ -588,9 +588,9 @@ bool CNode::IsBlockRelayOnly() const {
return (ignores_incoming_txs && !HasPermission(NetPermissionFlags::Relay)) || IsBlockOnlyConn();
}
std::string CNode::ConnectionTypeAsString() const
std::string ConnectionTypeAsString(ConnectionType conn_type)
{
switch (m_conn_type) {
switch (conn_type) {
case ConnectionType::INBOUND:
return "inbound";
case ConnectionType::MANUAL:
@ -700,7 +700,7 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
X(verifiedPubKeyHash);
}
X(m_masternode_connection);
stats.m_conn_type_string = ConnectionTypeAsString();
X(m_conn_type);
}
#undef X
@ -2169,7 +2169,7 @@ void CConnman::ThreadDNSAddressSeed()
{
LOCK(cs_vNodes);
for (const CNode* pnode : vNodes) {
if (pnode->fSuccessfullyConnected && !pnode->IsOutboundOrBlockRelayConn() && !pnode->m_masternode_probe_connection) ++nRelevant;
if (pnode->fSuccessfullyConnected && !pnode->IsFullOutboundConn() && !pnode->m_masternode_probe_connection) ++nRelevant;
}
}
if (nRelevant >= 2) {
@ -2256,7 +2256,7 @@ void CConnman::ProcessAddrFetch()
}
}
bool CConnman::GetTryNewOutboundPeer()
bool CConnman::GetTryNewOutboundPeer() const
{
return m_try_another_outbound_peer;
}
@ -2273,7 +2273,7 @@ void CConnman::SetTryNewOutboundPeer(bool flag)
// Also exclude peers that haven't finished initial connection handshake yet
// (so that we don't decide we're over our desired connection limit, and then
// evict some peer that has finished the handshake)
int CConnman::GetExtraFullOutboundCount()
int CConnman::GetExtraFullOutboundCount() const
{
int full_outbound_peers = 0;
{
@ -2291,7 +2291,7 @@ int CConnman::GetExtraFullOutboundCount()
return std::max(full_outbound_peers - m_max_outbound_full_relay, 0);
}
int CConnman::GetExtraBlockRelayCount()
int CConnman::GetExtraBlockRelayCount() const
{
int block_relay_peers = 0;
{
@ -2619,7 +2619,7 @@ std::vector<CAddress> CConnman::GetCurrentBlockRelayOnlyConns() const
return ret;
}
std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()
std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const
{
std::vector<AddedNodeInfo> ret;
@ -2965,6 +2965,7 @@ void CConnman::ThreadMessageHandler()
{
int64_t nLastSendMessagesTimeMasternodes = 0;
FastRandomContext rng;
while (!flagInterruptMsgProc)
{
std::vector<CNode*> vNodesCopy = CopyNodeVector();
@ -2976,6 +2977,10 @@ void CConnman::ThreadMessageHandler()
fSkipSendMessagesForMasternodes = false;
nLastSendMessagesTimeMasternodes = GetTimeMillis();
}
// Randomize the order in which we process messages from/to our peers.
// This prevents attacks in which an attacker exploits having multiple
// consecutive connections in the vNodes list.
Shuffle(vNodesCopy.begin(), vNodesCopy.end(), rng);
for (CNode* pnode : vNodesCopy)
{
@ -3616,7 +3621,7 @@ CConnman::~CConnman()
Stop();
}
std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pct, std::optional<Network> network)
std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
{
std::vector<CAddress> addresses = addrman.GetAddr(max_addresses, max_pct, network);
if (m_banman) {
@ -3837,7 +3842,7 @@ void CConnman::AddPendingProbeConnections(const std::set<uint256> &proTxHashes)
masternodePendingProbes.insert(proTxHashes.begin(), proTxHashes.end());
}
size_t CConnman::GetNodeCount(ConnectionDirection flags)
size_t CConnman::GetNodeCount(ConnectionDirection flags) const
{
LOCK(cs_vNodes);
@ -3864,7 +3869,7 @@ size_t CConnman::GetMaxOutboundNodeCount()
return m_max_outbound;
}
void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats)
void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
{
vstats.clear();
LOCK(cs_vNodes);
@ -4003,18 +4008,18 @@ void CConnman::RecordBytesSent(uint64_t bytes)
nMaxOutboundTotalBytesSentInCycle += bytes;
}
uint64_t CConnman::GetMaxOutboundTarget()
uint64_t CConnman::GetMaxOutboundTarget() const
{
LOCK(cs_totalBytesSent);
return nMaxOutboundLimit;
}
std::chrono::seconds CConnman::GetMaxOutboundTimeframe()
std::chrono::seconds CConnman::GetMaxOutboundTimeframe() const
{
return MAX_UPLOAD_TIMEFRAME;
}
std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle()
std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() const
{
LOCK(cs_totalBytesSent);
if (nMaxOutboundLimit == 0)
@ -4028,7 +4033,7 @@ std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle()
return (cycleEndTime < now) ? 0s : cycleEndTime - now;
}
bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit)
bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) const
{
LOCK(cs_totalBytesSent);
if (nMaxOutboundLimit == 0)
@ -4048,7 +4053,7 @@ bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit)
return false;
}
uint64_t CConnman::GetOutboundTargetBytesLeft()
uint64_t CConnman::GetOutboundTargetBytesLeft() const
{
LOCK(cs_totalBytesSent);
if (nMaxOutboundLimit == 0)
@ -4057,13 +4062,13 @@ uint64_t CConnman::GetOutboundTargetBytesLeft()
return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle;
}
uint64_t CConnman::GetTotalBytesRecv()
uint64_t CConnman::GetTotalBytesRecv() const
{
LOCK(cs_totalBytesRecv);
return nTotalBytesRecv;
}
uint64_t CConnman::GetTotalBytesSent()
uint64_t CConnman::GetTotalBytesSent() const
{
LOCK(cs_totalBytesSent);
return nTotalBytesSent;

134
src/net.h
View File

@ -213,6 +213,8 @@ enum class ConnectionType {
ADDR_FETCH,
};
/** Convert ConnectionType enum to a string value */
std::string ConnectionTypeAsString(ConnectionType conn_type);
void Discover();
uint16_t GetListenPort();
@ -307,7 +309,7 @@ public:
// In case this is a verified MN, this value is the hashed operator pubkey of the MN
uint256 verifiedPubKeyHash;
bool m_masternode_connection;
std::string m_conn_type_string;
ConnectionType m_conn_type;
};
@ -578,11 +580,6 @@ public:
assert(false);
}
protected:
mapMsgCmdSize mapSendBytesPerMsgCmd GUARDED_BY(cs_vSend);
mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv);
public:
struct TxRelay {
mutable RecursiveMutex cs_filter;
// We use fRelayTxes for two purposes -
@ -647,50 +644,6 @@ public:
CNode(const CNode&) = delete;
CNode& operator=(const CNode&) = delete;
private:
const NodeId id;
const uint64_t nLocalHostNonce;
const ConnectionType m_conn_type;
std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION};
//! Services offered to this peer.
//!
//! This is supplied by the parent CConnman during peer connection
//! (CConnman::ConnectNode()) from its attribute of the same name.
//!
//! This is const because there is no protocol defined for renegotiating
//! services initially offered to a peer. The set of local services we
//! offer should not change after initialization.
//!
//! An interesting example of this is NODE_NETWORK and initial block
//! download: a node which starts up from scratch doesn't have any blocks
//! to serve, but still advertises NODE_NETWORK because it will eventually
//! fulfill this role after IBD completes. P2P code is written in such a
//! way that it can gracefully handle peers who don't make good on their
//! service advertisements.
const ServiceFlags nLocalServices;
std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
mutable RecursiveMutex cs_addrName;
std::string addrName GUARDED_BY(cs_addrName);
// Our address, as reported by the peer
CService addrLocal GUARDED_BY(cs_addrLocal);
mutable RecursiveMutex cs_addrLocal;
//! Whether this peer is an inbound onion, e.g. connected via our Tor onion service.
const bool m_inbound_onion{false};
// Challenge sent in VERSION to be answered with MNAUTH (only happens between MNs)
mutable Mutex cs_mnauth;
uint256 sentMNAuthChallenge GUARDED_BY(cs_mnauth);
uint256 receivedMNAuthChallenge GUARDED_BY(cs_mnauth);
uint256 verifiedProRegTxHash GUARDED_BY(cs_mnauth);
uint256 verifiedPubKeyHash GUARDED_BY(cs_mnauth);
public:
NodeId GetId() const {
return id;
}
@ -782,7 +735,7 @@ public:
void MaybeSetAddrName(const std::string& addrNameIn);
std::string ConnectionTypeAsString() const;
std::string ConnectionTypeAsString() const { return ::ConnectionTypeAsString(m_conn_type); }
/** A ping-pong round trip has completed successfully. Update latest and minimum ping times. */
void PongReceived(std::chrono::microseconds ping_time) {
@ -835,6 +788,51 @@ public:
LOCK(cs_mnauth);
verifiedPubKeyHash = newVerifiedPubKeyHash;
}
private:
const NodeId id;
const uint64_t nLocalHostNonce;
const ConnectionType m_conn_type;
std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION};
//! Services offered to this peer.
//!
//! This is supplied by the parent CConnman during peer connection
//! (CConnman::ConnectNode()) from its attribute of the same name.
//!
//! This is const because there is no protocol defined for renegotiating
//! services initially offered to a peer. The set of local services we
//! offer should not change after initialization.
//!
//! An interesting example of this is NODE_NETWORK and initial block
//! download: a node which starts up from scratch doesn't have any blocks
//! to serve, but still advertises NODE_NETWORK because it will eventually
//! fulfill this role after IBD completes. P2P code is written in such a
//! way that it can gracefully handle peers who don't make good on their
//! service advertisements.
const ServiceFlags nLocalServices;
std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
mutable RecursiveMutex cs_addrName;
std::string addrName GUARDED_BY(cs_addrName);
// Our address, as reported by the peer
CService addrLocal GUARDED_BY(cs_addrLocal);
mutable RecursiveMutex cs_addrLocal;
//! Whether this peer is an inbound onion, e.g. connected via our Tor onion service.
const bool m_inbound_onion{false};
// Challenge sent in VERSION to be answered with MNAUTH (only happens between MNs)
mutable Mutex cs_mnauth;
uint256 sentMNAuthChallenge GUARDED_BY(cs_mnauth);
uint256 receivedMNAuthChallenge GUARDED_BY(cs_mnauth);
uint256 verifiedProRegTxHash GUARDED_BY(cs_mnauth);
uint256 verifiedPubKeyHash GUARDED_BY(cs_mnauth);
mapMsgCmdSize mapSendBytesPerMsgCmd GUARDED_BY(cs_vSend);
mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv);
};
/**
@ -1132,7 +1130,7 @@ public:
* @param[in] max_pct Maximum percentage of addresses to return (0 = all).
* @param[in] network Select only addresses of this network (nullopt = all).
*/
std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct, std::optional<Network> network);
std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct, std::optional<Network> network) const;
/**
* Cache is used to minimize topology leaks, so it should
@ -1145,7 +1143,7 @@ public:
// This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding
// a peer that is better than all our current peers.
void SetTryNewOutboundPeer(bool flag);
bool GetTryNewOutboundPeer();
bool GetTryNewOutboundPeer() const;
void StartExtraBlockRelayPeers() {
LogPrint(BCLog::NET, "net: enabling extra block-relay-only peers\n");
@ -1158,13 +1156,13 @@ public:
// return a value less than (num_outbound_connections - num_outbound_slots)
// in cases where some outbound connections are not yet fully connected, or
// not yet fully disconnected.
int GetExtraFullOutboundCount();
int GetExtraFullOutboundCount() const;
// Count the number of block-relay-only peers we have over our limit.
int GetExtraBlockRelayCount();
int GetExtraBlockRelayCount() const;
bool AddNode(const std::string& node);
bool RemoveAddedNode(const std::string& node);
std::vector<AddedNodeInfo> GetAddedNodeInfo();
std::vector<AddedNodeInfo> GetAddedNodeInfo() const;
/**
* Attempts to open a connection. Currently only used from tests.
@ -1191,9 +1189,9 @@ public:
bool IsMasternodeQuorumRelayMember(const uint256& protxHash);
void AddPendingProbeConnections(const std::set<uint256>& proTxHashes);
size_t GetNodeCount(ConnectionDirection);
size_t GetNodeCount(ConnectionDirection) const;
size_t GetMaxOutboundNodeCount();
void GetNodeStats(std::vector<CNodeStats>& vstats);
void GetNodeStats(std::vector<CNodeStats>& vstats) const;
bool DisconnectNode(const std::string& node);
bool DisconnectNode(const CSubNet& subnet);
bool DisconnectNode(const CNetAddr& addr);
@ -1207,24 +1205,24 @@ public:
//! that peer during `net_processing.cpp:PushNodeVersion()`.
ServiceFlags GetLocalServices() const;
uint64_t GetMaxOutboundTarget();
std::chrono::seconds GetMaxOutboundTimeframe();
uint64_t GetMaxOutboundTarget() const;
std::chrono::seconds GetMaxOutboundTimeframe() const;
//! check if the outbound target is reached
//! if param historicalBlockServingLimit is set true, the function will
//! response true if the limit for serving historical blocks has been reached
bool OutboundTargetReached(bool historicalBlockServingLimit);
bool OutboundTargetReached(bool historicalBlockServingLimit) const;
//! response the bytes left in the current max outbound cycle
//! in case of no limit, it will always response 0
uint64_t GetOutboundTargetBytesLeft();
uint64_t GetOutboundTargetBytesLeft() const;
//! returns the time left in the current max outbound cycle
//! in case of no limit, it will always return 0
std::chrono::seconds GetMaxOutboundTimeLeftInCycle();
std::chrono::seconds GetMaxOutboundTimeLeftInCycle() const;
uint64_t GetTotalBytesRecv();
uint64_t GetTotalBytesSent();
uint64_t GetTotalBytesRecv() const;
uint64_t GetTotalBytesSent() const;
/** Get a unique deterministic randomizer. */
CSipHasher GetDeterministicRandomizer(uint64_t id) const;
@ -1348,8 +1346,8 @@ private:
void UnregisterEvents(CNode* pnode);
// Network usage totals
RecursiveMutex cs_totalBytesRecv;
RecursiveMutex cs_totalBytesSent;
mutable RecursiveMutex cs_totalBytesRecv;
mutable RecursiveMutex cs_totalBytesSent;
uint64_t nTotalBytesRecv GUARDED_BY(cs_totalBytesRecv) {0};
uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent) {0};
@ -1375,7 +1373,7 @@ private:
std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
RecursiveMutex m_addr_fetches_mutex;
std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
RecursiveMutex cs_vAddedNodes;
mutable RecursiveMutex cs_vAddedNodes;
std::vector<uint256> vPendingMasternodes;
mutable RecursiveMutex cs_vPendingMasternodes;
std::map<std::pair<Consensus::LLMQType, uint256>, std::set<uint256>> masternodeQuorumNodes GUARDED_BY(cs_vPendingMasternodes);

View File

@ -355,7 +355,7 @@ public:
/** Implement PeerManager */
void CheckForStaleTipAndEvictPeers() override;
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) override;
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override;
bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; }
void SendPings() override;
void RelayTransaction(const uint256& txid) override;
@ -1440,7 +1440,7 @@ PeerRef PeerManagerImpl::RemovePeer(NodeId id)
return ret;
}
bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats)
bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const
{
{
LOCK(cs_main);

View File

@ -63,7 +63,7 @@ public:
virtual ~PeerManager() { }
/** Get statistics from node state */
virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) = 0;
virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const = 0;
/** Whether this node ignores txs received over p2p. */
virtual bool IgnoresIncomingTxs() = 0;

View File

@ -202,25 +202,16 @@ const static std::string netMessageTypesViolateBlocksOnly[] = {
};
const static std::set<std::string> netMessageTypesViolateBlocksOnlySet(std::begin(netMessageTypesViolateBlocksOnly), std::end(netMessageTypesViolateBlocksOnly));
CMessageHeader::CMessageHeader()
{
memset(pchMessageStart, 0, MESSAGE_START_SIZE);
memset(pchCommand, 0, sizeof(pchCommand));
memset(pchChecksum, 0, CHECKSUM_SIZE);
}
CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn)
{
memcpy(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE);
// Copy the command name, zero-padding to COMMAND_SIZE bytes
// 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
for (; i < COMMAND_SIZE; ++i) pchCommand[i] = 0;
nMessageSize = nMessageSizeIn;
memset(pchChecksum, 0, CHECKSUM_SIZE);
}
std::string CMessageHeader::GetCommand() const

View File

@ -39,7 +39,7 @@ public:
static constexpr size_t HEADER_SIZE = MESSAGE_START_SIZE + COMMAND_SIZE + MESSAGE_SIZE_SIZE + CHECKSUM_SIZE;
typedef unsigned char MessageStartChars[MESSAGE_START_SIZE];
explicit CMessageHeader();
explicit CMessageHeader() = default;
/** Construct a P2P message header from message-start characters, a command and the size of the message.
* @note Passing in a `pszCommand` longer than COMMAND_SIZE will result in a run-time assertion error.
@ -51,10 +51,10 @@ public:
SERIALIZE_METHODS(CMessageHeader, obj) { READWRITE(obj.pchMessageStart, obj.pchCommand, obj.nMessageSize, obj.pchChecksum); }
char pchMessageStart[MESSAGE_START_SIZE];
char pchCommand[COMMAND_SIZE];
char pchMessageStart[MESSAGE_START_SIZE]{};
char pchCommand[COMMAND_SIZE]{};
uint32_t nMessageSize{std::numeric_limits<uint32_t>::max()};
uint8_t pchChecksum[CHECKSUM_SIZE];
uint8_t pchChecksum[CHECKSUM_SIZE]{};
};
/**

View File

@ -1026,14 +1026,17 @@
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_23">
<widget class="QLabel" name="peerConnectionTypeLabel">
<property name="toolTip">
<string>The type of peer connection:&lt;ul&gt;&lt;li&gt;Inbound: initiated by peer&lt;/li&gt;&lt;li&gt;Outbound Full Relay: default&lt;/li&gt;&lt;li&gt;Outbound Block Relay: does not relay transactions or addresses&lt;/li&gt;&lt;li&gt;Outbound Manual: added using RPC %1 or %2/%3 configuration options&lt;/li&gt;&lt;li&gt;Outbound Feeler: short-lived, for testing addresses&lt;/li&gt;&lt;li&gt;Outbound Address Fetch: short-lived, for soliciting addresses&lt;/li&gt;&lt;/ul&gt;</string>
</property>
<property name="text">
<string>Direction</string>
<string>Connection Type</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="peerDirection">
<widget class="QLabel" name="peerConnectionType">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>

View File

@ -1660,6 +1660,19 @@ QString NetworkToQString(Network net)
assert(false);
}
QString ConnectionTypeToQString(ConnectionType conn_type)
{
switch (conn_type) {
case ConnectionType::INBOUND: return QObject::tr("Inbound");
case ConnectionType::OUTBOUND_FULL_RELAY: return QObject::tr("Outbound Full Relay");
case ConnectionType::BLOCK_RELAY: return QObject::tr("Outbound Block Relay");
case ConnectionType::MANUAL: return QObject::tr("Outbound Manual");
case ConnectionType::FEELER: return QObject::tr("Outbound Feeler");
case ConnectionType::ADDR_FETCH: return QObject::tr("Outbound Address Fetch");
} // no default case, so the compiler can warn about missing cases
assert(false);
}
QString formatDurationStr(int secs)
{
QStringList strList;

View File

@ -8,6 +8,7 @@
#include <amount.h>
#include <fs.h>
#include <qt/guiconstants.h>
#include <net.h>
#include <netaddress.h>
#include <util/check.h>
@ -15,13 +16,13 @@
#include <QEvent>
#include <QHeaderView>
#include <QItemDelegate>
#include <QLabel>
#include <QMessageBox>
#include <QMetaObject>
#include <QObject>
#include <QProgressBar>
#include <QString>
#include <QTableView>
#include <QLabel>
#include <cassert>
#include <chrono>
@ -396,6 +397,9 @@ namespace GUIUtil
/** Convert enum Network to QString */
QString NetworkToQString(Network net);
/** Convert enum ConnectionType to QString */
QString ConnectionTypeToQString(ConnectionType conn_type);
/** Convert seconds into a QString with days, hours, mins, secs */
QString formatDurationStr(int secs);

View File

@ -479,6 +479,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, QWidget* parent, Qt::WindowFlags
ui->dataDir->setToolTip(ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir"));
ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(QString(nonbreaking_hyphen) + "blocksdir"));
ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(PACKAGE_NAME));
ui->peerConnectionTypeLabel->setToolTip(ui->peerConnectionTypeLabel->toolTip().arg("addnode").arg(QString(nonbreaking_hyphen) + "addnode").arg(QString(nonbreaking_hyphen) + "connect"));
setButtonIcons();
@ -1249,11 +1250,7 @@ void RPCConsole::updateDetailWidget()
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion));
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
ui->peerDirection->setText(stats->nodeStats.fInbound
? tr("Inbound")
: stats->nodeStats.fRelayTxes
? tr("Outbound")
: tr("Outbound block-relay"));
ui->peerConnectionType->setText(GUIUtil::ConnectionTypeToQString(stats->nodeStats.m_conn_type));
ui->peerNetwork->setText(GUIUtil::NetworkToQString(stats->nodeStats.m_network));
if (stats->nodeStats.m_permissionFlags == NetPermissionFlags::None) {
ui->peerPermissions->setText(tr("N/A"));

View File

@ -26,6 +26,7 @@
#include <pow.h>
#include <rpc/blockchain.h>
#include <rpc/mining.h>
#include <rpc/net.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <script/descriptor.h>
@ -731,10 +732,8 @@ static RPCHelpMan getblocktemplate()
if (strMode != "template")
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
if (node.connman->GetNodeCount(ConnectionDirection::Both) == 0)
const CConnman& connman = EnsureConnman(node);
if (connman.GetNodeCount(ConnectionDirection::Both) == 0)
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
if (active_chainstate.IsInitialBlockDownload())

View File

@ -19,6 +19,7 @@
#include <net.h>
#include <node/context.h>
#include <rpc/blockchain.h>
#include <rpc/net.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <scheduler.h>
@ -213,15 +214,13 @@ static RPCHelpMan sporkupdate()
}
const NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
CConnman& connman = EnsureConnman(node);
// SPORK VALUE
int64_t nValue = request.params[1].get_int64();
// broadcast new spork
if (node.sporkman->UpdateSpork(nSporkID, nValue, *node.connman)) {
if (node.sporkman->UpdateSpork(nSporkID, nValue, connman)) {
return "success";
}

View File

@ -40,6 +40,22 @@ const std::vector<std::string> CONNECTION_TYPE_DOC{
"feeler (short-lived automatic connection for testing addresses)"
};
CConnman& EnsureConnman(const NodeContext& node)
{
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
return *node.connman;
}
PeerManager& EnsurePeerman(const NodeContext& node)
{
if (!node.peerman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
return *node.peerman;
}
static RPCHelpMan getconnectioncount()
{
return RPCHelpMan{"getconnectioncount",
@ -55,10 +71,9 @@ static RPCHelpMan getconnectioncount()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
const CConnman& connman = EnsureConnman(node);
return (int)node.connman->GetNodeCount(ConnectionDirection::Both);
return (int)connman.GetNodeCount(ConnectionDirection::Both);
},
};
}
@ -78,12 +93,10 @@ static RPCHelpMan ping()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.peerman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
PeerManager& peerman = EnsurePeerman(node);
// Request that each node send a ping during next message processing pass
node.peerman->SendPings();
peerman.SendPings();
return NullUniValue;
},
};
@ -133,9 +146,6 @@ static RPCHelpMan getpeerinfo()
{RPCResult::Type::STR, "subver", "The string version"},
{RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"},
{RPCResult::Type::BOOL, "addnode", "Whether connection was due to addnode/-connect or if it was an automatic/inbound connection"},
{RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
"Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
"best capture connection behaviors."},
{RPCResult::Type::BOOL, "masternode", "Whether connection was due to masternode connection attempt"},
{RPCResult::Type::NUM, "banscore", "The ban score (DEPRECATED, returned only if config option -deprecatedrpc=banscore is passed)"},
{RPCResult::Type::NUM, "startingheight", "The starting height (block) of the peer"},
@ -165,6 +175,9 @@ static RPCHelpMan getpeerinfo()
"When a message type is not listed in this json object, the bytes received are 0.\n"
"Only known message types can appear as keys in the object and all bytes received of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."}
}},
{RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
"Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
"best capture connection behaviors."},
}},
}}},
RPCExamples{
@ -174,19 +187,18 @@ static RPCHelpMan getpeerinfo()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman || !node.peerman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
const CConnman& connman = EnsureConnman(node);
const PeerManager& peerman = EnsurePeerman(node);
std::vector<CNodeStats> vstats;
node.connman->GetNodeStats(vstats);
connman.GetNodeStats(vstats);
UniValue ret(UniValue::VARR);
for (const CNodeStats& stats : vstats) {
UniValue obj(UniValue::VOBJ);
CNodeStateStats statestats;
bool fStateStats = node.peerman->GetNodeStateStats(stats.nodeid, statestats);
bool fStateStats = peerman.GetNodeStateStats(stats.nodeid, statestats);
obj.pushKV("id", stats.nodeid);
obj.pushKV("addr", stats.addrName);
if (stats.addrBind.IsValid()) {
@ -270,7 +282,7 @@ static RPCHelpMan getpeerinfo()
recvPerMsgCmd.pushKV(i.first, i.second);
}
obj.pushKV("bytesrecv_per_msg", recvPerMsgCmd);
obj.pushKV("connection_type", stats.m_conn_type_string);
obj.pushKV("connection_type", ConnectionTypeAsString(stats.m_conn_type));
ret.push_back(obj);
}
@ -303,27 +315,28 @@ static RPCHelpMan addnode()
strCommand = request.params[1].get_str();
const NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
CConnman& connman = EnsureConnman(node);
std::string strNode = request.params[0].get_str();
if (strCommand == "onetry")
{
CAddress addr;
node.connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), ConnectionType::MANUAL);
connman.OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), ConnectionType::MANUAL);
return NullUniValue;
}
if (strCommand == "add")
{
if(!node.connman->AddNode(strNode))
if (!connman.AddNode(strNode)) {
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
}
}
else if(strCommand == "remove")
{
if(!node.connman->RemoveAddedNode(strNode))
if (!connman.RemoveAddedNode(strNode)) {
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node could not be removed. It has not been added previously.");
}
}
return NullUniValue;
@ -368,11 +381,9 @@ static RPCHelpMan addconnection()
}
NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled.");
}
CConnman& connman = EnsureConnman(node);
const bool success = node.connman->AddConnection(address, conn_type);
const bool success = connman.AddConnection(address, conn_type);
if (!success) {
throw JSONRPCError(RPC_CLIENT_NODE_CAPACITY_REACHED, "Error: Already at capacity for specified connection type.");
}
@ -407,8 +418,7 @@ static RPCHelpMan disconnectnode()
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
CConnman& connman = EnsureConnman(node);
bool success;
const UniValue &address_arg = request.params[0];
@ -416,11 +426,11 @@ static RPCHelpMan disconnectnode()
if (!address_arg.isNull() && id_arg.isNull()) {
/* handle disconnect-by-address */
success = node.connman->DisconnectNode(address_arg.get_str());
success = connman.DisconnectNode(address_arg.get_str());
} else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) {
/* handle disconnect-by-id */
NodeId nodeid = (NodeId) id_arg.get_int64();
success = node.connman->DisconnectNode(nodeid);
success = connman.DisconnectNode(nodeid);
} else {
throw JSONRPCError(RPC_INVALID_PARAMS, "Only one of address and nodeid should be provided.");
}
@ -468,10 +478,9 @@ static RPCHelpMan getaddednodeinfo()
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
const CConnman& connman = EnsureConnman(node);;
std::vector<AddedNodeInfo> vInfo = node.connman->GetAddedNodeInfo();
std::vector<AddedNodeInfo> vInfo = connman.GetAddedNodeInfo();
if (!request.params[0].isNull()) {
bool found = false;
@ -539,21 +548,20 @@ static RPCHelpMan getnettotals()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
const CConnman& connman = EnsureConnman(node);
UniValue obj(UniValue::VOBJ);
obj.pushKV("totalbytesrecv", node.connman->GetTotalBytesRecv());
obj.pushKV("totalbytessent", node.connman->GetTotalBytesSent());
obj.pushKV("totalbytesrecv", connman.GetTotalBytesRecv());
obj.pushKV("totalbytessent", connman.GetTotalBytesSent());
obj.pushKV("timemillis", GetTimeMillis());
UniValue outboundLimit(UniValue::VOBJ);
outboundLimit.pushKV("timeframe", count_seconds(node.connman->GetMaxOutboundTimeframe()));
outboundLimit.pushKV("target", node.connman->GetMaxOutboundTarget());
outboundLimit.pushKV("target_reached", node.connman->OutboundTargetReached(false));
outboundLimit.pushKV("serve_historical_blocks", !node.connman->OutboundTargetReached(true));
outboundLimit.pushKV("bytes_left_in_cycle", node.connman->GetOutboundTargetBytesLeft());
outboundLimit.pushKV("time_left_in_cycle", count_seconds(node.connman->GetMaxOutboundTimeLeftInCycle()));
outboundLimit.pushKV("timeframe", count_seconds(connman.GetMaxOutboundTimeframe()));
outboundLimit.pushKV("target", connman.GetMaxOutboundTarget());
outboundLimit.pushKV("target_reached", connman.OutboundTargetReached(false));
outboundLimit.pushKV("serve_historical_blocks", !connman.OutboundTargetReached(true));
outboundLimit.pushKV("bytes_left_in_cycle", connman.GetOutboundTargetBytesLeft());
outboundLimit.pushKV("time_left_in_cycle", count_seconds(connman.GetMaxOutboundTimeLeftInCycle()));
obj.pushKV("uploadtarget", outboundLimit);
return obj;
},
@ -898,13 +906,11 @@ static RPCHelpMan setnetworkactive()
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
CConnman& connman = EnsureConnman(node);
node.connman->SetNetworkActive(request.params[0].get_bool(), node.mn_sync.get());
connman.SetNetworkActive(request.params[0].get_bool(), node.mn_sync.get());
return node.connman->GetNetworkActive();
return connman.GetNetworkActive();
},
};
}
@ -940,9 +946,7 @@ static RPCHelpMan getnodeaddresses()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
if (!node.connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
const CConnman& connman = EnsureConnman(node);
const int count{request.params[0].isNull() ? 1 : request.params[0].get_int()};
if (count < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range");
@ -953,7 +957,7 @@ static RPCHelpMan getnodeaddresses()
}
// returns a shuffled list of CAddress
const std::vector<CAddress> vAddr{node.connman->GetAddresses(count, /* max_pct */ 0, network)};
const std::vector<CAddress> vAddr{connman.GetAddresses(count, /* max_pct */ 0, network)};
UniValue ret(UniValue::VARR);
for (const CAddress& addr : vAddr) {

15
src/rpc/net.h Normal file
View File

@ -0,0 +1,15 @@
// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_RPC_NET_H
#define BITCOIN_RPC_NET_H
class CConnman;
class PeerManager;
struct NodeContext;
CConnman& EnsureConnman(const NodeContext& node);
PeerManager& EnsurePeerman(const NodeContext& node);
#endif // BITCOIN_RPC_NET_H

View File

@ -9,6 +9,7 @@ fpr
hights
hist
inout
invokable
mor
nin
ser