diff --git a/Dockerfile b/Dockerfile index b082c9c8..50a6d4ba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -52,7 +52,7 @@ RUN --mount=type=cache,target=/usr/local/cargo/git \ curl -L https://foundry.paradigm.xyz | bash && foundryup # changing our features doesn't change any of the steps above -ENV WEB3_PROXY_FEATURES "rdkafka-src,connectinfo" +ENV WEB3_PROXY_FEATURES "rdkafka-src" FROM rust as build_tests diff --git a/web3_proxy/Cargo.toml b/web3_proxy/Cargo.toml index 94e868d2..4730e14f 100644 --- a/web3_proxy/Cargo.toml +++ b/web3_proxy/Cargo.toml @@ -7,12 +7,11 @@ default-run = "web3_proxy_cli" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["connectinfo", "deadlock_detection"] +default = ["deadlock_detection"] deadlock_detection = ["parking_lot/deadlock_detection"] mimalloc = ["dep:mimalloc"] tokio-console = ["dep:tokio-console", "dep:console-subscriber"] rdkafka-src = ["rdkafka/cmake-build", "rdkafka/libz", "rdkafka/ssl-vendored", "rdkafka/zstd-pkg-config"] -connectinfo = [] [dependencies] deferred-rate-limiter = { path = "../deferred-rate-limiter" } diff --git a/web3_proxy/src/frontend/mod.rs b/web3_proxy/src/frontend/mod.rs index 62998126..db0f18bc 100644 --- a/web3_proxy/src/frontend/mod.rs +++ b/web3_proxy/src/frontend/mod.rs @@ -264,17 +264,16 @@ pub async fn serve( - forwarded header (new standard) - axum::extract::ConnectInfo (if not behind proxy) */ - #[cfg(feature = "connectinfo")] let make_service = { info!("connectinfo feature enabled"); router.into_make_service_with_connect_info::() }; - #[cfg(not(feature = "connectinfo"))] - let make_service = { - info!("connectinfo feature disabled"); - router.into_make_service() - }; + // #[cfg(not(feature = "connectinfo"))] + // let make_service = { + // info!("connectinfo feature disabled"); + // router.into_make_service() + // }; let server = server_builder.serve(make_service); diff --git a/web3_proxy/tests/common/app.rs b/web3_proxy/tests/common/app.rs new file mode 100644 index 00000000..1c9bf57f --- /dev/null +++ b/web3_proxy/tests/common/app.rs @@ -0,0 +1,162 @@ +use ethers::{ + prelude::{Http, Provider}, + signers::LocalWallet, + types::Address, + utils::{Anvil, AnvilInstance}, +}; +use hashbrown::HashMap; +use parking_lot::Mutex; +use std::{ + env, + str::FromStr, + sync::atomic::{AtomicU16, Ordering}, +}; +use std::{sync::Arc, time::Duration}; +use tokio::{ + sync::broadcast::{self, error::SendError}, + task::JoinHandle, + time::{sleep, Instant}, +}; +use tracing::info; +use web3_proxy::{ + config::{AppConfig, TopConfig, Web3RpcConfig}, + sub_commands::ProxydSubCommand, +}; + +pub struct TestApp { + /// anvil shuts down when this guard is dropped. + anvil: AnvilInstance, + + /// spawn handle for the proxy. + handle: Mutex>>>, + + /// tell the app to shut down (use `self.stop()`). + shutdown_sender: broadcast::Sender<()>, + + /// connection to anvil. + pub anvil_provider: Provider, + + /// connection to the proxy that is connected to anil. + pub proxy_provider: Provider, +} + +impl TestApp { + pub async fn spawn() -> Self { + let num_workers = 2; + + // TODO: move basic setup into a test fixture + let path = env::var("PATH").unwrap(); + + info!("path: {}", path); + + // TODO: configurable rpc and block + let anvil = Anvil::new() + // .fork("https://polygon.llamarpc.com@44300000") + .spawn(); + + info!("Anvil running at `{}`", anvil.endpoint()); + + let anvil_provider = Provider::::try_from(anvil.endpoint()).unwrap(); + + // make a test TopConfig + // TODO: test influx + // TODO: test redis + let top_config = TopConfig { + app: AppConfig { + chain_id: 31337, + // TODO: [make sqlite work]() + // db_url: Some("sqlite::memory:".into()), + default_user_max_requests_per_period: Some(6_000_000), + deposit_factory_contract: Address::from_str( + "4e3BC2054788De923A04936C6ADdB99A05B0Ea36", + ) + .ok(), + min_sum_soft_limit: 1, + min_synced_rpcs: 1, + public_requests_per_period: Some(1_000_000), + response_cache_max_bytes: 10_u64.pow(7), + ..Default::default() + }, + balanced_rpcs: HashMap::from([( + "anvil".to_string(), + Web3RpcConfig { + http_url: Some(anvil.endpoint()), + ws_url: Some(anvil.ws_endpoint()), + ..Default::default() + }, + )]), + private_rpcs: None, + bundler_4337_rpcs: None, + extra: Default::default(), + }; + + let (shutdown_sender, _shutdown_receiver) = broadcast::channel(1); + + let frontend_port_arc = Arc::new(AtomicU16::new(0)); + let prometheus_port_arc = Arc::new(AtomicU16::new(0)); + + // spawn the app + // TODO: spawn in a thread so we can run from non-async tests and so the Drop impl can wait for it to stop + let handle = { + tokio::spawn(ProxydSubCommand::_main( + top_config, + None, + frontend_port_arc.clone(), + prometheus_port_arc, + num_workers, + shutdown_sender.clone(), + )) + }; + + let mut frontend_port = frontend_port_arc.load(Ordering::Relaxed); + let start = Instant::now(); + while frontend_port == 0 { + if start.elapsed() > Duration::from_secs(1) { + panic!("took too long to start!"); + } + + sleep(Duration::from_millis(10)).await; + frontend_port = frontend_port_arc.load(Ordering::Relaxed); + } + + let proxy_endpoint = format!("http://127.0.0.1:{}", frontend_port); + + let proxy_provider = Provider::::try_from(proxy_endpoint).unwrap(); + + Self { + anvil, + anvil_provider, + handle: Mutex::new(Some(handle)), + proxy_provider, + shutdown_sender, + } + } + + pub fn stop(&self) -> Result> { + self.shutdown_sender.send(()) + } + + pub async fn wait(&self) { + // TODO: lock+take feels weird, but it works + let handle = self.handle.lock().take(); + + if let Some(handle) = handle { + let _ = self.stop(); + + info!("waiting for the app to stop..."); + handle.await.unwrap().unwrap(); + } + } + + pub fn wallet(&self, id: usize) -> LocalWallet { + self.anvil.keys()[id].clone().into() + } +} + +impl Drop for TestApp { + fn drop(&mut self) { + let _ = self.stop(); + + // TODO: do we care about waiting for it to stop? it will slow our tests down so we probably only care about waiting in some tests + } +} diff --git a/web3_proxy/tests/common/mod.rs b/web3_proxy/tests/common/mod.rs index f6283255..b948b7fc 100644 --- a/web3_proxy/tests/common/mod.rs +++ b/web3_proxy/tests/common/mod.rs @@ -1,157 +1,3 @@ -use ethers::{ - prelude::{Http, Provider}, - types::Address, - utils::{Anvil, AnvilInstance}, -}; -use hashbrown::HashMap; -use parking_lot::Mutex; -use std::{ - env, - str::FromStr, - sync::atomic::{AtomicU16, Ordering}, -}; -use std::{sync::Arc, time::Duration}; -use tokio::{ - sync::broadcast::{self, error::SendError}, - task::JoinHandle, - time::{sleep, Instant}, -}; -use tracing::info; -use web3_proxy::{ - config::{AppConfig, TopConfig, Web3RpcConfig}, - sub_commands::ProxydSubCommand, -}; +mod app; -pub struct TestApp { - /// anvil shuts down when this guard is dropped. - _anvil: AnvilInstance, - - /// spawn handle for the proxy. - handle: Mutex>>>, - - /// tell the app to shut down (use `self.stop()`). - shutdown_sender: broadcast::Sender<()>, - - /// connection to anvil. - pub anvil_provider: Provider, - - /// connection to the proxy that is connected to anil. - pub proxy_provider: Provider, -} - -impl TestApp { - pub async fn spawn() -> Self { - let num_workers = 2; - - // TODO: move basic setup into a test fixture - let path = env::var("PATH").unwrap(); - - info!("path: {}", path); - - // TODO: configurable rpc and block - let anvil = Anvil::new() - // .fork("https://polygon.llamarpc.com@44300000") - .spawn(); - - info!("Anvil running at `{}`", anvil.endpoint()); - - let anvil_provider = Provider::::try_from(anvil.endpoint()).unwrap(); - - // make a test TopConfig - // TODO: test influx - // TODO: test redis - let top_config = TopConfig { - app: AppConfig { - chain_id: 31337, - // TODO: [make sqlite work]() - // db_url: Some("sqlite::memory:".into()), - default_user_max_requests_per_period: Some(6_000_000), - deposit_factory_contract: Address::from_str( - "4e3BC2054788De923A04936C6ADdB99A05B0Ea36", - ) - .ok(), - min_sum_soft_limit: 1, - min_synced_rpcs: 1, - public_requests_per_period: Some(1_000_000), - response_cache_max_bytes: 10_u64.pow(7), - ..Default::default() - }, - balanced_rpcs: HashMap::from([( - "anvil".to_string(), - Web3RpcConfig { - http_url: Some(anvil.endpoint()), - ws_url: Some(anvil.ws_endpoint()), - ..Default::default() - }, - )]), - private_rpcs: None, - bundler_4337_rpcs: None, - extra: Default::default(), - }; - - let (shutdown_sender, _shutdown_receiver) = broadcast::channel(1); - - let frontend_port_arc = Arc::new(AtomicU16::new(0)); - let prometheus_port_arc = Arc::new(AtomicU16::new(0)); - - // spawn the app - // TODO: spawn in a thread so we can run from non-async tests and so the Drop impl can wait for it to stop - let handle = { - tokio::spawn(ProxydSubCommand::_main( - top_config, - None, - frontend_port_arc.clone(), - prometheus_port_arc, - num_workers, - shutdown_sender.clone(), - )) - }; - - let mut frontend_port = frontend_port_arc.load(Ordering::Relaxed); - let start = Instant::now(); - while frontend_port == 0 { - if start.elapsed() > Duration::from_secs(1) { - panic!("took too long to start!"); - } - - sleep(Duration::from_millis(10)).await; - frontend_port = frontend_port_arc.load(Ordering::Relaxed); - } - - let proxy_endpoint = format!("http://127.0.0.1:{}", frontend_port); - - let proxy_provider = Provider::::try_from(proxy_endpoint).unwrap(); - - Self { - handle: Mutex::new(Some(handle)), - anvil_provider, - proxy_provider, - shutdown_sender, - _anvil: anvil, - } - } - - pub fn stop(&self) -> Result> { - self.shutdown_sender.send(()) - } - - pub async fn wait(&self) { - // TODO: lock+take feels weird, but it works - let handle = self.handle.lock().take(); - - if let Some(handle) = handle { - let _ = self.stop(); - - info!("waiting for the app to stop..."); - handle.await.unwrap().unwrap(); - } - } -} - -impl Drop for TestApp { - fn drop(&mut self) { - let _ = self.stop(); - - // TODO: do we care about waiting for it to stop? it will slow our tests down so we probably only care about waiting in some tests - } -} +pub use self::app::TestApp; diff --git a/web3_proxy/tests/test_proxy.rs b/web3_proxy/tests/test_proxy.rs index ca710d84..ddefce15 100644 --- a/web3_proxy/tests/test_proxy.rs +++ b/web3_proxy/tests/test_proxy.rs @@ -2,8 +2,12 @@ mod common; use crate::common::TestApp; use ethers::prelude::U256; +use http::StatusCode; use std::time::Duration; -use tokio::time::{sleep, Instant}; +use tokio::{ + task::yield_now, + time::{sleep, Instant}, +}; use web3_proxy::rpcs::blockchain::ArcBlock; #[test_log::test(tokio::test)] @@ -26,6 +30,17 @@ async fn it_starts_and_stops() { assert_eq!(anvil_result, proxy_result); + // check the /health page + let proxy_url = x.proxy_provider.url(); + let health_response = reqwest::get(format!("{}health", proxy_url)).await; + dbg!(&health_response); + assert_eq!(health_response.unwrap().status(), StatusCode::OK); + + // check the /status page + let status_response = reqwest::get(format!("{}status", proxy_url)).await; + dbg!(&status_response); + assert_eq!(status_response.unwrap().status(), StatusCode::OK); + let first_block_num = anvil_result.number.unwrap(); // mine a block @@ -42,6 +57,8 @@ async fn it_starts_and_stops() { assert_eq!(first_block_num, second_block_num - 1); + yield_now().await; + let mut proxy_result; let start = Instant::now(); loop { @@ -55,7 +72,7 @@ async fn it_starts_and_stops() { .unwrap(); if let Some(ref proxy_result) = proxy_result { - if proxy_result.number != Some(first_block_num) { + if proxy_result.number == Some(second_block_num) { break; } } diff --git a/web3_proxy/tests/test_users.rs b/web3_proxy/tests/test_users.rs index 9a76051c..41d12396 100644 --- a/web3_proxy/tests/test_users.rs +++ b/web3_proxy/tests/test_users.rs @@ -7,6 +7,8 @@ use crate::common::TestApp; async fn test_log_in_and_out() { let x = TestApp::spawn().await; + let w = x.wallet(0); + todo!(); }