2024-02-14 00:55:21 -08:00
|
|
|
use std::borrow::Cow;
|
|
|
|
use std::fmt::{Debug, Display, Formatter};
|
2024-02-21 05:17:14 -08:00
|
|
|
use std::net::SocketAddr;
|
|
|
|
use std::str::FromStr;
|
2024-03-18 09:25:52 -07:00
|
|
|
use std::{env, time::Duration};
|
2023-11-27 00:54:59 -08:00
|
|
|
|
2024-03-18 12:01:02 -07:00
|
|
|
use crate::postgres_logger::{self, PostgresSessionConfig};
|
2023-04-18 05:22:51 -07:00
|
|
|
use crate::{
|
2023-08-31 05:26:46 -07:00
|
|
|
DEFAULT_FANOUT_SIZE, DEFAULT_GRPC_ADDR, DEFAULT_RETRY_TIMEOUT, DEFAULT_RPC_ADDR,
|
|
|
|
DEFAULT_WS_ADDR, MAX_RETRIES,
|
2023-04-18 05:22:51 -07:00
|
|
|
};
|
2023-11-27 00:54:59 -08:00
|
|
|
use anyhow::Context;
|
2022-12-07 07:05:18 -08:00
|
|
|
use clap::Parser;
|
2023-11-27 00:54:59 -08:00
|
|
|
use dotenv::dotenv;
|
2024-03-18 09:25:52 -07:00
|
|
|
use solana_lite_rpc_services::quic_connection_utils::QuicConnectionParameters;
|
2024-02-14 00:55:21 -08:00
|
|
|
use solana_rpc_client_api::client_error::reqwest::Url;
|
2022-11-12 05:32:01 -08:00
|
|
|
|
2023-07-20 04:45:54 -07:00
|
|
|
#[derive(Parser, Debug, Clone)]
|
2022-12-16 18:35:49 -08:00
|
|
|
#[command(author, version, about, long_about = None)]
|
2022-11-30 07:56:41 -08:00
|
|
|
pub struct Args {
|
2023-11-27 00:54:59 -08:00
|
|
|
/// config.json
|
2024-02-01 08:00:49 -08:00
|
|
|
#[arg(short = 'c', long)]
|
2023-11-27 00:54:59 -08:00
|
|
|
pub config: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, serde::Deserialize)]
|
|
|
|
pub struct Config {
|
|
|
|
#[serde(default = "Config::default_rpc_addr")]
|
2022-12-16 18:35:49 -08:00
|
|
|
pub rpc_addr: String,
|
2023-11-27 00:54:59 -08:00
|
|
|
#[serde(default = "Config::default_ws_addr")]
|
2022-12-16 18:35:49 -08:00
|
|
|
pub ws_addr: String,
|
2023-11-27 00:54:59 -08:00
|
|
|
#[serde(default = "Config::default_lite_rpc_http_addr")]
|
2023-01-05 02:54:00 -08:00
|
|
|
pub lite_rpc_http_addr: String,
|
2023-11-27 00:54:59 -08:00
|
|
|
#[serde(default = "Config::default_lite_rpc_ws_addr")]
|
2023-01-05 02:54:00 -08:00
|
|
|
pub lite_rpc_ws_addr: String,
|
2023-11-27 00:54:59 -08:00
|
|
|
#[serde(default = "Config::default_fanout_size")]
|
2023-01-10 07:45:30 -08:00
|
|
|
pub fanout_size: u64,
|
2023-11-27 07:31:59 -08:00
|
|
|
// Identity keypair path
|
2023-11-27 00:54:59 -08:00
|
|
|
#[serde(default)]
|
|
|
|
pub identity_keypair: Option<String>,
|
|
|
|
#[serde(default = "Config::default_prometheus_addr")]
|
2023-02-04 03:45:20 -08:00
|
|
|
pub prometheus_addr: String,
|
2023-11-27 00:54:59 -08:00
|
|
|
#[serde(default = "Config::default_maximum_retries_per_tx")]
|
2023-04-18 05:22:51 -07:00
|
|
|
pub maximum_retries_per_tx: usize,
|
2023-11-27 00:54:59 -08:00
|
|
|
#[serde(default = "Config::default_transaction_retry_after_secs")]
|
2023-04-18 05:22:51 -07:00
|
|
|
pub transaction_retry_after_secs: u64,
|
2023-11-27 00:54:59 -08:00
|
|
|
#[serde(default)]
|
2023-09-02 05:12:49 -07:00
|
|
|
pub quic_proxy_addr: Option<String>,
|
2023-11-27 00:54:59 -08:00
|
|
|
#[serde(default)]
|
2023-08-31 04:56:33 -07:00
|
|
|
pub use_grpc: bool,
|
2023-12-27 05:28:10 -08:00
|
|
|
#[serde(default)]
|
2024-04-02 01:21:46 -07:00
|
|
|
pub calculate_leader_schedule_from_geyser: bool,
|
2023-11-27 00:54:59 -08:00
|
|
|
#[serde(default = "Config::default_grpc_addr")]
|
2023-08-31 04:56:33 -07:00
|
|
|
pub grpc_addr: String,
|
2023-11-27 00:54:59 -08:00
|
|
|
#[serde(default)]
|
2023-11-07 02:04:17 -08:00
|
|
|
pub grpc_x_token: Option<String>,
|
2023-12-22 05:42:20 -08:00
|
|
|
|
|
|
|
#[serde(default)]
|
|
|
|
pub grpc_addr2: Option<String>,
|
|
|
|
#[serde(default)]
|
|
|
|
pub grpc_x_token2: Option<String>,
|
|
|
|
|
|
|
|
#[serde(default)]
|
|
|
|
pub grpc_addr3: Option<String>,
|
|
|
|
#[serde(default)]
|
|
|
|
pub grpc_x_token3: Option<String>,
|
|
|
|
|
|
|
|
#[serde(default)]
|
|
|
|
pub grpc_addr4: Option<String>,
|
|
|
|
#[serde(default)]
|
|
|
|
pub grpc_x_token4: Option<String>,
|
|
|
|
|
2024-02-07 06:51:22 -08:00
|
|
|
#[serde(default)]
|
|
|
|
pub enable_grpc_stream_inspection: bool,
|
|
|
|
|
2023-11-27 00:54:59 -08:00
|
|
|
/// postgres config
|
|
|
|
#[serde(default)]
|
2024-02-05 11:20:15 -08:00
|
|
|
pub postgres: Option<postgres_logger::PostgresSessionConfig>,
|
2024-02-05 05:06:24 -08:00
|
|
|
|
2024-02-06 08:59:46 -08:00
|
|
|
#[serde(default)]
|
2024-02-05 05:06:24 -08:00
|
|
|
pub max_number_of_connection: Option<usize>,
|
2024-02-06 08:59:46 -08:00
|
|
|
|
|
|
|
#[serde(default)]
|
|
|
|
pub address_lookup_tables_binary: Option<String>,
|
|
|
|
|
|
|
|
#[serde(default)]
|
|
|
|
pub enable_address_lookup_tables: Option<bool>,
|
2024-02-14 10:20:25 -08:00
|
|
|
|
|
|
|
#[serde(default)]
|
|
|
|
pub account_filters: Option<String>,
|
2024-02-28 06:40:11 -08:00
|
|
|
|
|
|
|
#[serde(default)]
|
2024-02-28 08:08:27 -08:00
|
|
|
pub enable_accounts_on_demand_accounts_service: Option<bool>,
|
2024-03-18 09:25:52 -07:00
|
|
|
|
|
|
|
#[serde(default)]
|
|
|
|
pub quic_connection_parameters: Option<QuicConnectionParameters>,
|
2023-11-27 00:54:59 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Config {
|
|
|
|
pub async fn load() -> anyhow::Result<Self> {
|
|
|
|
dotenv().ok();
|
|
|
|
|
|
|
|
let args = Args::parse();
|
|
|
|
|
|
|
|
let config_path = if args.config.is_some() {
|
|
|
|
args.config
|
|
|
|
} else {
|
|
|
|
let default_config_path = "config.json";
|
|
|
|
|
|
|
|
// check if config.json exists in current directory
|
|
|
|
if tokio::fs::metadata(default_config_path).await.is_err() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(default_config_path.to_string())
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let config = if let Some(config_path) = config_path {
|
|
|
|
tokio::fs::read_to_string(config_path)
|
|
|
|
.await
|
|
|
|
.context("Error reading config file")?
|
|
|
|
} else {
|
|
|
|
"{}".to_string()
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut config: Config =
|
|
|
|
serde_json::from_str(&config).context("Error parsing config file")?;
|
|
|
|
|
|
|
|
config.rpc_addr = env::var("RPC_ADDR").unwrap_or(config.rpc_addr);
|
|
|
|
|
|
|
|
config.ws_addr = env::var("WS_ADDR").unwrap_or(config.ws_addr);
|
|
|
|
|
|
|
|
config.lite_rpc_http_addr =
|
|
|
|
env::var("LITE_RPC_HTTP_ADDR").unwrap_or(config.lite_rpc_http_addr);
|
|
|
|
|
|
|
|
config.lite_rpc_ws_addr = env::var("LITE_RPC_WS_ADDR").unwrap_or(config.lite_rpc_ws_addr);
|
2024-02-21 05:17:14 -08:00
|
|
|
|
|
|
|
SocketAddr::from_str(&config.lite_rpc_http_addr).expect("invalid LITE_RPC_HTTP_ADDR");
|
|
|
|
SocketAddr::from_str(&config.lite_rpc_ws_addr).expect("invalid LITE_RPC_WS_ADDR");
|
2023-11-27 00:54:59 -08:00
|
|
|
|
|
|
|
config.fanout_size = env::var("FANOUT_SIZE")
|
|
|
|
.map(|size| size.parse().unwrap())
|
|
|
|
.unwrap_or(config.fanout_size);
|
|
|
|
|
2024-04-02 06:52:06 -07:00
|
|
|
// note: identity config is handled in load_identity_keypair
|
|
|
|
// the behavior is different from the other config values as it does either take a file path or the keypair as json array
|
2023-11-27 00:54:59 -08:00
|
|
|
|
|
|
|
config.prometheus_addr = env::var("PROMETHEUS_ADDR").unwrap_or(config.prometheus_addr);
|
|
|
|
|
|
|
|
config.maximum_retries_per_tx = env::var("MAX_RETRIES")
|
|
|
|
.map(|max| max.parse().unwrap())
|
|
|
|
.unwrap_or(config.maximum_retries_per_tx);
|
|
|
|
|
|
|
|
config.transaction_retry_after_secs = env::var("RETRY_TIMEOUT")
|
|
|
|
.map(|secs| secs.parse().unwrap())
|
|
|
|
.unwrap_or(config.transaction_retry_after_secs);
|
|
|
|
|
|
|
|
config.quic_proxy_addr = env::var("QUIC_PROXY_ADDR").ok();
|
|
|
|
|
|
|
|
config.use_grpc = env::var("USE_GRPC")
|
2024-04-02 01:21:46 -07:00
|
|
|
.map(|value| value.parse::<bool>().unwrap())
|
2023-11-27 00:54:59 -08:00
|
|
|
.unwrap_or(config.use_grpc);
|
|
|
|
|
2023-12-22 05:42:20 -08:00
|
|
|
// source 1
|
2023-11-27 00:54:59 -08:00
|
|
|
config.grpc_addr = env::var("GRPC_ADDR").unwrap_or(config.grpc_addr);
|
|
|
|
config.grpc_x_token = env::var("GRPC_X_TOKEN")
|
|
|
|
.map(Some)
|
|
|
|
.unwrap_or(config.grpc_x_token);
|
|
|
|
|
2023-12-22 05:42:20 -08:00
|
|
|
assert!(
|
|
|
|
env::var("GRPC_ADDR1").is_err(),
|
|
|
|
"use GRPC_ADDR instead of GRPC_ADDR1"
|
|
|
|
);
|
|
|
|
assert!(
|
|
|
|
env::var("GRPC_X_TOKEN1").is_err(),
|
|
|
|
"use GRPC_X_TOKEN instead of GRPC_X_TOKEN1"
|
|
|
|
);
|
|
|
|
|
|
|
|
// source 2
|
|
|
|
config.grpc_addr2 = env::var("GRPC_ADDR2")
|
|
|
|
.map(Some)
|
|
|
|
.unwrap_or(config.grpc_addr2);
|
|
|
|
config.grpc_x_token2 = env::var("GRPC_X_TOKEN2")
|
|
|
|
.map(Some)
|
|
|
|
.unwrap_or(config.grpc_x_token2);
|
|
|
|
|
|
|
|
// source 3
|
|
|
|
config.grpc_addr3 = env::var("GRPC_ADDR3")
|
|
|
|
.map(Some)
|
|
|
|
.unwrap_or(config.grpc_addr3);
|
|
|
|
config.grpc_x_token3 = env::var("GRPC_X_TOKEN3")
|
|
|
|
.map(Some)
|
|
|
|
.unwrap_or(config.grpc_x_token3);
|
|
|
|
|
|
|
|
// source 4
|
|
|
|
config.grpc_addr4 = env::var("GRPC_ADDR4")
|
|
|
|
.map(Some)
|
|
|
|
.unwrap_or(config.grpc_addr4);
|
|
|
|
config.grpc_x_token4 = env::var("GRPC_X_TOKEN4")
|
|
|
|
.map(Some)
|
|
|
|
.unwrap_or(config.grpc_x_token4);
|
|
|
|
|
2024-02-07 06:51:22 -08:00
|
|
|
config.enable_grpc_stream_inspection = env::var("ENABLE_GRPC_STREAM_INSPECTION")
|
|
|
|
.map(|value| value.parse::<bool>().expect("bool value"))
|
|
|
|
.unwrap_or(config.enable_grpc_stream_inspection);
|
|
|
|
|
2024-02-05 05:06:24 -08:00
|
|
|
config.max_number_of_connection = env::var("MAX_NB_OF_CONNECTIONS_WITH_LEADERS")
|
|
|
|
.map(|x| x.parse().ok())
|
|
|
|
.unwrap_or(config.max_number_of_connection);
|
|
|
|
|
2024-02-06 08:59:46 -08:00
|
|
|
config.enable_address_lookup_tables = env::var("ENABLE_ADDRESS_LOOKUP_TABLES")
|
|
|
|
.map(|value| value.parse::<bool>().unwrap())
|
|
|
|
.ok()
|
|
|
|
.or(config.enable_address_lookup_tables);
|
|
|
|
|
|
|
|
config.address_lookup_tables_binary = env::var("ADDRESS_LOOKUP_TABLES_BINARY")
|
|
|
|
.ok()
|
|
|
|
.or(config.address_lookup_tables_binary);
|
2024-02-28 08:08:27 -08:00
|
|
|
|
|
|
|
config.account_filters = env::var("ACCOUNT_FILTERS").ok().or(config.account_filters);
|
|
|
|
|
|
|
|
config.enable_accounts_on_demand_accounts_service = env::var("ENABLE_ACCOUNT_ON_DEMAND")
|
|
|
|
.map(|value| value.parse::<bool>().unwrap())
|
|
|
|
.ok()
|
|
|
|
.or(config.enable_accounts_on_demand_accounts_service);
|
2024-03-18 12:01:02 -07:00
|
|
|
|
2023-11-27 00:54:59 -08:00
|
|
|
config.postgres = PostgresSessionConfig::new_from_env()?.or(config.postgres);
|
2024-03-18 09:25:52 -07:00
|
|
|
config.quic_connection_parameters = config
|
|
|
|
.quic_connection_parameters
|
|
|
|
.or(quic_params_from_environment());
|
2023-11-27 00:54:59 -08:00
|
|
|
Ok(config)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn lite_rpc_ws_addr() -> String {
|
|
|
|
"[::]:8891".to_string()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn default_lite_rpc_http_addr() -> String {
|
|
|
|
"[::]:8890".to_string()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn default_rpc_addr() -> String {
|
|
|
|
DEFAULT_RPC_ADDR.to_string()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn default_ws_addr() -> String {
|
|
|
|
DEFAULT_WS_ADDR.to_string()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn default_lite_rpc_ws_addr() -> String {
|
|
|
|
"[::]:8891".to_string()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const fn default_fanout_size() -> u64 {
|
|
|
|
DEFAULT_FANOUT_SIZE
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn default_prometheus_addr() -> String {
|
|
|
|
"[::]:9091".to_string()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const fn default_maximum_retries_per_tx() -> usize {
|
|
|
|
MAX_RETRIES
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const fn default_transaction_retry_after_secs() -> u64 {
|
|
|
|
DEFAULT_RETRY_TIMEOUT
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn default_grpc_addr() -> String {
|
|
|
|
DEFAULT_GRPC_ADDR.to_string()
|
|
|
|
}
|
2023-12-22 05:42:20 -08:00
|
|
|
|
|
|
|
pub fn get_grpc_sources(&self) -> Vec<GrpcSource> {
|
|
|
|
let mut sources: Vec<GrpcSource> = vec![];
|
|
|
|
|
|
|
|
sources.push(GrpcSource {
|
|
|
|
addr: self.grpc_addr.clone(),
|
|
|
|
x_token: self.grpc_x_token.clone(),
|
|
|
|
});
|
|
|
|
|
|
|
|
if self.grpc_addr2.is_some() {
|
|
|
|
sources.push(GrpcSource {
|
|
|
|
addr: self.grpc_addr2.clone().unwrap(),
|
|
|
|
x_token: self.grpc_x_token2.clone(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.grpc_addr3.is_some() {
|
|
|
|
sources.push(GrpcSource {
|
|
|
|
addr: self.grpc_addr3.clone().unwrap(),
|
|
|
|
x_token: self.grpc_x_token3.clone(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.grpc_addr4.is_some() {
|
|
|
|
sources.push(GrpcSource {
|
|
|
|
addr: self.grpc_addr4.clone().unwrap(),
|
|
|
|
x_token: self.grpc_x_token4.clone(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
sources
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-14 00:55:21 -08:00
|
|
|
#[derive(Clone)]
|
2023-12-22 05:42:20 -08:00
|
|
|
pub struct GrpcSource {
|
|
|
|
pub addr: String,
|
|
|
|
pub x_token: Option<String>,
|
2022-11-12 05:32:01 -08:00
|
|
|
}
|
2024-02-14 00:55:21 -08:00
|
|
|
|
|
|
|
impl Display for GrpcSource {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"GrpcSource {} (x-token {})",
|
|
|
|
url_obfuscate_api_token(&self.addr),
|
|
|
|
obfuscate_token(&self.x_token)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for GrpcSource {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
Display::fmt(self, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// obfuscate urls with api token like http://mango.rpcpool.com/a991fba00fagbad
|
|
|
|
fn url_obfuscate_api_token(url: &str) -> Cow<str> {
|
|
|
|
if let Ok(mut parsed) = Url::parse(url) {
|
|
|
|
if parsed.path() == "/" {
|
|
|
|
return Cow::Borrowed(url);
|
|
|
|
} else {
|
|
|
|
parsed.set_path("omitted-secret");
|
|
|
|
Cow::Owned(parsed.to_string())
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Cow::Borrowed(url)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn obfuscate_token(token: &Option<String>) -> String {
|
|
|
|
match token {
|
|
|
|
None => "n/a".to_string(),
|
|
|
|
Some(token) => {
|
|
|
|
let mut token = token.clone();
|
|
|
|
token.truncate(5);
|
|
|
|
token += "...";
|
|
|
|
token
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-18 12:01:02 -07:00
|
|
|
|
2024-03-18 09:25:52 -07:00
|
|
|
fn quic_params_from_environment() -> Option<QuicConnectionParameters> {
|
|
|
|
let mut quic_connection_parameters = QuicConnectionParameters::default();
|
|
|
|
|
|
|
|
quic_connection_parameters.connection_timeout = env::var("QUIC_CONNECTION_TIMEOUT_MILLIS")
|
|
|
|
.map(|millis| Duration::from_millis(millis.parse().unwrap()))
|
|
|
|
.unwrap_or(quic_connection_parameters.connection_timeout);
|
|
|
|
|
|
|
|
quic_connection_parameters.unistream_timeout = env::var("QUIC_UNISTREAM_TIMEOUT_MILLIS")
|
|
|
|
.map(|millis| Duration::from_millis(millis.parse().unwrap()))
|
|
|
|
.unwrap_or(quic_connection_parameters.unistream_timeout);
|
|
|
|
|
|
|
|
quic_connection_parameters.write_timeout = env::var("QUIC_WRITE_TIMEOUT_MILLIS")
|
|
|
|
.map(|millis| Duration::from_millis(millis.parse().unwrap()))
|
|
|
|
.unwrap_or(quic_connection_parameters.write_timeout);
|
|
|
|
|
|
|
|
quic_connection_parameters.finalize_timeout = env::var("QUIC_FINALIZE_TIMEOUT_MILLIS")
|
|
|
|
.map(|millis| Duration::from_millis(millis.parse().unwrap()))
|
|
|
|
.unwrap_or(quic_connection_parameters.finalize_timeout);
|
|
|
|
|
|
|
|
quic_connection_parameters.connection_retry_count = env::var("QUIC_CONNECTION_RETRY_COUNT")
|
|
|
|
.map(|millis| millis.parse().unwrap())
|
|
|
|
.unwrap_or(quic_connection_parameters.connection_retry_count);
|
|
|
|
|
|
|
|
quic_connection_parameters.max_number_of_connections =
|
|
|
|
env::var("QUIC_MAX_NUMBER_OF_CONNECTIONS")
|
|
|
|
.map(|millis| millis.parse().unwrap())
|
|
|
|
.unwrap_or(quic_connection_parameters.max_number_of_connections);
|
|
|
|
|
|
|
|
quic_connection_parameters.number_of_transactions_per_unistream =
|
|
|
|
env::var("QUIC_NUMBER_OF_TRANSACTIONS_PER_TASK")
|
|
|
|
.map(|millis| millis.parse().unwrap())
|
|
|
|
.unwrap_or(quic_connection_parameters.number_of_transactions_per_unistream);
|
|
|
|
|
2024-03-19 06:37:08 -07:00
|
|
|
quic_connection_parameters.unistreams_to_create_new_connection_in_percentage =
|
2024-03-18 09:25:52 -07:00
|
|
|
env::var("QUIC_PERCENTAGE_TO_CREATE_NEW_CONNECTION")
|
|
|
|
.map(|millis| millis.parse().unwrap())
|
2024-03-19 06:37:08 -07:00
|
|
|
.unwrap_or(
|
|
|
|
quic_connection_parameters.unistreams_to_create_new_connection_in_percentage,
|
|
|
|
);
|
2024-03-18 09:25:52 -07:00
|
|
|
|
|
|
|
Some(quic_connection_parameters)
|
|
|
|
}
|