aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/addrman.cpp98
-rw-r--r--src/addrman.h24
-rw-r--r--src/net.cpp21
-rw-r--r--src/net.h1
-rw-r--r--src/net_permissions.h3
-rw-r--r--src/net_processing.cpp64
-rw-r--r--src/net_processing.h2
-rw-r--r--src/node/transaction.cpp119
-rw-r--r--src/rpc/net.cpp6
-rw-r--r--src/test/addrman_tests.cpp117
-rw-r--r--src/test/fuzz/process_message.cpp12
11 files changed, 167 insertions, 300 deletions
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 389d106164..8192b4eba6 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -6,7 +6,6 @@
#include <addrman.h>
#include <hash.h>
-#include <i2p.h>
#include <logging.h>
#include <netaddress.h>
#include <serialize.h>
@@ -732,100 +731,3 @@ std::vector<bool> CAddrMan::DecodeAsmap(fs::path path)
}
return bits;
}
-
-void CAddrMan::ResetI2PPorts()
-{
- for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; ++bucket) {
- for (int i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
- const auto id = vvNew[bucket][i];
- if (id == -1) {
- continue;
- }
- auto it = mapInfo.find(id);
- if (it == mapInfo.end()) {
- return;
- }
- auto& addr_info = it->second;
- if (!addr_info.IsI2P() || addr_info.GetPort() == I2P_SAM31_PORT) {
- continue;
- }
-
- auto addr_info_newport = addr_info;
- // The below changes addr_info_newport.GetKey(), which is used in finding a
- // bucket and a position within that bucket. So a re-bucketing may be necessary.
- addr_info_newport.port = I2P_SAM31_PORT;
-
- // Reposition entries of vvNew within the same bucket because we don't know the source
- // address which led to the decision to store the entry in vvNew[bucket] so we can't
- // re-evaluate that decision, but even if we could, CAddrInfo::GetNewBucket() does not
- // use CAddrInfo::GetKey() so it would end up in the same bucket as before the port
- // change.
- const auto i_target = addr_info_newport.GetBucketPosition(nKey, true, bucket);
-
- if (i_target == i) { // No need to re-position.
- addr_info = addr_info_newport;
- continue;
- }
-
- // Reposition from i to i_target, removing the entry from i_target (if any).
- ClearNew(bucket, i_target);
- vvNew[bucket][i_target] = id;
- vvNew[bucket][i] = -1;
- addr_info = addr_info_newport;
- }
- }
-
- for (int bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; ++bucket) {
- for (int i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
- const auto id = vvTried[bucket][i];
- if (id == -1) {
- continue;
- }
- auto it = mapInfo.find(id);
- if (it == mapInfo.end()) {
- return;
- }
- auto& addr_info = it->second;
- if (!addr_info.IsI2P() || addr_info.GetPort() == I2P_SAM31_PORT) {
- continue;
- }
-
- auto addr_info_newport = addr_info;
- // The below changes addr_info_newport.GetKey(), which is used in finding a
- // bucket and a position within that bucket. So a re-bucketing may be necessary.
- addr_info_newport.port = I2P_SAM31_PORT;
-
- const auto bucket_target = addr_info_newport.GetTriedBucket(nKey, m_asmap);
- const auto i_target = addr_info_newport.GetBucketPosition(nKey, false, bucket_target);
-
- if (bucket_target == bucket && i_target == i) { // No need to re-position.
- addr_info = addr_info_newport;
- continue;
- }
-
- // Reposition from (bucket, i) to (bucket_target, i_target). If the latter is
- // occupied, then move the entry from there to vvNew.
-
- const auto old_target_id = vvTried[bucket_target][i_target];
- if (old_target_id != -1) {
- CAddrInfo& old_target_info = mapInfo[old_target_id];
-
- old_target_info.fInTried = false;
- vvTried[bucket_target][i_target] = -1;
- --nTried;
-
- const auto new_bucket = old_target_info.GetNewBucket(nKey, m_asmap);
- const auto new_bucket_i = old_target_info.GetBucketPosition(nKey, true, new_bucket);
- ClearNew(new_bucket, new_bucket_i);
-
- old_target_info.nRefCount = 1;
- vvNew[new_bucket][new_bucket_i] = old_target_id;
- ++nNew;
- }
-
- vvTried[bucket_target][i_target] = id;
- vvTried[bucket][i] = -1;
- addr_info = addr_info_newport;
- }
- }
-}
diff --git a/src/addrman.h b/src/addrman.h
index 2a5c6c06b4..6f081b8dc1 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -334,12 +334,18 @@ public:
nUBuckets ^= (1 << 30);
}
- if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
- throw std::ios_base::failure("Corrupt CAddrMan serialization, nNew exceeds limit.");
+ if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {
+ throw std::ios_base::failure(
+ strprintf("Corrupt CAddrMan serialization: nNew=%d, should be in [0, %u]",
+ nNew,
+ ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
}
- if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {
- throw std::ios_base::failure("Corrupt CAddrMan serialization, nTried exceeds limit.");
+ if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) {
+ throw std::ios_base::failure(
+ strprintf("Corrupt CAddrMan serialization: nTried=%d, should be in [0, %u]",
+ nTried,
+ ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
}
// Deserialize entries from the new table.
@@ -452,8 +458,6 @@ public:
RemoveInvalid();
- ResetI2PPorts();
-
Check();
}
@@ -769,14 +773,6 @@ private:
//! Remove invalid addresses.
void RemoveInvalid() EXCLUSIVE_LOCKS_REQUIRED(cs);
- /**
- * Reset the ports of I2P peers to 0.
- * This is needed as a temporary measure because now we enforce port 0 and
- * only connect to I2P hosts if the port is 0, but in the early days some
- * I2P addresses with port 8333 were rumoured and persisted into addrmans.
- */
- void ResetI2PPorts() EXCLUSIVE_LOCKS_REQUIRED(cs);
-
friend class CAddrManTest;
};
diff --git a/src/net.cpp b/src/net.cpp
index 70ba875c4b..3a1bb138ab 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1212,16 +1212,29 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type)
{
- if (conn_type != ConnectionType::OUTBOUND_FULL_RELAY && conn_type != ConnectionType::BLOCK_RELAY) return false;
-
- const int max_connections = conn_type == ConnectionType::OUTBOUND_FULL_RELAY ? m_max_outbound_full_relay : m_max_outbound_block_relay;
+ std::optional<int> max_connections;
+ switch (conn_type) {
+ case ConnectionType::INBOUND:
+ case ConnectionType::MANUAL:
+ case ConnectionType::FEELER:
+ return false;
+ case ConnectionType::OUTBOUND_FULL_RELAY:
+ max_connections = m_max_outbound_full_relay;
+ break;
+ case ConnectionType::BLOCK_RELAY:
+ max_connections = m_max_outbound_block_relay;
+ break;
+ // no limit for ADDR_FETCH because -seednode has no limit either
+ case ConnectionType::ADDR_FETCH:
+ break;
+ } // no default case, so the compiler can warn about missing cases
// Count existing connections
int existing_connections = WITH_LOCK(cs_vNodes,
return std::count_if(vNodes.begin(), vNodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; }););
// Max connections of specified type already exist
- if (existing_connections >= max_connections) return false;
+ if (max_connections != std::nullopt && existing_connections >= max_connections) return false;
// Max total outbound connections already exist
CSemaphoreGrant grant(*semOutbound, true);
diff --git a/src/net.h b/src/net.h
index e1f109a2c4..a8836dfcb4 100644
--- a/src/net.h
+++ b/src/net.h
@@ -893,6 +893,7 @@ public:
*
* @param[in] address Address of node to try connecting to
* @param[in] conn_type ConnectionType::OUTBOUND or ConnectionType::BLOCK_RELAY
+ * or ConnectionType::ADDR_FETCH
* @return bool Returns false if there are no available
* slots for this connection:
* - conn_type not a supported ConnectionType
diff --git a/src/net_permissions.h b/src/net_permissions.h
index c00689465e..bc979e3792 100644
--- a/src/net_permissions.h
+++ b/src/net_permissions.h
@@ -31,7 +31,8 @@ enum class NetPermissionFlags : uint32_t {
NoBan = (1U << 4) | Download,
// Can query the mempool
Mempool = (1U << 5),
- // Can request addrs without hitting a privacy-preserving cache
+ // Can request addrs without hitting a privacy-preserving cache, and send us
+ // unlimited amounts of addrs.
Addr = (1U << 7),
// True if the user did not specifically set fine grained permissions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 315d2ac5cd..44f9879a23 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -155,6 +155,13 @@ static constexpr uint32_t MAX_GETCFHEADERS_SIZE = 2000;
static constexpr size_t MAX_PCT_ADDR_TO_SEND = 23;
/** The maximum number of address records permitted in an ADDR message. */
static constexpr size_t MAX_ADDR_TO_SEND{1000};
+/** The maximum rate of address records we're willing to process on average. Can be bypassed using
+ * the NetPermissionFlags::Addr permission. */
+static constexpr double MAX_ADDR_RATE_PER_SECOND{0.1};
+/** The soft limit of the address processing token bucket (the regular MAX_ADDR_RATE_PER_SECOND
+ * based increments won't go above this, but the MAX_ADDR_TO_SEND increment following GETADDR
+ * is exempt from this limit. */
+static constexpr size_t MAX_ADDR_PROCESSING_TOKEN_BUCKET{MAX_ADDR_TO_SEND};
// Internal stuff
namespace {
@@ -233,6 +240,15 @@ struct Peer {
std::atomic_bool m_wants_addrv2{false};
/** Whether this peer has already sent us a getaddr message. */
bool m_getaddr_recvd{false};
+ /** Number of addr messages that can be processed from this peer. Start at 1 to
+ * permit self-announcement. */
+ double m_addr_token_bucket{1.0};
+ /** When m_addr_token_bucket was last updated */
+ std::chrono::microseconds m_addr_token_timestamp{GetTime<std::chrono::microseconds>()};
+ /** Total number of addresses that were dropped due to rate limiting. */
+ std::atomic<uint64_t> m_addr_rate_limited{0};
+ /** Total number of addresses that were processed (excludes rate limited ones). */
+ std::atomic<uint64_t> m_addr_processed{0};
/** Set of txids to reconsider once their parent transactions have been accepted **/
std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
@@ -1239,6 +1255,8 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c
}
stats.m_ping_wait = ping_wait;
+ stats.m_addr_processed = peer->m_addr_processed.load();
+ stats.m_addr_rate_limited = peer->m_addr_rate_limited.load();
return true;
}
@@ -2583,6 +2601,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Get recent addresses
m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::GETADDR));
peer->m_getaddr_sent = true;
+ // When requesting a getaddr, accept an additional MAX_ADDR_TO_SEND addresses in response
+ // (bypassing the MAX_ADDR_PROCESSING_TOKEN_BUCKET limit).
+ peer->m_addr_token_bucket += MAX_ADDR_TO_SEND;
}
if (!pfrom.IsInboundConn()) {
@@ -2777,11 +2798,34 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
std::vector<CAddress> vAddrOk;
int64_t nNow = GetAdjustedTime();
int64_t nSince = nNow - 10 * 60;
+
+ // Update/increment addr rate limiting bucket.
+ const auto current_time = GetTime<std::chrono::microseconds>();
+ if (peer->m_addr_token_bucket < MAX_ADDR_PROCESSING_TOKEN_BUCKET) {
+ // Don't increment bucket if it's already full
+ const auto time_diff = std::max(current_time - peer->m_addr_token_timestamp, 0us);
+ const double increment = CountSecondsDouble(time_diff) * MAX_ADDR_RATE_PER_SECOND;
+ peer->m_addr_token_bucket = std::min<double>(peer->m_addr_token_bucket + increment, MAX_ADDR_PROCESSING_TOKEN_BUCKET);
+ }
+ peer->m_addr_token_timestamp = current_time;
+
+ const bool rate_limited = !pfrom.HasPermission(NetPermissionFlags::Addr);
+ uint64_t num_proc = 0;
+ uint64_t num_rate_limit = 0;
+ Shuffle(vAddr.begin(), vAddr.end(), FastRandomContext());
for (CAddress& addr : vAddr)
{
if (interruptMsgProc)
return;
+ // Apply rate limiting.
+ if (rate_limited) {
+ if (peer->m_addr_token_bucket < 1.0) {
+ ++num_rate_limit;
+ continue;
+ }
+ peer->m_addr_token_bucket -= 1.0;
+ }
// We only bother storing full nodes, though this may include
// things which we would not make an outbound connection to, in
// part because we may make feeler connections to them.
@@ -2795,6 +2839,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Do not process banned/discouraged addresses beyond remembering we received them
continue;
}
+ ++num_proc;
bool fReachable = IsReachable(addr);
if (addr.nTime > nSince && !peer->m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) {
// Relay to a limited number of other nodes
@@ -2804,9 +2849,20 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (fReachable)
vAddrOk.push_back(addr);
}
+ peer->m_addr_processed += num_proc;
+ peer->m_addr_rate_limited += num_rate_limit;
+ LogPrint(BCLog::NET, "Received addr: %u addresses (%u processed, %u rate-limited) from peer=%d%s\n",
+ vAddr.size(),
+ num_proc,
+ num_rate_limit,
+ pfrom.GetId(),
+ fLogIPs ? ", peeraddr=" + pfrom.addr.ToString() : "");
+
m_addrman.Add(vAddrOk, pfrom.addr, 2 * 60 * 60);
if (vAddr.size() < 1000) peer->m_getaddr_sent = false;
- if (pfrom.IsAddrFetchConn()) {
+
+ // AddrFetch: Require multiple addresses to avoid disconnecting on self-announcements
+ if (pfrom.IsAddrFetchConn() && vAddr.size() > 1) {
LogPrint(BCLog::NET, "addrfetch connection completed peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
}
@@ -4390,6 +4446,12 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
const auto current_time = GetTime<std::chrono::microseconds>();
+ if (pto->IsAddrFetchConn() && current_time - std::chrono::seconds(pto->nTimeConnected) > 10 * AVG_ADDRESS_BROADCAST_INTERVAL) {
+ LogPrint(BCLog::NET, "addrfetch connection timeout; disconnecting peer=%d\n", pto->GetId());
+ pto->fDisconnect = true;
+ return true;
+ }
+
MaybeSendPing(*pto, *peer, current_time);
// MaybeSendPing may have marked peer for disconnection
diff --git a/src/net_processing.h b/src/net_processing.h
index d5801aadd3..c537efb5db 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -29,6 +29,8 @@ struct CNodeStateStats {
int m_starting_height = -1;
std::chrono::microseconds m_ping_wait;
std::vector<int> vHeightInFlight;
+ uint64_t m_addr_processed = 0;
+ uint64_t m_addr_rate_limited = 0;
};
class PeerManager : public CValidationInterface, public NetEventsInterface
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index f21b390915..d3bce069b0 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -28,65 +28,83 @@ static TransactionError HandleATMPError(const TxValidationState& state, std::str
TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
{
- // BroadcastTransaction can be called by either sendrawtransaction RPC or wallet RPCs.
- // node.peerman is assigned both before chain clients and before RPC server is accepting calls,
- // and reset after chain clients and RPC sever are stopped. node.peerman should never be null here.
- assert(node.peerman);
+ // BroadcastTransaction can be called by either sendrawtransaction RPC or the wallet.
+ // chainman, mempool and peerman are initialized before the RPC server and wallet are started
+ // and reset after the RPC sever and wallet are stopped.
+ assert(node.chainman);
assert(node.mempool);
+ assert(node.peerman);
+
std::promise<void> promise;
- uint256 hashTx = tx->GetHash();
+ uint256 txid = tx->GetHash();
+ uint256 wtxid = tx->GetWitnessHash();
bool callback_set = false;
- { // cs_main scope
- assert(node.chainman);
- LOCK(cs_main);
- // If the transaction is already confirmed in the chain, don't do anything
- // and return early.
- CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip();
- for (size_t o = 0; o < tx->vout.size(); o++) {
- const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
- // IsSpent doesn't mean the coin is spent, it means the output doesn't exist.
- // So if the output does exist, then this transaction exists in the chain.
- if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN;
- }
- if (!node.mempool->exists(hashTx)) {
- // Transaction is not already in the mempool.
- if (max_tx_fee > 0) {
- // First, call ATMP with test_accept and check the fee. If ATMP
- // fails here, return error immediately.
+ {
+ LOCK(cs_main);
+
+ // If the transaction is already confirmed in the chain, don't do anything
+ // and return early.
+ CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip();
+ for (size_t o = 0; o < tx->vout.size(); o++) {
+ const Coin& existingCoin = view.AccessCoin(COutPoint(txid, o));
+ // IsSpent doesn't mean the coin is spent, it means the output doesn't exist.
+ // So if the output does exist, then this transaction exists in the chain.
+ if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN;
+ }
+
+ if (auto mempool_tx = node.mempool->get(txid); mempool_tx) {
+ // There's already a transaction in the mempool with this txid. Don't
+ // try to submit this transaction to the mempool (since it'll be
+ // rejected as a TX_CONFLICT), but do attempt to reannounce the mempool
+ // transaction if relay=true.
+ //
+ // The mempool transaction may have the same or different witness (and
+ // wtxid) as this transaction. Use the mempool's wtxid for reannouncement.
+ wtxid = mempool_tx->GetWitnessHash();
+ } else {
+ // Transaction is not already in the mempool.
+ if (max_tx_fee > 0) {
+ // First, call ATMP with test_accept and check the fee. If ATMP
+ // fails here, return error immediately.
+ const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, false /* bypass_limits */,
+ true /* test_accept */);
+ if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
+ return HandleATMPError(result.m_state, err_string);
+ } else if (result.m_base_fees.value() > max_tx_fee) {
+ return TransactionError::MAX_FEE_EXCEEDED;
+ }
+ }
+ // Try to submit the transaction to the mempool.
const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, false /* bypass_limits */,
- true /* test_accept */);
+ false /* test_accept */);
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
return HandleATMPError(result.m_state, err_string);
- } else if (result.m_base_fees.value() > max_tx_fee) {
- return TransactionError::MAX_FEE_EXCEEDED;
}
- }
- // Try to submit the transaction to the mempool.
- const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, false /* bypass_limits */,
- false /* test_accept */);
- if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
- return HandleATMPError(result.m_state, err_string);
- }
- // Transaction was accepted to the mempool.
+ // Transaction was accepted to the mempool.
- if (wait_callback) {
- // For transactions broadcast from outside the wallet, make sure
- // that the wallet has been notified of the transaction before
- // continuing.
- //
- // This prevents a race where a user might call sendrawtransaction
- // with a transaction to/from their wallet, immediately call some
- // wallet RPC, and get a stale result because callbacks have not
- // yet been processed.
- CallFunctionInValidationInterfaceQueue([&promise] {
- promise.set_value();
- });
- callback_set = true;
- }
- }
+ if (relay) {
+ // the mempool tracks locally submitted transactions to make a
+ // best-effort of initial broadcast
+ node.mempool->AddUnbroadcastTx(txid);
+ }
+ if (wait_callback) {
+ // For transactions broadcast from outside the wallet, make sure
+ // that the wallet has been notified of the transaction before
+ // continuing.
+ //
+ // This prevents a race where a user might call sendrawtransaction
+ // with a transaction to/from their wallet, immediately call some
+ // wallet RPC, and get a stale result because callbacks have not
+ // yet been processed.
+ CallFunctionInValidationInterfaceQueue([&promise] {
+ promise.set_value();
+ });
+ callback_set = true;
+ }
+ }
} // cs_main
if (callback_set) {
@@ -96,10 +114,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
}
if (relay) {
- // the mempool tracks locally submitted transactions to make a
- // best-effort of initial broadcast
- node.mempool->AddUnbroadcastTx(hashTx);
- node.peerman->RelayTransaction(hashTx, tx->GetWitnessHash());
+ node.peerman->RelayTransaction(txid, wtxid);
}
return TransactionError::OK;
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 3013c76825..dba0f971b2 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -242,6 +242,8 @@ static RPCHelpMan getpeerinfo()
heights.push_back(height);
}
obj.pushKV("inflight", heights);
+ obj.pushKV("addr_processed", statestats.m_addr_processed);
+ obj.pushKV("addr_rate_limited", statestats.m_addr_rate_limited);
}
UniValue permissions(UniValue::VARR);
for (const auto& permission : NetPermissions::ToStrings(stats.m_permissionFlags)) {
@@ -337,7 +339,7 @@ static RPCHelpMan addconnection()
"\nOpen an outbound connection to a specified node. This RPC is for testing only.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address and port to attempt connecting to."},
- {"connection_type", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of connection to open, either \"outbound-full-relay\" or \"block-relay-only\"."},
+ {"connection_type", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of connection to open (\"outbound-full-relay\", \"block-relay-only\" or \"addr-fetch\")."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -363,6 +365,8 @@ static RPCHelpMan addconnection()
conn_type = ConnectionType::OUTBOUND_FULL_RELAY;
} else if (conn_type_in == "block-relay-only") {
conn_type = ConnectionType::BLOCK_RELAY;
+ } else if (conn_type_in == "addr-fetch") {
+ conn_type = ConnectionType::ADDR_FETCH;
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, self.ToString());
}
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index f2eed956cd..1103292c1a 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <addrman.h>
-#include <i2p.h>
#include <test/data/asmap.raw.h>
#include <test/util/setup_common.h>
#include <util/asmap.h>
@@ -967,121 +966,5 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
}
-BOOST_AUTO_TEST_CASE(reset_i2p_ports)
-{
- CAddrManTest addrman1;
- CAddrManTest addrman2;
- const uint32_t good_time{static_cast<uint32_t>(GetAdjustedTime())};
- constexpr uint16_t port = 8333;
-
- // Has its port changed, will be re-positioned within the same bucket in vvNew.
- const CAddress i2p_new1{
- ResolveService("72l3ucjkuscrbiiepoehuwqgknyzgo7zuix5ty4puwrkyhtmnsga.b32.i2p", port),
- NODE_NONE,
- good_time};
-
- // Has its port changed, will not be re-positioned in vvNew because ports 0 and 10075 result in
- // the same bucket position.
- const CAddress i2p_new2{
- ResolveService("gehtac45oaghz54ypyopim64mql7oad2bqclla74l6tfeolzmodq.b32.i2p", 10075),
- NODE_NONE,
- good_time};
-
- // Remains unchanged, port is already as it should be.
- const CAddress i2p_new3{
- ResolveService("c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p",
- I2P_SAM31_PORT),
- NODE_NONE,
- good_time};
-
- // Has its port changed, re-positioning in vvNew will cause i2p_new3 to be evicted.
- const CAddress i2p_new4{
- ResolveService("c4cbbkn46qxftwja53pxiykntegfyfjqtnzbm6iv6r5mungmqgmq.b32.i2p", port),
- NODE_NONE,
- good_time};
-
- // Remains unchanged.
- const CAddress ipv4_new{ResolveService("1.2.3.4", port), NODE_NONE, good_time};
-
- // Has its port changed, will be re-positioned in vvTried.
- const CAddress i2p_tried1{
- ResolveService("h3r6bkn46qxftwja53pxiykntegfyfjqtnzbm6iv6r5mungmqgmq.b32.i2p", port),
- NODE_NONE,
- good_time};
-
- // Has its port changed, will not be re-positioned in vvTried because ports 0 and 10537
- // result in the same position (bucket, i).
- const CAddress i2p_tried2{
- ResolveService("pjs7or2ctvteeo5tu4bwyrtydeuhqhvdprtujn4daxr75jpebjxa.b32.i2p", 10537),
- NODE_NONE,
- good_time};
-
- // Remains unchanged, port is already as it should be.
- const CAddress i2p_tried3{
- ResolveService("hnbbyjpxx54623l555sta7pocy3se4sdgmuebi5k6reesz5rjp6q.b32.i2p",
- I2P_SAM31_PORT),
- NODE_NONE,
- good_time};
-
- // Has its port changed, re-positioning in vvTried will cause i2p_tried3 to be moved to vvNew.
- const CAddress i2p_tried4{
- ResolveService("hna37nqr3ahkqv62cuqfwgtneekvvpnuc4i4f6yo7tpoqjswvcwa.b32.i2p", port),
- NODE_NONE,
- good_time};
-
- // Remains unchanged.
- const CAddress ipv4_tried{ResolveService("2.3.4.5", port), NODE_NONE, good_time};
-
- const CNetAddr source;
-
- CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
-
- addrman1.Add(i2p_new1, source);
- addrman1.Add(i2p_new2, source);
- addrman1.Add(i2p_new3, source);
- addrman1.Add(i2p_new4, source);
- addrman1.Add(ipv4_new, source);
-
- addrman1.Add(i2p_tried1, source);
- addrman1.Good(i2p_tried1);
- addrman1.Add(i2p_tried2, source);
- addrman1.Good(i2p_tried2);
- addrman1.Add(i2p_tried3, source);
- addrman1.Good(i2p_tried3);
- addrman1.Add(i2p_tried4, source);
- addrman1.Good(i2p_tried4);
- addrman1.Add(ipv4_tried, source);
- addrman1.Good(ipv4_tried);
-
- stream << addrman1;
- stream >> addrman2;
-
- const size_t max_addresses{0};
- const size_t max_pct{0};
-
- auto addresses = addrman2.GetAddr(max_addresses, max_pct, NET_I2P);
- BOOST_REQUIRE_EQUAL(addresses.size(), 7UL);
- std::sort(addresses.begin(), addresses.end()); // Just some deterministic order.
- BOOST_CHECK_EQUAL(addresses[0].ToStringIP(), i2p_new4.ToStringIP());
- BOOST_CHECK_EQUAL(addresses[0].GetPort(), I2P_SAM31_PORT);
- BOOST_CHECK_EQUAL(addresses[1].ToStringIP(), i2p_new2.ToStringIP());
- BOOST_CHECK_EQUAL(addresses[1].GetPort(), I2P_SAM31_PORT);
- BOOST_CHECK_EQUAL(addresses[2].ToStringIP(), i2p_tried4.ToStringIP());
- BOOST_CHECK_EQUAL(addresses[2].GetPort(), I2P_SAM31_PORT);
- BOOST_CHECK_EQUAL(addresses[3].ToStringIP(), i2p_tried3.ToStringIP());
- BOOST_CHECK_EQUAL(addresses[3].GetPort(), I2P_SAM31_PORT);
- BOOST_CHECK_EQUAL(addresses[4].ToStringIP(), i2p_tried1.ToStringIP());
- BOOST_CHECK_EQUAL(addresses[4].GetPort(), I2P_SAM31_PORT);
- BOOST_CHECK_EQUAL(addresses[5].ToStringIP(), i2p_tried2.ToStringIP());
- BOOST_CHECK_EQUAL(addresses[5].GetPort(), I2P_SAM31_PORT);
- BOOST_CHECK_EQUAL(addresses[6].ToStringIP(), i2p_new1.ToStringIP());
- BOOST_CHECK_EQUAL(addresses[6].GetPort(), I2P_SAM31_PORT);
-
- addresses = addrman2.GetAddr(max_addresses, max_pct, NET_IPV4);
- BOOST_REQUIRE_EQUAL(addresses.size(), 2UL);
- std::sort(addresses.begin(), addresses.end()); // Just some deterministic order.
- BOOST_CHECK_EQUAL(addresses[0].ToStringIPPort(), ipv4_new.ToStringIPPort());
- BOOST_CHECK_EQUAL(addresses[1].ToStringIPPort(), ipv4_tried.ToStringIPPort());
-}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index c4e4d4c785..7b99193ad0 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -58,19 +58,7 @@ void initialize_process_message()
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
-
- // Temporary debug for https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=35027
- {
- LOCK(::cs_main);
- assert(CheckDiskSpace(gArgs.GetDataDirNet()));
- assert(CheckDiskSpace(gArgs.GetDataDirNet(), 48 * 2 * 2 * g_setup->m_node.chainman->ActiveChainstate().CoinsTip().GetCacheSize()));
- }
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
- {
- LOCK(::cs_main);
- assert(CheckDiskSpace(gArgs.GetDataDirNet()));
- assert(CheckDiskSpace(gArgs.GetDataDirNet(), 48 * 2 * 2 * g_setup->m_node.chainman->ActiveChainstate().CoinsTip().GetCacheSize()));
- }
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
}
SyncWithValidationInterfaceQueue();