diff --git a/Cargo.lock b/Cargo.lock index 0f3b45e9..58ca010f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4485,15 +4485,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_xoshiro" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" -dependencies = [ - "rand_core", -] - [[package]] name = "rate-counter" version = "0.1.0" @@ -6090,14 +6081,6 @@ dependencies = [ "syn 2.0.18", ] -[[package]] -name = "thread-fast-rng" -version = "0.1.0" -dependencies = [ - "rand", - "rand_xoshiro", -] - [[package]] name = "thread-id" version = "4.1.0" @@ -7062,6 +7045,7 @@ dependencies = [ "migration", "mimalloc", "moka", + "nanorand", "num", "num-traits", "once_cell", @@ -7083,7 +7067,6 @@ dependencies = [ "serde_prometheus", "siwe", "strum", - "thread-fast-rng", "time 0.3.22", "tokio", "tokio-console", diff --git a/Cargo.toml b/Cargo.toml index d48b9b26..e83ef6d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,6 @@ members = [ "payment-contracts", "rate-counter", "redis-rate-limiter", - "thread-fast-rng", "web3_proxy", ] resolver = "2" diff --git a/thread-fast-rng/Cargo.toml b/thread-fast-rng/Cargo.toml deleted file mode 100644 index 9bb5c46b..00000000 --- a/thread-fast-rng/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "thread-fast-rng" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -rand = "0.8.5" -rand_xoshiro = "0.6.0" diff --git a/thread-fast-rng/src/lib.rs b/thread-fast-rng/src/lib.rs deleted file mode 100644 index 9e9402cd..00000000 --- a/thread-fast-rng/src/lib.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! works just like rand::thread_rng but with a rng that is **not** cryptographically secure -//! -//! TODO: currently uses Xoshiro256Plus. do some benchmarks -pub use rand; - -use rand::{Error, Rng, RngCore, SeedableRng}; -use rand_xoshiro::Xoshiro256Plus; -use std::{cell::UnsafeCell, rc::Rc}; - -#[derive(Clone, Debug)] -pub struct ThreadFastRng { - // Rc is explicitly !Send and !Sync - rng: Rc>, -} - -thread_local! { - pub static THREAD_FAST_RNG: Rc> = { - // use a cryptographically secure rng for the seed - let mut crypto_rng = rand::thread_rng(); - let seed = crypto_rng.gen(); - // use a fast rng for things that aren't cryptography - let rng = Xoshiro256Plus::seed_from_u64(seed); - Rc::new(UnsafeCell::new(rng)) - }; -} - -pub fn thread_fast_rng() -> ThreadFastRng { - let rng = THREAD_FAST_RNG.with(|t| t.clone()); - ThreadFastRng { rng } -} - -impl Default for ThreadFastRng { - fn default() -> Self { - thread_fast_rng() - } -} - -impl RngCore for ThreadFastRng { - #[inline(always)] - fn next_u32(&mut self) -> u32 { - // SAFETY: We must make sure to stop using `rng` before anyone else - // creates another mutable reference - let rng = unsafe { &mut *self.rng.get() }; - rng.next_u32() - } - - #[inline(always)] - fn next_u64(&mut self) -> u64 { - // SAFETY: We must make sure to stop using `rng` before anyone else - // creates another mutable reference - let rng = unsafe { &mut *self.rng.get() }; - rng.next_u64() - } - - fn fill_bytes(&mut self, dest: &mut [u8]) { - // SAFETY: We must make sure to stop using `rng` before anyone else - // creates another mutable reference - let rng = unsafe { &mut *self.rng.get() }; - rng.fill_bytes(dest) - } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - // SAFETY: We must make sure to stop using `rng` before anyone else - // creates another mutable reference - let rng = unsafe { &mut *self.rng.get() }; - rng.try_fill_bytes(dest) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_thread_fast_rng() { - let mut r = thread_fast_rng(); - r.gen::(); - assert_eq!(r.gen_range(0..1), 0); - } - - #[test] - fn test_thread_fast_rng_struct() { - let mut r = ThreadFastRng::default(); - r.gen::(); - assert_eq!(r.gen_range(0..1), 0); - } -} diff --git a/web3_proxy/Cargo.toml b/web3_proxy/Cargo.toml index 5490c8a7..b762a27a 100644 --- a/web3_proxy/Cargo.toml +++ b/web3_proxy/Cargo.toml @@ -21,7 +21,6 @@ latency = { path = "../latency" } migration = { path = "../migration" } payment-contracts = { path = "../payment-contracts" } redis-rate-limiter = { path = "../redis-rate-limiter" } -thread-fast-rng = { path = "../thread-fast-rng" } influxdb2 = { git = "https://github.com/llamanodes/influxdb2", features = ["rustls"] } influxdb2-structmap = { git = "https://github.com/llamanodes/influxdb2/"} @@ -43,6 +42,7 @@ async-trait = "0.1.68" axum = { version = "0.6.18", features = ["headers", "ws"] } axum-client-ip = "0.4.1" axum-macros = "0.3.7" +base64 = "0.21.2" check-if-email-exists = "0.9.0" chrono = "0.4.26" console-subscriber = { version = "0.1.9", optional = true } @@ -60,6 +60,7 @@ gethostname = "0.4.3" glob = "0.3.1" handlebars = "4.3.7" hashbrown = { version = "0.14.0", features = ["serde"] } +hdrhistogram = "7.5.2" hostname = "0.3.1" http = "0.2.9" hyper = { version = "0.14.26", features = ["full", "nightly"] } @@ -69,6 +70,7 @@ listenfd = "1.0.1" log = "0.4.19" mimalloc = { version = "0.1.37", optional = true} moka = { version = "0.11.2", features = ["future"] } +nanorand = { version = "0.7.0", default-features = false, features = ["alloc", "std", "tls", "wyrand"] } num = "0.4.0" num-traits = "0.2.15" once_cell = { version = "1.18.0" } @@ -101,8 +103,6 @@ tracing-subscriber = "0.3" ulid = { version = "1.0.0", features = ["rand", "uuid", "serde"] } url = "2.4.0" uuid = { version = "1.3.3", default-features = false, features = ["fast-rng", "serde", "v4", "zerocopy"] } -hdrhistogram = "7.5.2" -base64 = "0.21.2" [dev-dependencies] tokio = { version = "1.28.2", features = ["full", "test-util"] } diff --git a/web3_proxy/src/app/mod.rs b/web3_proxy/src/app/mod.rs index a9dd98b5..c24649d3 100644 --- a/web3_proxy/src/app/mod.rs +++ b/web3_proxy/src/app/mod.rs @@ -101,8 +101,8 @@ pub struct AuthorizationChecks { pub tracking_level: TrackingLevel, /// Chance to save reverting eth_call, eth_estimateGas, and eth_sendRawTransaction to the database. /// depending on the caller, errors might be expected. this keeps us from bloating our database - /// TODO: f32 would be fine - pub log_revert_chance: f64, + /// u16::MAX == 100% + pub log_revert_chance: u16, /// if true, transactions are broadcast only to private mempools. /// IMPORTANT! Once confirmed by a miner, they will be public on the blockchain! pub private_txs: bool, diff --git a/web3_proxy/src/frontend/authorization.rs b/web3_proxy/src/frontend/authorization.rs index ecdf4bed..e437cc51 100644 --- a/web3_proxy/src/frontend/authorization.rs +++ b/web3_proxy/src/frontend/authorization.rs @@ -644,7 +644,7 @@ impl Authorization { pub fn internal(db_conn: Option) -> Web3ProxyResult { let authorization_checks = AuthorizationChecks { // any error logs on a local (internal) query are likely problems. log them all - log_revert_chance: 1.0, + log_revert_chance: 100, tracking_level: TrackingLevel::Detailed, // default for everything else should be fine. we don't have a user_id or ip to give ..Default::default() @@ -1288,7 +1288,8 @@ impl Web3ProxyApp { allowed_referers, allowed_user_agents, tracking_level: rpc_key_model.log_level, - log_revert_chance: rpc_key_model.log_revert_chance, + // TODO: is floating point math going to scale this correctly + log_revert_chance: (rpc_key_model.log_revert_chance * u16::MAX as f64) as u16, max_concurrent_requests: user_tier_model.max_concurrent_requests, max_requests_per_period: user_tier_model.max_requests_per_period, private_txs: rpc_key_model.private_txs, diff --git a/web3_proxy/src/rpcs/one.rs b/web3_proxy/src/rpcs/one.rs index 275ee3b0..6016205b 100644 --- a/web3_proxy/src/rpcs/one.rs +++ b/web3_proxy/src/rpcs/one.rs @@ -17,6 +17,7 @@ use futures::StreamExt; use latency::{EwmaLatency, PeakEwmaLatency}; use log::{debug, info, trace, warn, Level}; use migration::sea_orm::DatabaseConnection; +use nanorand::Rng; use ordered_float::OrderedFloat; use parking_lot::RwLock; use redis_rate_limiter::{RedisPool, RedisRateLimitResult, RedisRateLimiter}; @@ -28,7 +29,6 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::sync::atomic::{self, AtomicU64, AtomicU8, AtomicUsize}; use std::{cmp::Ordering, sync::Arc}; -use thread_fast_rng::rand::Rng; use tokio::select; use tokio::sync::watch; use tokio::time::{sleep, sleep_until, timeout, Duration, Instant}; @@ -270,9 +270,9 @@ impl Web3Rpc { ) -> ((bool, u8, Reverse), u32) { let sort_on = self.sort_on(max_block); - let mut rng = thread_fast_rng::thread_fast_rng(); + let mut rng = nanorand::tls_rng(); - let r = rng.gen::(); + let r = rng.generate::(); (sort_on, r) } diff --git a/web3_proxy/src/rpcs/request.rs b/web3_proxy/src/rpcs/request.rs index 3c483ad8..89c24727 100644 --- a/web3_proxy/src/rpcs/request.rs +++ b/web3_proxy/src/rpcs/request.rs @@ -11,10 +11,10 @@ use ethers::providers::ProviderError; use ethers::types::{Address, Bytes}; use log::{debug, error, trace, warn, Level}; use migration::sea_orm::{self, ActiveEnum, ActiveModelTrait}; +use nanorand::Rng; use serde_json::json; use std::sync::atomic; use std::sync::Arc; -use thread_fast_rng::rand::Rng; use tokio::time::{Duration, Instant}; #[derive(Debug, From)] @@ -225,15 +225,13 @@ impl OpenRequestHandle { } else if self.authorization.db_conn.is_some() { let log_revert_chance = self.authorization.checks.log_revert_chance; - if log_revert_chance == 0.0 { + if log_revert_chance == 0 { // trace!(%method, "no chance. skipping save on revert"); RequestErrorHandler::TraceLevel - } else if log_revert_chance == 1.0 { + } else if log_revert_chance == u16::MAX { // trace!(%method, "gaurenteed chance. SAVING on revert"); self.error_handler - } else if thread_fast_rng::thread_fast_rng().gen_range(0.0f64..=1.0) - < log_revert_chance - { + } else if nanorand::tls_rng().generate_range(0u16..u16::MAX) < log_revert_chance { // trace!(%method, "missed chance. skipping save on revert"); RequestErrorHandler::TraceLevel } else {