Skip to content
Draft
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
12 changes: 6 additions & 6 deletions src/addrman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@ int AddrManImpl::GetEntry(bool use_tried, size_t bucket, size_t position) const
return -1;
}

std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const
{
AssertLockHeld(cs);

Expand Down Expand Up @@ -838,7 +838,7 @@ std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct
if (network != std::nullopt && ai.GetNetClass() != network) continue;

// Filter for quality
if (ai.IsTerrible(now)) continue;
if (ai.IsTerrible(now) && filtered) continue;

addresses.push_back(ai);
}
Expand Down Expand Up @@ -1209,11 +1209,11 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool new_only, std::optiona
return addrRet;
}

std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const
{
LOCK(cs);
Check();
const auto addresses = GetAddr_(max_addresses, max_pct, network);
const auto addresses = GetAddr_(max_addresses, max_pct, network, filtered);
Check();
return addresses;
}
Expand Down Expand Up @@ -1315,9 +1315,9 @@ std::pair<CAddress, NodeSeconds> AddrMan::Select(bool new_only, std::optional<Ne
return m_impl->Select(new_only, network);
}

std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const
{
return m_impl->GetAddr(max_addresses, max_pct, network);
return m_impl->GetAddr(max_addresses, max_pct, network, filtered);
}

void AddrMan::Connected(const CService& addr, NodeSeconds time)
Expand Down
3 changes: 2 additions & 1 deletion src/addrman.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,11 @@ class AddrMan
* @param[in] max_addresses Maximum number of addresses to return (0 = all).
* @param[in] max_pct Maximum percentage of addresses to return (0 = all).
* @param[in] network Select only addresses of this network (nullopt = all).
* @param[in] filtered Select only addresses that are considered good quality (false = all).
*
* @return A vector of randomly selected addresses from vRandom.
*/
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const;
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered = true) const;

/** We have successfully connected to this peer. Calling this function
* updates the CAddress's nTime, which is used in our IsTerrible()
Expand Down
4 changes: 2 additions & 2 deletions src/addrman_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class AddrManImpl
std::pair<CAddress, NodeSeconds> Select(bool new_only, std::optional<Network> network) const
EXCLUSIVE_LOCKS_REQUIRED(!cs);

std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered = true) const
EXCLUSIVE_LOCKS_REQUIRED(!cs);

void Connected(const CService& addr, NodeSeconds time)
Expand Down Expand Up @@ -262,7 +262,7 @@ class AddrManImpl
* */
int GetEntry(bool use_tried, size_t bucket, size_t position) const EXCLUSIVE_LOCKS_REQUIRED(cs);

std::vector<CAddress> GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
std::vector<CAddress> GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered = true) const EXCLUSIVE_LOCKS_REQUIRED(cs);

void Connected_(const CService& addr, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);

Expand Down
1 change: 1 addition & 0 deletions src/httprpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <crypto/hmac_sha256.h>
#include <httpserver.h>
#include <netaddress.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
#include <util/strencodings.h>
Expand Down
23 changes: 21 additions & 2 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4089,6 +4089,12 @@ bool CConnman::Start(CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_met
// Dump network addresses
scheduler.scheduleEvery([this] { DumpAddresses(); }, DUMP_PEERS_INTERVAL);

// Run the ASMap Health check once and then schedule it to run every 24h.
if (m_netgroupman.UsingASMap()) {
ASMapHealthCheck();
scheduler.scheduleEvery([this] { ASMapHealthCheck(); }, ASMAP_HEALTH_CHECK_INTERVAL);
}

return true;
}

Expand Down Expand Up @@ -4223,9 +4229,9 @@ CConnman::~CConnman()
Stop();
}

std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const
{
std::vector<CAddress> addresses = addrman.GetAddr(max_addresses, max_pct, network);
std::vector<CAddress> addresses = addrman.GetAddr(max_addresses, max_pct, network, filtered);
if (m_banman) {
addresses.erase(std::remove_if(addresses.begin(), addresses.end(),
[this](const CAddress& addr){return m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr);}),
Expand Down Expand Up @@ -4945,6 +4951,19 @@ void CConnman::PerformReconnections()
}
}

void CConnman::ASMapHealthCheck()
{
const std::vector<CAddress> v4_addrs{GetAddresses(/*max_addresses=*/ 0, /*max_pct=*/ 0, Network::NET_IPV4, /*filtered=*/ false)};
const std::vector<CAddress> v6_addrs{GetAddresses(/*max_addresses=*/ 0, /*max_pct=*/ 0, Network::NET_IPV6, /*filtered=*/ false)};
std::vector<CNetAddr> clearnet_addrs;
clearnet_addrs.reserve(v4_addrs.size() + v6_addrs.size());
std::transform(v4_addrs.begin(), v4_addrs.end(), std::back_inserter(clearnet_addrs),
[](const CAddress& addr) { return static_cast<CNetAddr>(addr); });
std::transform(v6_addrs.begin(), v6_addrs.end(), std::back_inserter(clearnet_addrs),
[](const CAddress& addr) { return static_cast<CNetAddr>(addr); });
m_netgroupman.ASMapHealthCheck(clearnet_addrs);
}

// Dump binary message to file, with timestamp.
static void CaptureMessageToFile(const CAddress& addr,
const std::string& msg_type,
Expand Down
6 changes: 5 additions & 1 deletion src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ static const bool DEFAULT_BLOCKSONLY = false;
static const int64_t DEFAULT_PEER_CONNECT_TIMEOUT = 60;
/** Number of file descriptors required for message capture **/
static const int NUM_FDS_MESSAGE_CAPTURE = 1;
/** Interval for ASMap Health Check **/
static constexpr std::chrono::hours ASMAP_HEALTH_CHECK_INTERVAL{24};

static constexpr bool DEFAULT_FORCEDNSSEED{false};
static constexpr bool DEFAULT_DNSSEED{true};
Expand Down Expand Up @@ -1295,6 +1297,7 @@ friend class CNode;
void OpenMasternodeConnection(const CAddress& addrConnect, bool use_v2transport, MasternodeProbeConn probe = MasternodeProbeConn::IsConnection)
EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex, !m_unused_i2p_sessions_mutex, !mutexMsgProc, !cs_mapSocketToNode);
bool CheckIncomingNonce(uint64_t nonce) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex);
void ASMapHealthCheck();

// alias for thread safety annotations only, not defined
SharedMutex& GetNodesMutex() const LOCK_RETURNED(m_nodes_mutex);
Expand Down Expand Up @@ -1405,8 +1408,9 @@ friend class CNode;
* @param[in] max_addresses Maximum number of addresses to return (0 = all).
* @param[in] max_pct Maximum percentage of addresses to return (0 = all).
* @param[in] network Select only addresses of this network (nullopt = all).
* @param[in] filtered Select only addresses that are considered high quality (false = all).
*/
std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct, std::optional<Network> network) const;
std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered = true) const;

/**
* Cache is used to minimize topology leaks, so it should
Expand Down
21 changes: 21 additions & 0 deletions src/netgroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <netgroup.h>

#include <hash.h>
#include <logging.h>
#include <util/asmap.h>

uint256 NetGroupManager::GetAsmapChecksum() const
Expand Down Expand Up @@ -109,3 +110,23 @@ uint32_t NetGroupManager::GetMappedAS(const CNetAddr& address) const
uint32_t mapped_as = Interpret(m_asmap, ip_bits);
return mapped_as;
}

void NetGroupManager::ASMapHealthCheck(const std::vector<CNetAddr>& clearnet_addrs) const {
std::set<uint32_t> clearnet_asns{};
int unmapped_count{0};

for (const auto& addr : clearnet_addrs) {
uint32_t asn = GetMappedAS(addr);
if (asn == 0) {
++unmapped_count;
continue;
}
clearnet_asns.insert(asn);
}

LogPrintf("ASMap Health Check: %i clearnet peers are mapped to %i ASNs with %i peers being unmapped\n", clearnet_addrs.size(), clearnet_asns.size(), unmapped_count);
}

bool NetGroupManager::UsingASMap() const {
return m_asmap.size() > 0;
}
10 changes: 10 additions & 0 deletions src/netgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ class NetGroupManager {
*/
uint32_t GetMappedAS(const CNetAddr& address) const;

/**
* Analyze and log current health of ASMap based buckets.
*/
void ASMapHealthCheck(const std::vector<CNetAddr>& clearnet_addrs) const;

/**
* Indicates whether ASMap is being used for clearnet bucketing.
*/
bool UsingASMap() const;

private:
/** Compressed IP->ASN mapping, loaded from a file when a node starts.
*
Expand Down
1 change: 1 addition & 0 deletions src/rest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <sync.h>
#include <txmempool.h>
#include <util/check.h>
#include <util/strencodings.h>
#include <validation.h>
#include <version.h>

Expand Down
1 change: 1 addition & 0 deletions src/rpc/mempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <util/moneystr.h>
#include <validation.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <util/time.h>

#include <instantsend/instantsend.h>
Expand Down
13 changes: 13 additions & 0 deletions src/rpc/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <netbase.h>
#include <node/context.h>
#include <policy/settings.h>
#include <protocol.h>
#include <rpc/blockchain.h>
#include <rpc/protocol.h>
#include <rpc/server_util.h>
Expand Down Expand Up @@ -95,6 +96,18 @@ static RPCHelpMan ping()
};
}

/** Returns, given services flags, a list of humanly readable (known) network services */
static UniValue GetServicesNames(ServiceFlags services)
{
UniValue servicesNames(UniValue::VARR);

for (const auto& flag : serviceFlagsToStr(services)) {
servicesNames.push_back(flag);
}

return servicesNames;
}

static RPCHelpMan getpeerinfo()
{
return RPCHelpMan{
Expand Down
5 changes: 3 additions & 2 deletions src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,9 @@ static std::vector<RPCArg> CreateTxDoc()
},
},
},
{"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n"
"That is, each address can only appear once and there can only be one 'data' object.\n"
{"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs specified as key-value pairs.\n"
"Each key may only appear once, i.e. there can only be one 'data' output, and no address may be duplicated.\n"
"At least one output of either type must be specified.\n"
"For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
" accepted as second parameter.",
{
Expand Down
11 changes: 0 additions & 11 deletions src/rpc/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,17 +990,6 @@ UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_s
}
}

UniValue GetServicesNames(ServiceFlags services)
{
UniValue servicesNames(UniValue::VARR);

for (const auto& flag : serviceFlagsToStr(services)) {
servicesNames.push_back(flag);
}

return servicesNames;
}

std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider)
{
std::string desc_str;
Expand Down
4 changes: 0 additions & 4 deletions src/rpc/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#define BITCOIN_RPC_UTIL_H

#include <node/transaction.h>
#include <protocol.h>
#include <pubkey.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
Expand Down Expand Up @@ -44,7 +43,6 @@ extern const std::string EXAMPLE_ADDRESS[2];

class FillableSigningProvider;
class FillableSigningProvider;
class CPubKey;
class CScript;
struct Sections;

Expand Down Expand Up @@ -122,8 +120,6 @@ UniValue DescribeAddress(const CTxDestination& dest);
//! Parse a confirm target option and raise an RPC error if it is invalid.
unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target);

/** Returns, given services flags, a list of humanly readable (known) network services */
UniValue GetServicesNames(ServiceFlags services);

//! Parse a JSON range specified as int64, or [int64, int64]
std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value);
Expand Down
18 changes: 18 additions & 0 deletions src/test/addrman_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,24 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
BOOST_CHECK_EQUAL(addrman->Size(), 2006U);
}

BOOST_AUTO_TEST_CASE(getaddr_unfiltered)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));

// Set time on this addr so isTerrible = false
CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
addr1.nTime = Now<NodeSeconds>();
// Not setting time so this addr should be isTerrible = true
CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);

CNetAddr source = ResolveIP("250.1.2.1");
BOOST_CHECK(addrman->Add({addr1, addr2}, source));

// Filtered GetAddr should only return addr1
BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 1U);
// Unfiltered GetAddr should return addr1 and addr2
BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt, /*filtered=*/false).size(), 2U);
}

BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
{
Expand Down
3 changes: 2 additions & 1 deletion src/test/fuzz/addrman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,8 @@ FUZZ_TARGET(addrman, .init = initialize_addrman)
(void)const_addr_man.GetAddr(
/* max_addresses */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
/* max_pct */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
/* network */ std::nullopt);
/* network */ std::nullopt,
/* filtered =*/ fuzzed_data_provider.ConsumeBool());
(void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool());
(void)const_addr_man.Size();
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION);
Expand Down
3 changes: 2 additions & 1 deletion src/test/fuzz/connman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ FUZZ_TARGET(connman, .init = initialize_connman)
(void)connman.GetAddresses(
/*max_addresses=*/fuzzed_data_provider.ConsumeIntegral<size_t>(),
/*max_pct=*/fuzzed_data_provider.ConsumeIntegral<size_t>(),
/*network=*/std::nullopt);
/*network=*/std::nullopt,
/*filtered=*/fuzzed_data_provider.ConsumeBool());
},
[&] {
(void)connman.GetAddresses(
Expand Down
10 changes: 6 additions & 4 deletions src/wallet/rpc/spend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -803,8 +803,9 @@ RPCHelpMan send()
"\nEXPERIMENTAL warning: this call may be changed in future releases.\n"
"\nSend a transaction.\n",
{
{"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n"
"That is, each address can only appear once and there can only be one 'data' object.\n"
{"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs specified as key-value pairs.\n"
"Each key may only appear once, i.e. there can only be one 'data' output, and no address may be duplicated.\n"
"At least one output of either type must be specified.\n"
"For convenience, a dictionary, which holds the key-value pairs directly, is also accepted.",
{
{"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "",
Expand Down Expand Up @@ -1097,8 +1098,9 @@ RPCHelpMan walletcreatefundedpsbt()
},
},
},
{"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n"
"That is, each address can only appear once and there can only be one 'data' object.\n"
{"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs specified as key-value pairs.\n"
"Each key may only appear once, i.e. there can only be one 'data' output, and no address may be duplicated.\n"
"At least one output of either type must be specified.\n"
"For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
"accepted as second parameter.",
{
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/rpc/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ static RPCHelpMan getwalletinfo()
}},
{RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"},
{RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
{RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
RESULT_LAST_PROCESSED_BLOCK,
},
},
Expand Down Expand Up @@ -271,6 +272,7 @@ static RPCHelpMan getwalletinfo()
}
obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));

AppendLastProcessedBlock(obj, *pwallet);
return obj;
Expand Down
Loading
Loading