2022-03-15 15:16:35 -07:00
|
|
|
use {
|
2022-03-21 09:31:37 -07:00
|
|
|
crate::{
|
2022-06-06 10:28:31 -07:00
|
|
|
quic_client::QuicTpuConnection,
|
|
|
|
tpu_connection::{ClientStats, Connection},
|
|
|
|
udp_client::UdpTpuConnection,
|
2022-03-21 09:31:37 -07:00
|
|
|
},
|
2022-05-04 12:38:03 -07:00
|
|
|
indexmap::map::IndexMap,
|
2022-03-15 15:16:35 -07:00
|
|
|
lazy_static::lazy_static,
|
2022-05-02 13:02:49 -07:00
|
|
|
rand::{thread_rng, Rng},
|
2022-04-29 09:58:01 -07:00
|
|
|
solana_measure::measure::Measure,
|
2022-05-26 08:21:16 -07:00
|
|
|
solana_sdk::timing::AtomicInterval,
|
2022-03-15 15:16:35 -07:00
|
|
|
std::{
|
2022-05-16 11:13:18 -07:00
|
|
|
net::SocketAddr,
|
2022-04-12 20:04:40 -07:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicU64, Ordering},
|
2022-05-02 13:02:49 -07:00
|
|
|
Arc, RwLock,
|
2022-04-12 20:04:40 -07:00
|
|
|
},
|
2022-03-15 15:16:35 -07:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
// Should be non-zero
|
2022-04-15 12:09:24 -07:00
|
|
|
static MAX_CONNECTIONS: usize = 1024;
|
2022-03-15 15:16:35 -07:00
|
|
|
|
2022-04-12 20:04:40 -07:00
|
|
|
#[derive(Default)]
|
2022-05-19 12:29:27 -07:00
|
|
|
pub struct ConnectionCacheStats {
|
2022-04-12 20:04:40 -07:00
|
|
|
cache_hits: AtomicU64,
|
|
|
|
cache_misses: AtomicU64,
|
2022-05-02 19:27:40 -07:00
|
|
|
cache_evictions: AtomicU64,
|
|
|
|
eviction_time_ms: AtomicU64,
|
2022-04-12 20:04:40 -07:00
|
|
|
sent_packets: AtomicU64,
|
|
|
|
total_batches: AtomicU64,
|
|
|
|
batch_success: AtomicU64,
|
|
|
|
batch_failure: AtomicU64,
|
2022-04-29 09:58:01 -07:00
|
|
|
get_connection_ms: AtomicU64,
|
|
|
|
get_connection_lock_ms: AtomicU64,
|
|
|
|
get_connection_hit_ms: AtomicU64,
|
|
|
|
get_connection_miss_ms: AtomicU64,
|
2022-04-12 20:04:40 -07:00
|
|
|
|
|
|
|
// Need to track these separately per-connection
|
|
|
|
// because we need to track the base stat value from quinn
|
2022-05-19 12:29:27 -07:00
|
|
|
pub total_client_stats: ClientStats,
|
2022-04-12 20:04:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const CONNECTION_STAT_SUBMISSION_INTERVAL: u64 = 2000;
|
|
|
|
|
|
|
|
impl ConnectionCacheStats {
|
2022-05-26 08:21:16 -07:00
|
|
|
pub fn add_client_stats(
|
|
|
|
&self,
|
|
|
|
client_stats: &ClientStats,
|
|
|
|
num_packets: usize,
|
|
|
|
is_success: bool,
|
|
|
|
) {
|
2022-04-12 20:04:40 -07:00
|
|
|
self.total_client_stats.total_connections.fetch_add(
|
|
|
|
client_stats.total_connections.load(Ordering::Relaxed),
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
|
|
|
self.total_client_stats.connection_reuse.fetch_add(
|
|
|
|
client_stats.connection_reuse.load(Ordering::Relaxed),
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
2022-05-10 09:44:07 -07:00
|
|
|
self.total_client_stats.connection_errors.fetch_add(
|
|
|
|
client_stats.connection_errors.load(Ordering::Relaxed),
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
|
|
|
self.total_client_stats.zero_rtt_accepts.fetch_add(
|
|
|
|
client_stats.zero_rtt_accepts.load(Ordering::Relaxed),
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
|
|
|
self.total_client_stats.zero_rtt_rejects.fetch_add(
|
|
|
|
client_stats.zero_rtt_rejects.load(Ordering::Relaxed),
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
2022-05-18 13:23:29 -07:00
|
|
|
self.total_client_stats.make_connection_ms.fetch_add(
|
|
|
|
client_stats.make_connection_ms.load(Ordering::Relaxed),
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
2022-04-12 20:04:40 -07:00
|
|
|
self.sent_packets
|
|
|
|
.fetch_add(num_packets as u64, Ordering::Relaxed);
|
|
|
|
self.total_batches.fetch_add(1, Ordering::Relaxed);
|
|
|
|
if is_success {
|
|
|
|
self.batch_success.fetch_add(1, Ordering::Relaxed);
|
|
|
|
} else {
|
|
|
|
self.batch_failure.fetch_add(1, Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn report(&self) {
|
|
|
|
datapoint_info!(
|
|
|
|
"quic-client-connection-stats",
|
|
|
|
(
|
|
|
|
"cache_hits",
|
|
|
|
self.cache_hits.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"cache_misses",
|
|
|
|
self.cache_misses.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
2022-05-02 19:27:40 -07:00
|
|
|
(
|
|
|
|
"cache_evictions",
|
|
|
|
self.cache_evictions.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"eviction_time_ms",
|
|
|
|
self.eviction_time_ms.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
2022-04-29 09:58:01 -07:00
|
|
|
(
|
|
|
|
"get_connection_ms",
|
|
|
|
self.get_connection_ms.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"get_connection_lock_ms",
|
|
|
|
self.get_connection_lock_ms.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"get_connection_hit_ms",
|
|
|
|
self.get_connection_hit_ms.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"get_connection_miss_ms",
|
|
|
|
self.get_connection_miss_ms.swap(0, Ordering::Relaxed),
|
2022-05-18 13:23:29 -07:00
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"make_connection_ms",
|
|
|
|
self.total_client_stats
|
|
|
|
.make_connection_ms
|
|
|
|
.swap(0, Ordering::Relaxed),
|
2022-04-29 09:58:01 -07:00
|
|
|
i64
|
|
|
|
),
|
2022-04-12 20:04:40 -07:00
|
|
|
(
|
|
|
|
"total_connections",
|
|
|
|
self.total_client_stats
|
|
|
|
.total_connections
|
|
|
|
.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"connection_reuse",
|
|
|
|
self.total_client_stats
|
|
|
|
.connection_reuse
|
|
|
|
.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
2022-05-10 09:44:07 -07:00
|
|
|
(
|
|
|
|
"connection_errors",
|
|
|
|
self.total_client_stats
|
|
|
|
.connection_errors
|
|
|
|
.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"zero_rtt_accepts",
|
|
|
|
self.total_client_stats
|
|
|
|
.zero_rtt_accepts
|
|
|
|
.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"zero_rtt_rejects",
|
|
|
|
self.total_client_stats
|
|
|
|
.zero_rtt_rejects
|
|
|
|
.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
2022-04-12 20:04:40 -07:00
|
|
|
(
|
|
|
|
"congestion_events",
|
|
|
|
self.total_client_stats.congestion_events.load_and_reset(),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"tx_streams_blocked_uni",
|
|
|
|
self.total_client_stats
|
|
|
|
.tx_streams_blocked_uni
|
|
|
|
.load_and_reset(),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"tx_data_blocked",
|
|
|
|
self.total_client_stats.tx_data_blocked.load_and_reset(),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"tx_acks",
|
|
|
|
self.total_client_stats.tx_acks.load_and_reset(),
|
|
|
|
i64
|
|
|
|
),
|
2022-04-20 04:59:54 -07:00
|
|
|
(
|
|
|
|
"num_packets",
|
|
|
|
self.sent_packets.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"total_batches",
|
|
|
|
self.total_batches.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"batch_failure",
|
|
|
|
self.batch_failure.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
2022-04-12 20:04:40 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-15 12:09:24 -07:00
|
|
|
struct ConnectionMap {
|
2022-05-26 08:21:16 -07:00
|
|
|
map: IndexMap<SocketAddr, Arc<Connection>>,
|
2022-04-12 20:04:40 -07:00
|
|
|
stats: Arc<ConnectionCacheStats>,
|
|
|
|
last_stats: AtomicInterval,
|
2022-03-21 09:31:37 -07:00
|
|
|
use_quic: bool,
|
2022-03-15 15:16:35 -07:00
|
|
|
}
|
|
|
|
|
2022-04-15 12:09:24 -07:00
|
|
|
impl ConnectionMap {
|
2022-03-15 15:16:35 -07:00
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
2022-05-04 12:38:03 -07:00
|
|
|
map: IndexMap::with_capacity(MAX_CONNECTIONS),
|
2022-04-12 20:04:40 -07:00
|
|
|
stats: Arc::new(ConnectionCacheStats::default()),
|
|
|
|
last_stats: AtomicInterval::default(),
|
2022-03-21 09:31:37 -07:00
|
|
|
use_quic: false,
|
2022-03-15 15:16:35 -07:00
|
|
|
}
|
|
|
|
}
|
2022-03-21 09:31:37 -07:00
|
|
|
|
|
|
|
pub fn set_use_quic(&mut self, use_quic: bool) {
|
|
|
|
self.use_quic = use_quic;
|
|
|
|
}
|
2022-03-15 15:16:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
lazy_static! {
|
2022-05-02 13:02:49 -07:00
|
|
|
static ref CONNECTION_MAP: RwLock<ConnectionMap> = RwLock::new(ConnectionMap::new());
|
2022-03-15 15:16:35 -07:00
|
|
|
}
|
|
|
|
|
2022-03-21 09:31:37 -07:00
|
|
|
pub fn set_use_quic(use_quic: bool) {
|
2022-05-02 13:02:49 -07:00
|
|
|
let mut map = (*CONNECTION_MAP).write().unwrap();
|
2022-03-21 09:31:37 -07:00
|
|
|
map.set_use_quic(use_quic);
|
|
|
|
}
|
|
|
|
|
2022-05-02 13:02:49 -07:00
|
|
|
struct GetConnectionResult {
|
2022-05-26 08:21:16 -07:00
|
|
|
connection: Arc<Connection>,
|
2022-05-02 13:02:49 -07:00
|
|
|
cache_hit: bool,
|
|
|
|
report_stats: bool,
|
2022-05-02 19:27:40 -07:00
|
|
|
map_timing_ms: u64,
|
|
|
|
lock_timing_ms: u64,
|
2022-05-02 13:02:49 -07:00
|
|
|
connection_cache_stats: Arc<ConnectionCacheStats>,
|
2022-05-02 19:27:40 -07:00
|
|
|
num_evictions: u64,
|
|
|
|
eviction_timing_ms: u64,
|
2022-05-02 13:02:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_or_add_connection(addr: &SocketAddr) -> GetConnectionResult {
|
2022-04-29 09:58:01 -07:00
|
|
|
let mut get_connection_map_lock_measure = Measure::start("get_connection_map_lock_measure");
|
2022-05-02 13:02:49 -07:00
|
|
|
let map = (*CONNECTION_MAP).read().unwrap();
|
2022-04-29 09:58:01 -07:00
|
|
|
get_connection_map_lock_measure.stop();
|
2022-04-06 07:58:32 -07:00
|
|
|
|
2022-05-02 19:27:40 -07:00
|
|
|
let mut lock_timing_ms = get_connection_map_lock_measure.as_ms();
|
2022-05-02 13:02:49 -07:00
|
|
|
|
|
|
|
let report_stats = map
|
2022-04-12 20:04:40 -07:00
|
|
|
.last_stats
|
2022-05-02 13:02:49 -07:00
|
|
|
.should_update(CONNECTION_STAT_SUBMISSION_INTERVAL);
|
2022-04-12 20:04:40 -07:00
|
|
|
|
2022-04-29 09:58:01 -07:00
|
|
|
let mut get_connection_map_measure = Measure::start("get_connection_hit_measure");
|
2022-05-16 11:13:18 -07:00
|
|
|
let (connection, cache_hit, connection_cache_stats, num_evictions, eviction_timing_ms) =
|
|
|
|
match map.map.get(addr) {
|
|
|
|
Some(connection) => (connection.clone(), true, map.stats.clone(), 0, 0),
|
|
|
|
None => {
|
|
|
|
// Upgrade to write access by dropping read lock and acquire write lock
|
|
|
|
drop(map);
|
|
|
|
let mut get_connection_map_lock_measure =
|
|
|
|
Measure::start("get_connection_map_lock_measure");
|
|
|
|
let mut map = (*CONNECTION_MAP).write().unwrap();
|
|
|
|
get_connection_map_lock_measure.stop();
|
2022-05-02 13:02:49 -07:00
|
|
|
|
2022-05-16 11:13:18 -07:00
|
|
|
lock_timing_ms =
|
|
|
|
lock_timing_ms.saturating_add(get_connection_map_lock_measure.as_ms());
|
2022-05-02 13:02:49 -07:00
|
|
|
|
2022-05-16 11:13:18 -07:00
|
|
|
// Read again, as it is possible that between read lock dropped and the write lock acquired
|
|
|
|
// another thread could have setup the connection.
|
|
|
|
match map.map.get(addr) {
|
|
|
|
Some(connection) => (connection.clone(), true, map.stats.clone(), 0, 0),
|
|
|
|
None => {
|
2022-05-26 08:21:16 -07:00
|
|
|
let connection: Connection = if map.use_quic {
|
|
|
|
QuicTpuConnection::new(*addr, map.stats.clone()).into()
|
2022-05-16 11:13:18 -07:00
|
|
|
} else {
|
2022-05-26 08:21:16 -07:00
|
|
|
UdpTpuConnection::new(*addr, map.stats.clone()).into()
|
2022-05-16 11:13:18 -07:00
|
|
|
};
|
2022-05-02 13:02:49 -07:00
|
|
|
|
2022-05-26 08:21:16 -07:00
|
|
|
let connection = Arc::new(connection);
|
|
|
|
|
2022-05-16 11:13:18 -07:00
|
|
|
// evict a connection if the cache is reaching upper bounds
|
|
|
|
let mut num_evictions = 0;
|
|
|
|
let mut get_connection_cache_eviction_measure =
|
|
|
|
Measure::start("get_connection_cache_eviction_measure");
|
|
|
|
while map.map.len() >= MAX_CONNECTIONS {
|
|
|
|
let mut rng = thread_rng();
|
|
|
|
let n = rng.gen_range(0, MAX_CONNECTIONS);
|
|
|
|
map.map.swap_remove_index(n);
|
|
|
|
num_evictions += 1;
|
|
|
|
}
|
|
|
|
get_connection_cache_eviction_measure.stop();
|
2022-05-14 15:02:13 -07:00
|
|
|
|
2022-05-16 11:13:18 -07:00
|
|
|
map.map.insert(*addr, connection.clone());
|
|
|
|
(
|
|
|
|
connection,
|
|
|
|
false,
|
|
|
|
map.stats.clone(),
|
|
|
|
num_evictions,
|
|
|
|
get_connection_cache_eviction_measure.as_ms(),
|
|
|
|
)
|
2022-05-14 15:02:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-16 11:13:18 -07:00
|
|
|
};
|
2022-04-29 09:58:01 -07:00
|
|
|
get_connection_map_measure.stop();
|
2022-04-12 20:04:40 -07:00
|
|
|
|
2022-05-02 13:02:49 -07:00
|
|
|
GetConnectionResult {
|
|
|
|
connection,
|
|
|
|
cache_hit,
|
|
|
|
report_stats,
|
2022-05-02 19:27:40 -07:00
|
|
|
map_timing_ms: get_connection_map_measure.as_ms(),
|
|
|
|
lock_timing_ms,
|
2022-05-02 13:02:49 -07:00
|
|
|
connection_cache_stats,
|
2022-05-02 19:27:40 -07:00
|
|
|
num_evictions,
|
|
|
|
eviction_timing_ms,
|
2022-05-02 13:02:49 -07:00
|
|
|
}
|
|
|
|
}
|
2022-04-12 20:04:40 -07:00
|
|
|
|
2022-05-02 13:02:49 -07:00
|
|
|
// TODO: see https://github.com/solana-labs/solana/issues/23661
|
|
|
|
// remove lazy_static and optimize and refactor this
|
2022-05-26 08:21:16 -07:00
|
|
|
pub fn get_connection(addr: &SocketAddr) -> Arc<Connection> {
|
2022-05-02 13:02:49 -07:00
|
|
|
let mut get_connection_measure = Measure::start("get_connection_measure");
|
|
|
|
let GetConnectionResult {
|
|
|
|
connection,
|
|
|
|
cache_hit,
|
|
|
|
report_stats,
|
2022-05-02 19:27:40 -07:00
|
|
|
map_timing_ms,
|
|
|
|
lock_timing_ms,
|
2022-05-02 13:02:49 -07:00
|
|
|
connection_cache_stats,
|
2022-05-02 19:27:40 -07:00
|
|
|
num_evictions,
|
|
|
|
eviction_timing_ms,
|
2022-05-02 13:02:49 -07:00
|
|
|
} = get_or_add_connection(addr);
|
|
|
|
|
|
|
|
if report_stats {
|
|
|
|
connection_cache_stats.report();
|
|
|
|
}
|
|
|
|
|
|
|
|
if cache_hit {
|
|
|
|
connection_cache_stats
|
|
|
|
.cache_hits
|
|
|
|
.fetch_add(1, Ordering::Relaxed);
|
|
|
|
connection_cache_stats
|
2022-04-29 09:58:01 -07:00
|
|
|
.get_connection_hit_ms
|
2022-05-02 19:27:40 -07:00
|
|
|
.fetch_add(map_timing_ms, Ordering::Relaxed);
|
2022-04-12 20:04:40 -07:00
|
|
|
} else {
|
2022-05-02 13:02:49 -07:00
|
|
|
connection_cache_stats
|
|
|
|
.cache_misses
|
|
|
|
.fetch_add(1, Ordering::Relaxed);
|
|
|
|
connection_cache_stats
|
2022-04-29 09:58:01 -07:00
|
|
|
.get_connection_miss_ms
|
2022-05-02 19:27:40 -07:00
|
|
|
.fetch_add(map_timing_ms, Ordering::Relaxed);
|
|
|
|
connection_cache_stats
|
|
|
|
.cache_evictions
|
|
|
|
.fetch_add(num_evictions, Ordering::Relaxed);
|
|
|
|
connection_cache_stats
|
|
|
|
.eviction_time_ms
|
|
|
|
.fetch_add(eviction_timing_ms, Ordering::Relaxed);
|
2022-03-15 15:16:35 -07:00
|
|
|
}
|
2022-05-02 13:02:49 -07:00
|
|
|
|
2022-04-29 09:58:01 -07:00
|
|
|
get_connection_measure.stop();
|
2022-05-02 13:02:49 -07:00
|
|
|
connection_cache_stats
|
2022-04-29 09:58:01 -07:00
|
|
|
.get_connection_lock_ms
|
2022-05-02 19:27:40 -07:00
|
|
|
.fetch_add(lock_timing_ms, Ordering::Relaxed);
|
2022-05-02 13:02:49 -07:00
|
|
|
connection_cache_stats
|
2022-04-29 09:58:01 -07:00
|
|
|
.get_connection_ms
|
2022-05-02 13:02:49 -07:00
|
|
|
.fetch_add(get_connection_measure.as_ms(), Ordering::Relaxed);
|
2022-03-15 15:16:35 -07:00
|
|
|
|
2022-05-26 08:21:16 -07:00
|
|
|
connection
|
2022-03-24 08:40:26 -07:00
|
|
|
}
|
|
|
|
|
2022-03-15 15:16:35 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use {
|
2022-03-24 08:40:26 -07:00
|
|
|
crate::{
|
2022-05-26 08:21:16 -07:00
|
|
|
connection_cache::{get_connection, CONNECTION_MAP, MAX_CONNECTIONS},
|
2022-03-24 08:40:26 -07:00
|
|
|
tpu_connection::TpuConnection,
|
|
|
|
},
|
2022-03-15 15:16:35 -07:00
|
|
|
rand::{Rng, SeedableRng},
|
|
|
|
rand_chacha::ChaChaRng,
|
2022-05-26 08:21:16 -07:00
|
|
|
std::net::SocketAddr,
|
2022-03-15 15:16:35 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
fn get_addr(rng: &mut ChaChaRng) -> SocketAddr {
|
|
|
|
let a = rng.gen_range(1, 255);
|
|
|
|
let b = rng.gen_range(1, 255);
|
|
|
|
let c = rng.gen_range(1, 255);
|
|
|
|
let d = rng.gen_range(1, 255);
|
|
|
|
|
|
|
|
let addr_str = format!("{}.{}.{}.{}:80", a, b, c, d);
|
|
|
|
|
|
|
|
addr_str.parse().expect("Invalid address")
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_connection_cache() {
|
2022-04-15 12:09:24 -07:00
|
|
|
solana_logger::setup();
|
2022-03-15 15:16:35 -07:00
|
|
|
// Allow the test to run deterministically
|
|
|
|
// with the same pseudorandom sequence between runs
|
|
|
|
// and on different platforms - the cryptographic security
|
|
|
|
// property isn't important here but ChaChaRng provides a way
|
|
|
|
// to get the same pseudorandom sequence on different platforms
|
|
|
|
let mut rng = ChaChaRng::seed_from_u64(42);
|
|
|
|
|
|
|
|
// Generate a bunch of random addresses and create TPUConnections to them
|
|
|
|
// Since TPUConnection::new is infallible, it should't matter whether or not
|
|
|
|
// we can actually connect to those addresses - TPUConnection implementations should either
|
|
|
|
// be lazy and not connect until first use or handle connection errors somehow
|
|
|
|
// (without crashing, as would be required in a real practical validator)
|
|
|
|
let addrs = (0..MAX_CONNECTIONS)
|
|
|
|
.into_iter()
|
|
|
|
.map(|_| {
|
|
|
|
let addr = get_addr(&mut rng);
|
|
|
|
get_connection(&addr);
|
|
|
|
addr
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
{
|
2022-05-02 13:02:49 -07:00
|
|
|
let map = (*CONNECTION_MAP).read().unwrap();
|
|
|
|
assert!(map.map.len() == MAX_CONNECTIONS);
|
2022-03-15 15:16:35 -07:00
|
|
|
addrs.iter().for_each(|a| {
|
2022-05-02 13:02:49 -07:00
|
|
|
let conn = map.map.get(a).expect("Address not found");
|
2022-05-26 08:21:16 -07:00
|
|
|
assert!(a.ip() == conn.tpu_addr().ip());
|
2022-03-15 15:16:35 -07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-05-02 13:02:49 -07:00
|
|
|
let addr = get_addr(&mut rng);
|
|
|
|
get_connection(&addr);
|
|
|
|
|
|
|
|
let map = (*CONNECTION_MAP).read().unwrap();
|
|
|
|
assert!(map.map.len() == MAX_CONNECTIONS);
|
|
|
|
let _conn = map.map.get(&addr).expect("Address not found");
|
2022-03-15 15:16:35 -07:00
|
|
|
}
|
|
|
|
}
|