2022-09-30 18:51:50 -07:00
|
|
|
#![allow(clippy::integer_arithmetic)]
|
|
|
|
|
|
|
|
pub mod nonblocking;
|
|
|
|
pub mod quic_client;
|
|
|
|
|
2022-11-18 11:21:45 -08:00
|
|
|
#[macro_use]
|
|
|
|
extern crate solana_metrics;
|
|
|
|
|
2022-09-30 18:51:50 -07:00
|
|
|
use {
|
|
|
|
crate::{
|
|
|
|
nonblocking::quic_client::{
|
2023-02-01 18:10:06 -08:00
|
|
|
QuicClient, QuicClientCertificate,
|
|
|
|
QuicClientConnection as NonblockingQuicClientConnection, QuicLazyInitializedEndpoint,
|
2022-09-30 18:51:50 -07:00
|
|
|
},
|
2023-02-01 18:10:06 -08:00
|
|
|
quic_client::QuicClientConnection as BlockingQuicClientConnection,
|
|
|
|
},
|
|
|
|
quinn::Endpoint,
|
2023-04-12 12:53:25 -07:00
|
|
|
rcgen::RcgenError,
|
2023-02-01 18:10:06 -08:00
|
|
|
solana_connection_cache::{
|
|
|
|
connection_cache::{
|
2023-06-12 15:58:27 -07:00
|
|
|
BaseClientConnection, ClientError, ConnectionCache, ConnectionManager, ConnectionPool,
|
2023-06-06 14:28:29 -07:00
|
|
|
ConnectionPoolError, Protocol,
|
2023-02-01 18:10:06 -08:00
|
|
|
},
|
|
|
|
connection_cache_stats::ConnectionCacheStats,
|
2022-09-30 18:51:50 -07:00
|
|
|
},
|
2023-06-12 15:58:27 -07:00
|
|
|
solana_sdk::{
|
|
|
|
pubkey::Pubkey,
|
|
|
|
signature::{Keypair, Signer},
|
|
|
|
},
|
2022-09-30 18:51:50 -07:00
|
|
|
solana_streamer::{
|
|
|
|
nonblocking::quic::{compute_max_allowed_uni_streams, ConnectionPeerType},
|
|
|
|
streamer::StakedNodes,
|
2023-01-12 15:24:02 -08:00
|
|
|
tls_certificates::new_self_signed_tls_certificate,
|
2022-09-30 18:51:50 -07:00
|
|
|
},
|
|
|
|
std::{
|
|
|
|
net::{IpAddr, Ipv4Addr, SocketAddr},
|
|
|
|
sync::{Arc, RwLock},
|
|
|
|
},
|
2022-11-17 19:13:43 -08:00
|
|
|
thiserror::Error,
|
2022-09-30 18:51:50 -07:00
|
|
|
};
|
|
|
|
|
2022-11-17 19:13:43 -08:00
|
|
|
#[derive(Error, Debug)]
|
|
|
|
pub enum QuicClientError {
|
|
|
|
#[error("Certificate error: {0}")]
|
2023-04-12 12:53:25 -07:00
|
|
|
CertificateError(#[from] RcgenError),
|
2022-11-17 19:13:43 -08:00
|
|
|
}
|
|
|
|
|
2022-09-30 18:51:50 -07:00
|
|
|
pub struct QuicPool {
|
2023-02-08 16:50:44 -08:00
|
|
|
connections: Vec<Arc<Quic>>,
|
2022-09-30 18:51:50 -07:00
|
|
|
endpoint: Arc<QuicLazyInitializedEndpoint>,
|
|
|
|
}
|
|
|
|
impl ConnectionPool for QuicPool {
|
2023-02-08 16:50:44 -08:00
|
|
|
type BaseClientConnection = Quic;
|
|
|
|
type NewConnectionConfig = QuicConfig;
|
|
|
|
|
|
|
|
fn add_connection(&mut self, config: &Self::NewConnectionConfig, addr: &SocketAddr) {
|
2023-02-01 18:10:06 -08:00
|
|
|
let connection = self.create_pool_entry(config, addr);
|
2022-09-30 18:51:50 -07:00
|
|
|
self.connections.push(connection);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn num_connections(&self) -> usize {
|
|
|
|
self.connections.len()
|
|
|
|
}
|
|
|
|
|
2023-02-08 16:50:44 -08:00
|
|
|
fn get(&self, index: usize) -> Result<Arc<Self::BaseClientConnection>, ConnectionPoolError> {
|
2022-09-30 18:51:50 -07:00
|
|
|
self.connections
|
|
|
|
.get(index)
|
|
|
|
.cloned()
|
|
|
|
.ok_or(ConnectionPoolError::IndexOutOfRange)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn create_pool_entry(
|
|
|
|
&self,
|
2023-02-08 16:50:44 -08:00
|
|
|
config: &Self::NewConnectionConfig,
|
2022-09-30 18:51:50 -07:00
|
|
|
addr: &SocketAddr,
|
2023-02-08 16:50:44 -08:00
|
|
|
) -> Arc<Self::BaseClientConnection> {
|
2023-02-01 18:10:06 -08:00
|
|
|
Arc::new(Quic(Arc::new(QuicClient::new(
|
2022-09-30 18:51:50 -07:00
|
|
|
self.endpoint.clone(),
|
|
|
|
*addr,
|
|
|
|
config.compute_max_parallel_streams(),
|
2023-02-01 18:10:06 -08:00
|
|
|
))))
|
2022-09-30 18:51:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-08 09:46:22 -07:00
|
|
|
#[derive(Clone)]
|
2022-09-30 18:51:50 -07:00
|
|
|
pub struct QuicConfig {
|
|
|
|
client_certificate: Arc<QuicClientCertificate>,
|
|
|
|
maybe_staked_nodes: Option<Arc<RwLock<StakedNodes>>>,
|
|
|
|
maybe_client_pubkey: Option<Pubkey>,
|
|
|
|
|
2023-02-01 18:10:06 -08:00
|
|
|
// The optional specified endpoint for the quic based client connections
|
|
|
|
// If not specified, the connection cache will create as needed.
|
|
|
|
client_endpoint: Option<Endpoint>,
|
|
|
|
}
|
2022-11-17 19:13:43 -08:00
|
|
|
|
2023-06-06 14:28:29 -07:00
|
|
|
impl QuicConfig {
|
|
|
|
pub fn new() -> Result<Self, ClientError> {
|
2023-01-12 15:24:02 -08:00
|
|
|
let (cert, priv_key) =
|
2023-04-12 12:53:25 -07:00
|
|
|
new_self_signed_tls_certificate(&Keypair::new(), IpAddr::V4(Ipv4Addr::UNSPECIFIED))?;
|
2022-11-17 19:13:43 -08:00
|
|
|
Ok(Self {
|
2022-09-30 18:51:50 -07:00
|
|
|
client_certificate: Arc::new(QuicClientCertificate {
|
2023-01-12 15:24:02 -08:00
|
|
|
certificate: cert,
|
2022-09-30 18:51:50 -07:00
|
|
|
key: priv_key,
|
|
|
|
}),
|
|
|
|
maybe_staked_nodes: None,
|
|
|
|
maybe_client_pubkey: None,
|
2023-02-01 18:10:06 -08:00
|
|
|
client_endpoint: None,
|
2022-11-17 19:13:43 -08:00
|
|
|
})
|
2022-09-30 18:51:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QuicConfig {
|
2023-02-01 18:10:06 -08:00
|
|
|
fn create_endpoint(&self) -> QuicLazyInitializedEndpoint {
|
|
|
|
QuicLazyInitializedEndpoint::new(
|
2022-09-30 18:51:50 -07:00
|
|
|
self.client_certificate.clone(),
|
2023-02-01 18:10:06 -08:00
|
|
|
self.client_endpoint.as_ref().cloned(),
|
|
|
|
)
|
2022-09-30 18:51:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn compute_max_parallel_streams(&self) -> usize {
|
|
|
|
let (client_type, stake, total_stake) =
|
|
|
|
self.maybe_client_pubkey
|
|
|
|
.map_or((ConnectionPeerType::Unstaked, 0, 0), |pubkey| {
|
|
|
|
self.maybe_staked_nodes.as_ref().map_or(
|
|
|
|
(ConnectionPeerType::Unstaked, 0, 0),
|
|
|
|
|stakes| {
|
|
|
|
let rstakes = stakes.read().unwrap();
|
2023-04-10 10:07:40 -07:00
|
|
|
rstakes.get_node_stake(&pubkey).map_or(
|
|
|
|
(ConnectionPeerType::Unstaked, 0, rstakes.total_stake()),
|
|
|
|
|stake| (ConnectionPeerType::Staked, stake, rstakes.total_stake()),
|
2022-09-30 18:51:50 -07:00
|
|
|
)
|
|
|
|
},
|
|
|
|
)
|
|
|
|
});
|
|
|
|
compute_max_allowed_uni_streams(client_type, stake, total_stake)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update_client_certificate(
|
|
|
|
&mut self,
|
|
|
|
keypair: &Keypair,
|
|
|
|
ipaddr: IpAddr,
|
2023-04-12 12:53:25 -07:00
|
|
|
) -> Result<(), RcgenError> {
|
2023-01-12 15:24:02 -08:00
|
|
|
let (cert, priv_key) = new_self_signed_tls_certificate(keypair, ipaddr)?;
|
2022-09-30 18:51:50 -07:00
|
|
|
self.client_certificate = Arc::new(QuicClientCertificate {
|
2023-01-12 15:24:02 -08:00
|
|
|
certificate: cert,
|
2022-09-30 18:51:50 -07:00
|
|
|
key: priv_key,
|
|
|
|
});
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_staked_nodes(
|
|
|
|
&mut self,
|
|
|
|
staked_nodes: &Arc<RwLock<StakedNodes>>,
|
|
|
|
client_pubkey: &Pubkey,
|
|
|
|
) {
|
|
|
|
self.maybe_staked_nodes = Some(staked_nodes.clone());
|
|
|
|
self.maybe_client_pubkey = Some(*client_pubkey);
|
|
|
|
}
|
2023-02-01 18:10:06 -08:00
|
|
|
|
|
|
|
pub fn update_client_endpoint(&mut self, client_endpoint: Endpoint) {
|
|
|
|
self.client_endpoint = Some(client_endpoint);
|
|
|
|
}
|
2022-09-30 18:51:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Quic(Arc<QuicClient>);
|
2023-02-01 18:10:06 -08:00
|
|
|
impl BaseClientConnection for Quic {
|
2023-02-08 16:50:44 -08:00
|
|
|
type BlockingClientConnection = BlockingQuicClientConnection;
|
|
|
|
type NonblockingClientConnection = NonblockingQuicClientConnection;
|
|
|
|
|
2022-09-30 18:51:50 -07:00
|
|
|
fn new_blocking_connection(
|
|
|
|
&self,
|
|
|
|
_addr: SocketAddr,
|
|
|
|
stats: Arc<ConnectionCacheStats>,
|
2023-02-08 16:50:44 -08:00
|
|
|
) -> Arc<Self::BlockingClientConnection> {
|
2023-02-01 18:10:06 -08:00
|
|
|
Arc::new(BlockingQuicClientConnection::new_with_client(
|
|
|
|
self.0.clone(),
|
|
|
|
stats,
|
|
|
|
))
|
2022-09-30 18:51:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn new_nonblocking_connection(
|
|
|
|
&self,
|
|
|
|
_addr: SocketAddr,
|
|
|
|
stats: Arc<ConnectionCacheStats>,
|
2023-02-08 16:50:44 -08:00
|
|
|
) -> Arc<Self::NonblockingClientConnection> {
|
2023-02-01 18:10:06 -08:00
|
|
|
Arc::new(NonblockingQuicClientConnection::new_with_client(
|
|
|
|
self.0.clone(),
|
|
|
|
stats,
|
|
|
|
))
|
2022-09-30 18:51:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-01 18:10:06 -08:00
|
|
|
pub struct QuicConnectionManager {
|
2023-06-06 14:27:56 -07:00
|
|
|
connection_config: QuicConfig,
|
2023-02-01 18:10:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ConnectionManager for QuicConnectionManager {
|
2023-02-08 16:50:44 -08:00
|
|
|
type ConnectionPool = QuicPool;
|
|
|
|
type NewConnectionConfig = QuicConfig;
|
|
|
|
|
2023-05-09 06:46:17 -07:00
|
|
|
const PROTOCOL: Protocol = Protocol::QUIC;
|
|
|
|
|
2023-02-08 16:50:44 -08:00
|
|
|
fn new_connection_pool(&self) -> Self::ConnectionPool {
|
|
|
|
QuicPool {
|
2023-02-01 18:10:06 -08:00
|
|
|
connections: Vec::default(),
|
2023-06-06 14:27:56 -07:00
|
|
|
endpoint: Arc::new(self.connection_config.create_endpoint()),
|
2023-02-08 16:50:44 -08:00
|
|
|
}
|
2023-02-01 18:10:06 -08:00
|
|
|
}
|
|
|
|
|
2023-02-08 16:50:44 -08:00
|
|
|
fn new_connection_config(&self) -> QuicConfig {
|
2023-06-08 09:46:22 -07:00
|
|
|
self.connection_config.clone()
|
2023-02-01 18:10:06 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QuicConnectionManager {
|
2023-06-06 14:27:56 -07:00
|
|
|
pub fn new_with_connection_config(connection_config: QuicConfig) -> Self {
|
|
|
|
Self { connection_config }
|
2023-02-01 18:10:06 -08:00
|
|
|
}
|
|
|
|
}
|
2023-06-12 15:58:27 -07:00
|
|
|
|
|
|
|
pub type QuicConnectionCache = ConnectionCache<QuicPool, QuicConnectionManager, QuicConfig>;
|
|
|
|
|
|
|
|
pub fn new_quic_connection_cache(
|
|
|
|
name: &'static str,
|
|
|
|
keypair: &Keypair,
|
|
|
|
ipaddr: IpAddr,
|
|
|
|
staked_nodes: &Arc<RwLock<StakedNodes>>,
|
|
|
|
connection_pool_size: usize,
|
|
|
|
) -> Result<QuicConnectionCache, ClientError> {
|
|
|
|
let mut config = QuicConfig::new()?;
|
|
|
|
config.update_client_certificate(keypair, ipaddr)?;
|
|
|
|
config.set_staked_nodes(staked_nodes, &keypair.pubkey());
|
|
|
|
let connection_manager = QuicConnectionManager::new_with_connection_config(config);
|
|
|
|
ConnectionCache::new(name, connection_manager, connection_pool_size)
|
|
|
|
}
|
|
|
|
|
2022-09-30 18:51:50 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use {
|
|
|
|
super::*,
|
|
|
|
solana_sdk::quic::{
|
|
|
|
QUIC_MAX_UNSTAKED_CONCURRENT_STREAMS, QUIC_MIN_STAKED_CONCURRENT_STREAMS,
|
2022-11-03 05:45:44 -07:00
|
|
|
QUIC_TOTAL_STAKED_CONCURRENT_STREAMS,
|
2022-09-30 18:51:50 -07:00
|
|
|
},
|
2023-04-10 10:07:40 -07:00
|
|
|
std::collections::HashMap,
|
2022-09-30 18:51:50 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_connection_cache_max_parallel_chunks() {
|
|
|
|
solana_logger::setup();
|
2023-02-01 18:10:06 -08:00
|
|
|
|
|
|
|
let mut connection_config = QuicConfig::new().unwrap();
|
2022-09-30 18:51:50 -07:00
|
|
|
assert_eq!(
|
2023-02-01 18:10:06 -08:00
|
|
|
connection_config.compute_max_parallel_streams(),
|
2022-09-30 18:51:50 -07:00
|
|
|
QUIC_MAX_UNSTAKED_CONCURRENT_STREAMS
|
|
|
|
);
|
|
|
|
|
|
|
|
let staked_nodes = Arc::new(RwLock::new(StakedNodes::default()));
|
|
|
|
let pubkey = Pubkey::new_unique();
|
2023-02-01 18:10:06 -08:00
|
|
|
connection_config.set_staked_nodes(&staked_nodes, &pubkey);
|
2022-09-30 18:51:50 -07:00
|
|
|
assert_eq!(
|
2023-02-01 18:10:06 -08:00
|
|
|
connection_config.compute_max_parallel_streams(),
|
2022-09-30 18:51:50 -07:00
|
|
|
QUIC_MAX_UNSTAKED_CONCURRENT_STREAMS
|
|
|
|
);
|
2023-04-10 10:07:40 -07:00
|
|
|
let overrides = HashMap::<Pubkey, u64>::default();
|
|
|
|
let mut stakes = HashMap::from([(Pubkey::new_unique(), 10_000)]);
|
|
|
|
*staked_nodes.write().unwrap() =
|
|
|
|
StakedNodes::new(Arc::new(stakes.clone()), overrides.clone());
|
2022-09-30 18:51:50 -07:00
|
|
|
assert_eq!(
|
2023-02-01 18:10:06 -08:00
|
|
|
connection_config.compute_max_parallel_streams(),
|
2022-09-30 18:51:50 -07:00
|
|
|
QUIC_MAX_UNSTAKED_CONCURRENT_STREAMS
|
|
|
|
);
|
|
|
|
|
2023-04-10 10:07:40 -07:00
|
|
|
stakes.insert(pubkey, 1);
|
|
|
|
*staked_nodes.write().unwrap() =
|
|
|
|
StakedNodes::new(Arc::new(stakes.clone()), overrides.clone());
|
2022-11-03 05:45:44 -07:00
|
|
|
let delta =
|
|
|
|
(QUIC_TOTAL_STAKED_CONCURRENT_STREAMS - QUIC_MIN_STAKED_CONCURRENT_STREAMS) as f64;
|
|
|
|
|
2022-09-30 18:51:50 -07:00
|
|
|
assert_eq!(
|
2023-02-01 18:10:06 -08:00
|
|
|
connection_config.compute_max_parallel_streams(),
|
2022-11-03 05:45:44 -07:00
|
|
|
(QUIC_MIN_STAKED_CONCURRENT_STREAMS as f64 + (1f64 / 10000f64) * delta) as usize
|
2022-09-30 18:51:50 -07:00
|
|
|
);
|
2023-04-10 10:07:40 -07:00
|
|
|
stakes.insert(pubkey, 1_000);
|
|
|
|
*staked_nodes.write().unwrap() = StakedNodes::new(Arc::new(stakes.clone()), overrides);
|
2022-09-30 18:51:50 -07:00
|
|
|
assert_ne!(
|
2023-02-01 18:10:06 -08:00
|
|
|
connection_config.compute_max_parallel_streams(),
|
2022-09-30 18:51:50 -07:00
|
|
|
QUIC_MIN_STAKED_CONCURRENT_STREAMS
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|