use WyRand instead of Xoshiro

This commit is contained in:
Bryan Stitt 2023-06-12 19:13:06 -07:00
parent a8f0c1f6f4
commit c771479d94
9 changed files with 16 additions and 132 deletions

19
Cargo.lock generated

@ -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",

@ -7,7 +7,6 @@ members = [
"payment-contracts",
"rate-counter",
"redis-rate-limiter",
"thread-fast-rng",
"web3_proxy",
]
resolver = "2"

@ -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"

@ -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<UnsafeCell<Xoshiro256Plus>>,
}
thread_local! {
pub static THREAD_FAST_RNG: Rc<UnsafeCell<Xoshiro256Plus>> = {
// 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::<i32>();
assert_eq!(r.gen_range(0..1), 0);
}
#[test]
fn test_thread_fast_rng_struct() {
let mut r = ThreadFastRng::default();
r.gen::<i32>();
assert_eq!(r.gen_range(0..1), 0);
}
}

@ -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"] }

@ -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,

@ -644,7 +644,7 @@ impl Authorization {
pub fn internal(db_conn: Option<DatabaseConnection>) -> Web3ProxyResult<Self> {
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,

@ -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<U64>), 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::<u32>();
let r = rng.generate::<u32>();
(sort_on, r)
}

@ -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 {