Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-forcednsseed", strprintf("Always query for peer addresses via DNS lookup (default: %u)", DEFAULT_FORCEDNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-listen", strprintf("Accept connections from outside (default: %u if no -proxy, -connect or -maxconnections=0)", DEFAULT_LISTEN), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-listenonion", strprintf("Automatically create Tor onion service (default: %d)", DEFAULT_LISTEN_ONION), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxconnections=<n>", strprintf("Maintain at most <n> connections to peers (temporary service connections excluded) (default: %u). This limit does not apply to connections manually added via -addnode or the addnode RPC, which have a separate limit of %u.", DEFAULT_MAX_PEER_CONNECTIONS, MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxconnections=<n>", strprintf("Maintain at most <n> automatic connections to peers (temporary service connections excluded) (default: %u). This limit does not apply to connections manually added via -addnode or the addnode RPC, which have a separate limit of %u.", DEFAULT_MAX_PEER_CONNECTIONS, MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxreceivebuffer=<n>", strprintf("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxsendbuffer=<n>", strprintf("Maximum per-connection memory usage for the send buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by outbound peers forward or backward by this amount (default: %u seconds).", DEFAULT_MAX_TIME_ADJUSTMENT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
Expand Down Expand Up @@ -2512,12 +2512,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)

CConnman::Options connOptions;
connOptions.nLocalServices = nLocalServices;
connOptions.nMaxConnections = nMaxConnections;
connOptions.m_max_outbound_full_relay = std::min(MAX_OUTBOUND_FULL_RELAY_CONNECTIONS, connOptions.nMaxConnections);
connOptions.m_max_outbound_block_relay = std::min(MAX_BLOCK_RELAY_ONLY_CONNECTIONS, connOptions.nMaxConnections-connOptions.m_max_outbound_full_relay);
connOptions.m_max_outbound_onion = std::min(MAX_DESIRED_ONION_CONNECTIONS, connOptions.nMaxConnections / 2);
connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS;
connOptions.nMaxFeeler = MAX_FEELER_CONNECTIONS;
connOptions.m_max_automatic_connections = nMaxConnections;
Comment thread
knst marked this conversation as resolved.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: bitcoin#28464 merge resolution drops Dash's onion outbound-limit calculation

New in the latest delta, superseding the assignment-order mechanism reported by prior-1, prior-2, and prior-4. Before this backport, AppInitMain() assigned connOptions.nMaxConnections and then derived m_max_outbound_onion as min(MAX_DESIRED_ONION_CONNECTIONS, nMaxConnections / 2). Upstream bitcoin#28464 moved its per-type connection-limit calculations into CConnman::Init(), and the current merge resolution removes Dash's additional onion calculation without moving it there. CConnman::Options::m_max_outbound_onion consequently remains at its default zero in src/net.h:1201, and CConnman::Init() copies that zero unchanged at line 1236. There are no other assignments in the tree, so the onion-preferred branch in ThreadOpenConnections() cannot request a peer and the Tor-peer eviction protection receives a limit of zero. Initialize the onion budget from the automatic connection limit, preferably alongside the other derived limits in CConnman::Init().

Suggested change
connOptions.m_max_automatic_connections = nMaxConnections;
connOptions.m_max_automatic_connections = nMaxConnections;
connOptions.m_max_outbound_onion = std::min(MAX_DESIRED_ONION_CONNECTIONS, connOptions.m_max_automatic_connections / 2);

source: ['codex']

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this update — bitcoin#28464 merge resolution drops Dash's onion outbound-limit calculation no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

connOptions.uiInterface = &uiInterface;
Comment thread
knst marked this conversation as resolved.
connOptions.m_banman = node.banman.get();
connOptions.m_msgproc = node.peerman.get();
Expand Down
17 changes: 8 additions & 9 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1880,7 +1880,6 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
{
int nInbound = 0;
int nVerifiedInboundMasternodes = 0;
int nMaxInbound = nMaxConnections - m_max_outbound;

AddWhitelistPermissionFlags(permission_flags, addr);
if (NetPermissions::HasFlag(permission_flags, NetPermissionFlags::Implicit)) {
Expand Down Expand Up @@ -1939,7 +1938,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,

// Only accept connections from discouraged peers if our inbound slots aren't (almost) full.
bool discouraged = m_banman && m_banman->IsDiscouraged(addr);
if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && nInbound + 1 >= nMaxInbound && discouraged)
if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && nInbound + 1 >= m_max_inbound && discouraged)
{
LogPrint(BCLog::NET_NETCONN, "connection from %s dropped (discouraged)\n", addr.ToStringAddrPort());
return;
Expand All @@ -1950,7 +1949,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
// We don't evict verified MN connections and also don't take them into account when checking limits. We can do
// this because such connections are limited by the total number of MNs times MAX_VERIFIED_INBOUND_PER_PROTX
// (enforced in TryMarkVerified), so this is not usable for attacks.
while (nInbound - nVerifiedInboundMasternodes >= nMaxInbound)
while (nInbound - nVerifiedInboundMasternodes >= m_max_inbound)
{
if (!AttemptToEvictConnection()) {
// No connection to evict, disconnect the new connection
Expand Down Expand Up @@ -3284,7 +3283,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, CDe
// different netgroups in ipv4/ipv6 networks + all peers in Tor/I2P/CJDNS networks.
// Don't record addrman failure attempts when node is offline. This can be identified since all local
// network connections (if any) belong in the same netgroup, and the size of `outbound_ipv46_peer_netgroups` would only be 1.
const bool count_failures{((int)outbound_ipv46_peer_netgroups.size() + outbound_privacy_network_peers) >= std::min(nMaxConnections - 1, 2)};
const bool count_failures{((int)outbound_ipv46_peer_netgroups.size() + outbound_privacy_network_peers) >= std::min(m_max_automatic_connections - 1, 2)};
// Use BIP324 transport when both us and them have NODE_V2_P2P set.
const bool use_v2transport(addrConnect.nServices & GetLocalServices() & NODE_P2P_V2);
OpenNetworkConnection(addrConnect, count_failures, std::move(grant), /*strDest=*/nullptr, conn_type, use_v2transport);
Expand Down Expand Up @@ -4027,11 +4026,11 @@ bool CConnman::Start(CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_met

if (semOutbound == nullptr) {
// initialize semaphore
semOutbound = std::make_unique<CSemaphore>(std::min(m_max_outbound, nMaxConnections));
semOutbound = std::make_unique<CSemaphore>(std::min(m_max_automatic_outbound, m_max_automatic_connections));
}
if (semAddnode == nullptr) {
// initialize semaphore
semAddnode = std::make_unique<CSemaphore>(nMaxAddnode);
semAddnode = std::make_unique<CSemaphore>(m_max_addnode);
}

//
Expand Down Expand Up @@ -4140,13 +4139,13 @@ void CConnman::Interrupt()
InterruptSocks5(true);

if (semOutbound) {
for (int i=0; i<m_max_outbound; i++) {
for (int i=0; i<m_max_automatic_outbound; i++) {
semOutbound->post();
}
}

if (semAddnode) {
for (int i=0; i<nMaxAddnode; i++) {
for (int i=0; i<m_max_addnode; i++) {
semAddnode->post();
}
}
Expand Down Expand Up @@ -4534,7 +4533,7 @@ std::map<CNetAddr, LocalServiceInfo> CConnman::getNetLocalAddresses() const

size_t CConnman::GetMaxOutboundNodeCount()
{
return m_max_outbound;
return m_max_automatic_outbound;
}

size_t CConnman::GetMaxOutboundOnionNodeCount()
Expand Down
40 changes: 24 additions & 16 deletions src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -1218,12 +1218,8 @@ friend class CNode;
struct Options
{
ServiceFlags nLocalServices = NODE_NONE;
int nMaxConnections = 0;
int m_max_outbound_full_relay = 0;
int m_max_outbound_block_relay = 0;
int m_max_outbound_onion = 0;
int nMaxAddnode = 0;
int nMaxFeeler = 0;
int m_max_automatic_connections = 0;
CClientUIInterface* uiInterface = nullptr;
NetEventsInterface* m_msgproc = nullptr;
BanMan* m_banman = nullptr;
Expand Down Expand Up @@ -1252,14 +1248,13 @@ friend class CNode;
AssertLockNotHeld(m_total_bytes_sent_mutex);

nLocalServices = connOptions.nLocalServices;
nMaxConnections = connOptions.nMaxConnections;
m_max_outbound_full_relay = std::min(connOptions.m_max_outbound_full_relay, connOptions.nMaxConnections);
m_max_outbound_block_relay = connOptions.m_max_outbound_block_relay;
m_max_automatic_connections = connOptions.m_max_automatic_connections;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Derive the onion outbound budget from maxconnections

When this newly-derived automatic limit is set, m_max_outbound_onion is still copied from Options unchanged later, and AppInit now only assigns connOptions.m_max_automatic_connections = nMaxConnections; fresh evidence in this revision is that Options::m_max_outbound_onion still defaults to 0 and is never derived from this value. With Tor reachable, the onion-only branch in ThreadOpenConnections() and the onion eviction protection both see a zero budget, so the default up-to-two onion outbound peers are never opened or protected.

Useful? React with 👍 / 👎.

m_max_outbound_full_relay = std::min(MAX_OUTBOUND_FULL_RELAY_CONNECTIONS, m_max_automatic_connections);
m_max_outbound_block_relay = std::min(MAX_BLOCK_RELAY_ONLY_CONNECTIONS, m_max_automatic_connections - m_max_outbound_full_relay);
m_max_automatic_outbound = m_max_outbound_full_relay + m_max_outbound_block_relay + m_max_feeler;
m_max_inbound = std::max(0, m_max_automatic_connections - m_max_automatic_outbound);
m_max_outbound_onion = connOptions.m_max_outbound_onion;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: bitcoin#28464 merge resolution drops Dash's onion outbound-limit calculation

Before this backport, AppInitMain() derived m_max_outbound_onion as min(MAX_DESIRED_ONION_CONNECTIONS, nMaxConnections / 2). The backport now initializes only connOptions.m_max_automatic_connections, while Options::m_max_outbound_onion remains at its default zero and this line copies that zero into CConnman. No other production assignment exists. Consequently, the onion-preferred branch in ThreadOpenConnections() can never request an onion peer, and GetMaxOutboundOnionNodeCount() returns zero to the outbound eviction logic instead of preserving up to two onion peers. Derive the Dash-specific onion budget from m_max_automatic_connections alongside the other connection limits in CConnman::Init().

Suggested change
m_max_outbound_onion = connOptions.m_max_outbound_onion;
m_max_outbound_onion = std::min(MAX_DESIRED_ONION_CONNECTIONS, m_max_automatic_connections / 2);

source: ['codex']

m_use_addrman_outgoing = connOptions.m_use_addrman_outgoing;
nMaxAddnode = connOptions.nMaxAddnode;
nMaxFeeler = connOptions.nMaxFeeler;
m_max_outbound = m_max_outbound_full_relay + m_max_outbound_block_relay + nMaxFeeler;
m_client_interface = connOptions.uiInterface;
m_banman = connOptions.m_banman;
m_msgproc = connOptions.m_msgproc;
Expand Down Expand Up @@ -1874,7 +1869,18 @@ friend class CNode;

std::unique_ptr<CSemaphore> semOutbound;
std::unique_ptr<CSemaphore> semAddnode;
int nMaxConnections;

/**
* Maximum number of automatic connections permitted, excluding manual
* connections but including inbounds. May be changed by the user and is
* potentially limited by the operating system (number of file descriptors).
*/
int m_max_automatic_connections;

/*
* Maximum number of peers by connection type. Might vary from defaults
* based on -maxconnections init value.
*/

// How many full-relay (tx, block, addr) outbound peers we want
int m_max_outbound_full_relay;
Expand All @@ -1883,12 +1889,14 @@ friend class CNode;
// We do not relay tx or addr messages with these peers
int m_max_outbound_block_relay;

// How many onion outbound peers we want; don't care if full or block only; does not increase m_max_outbound
// How many onion outbound peers we want; don't care if full or block only; does not increase m_max_automatic_outbound
int m_max_outbound_onion;

int nMaxAddnode;
int nMaxFeeler;
int m_max_outbound;
int m_max_addnode{MAX_ADDNODE_CONNECTIONS};
int m_max_feeler{MAX_FEELER_CONNECTIONS};
int m_max_automatic_outbound;
int m_max_inbound;

bool m_use_addrman_outgoing;
CClientUIInterface* m_client_interface;
NetEventsInterface* m_msgproc;
Expand Down
15 changes: 8 additions & 7 deletions src/rpc/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <util/system.h>
#include <util/translation.h>

#include <string_view>
const std::string UNIX_EPOCH_TIME = "UNIX epoch time";
const std::string EXAMPLE_ADDRESS[2] = {"XunLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPw0", "XwQQkwA4FYkq2XERzMY2CiAZhJTEDAbtc0"};

Expand Down Expand Up @@ -95,29 +96,29 @@ CAmount AmountFromValue(const UniValue& value, int decimals)
return amount;
}

uint256 ParseHashV(const UniValue& v, std::string strName)
uint256 ParseHashV(const UniValue& v, std::string_view name)
{
const std::string& strHex(v.get_str());
if (64 != strHex.length())
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", strName, 64, strHex.length(), strHex));
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", name, 64, strHex.length(), strHex));
if (!IsHex(strHex)) // Note: IsHex("") is false
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be hexadecimal string (not '%s')", name, strHex));
return uint256S(strHex);
}
uint256 ParseHashO(const UniValue& o, std::string strKey)
uint256 ParseHashO(const UniValue& o, std::string_view strKey)
{
return ParseHashV(o.find_value(strKey), strKey);
}
std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
std::vector<unsigned char> ParseHexV(const UniValue& v, std::string_view name)
{
std::string strHex;
if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex))
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be hexadecimal string (not '%s')", name, strHex));
return ParseHex(strHex);
}
std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
std::vector<unsigned char> ParseHexO(const UniValue& o, std::string_view strKey)
{
return ParseHexV(o.find_value(strKey), strKey);
}
Expand Down
9 changes: 5 additions & 4 deletions src/rpc/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#include <variant>
Expand Down Expand Up @@ -103,10 +104,10 @@ void RPCTypeCheckObj(const UniValue& o,
* Utilities: convert hex-encoded Values
* (throws error if not hex).
*/
uint256 ParseHashV(const UniValue& v, std::string strName);
uint256 ParseHashO(const UniValue& o, std::string strKey);
std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
uint256 ParseHashV(const UniValue& v, std::string_view name);
uint256 ParseHashO(const UniValue& o, std::string_view strKey);
std::vector<unsigned char> ParseHexV(const UniValue& v, std::string_view name);
std::vector<unsigned char> ParseHexO(const UniValue& o, std::string_view strKey);

bool ParseBoolV(const UniValue& v, const std::string &strName);

Expand Down
8 changes: 2 additions & 6 deletions src/test/denialofservice_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)

constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;
CConnman::Options options;
options.nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
options.m_max_outbound_full_relay = max_outbound_full_relay;
options.nMaxFeeler = MAX_FEELER_CONNECTIONS;
options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS;

const auto time_init{GetTime<std::chrono::seconds>()};
SetMockTime(time_init);
Expand Down Expand Up @@ -250,9 +248,7 @@ BOOST_AUTO_TEST_CASE(block_relay_only_eviction)
constexpr int max_outbound_block_relay{MAX_BLOCK_RELAY_ONLY_CONNECTIONS};
constexpr int64_t MINIMUM_CONNECT_TIME{30};
CConnman::Options options;
options.nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
options.m_max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;
options.m_max_outbound_block_relay = max_outbound_block_relay;
options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS;

connman->Init(options);
std::vector<CNode*> vNodes;
Expand Down
1 change: 0 additions & 1 deletion src/util/strencodings.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ bool TimingResistantEqual(const T& a, const T& b)
}

/** Parse number as fixed point according to JSON number syntax.
* See https://json.org/number.gif
* @returns true on success, false on error.
* @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger.
*/
Expand Down
Loading