web3-proxy/web3_proxy/src/config.rs

275 lines
9.3 KiB
Rust
Raw Normal View History

use crate::rpcs::blockchain::BlockHashesCache;
use crate::rpcs::one::Web3Rpc;
2022-08-30 23:01:42 +03:00
use crate::{app::AnyhowJoinHandle, rpcs::blockchain::ArcBlock};
2022-05-06 00:25:40 +03:00
use argh::FromArgs;
2022-08-30 23:01:42 +03:00
use ethers::prelude::TxHash;
2023-01-20 05:08:53 +03:00
use ethers::types::U256;
2022-07-23 02:26:04 +03:00
use hashbrown::HashMap;
2022-12-28 19:36:22 +03:00
use log::warn;
2022-11-14 21:24:52 +03:00
use migration::sea_orm::DatabaseConnection;
2022-05-05 22:07:09 +03:00
use serde::Deserialize;
use std::sync::Arc;
2022-06-29 22:15:05 +03:00
use tokio::sync::broadcast;
2022-05-05 22:07:09 +03:00
pub type BlockAndRpc = (Option<ArcBlock>, Arc<Web3Rpc>);
pub type TxHashAndRpc = (TxHash, Arc<Web3Rpc>);
2022-07-22 08:11:26 +03:00
2022-05-22 02:34:05 +03:00
#[derive(Debug, FromArgs)]
2022-08-06 08:46:33 +03:00
/// Web3_proxy is a fast caching and load balancing proxy for web3 (Ethereum or similar) JsonRPC servers.
2022-05-06 00:25:40 +03:00
pub struct CliConfig {
/// path to a toml of rpc servers
#[argh(option, default = "\"./config/development.toml\".to_string()")]
pub config: String,
2022-05-06 00:25:40 +03:00
/// what port the proxy should listen on
2022-05-06 09:33:29 +03:00
#[argh(option, default = "8544")]
2022-05-18 23:28:00 +03:00
pub port: u16,
2022-05-06 00:25:40 +03:00
/// what port the proxy should expose prometheus stats on
#[argh(option, default = "8543")]
pub prometheus_port: u16,
2022-06-06 01:39:44 +03:00
/// number of worker threads. Defaults to the number of logical processors
2022-05-18 19:35:06 +03:00
#[argh(option, default = "0")]
2022-05-18 23:28:00 +03:00
pub workers: usize,
/// path to a binary file used to encrypt cookies. Should be at least 64 bytes.
#[argh(option, default = "\"./data/development_cookie_key\".to_string()")]
pub cookie_key_filename: String,
2022-05-06 00:25:40 +03:00
}
#[derive(Clone, Debug, Deserialize)]
2022-08-12 22:07:14 +03:00
pub struct TopConfig {
pub app: AppConfig,
pub balanced_rpcs: HashMap<String, Web3RpcConfig>,
2022-12-28 19:36:22 +03:00
// TODO: instead of an option, give it a default
pub private_rpcs: Option<HashMap<String, Web3RpcConfig>>,
2022-12-28 19:36:22 +03:00
/// unknown config options get put here
#[serde(flatten, default = "HashMap::default")]
2022-12-28 19:36:22 +03:00
pub extra: HashMap<String, serde_json::Value>,
2022-05-05 22:07:09 +03:00
}
/// shared configuration between Web3Rpcs
2022-10-03 21:08:01 +03:00
// TODO: no String, only &str
#[derive(Clone, Debug, Default, Deserialize)]
2022-08-12 22:07:14 +03:00
pub struct AppConfig {
2022-10-25 00:07:29 +03:00
/// Request limit for allowed origins for anonymous users.
2022-10-25 07:34:24 +03:00
/// These requests get rate limited by IP.
#[serde(default = "default_allowed_origin_requests_per_period")]
2022-11-01 22:12:57 +03:00
pub allowed_origin_requests_per_period: HashMap<String, u64>,
2022-10-25 00:07:29 +03:00
2023-02-06 04:58:03 +03:00
/// erigon defaults to pruning beyond 90,000 blocks
#[serde(default = "default_archive_depth")]
pub archive_depth: u64,
/// EVM chain id. 1 for ETH
2022-11-08 01:30:02 +03:00
/// TODO: better type for chain_id? max of `u64::MAX / 2 - 36` <https://github.com/ethereum/EIPs/issues/2294>
pub chain_id: u64,
2022-10-25 00:07:29 +03:00
/// Database is used for user data.
/// Currently supports mysql or compatible backend.
2022-07-26 07:53:38 +03:00
pub db_url: Option<String>,
2022-10-25 00:07:29 +03:00
/// minimum size of the connection pool for the database.
/// If none, the number of workers are used.
2022-09-06 23:50:37 +03:00
pub db_min_connections: Option<u32>,
2022-10-25 00:07:29 +03:00
/// maximum size of the connection pool for the database.
/// If none, the minimum * 2 is used.
2022-09-02 23:16:20 +03:00
pub db_max_connections: Option<u32>,
2022-10-25 00:07:29 +03:00
/// Read-only replica of db_url.
pub db_replica_url: Option<String>,
/// minimum size of the connection pool for the database replica.
/// If none, db_min_connections is used.
pub db_replica_min_connections: Option<u32>,
/// maximum size of the connection pool for the database replica.
/// If none, db_max_connections is used.
pub db_replica_max_connections: Option<u32>,
/// Default request limit for registered users.
/// 0 = block all requests
/// None = allow all requests
2022-11-01 22:12:57 +03:00
pub default_user_max_requests_per_period: Option<u64>,
2022-10-25 00:07:29 +03:00
2023-01-20 05:08:53 +03:00
/// minimum amount to increase eth_estimateGas results
pub gas_increase_min: Option<U256>,
/// percentage to increase eth_estimateGas results. 100 == 100%
pub gas_increase_percent: Option<U256>,
/// Restrict user registration.
/// None = no code needed
2022-09-02 23:16:20 +03:00
pub invite_code: Option<String>,
2022-11-28 22:59:42 +03:00
pub login_domain: Option<String>,
2022-10-25 00:07:29 +03:00
/// Rate limit for bearer token authenticated entrypoints.
/// This is separate from the rpc limits.
#[serde(default = "default_bearer_token_max_concurrent_requests")]
pub bearer_token_max_concurrent_requests: u64,
2022-10-25 07:34:24 +03:00
/// Rate limit for the login entrypoint.
/// This is separate from the rpc limits.
2022-11-01 22:12:57 +03:00
#[serde(default = "default_login_rate_limit_per_period")]
pub login_rate_limit_per_period: u64,
2022-10-25 07:34:24 +03:00
/// The soft limit prevents thundering herds as new blocks are seen.
2022-08-27 06:11:58 +03:00
#[serde(default = "default_min_sum_soft_limit")]
pub min_sum_soft_limit: u32,
2022-10-25 00:07:29 +03:00
/// Another knob for preventing thundering herds as new blocks are seen.
2022-08-27 03:33:45 +03:00
#[serde(default = "default_min_synced_rpcs")]
pub min_synced_rpcs: usize,
2022-10-25 00:07:29 +03:00
2022-10-25 07:01:41 +03:00
/// Concurrent request limit for anonymous users.
/// Some(0) = block all requests
/// None = allow all requests
pub public_max_concurrent_requests: Option<usize>,
2022-10-25 07:34:24 +03:00
/// Request limit for anonymous users.
/// Some(0) = block all requests
/// None = allow all requests
2022-11-01 22:12:57 +03:00
pub public_requests_per_period: Option<u64>,
2022-10-25 00:07:29 +03:00
2022-12-28 09:11:18 +03:00
/// Salt for hashing recent ips
pub public_recent_ips_salt: Option<String>,
/// RPC responses are cached locally
2022-07-22 22:30:39 +03:00
#[serde(default = "default_response_cache_max_bytes")]
pub response_cache_max_bytes: u64,
2022-10-25 00:07:29 +03:00
2022-08-12 22:07:14 +03:00
/// the stats page url for an anonymous user.
2022-10-18 00:47:58 +03:00
pub redirect_public_url: Option<String>,
2022-10-25 00:07:29 +03:00
2022-11-11 01:17:22 +03:00
/// the stats page url for a logged in user. if set, must contain "{rpc_key_id}"
pub redirect_rpc_key_url: Option<String>,
2022-10-25 00:07:29 +03:00
2022-10-25 07:12:24 +03:00
/// Optionally send errors to <https://sentry.io>
2022-10-25 00:07:29 +03:00
pub sentry_url: Option<String>,
2022-10-25 07:34:24 +03:00
/// Track rate limits in a redis (or compatible backend)
/// It is okay if this data is lost.
pub volatile_redis_url: Option<String>,
/// maximum size of the connection pool for the cache
/// If none, the minimum * 2 is used
pub volatile_redis_max_connections: Option<usize>,
2022-12-28 19:36:22 +03:00
/// unknown config options get put here
#[serde(flatten, default = "HashMap::default")]
2022-12-28 19:36:22 +03:00
pub extra: HashMap<String, serde_json::Value>,
2022-07-22 22:30:39 +03:00
}
2023-02-06 04:58:03 +03:00
fn default_archive_depth() -> u64 {
90_000
}
fn default_allowed_origin_requests_per_period() -> HashMap<String, u64> {
HashMap::new()
}
/// This might cause a thundering herd!
2022-08-27 06:11:58 +03:00
fn default_min_sum_soft_limit() -> u32 {
2022-08-27 03:33:45 +03:00
1
}
/// Only require 1 server. This might cause a thundering herd!
fn default_min_synced_rpcs() -> usize {
2022-08-27 06:11:58 +03:00
1
}
/// Having a low amount of concurrent requests for bearer tokens keeps us from hammering the database.
fn default_bearer_token_max_concurrent_requests() -> u64 {
2
}
2022-11-01 22:12:57 +03:00
/// Having a low amount of requests per period (usually minute) for login is safest.
fn default_login_rate_limit_per_period() -> u64 {
2022-09-24 06:59:21 +03:00
10
}
fn default_response_cache_max_bytes() -> u64 {
2022-07-22 22:30:39 +03:00
// TODO: default to some percentage of the system?
// 100 megabytes
10u64.pow(8)
2022-05-12 21:49:57 +03:00
}
2022-10-19 02:27:33 +03:00
/// Configuration for a backend web3 RPC server
#[derive(Clone, Debug, Default, Deserialize)]
pub struct Web3RpcConfig {
2022-10-19 02:27:33 +03:00
/// simple way to disable a connection without deleting the row
#[serde(default)]
pub disabled: bool,
2022-11-14 00:05:37 +03:00
/// a name used in /status and other user facing messages
pub display_name: Option<String>,
/// (deprecated) rpc url
pub url: Option<String>,
/// while not absolutely required, a ws:// or wss:// connection will be able to subscribe to head blocks
pub ws_url: Option<String>,
/// while not absolutely required, a http:// or https:// connection will allow erigon to stream JSON
pub http_url: Option<String>,
/// block data limit. If None, will be queried
pub block_data_limit: Option<u64>,
/// the requests per second at which the server starts slowing down
2022-10-19 02:27:33 +03:00
pub soft_limit: u32,
/// the requests per second at which the server throws errors (rate limit or otherwise)
2022-10-19 02:27:33 +03:00
pub hard_limit: Option<u64>,
/// only use this rpc if everything else is lagging too far. this allows us to ignore fast but very low limit rpcs
#[serde(default)]
pub backup: bool,
2023-01-04 09:37:51 +03:00
/// All else equal, a server with a lower tier receives all requests
#[serde(default = "default_tier")]
pub tier: u64,
/// Subscribe to the firehose of pending transactions
/// Don't do this with free rpcs
2022-10-19 02:27:33 +03:00
#[serde(default)]
pub subscribe_txs: bool,
2022-12-28 19:36:22 +03:00
/// unknown config options get put here
#[serde(flatten, default = "HashMap::default")]
2022-12-28 19:36:22 +03:00
pub extra: HashMap<String, serde_json::Value>,
2022-05-05 22:07:09 +03:00
}
2023-01-04 09:37:51 +03:00
fn default_tier() -> u64 {
2022-11-14 00:05:37 +03:00
0
}
impl Web3RpcConfig {
/// Create a Web3Rpc from config
/// TODO: move this into Web3Rpc? (just need to make things pub(crate))
2022-08-10 08:56:09 +03:00
#[allow(clippy::too_many_arguments)]
2022-06-14 08:43:28 +03:00
pub async fn spawn(
2022-05-05 22:07:09 +03:00
self,
2022-08-10 08:56:09 +03:00
name: String,
db_conn: Option<DatabaseConnection>,
2022-09-15 20:57:24 +03:00
redis_pool: Option<redis_rate_limiter::RedisPool>,
chain_id: u64,
http_client: Option<reqwest::Client>,
2022-06-29 22:15:05 +03:00
http_interval_sender: Option<Arc<broadcast::Sender<()>>>,
block_map: BlockHashesCache,
2022-07-22 08:11:26 +03:00
block_sender: Option<flume::Sender<BlockAndRpc>>,
2022-08-30 23:01:42 +03:00
tx_id_sender: Option<flume::Sender<TxHashAndRpc>>,
reconnect: bool,
) -> anyhow::Result<(Arc<Web3Rpc>, AnyhowJoinHandle<()>)> {
2022-12-28 19:36:22 +03:00
if !self.extra.is_empty() {
warn!("unknown Web3RpcConfig fields!: {:?}", self.extra.keys());
2022-12-28 19:36:22 +03:00
}
Web3Rpc::spawn(
self,
2022-08-10 08:56:09 +03:00
name,
2022-05-12 21:49:57 +03:00
chain_id,
db_conn,
2022-05-05 22:07:09 +03:00
http_client,
2022-06-29 22:15:05 +03:00
http_interval_sender,
redis_pool,
2022-08-26 20:26:17 +03:00
block_map,
2022-06-14 08:43:28 +03:00
block_sender,
tx_id_sender,
reconnect,
2022-05-05 22:07:09 +03:00
)
.await
}
}