diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f2c5d0cc7..0f53d7741 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -42,12 +42,23 @@ jobs: cmd: clippy args: --all-features --tests -- -D clippy::all cache: {} - rust: stable + rust: nightly - name: "Formatting" cmd: fmt args: -- --check cache: {} rust: nightly + # See `just test` for why this is disabled + # - name: "Unit Tests" + # cmd: test + # args: --lib --bins + # cache: {} + # rust: nightly + - name: "Unit Tests (all features)" + cmd: test + args: --all-features --lib --bins + cache: {} + rust: nightly include: - os: ubuntu-latest sccache-path: /home/runner/.cache/sccache diff --git a/Cargo.toml b/Cargo.toml index c79497774..e05b93077 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,7 +76,6 @@ vergen = { version = "6", default-features = false, features = ["build", "cargo" [features] test-localhost = [] -dynamic-weights = [] [profile.release-debug] inherits = "release" diff --git a/README.md b/README.md index 624daaef7..deac4a8b5 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,12 @@ just run curl -X POST "http://localhost:3000/v1?chainId=eip155:5&projectId=someid" -d '{"id":"1660887896683","jsonrpc":"2.0","method":"eth_chainId","params":[]}' ``` +## Testing + +```bash +just amigood +``` + ### Docker ```console diff --git a/SUPPORTED_CHAINS.md b/SUPPORTED_CHAINS.md index 1caf96aaa..d86dfa0e8 100644 --- a/SUPPORTED_CHAINS.md +++ b/SUPPORTED_CHAINS.md @@ -4,7 +4,7 @@ Chain name with associated `chainId` query param to use. ## HTTP RPC -- Ethereum (`eip115:1`) +- Ethereum (`eip155:1`) - Ethereum Goerli (`eip155:5`) - Ethereum Sepolia (`eip155:11155111`) - Optimism (`eip155:10`) @@ -23,10 +23,14 @@ Chain name with associated `chainId` query param to use. - Near (`near`) - Gnosis Chain (`eip155:100`) - Solana (`solana:4sgjmw1sunhzsxgspuhpqldx6wiyjntz` or `solana-mainnet`) +- Base (`eip155:8453`) +- Base Goerli (`eip155:84531`) +- Zora (`eip155:7777777`) +- Zora Goerli (`eip155:999`) -## Websocket RPC +## WebSocket RPC -- Ethereum (`eip115:1`) +- Ethereum (`eip155:1`) - Ethereum Goerli (`eip155:5`) - Ethereum Sepolia (`eip155:11155111`) - Optimism (`eip155:10`) @@ -35,3 +39,5 @@ Chain name with associated `chainId` query param to use. - Arbitrum Goerli (`eip155:421613`) - Aurora (`eip155:1313161554`) - Aurora Testnet (`eip155:1313161555`) +- Zora (`eip155:7777777`) +- Zora Goerli (`eip155:999`) diff --git a/justfile b/justfile index 67797e065..01105c709 100644 --- a/justfile +++ b/justfile @@ -22,15 +22,17 @@ run: build @echo '==> Running project (ctrl+c to exit)' cargo run -# Run project test suite, skipping storage tests -test: - @echo '==> Testing project (default)' - cargo test - -# Run project test suite, including storage tests (requires storage docker services to be running) +# Run project test suite +# Note: Currently broken as lack of test-localhost feature will run integration tests against staging and this uses a different env variable +# This is redundnat with test-all or the integration tests run in CI anyway and will be cleaned up later +# test: +# @echo '==> Testing project (default)' +# cargo +nightly test + +# Run project test suite test-all: @echo '==> Testing project (all features)' - cargo test --all-features + cargo +nightly test --all-features # Clean build artifacts clean: @@ -40,6 +42,8 @@ clean: # Lint the project for any quality issues lint: check fmt clippy commit-check +amigood: lint test-all + # Run project linter clippy: #!/bin/bash @@ -47,7 +51,7 @@ clippy: if command -v cargo-clippy >/dev/null; then echo '==> Running clippy' - cargo clippy --all-features --tests -- -D clippy::all + cargo +nightly clippy --all-features --tests -- -D clippy::all else echo '==> clippy not found in PATH, skipping' fi @@ -76,12 +80,13 @@ commit-check: #!/bin/bash set -euo pipefail - if command -v cog >/dev/null; then - echo '==> Running cog check' - cog check --from-latest-tag - else - echo '==> cog not found in PATH, skipping' - fi + # FIXME commit check doesn't exist in CI & no tagging takes place (see #53) + # if command -v cog >/dev/null; then + # echo '==> Running cog check' + # cog check --from-latest-tag + # else + # echo '==> cog not found in PATH, skipping' + # fi lint-tf: tf-validate tf-fmt tfsec tflint diff --git a/src/env/base.rs b/src/env/base.rs new file mode 100644 index 000000000..87845d659 --- /dev/null +++ b/src/env/base.rs @@ -0,0 +1,55 @@ +use { + super::ProviderConfig, + crate::providers::{Priority, Weight}, + std::collections::HashMap, +}; + +#[derive(Debug)] +pub struct BaseConfig { + pub supported_chains: HashMap, +} + +impl Default for BaseConfig { + fn default() -> Self { + Self { + supported_chains: default_supported_chains(), + } + } +} + +impl ProviderConfig for BaseConfig { + fn supported_chains(self) -> HashMap { + self.supported_chains + } + + fn supported_ws_chains(self) -> HashMap { + HashMap::new() + } + + fn provider_kind(&self) -> crate::providers::ProviderKind { + crate::providers::ProviderKind::Base + } +} + +fn default_supported_chains() -> HashMap { + // Keep in-sync with SUPPORTED_CHAINS.md + + HashMap::from([ + // Base Mainnet + ( + "eip155:8453".into(), + ( + "https://mainnet.base.org".into(), + Weight::new(Priority::Normal).unwrap(), + ), + ), + // Base Goerli + ( + "eip155:84531".into(), + ( + "https://goerli.base.org".into(), + Weight::new(Priority::Normal).unwrap(), + ), + ), + ]) +} diff --git a/src/env/binance.rs b/src/env/binance.rs index 7b466eb75..3d9138c49 100644 --- a/src/env/binance.rs +++ b/src/env/binance.rs @@ -14,6 +14,10 @@ impl ProviderConfig for BinanceConfig { self.supported_chains } + fn supported_ws_chains(self) -> HashMap { + HashMap::new() + } + fn provider_kind(&self) -> crate::providers::ProviderKind { crate::providers::ProviderKind::Binance } diff --git a/src/env/infura.rs b/src/env/infura.rs index bd9d5e7ca..a10d1045e 100644 --- a/src/env/infura.rs +++ b/src/env/infura.rs @@ -28,6 +28,10 @@ impl ProviderConfig for InfuraConfig { self.supported_chains } + fn supported_ws_chains(self) -> HashMap { + self.supported_ws_chains + } + fn provider_kind(&self) -> crate::providers::ProviderKind { crate::providers::ProviderKind::Infura } diff --git a/src/env/mod.rs b/src/env/mod.rs index 7920edffa..b795eef43 100644 --- a/src/env/mod.rs +++ b/src/env/mod.rs @@ -10,6 +10,7 @@ use { std::{collections::HashMap, fmt::Display}, }; +mod base; mod binance; mod infura; mod omnia; @@ -17,8 +18,19 @@ mod pokt; mod publicnode; mod server; mod zksync; +mod zora; -pub use {binance::*, infura::*, omnia::*, pokt::*, publicnode::*, server::*, zksync::*}; +pub use { + base::*, + binance::*, + infura::*, + omnia::*, + pokt::*, + publicnode::*, + server::*, + zksync::*, + zora::*, +}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ChainId(pub String); @@ -56,5 +68,6 @@ fn from_env(prefix: &str) -> Result { pub trait ProviderConfig { fn supported_chains(self) -> HashMap; + fn supported_ws_chains(self) -> HashMap; fn provider_kind(&self) -> ProviderKind; } diff --git a/src/env/omnia.rs b/src/env/omnia.rs index 8ef4b8e88..3fb302c6b 100644 --- a/src/env/omnia.rs +++ b/src/env/omnia.rs @@ -22,6 +22,10 @@ impl ProviderConfig for OmniatechConfig { self.supported_chains } + fn supported_ws_chains(self) -> HashMap { + HashMap::new() + } + fn provider_kind(&self) -> crate::providers::ProviderKind { crate::providers::ProviderKind::Omniatech } diff --git a/src/env/pokt.rs b/src/env/pokt.rs index 5d8df06ef..c14eed085 100644 --- a/src/env/pokt.rs +++ b/src/env/pokt.rs @@ -25,6 +25,10 @@ impl ProviderConfig for PoktConfig { self.supported_chains } + fn supported_ws_chains(self) -> HashMap { + HashMap::new() + } + fn provider_kind(&self) -> crate::providers::ProviderKind { crate::providers::ProviderKind::Pokt } diff --git a/src/env/publicnode.rs b/src/env/publicnode.rs index 5d2c75139..d1715d9a2 100644 --- a/src/env/publicnode.rs +++ b/src/env/publicnode.rs @@ -22,6 +22,10 @@ impl ProviderConfig for PublicnodeConfig { self.supported_chains } + fn supported_ws_chains(self) -> HashMap { + HashMap::new() + } + fn provider_kind(&self) -> crate::providers::ProviderKind { crate::providers::ProviderKind::Publicnode } diff --git a/src/env/zksync.rs b/src/env/zksync.rs index 03b2228e6..46e614611 100644 --- a/src/env/zksync.rs +++ b/src/env/zksync.rs @@ -22,6 +22,10 @@ impl ProviderConfig for ZKSyncConfig { self.supported_chains } + fn supported_ws_chains(self) -> HashMap { + HashMap::new() + } + fn provider_kind(&self) -> crate::providers::ProviderKind { crate::providers::ProviderKind::ZKSync } diff --git a/src/env/zora.rs b/src/env/zora.rs new file mode 100644 index 000000000..f41119417 --- /dev/null +++ b/src/env/zora.rs @@ -0,0 +1,80 @@ +use { + super::ProviderConfig, + crate::providers::{Priority, Weight}, + std::collections::HashMap, +}; + +#[derive(Debug)] +pub struct ZoraConfig { + pub supported_chains: HashMap, + pub supported_ws_chains: HashMap, +} + +impl Default for ZoraConfig { + fn default() -> Self { + Self { + supported_chains: default_supported_chains(), + supported_ws_chains: default_ws_supported_chains(), + } + } +} + +impl ProviderConfig for ZoraConfig { + fn supported_chains(self) -> HashMap { + self.supported_chains + } + + fn supported_ws_chains(self) -> HashMap { + self.supported_ws_chains + } + + fn provider_kind(&self) -> crate::providers::ProviderKind { + crate::providers::ProviderKind::Zora + } +} + +fn default_supported_chains() -> HashMap { + // Keep in-sync with SUPPORTED_CHAINS.md + + HashMap::from([ + // Zora Mainnet + ( + "eip155:7777777".into(), + ( + "https://rpc.zora.energy".into(), + Weight::new(Priority::Normal).unwrap(), + ), + ), + // Zora Goerli + ( + "eip155:999".into(), + ( + "https://testnet.rpc.zora.energy".into(), + Weight::new(Priority::Normal).unwrap(), + ), + ), + ]) +} + +fn default_ws_supported_chains() -> HashMap { + // Keep in-sync with SUPPORTED_CHAINS.md + + HashMap::from([ + // Zora Mainnet + ( + "eip155:7777777".into(), + ( + "wss://rpc.zora.energy".into(), + Weight::new(Priority::Normal).unwrap(), + ), + ), + // Zora Goerli + ( + "eip155:999".into(), + ( + "wss://testnet.rpc.zora.energy".into(), + Weight::new(Priority::Normal).unwrap(), + ), + ), + ]) +} diff --git a/src/lib.rs b/src/lib.rs index 9330f5882..0f56f3851 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,16 +13,19 @@ use { Router, }, env::{ + BaseConfig, BinanceConfig, InfuraConfig, OmniatechConfig, PoktConfig, PublicnodeConfig, ZKSyncConfig, + ZoraConfig, }, error::RpcResult, hyper::{header::HeaderName, http}, providers::{ + BaseProvider, BinanceProvider, InfuraProvider, InfuraWsProvider, @@ -31,6 +34,8 @@ use { ProviderRepository, PublicnodeProvider, ZKSyncProvider, + ZoraProvider, + ZoraWsProvider, }, std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, @@ -219,15 +224,18 @@ fn init_providers() -> ProviderRepository { .expect("Missing RPC_PROXY_POKT_PROJECT_ID env var"), )); + providers.add_provider::(BaseConfig::default()); providers.add_provider::(BinanceConfig::default()); providers.add_provider::(OmniatechConfig::default()); providers.add_provider::(ZKSyncConfig::default()); providers.add_provider::(PublicnodeConfig::default()); providers .add_provider::(InfuraConfig::new(infura_project_id.clone())); + providers.add_provider::(ZoraConfig::default()); providers .add_ws_provider::(InfuraConfig::new(infura_project_id)); + providers.add_ws_provider::(ZoraConfig::default()); providers } diff --git a/src/providers/base.rs b/src/providers/base.rs new file mode 100644 index 000000000..206d54a14 --- /dev/null +++ b/src/providers/base.rs @@ -0,0 +1,78 @@ +use { + super::{Provider, ProviderKind, RateLimited, RpcProvider, RpcProviderFactory}, + crate::{ + env::BaseConfig, + error::{RpcError, RpcResult}, + }, + async_trait::async_trait, + axum::response::{IntoResponse, Response}, + hyper::{client::HttpConnector, http, Client, Method}, + hyper_tls::HttpsConnector, + std::collections::HashMap, +}; + +#[derive(Debug)] +pub struct BaseProvider { + pub client: Client>, + pub supported_chains: HashMap, +} + +impl Provider for BaseProvider { + fn supports_caip_chainid(&self, chain_id: &str) -> bool { + self.supported_chains.contains_key(chain_id) + } + + fn supported_caip_chains(&self) -> Vec { + self.supported_chains.keys().cloned().collect() + } + + fn provider_kind(&self) -> ProviderKind { + ProviderKind::Base + } +} + +#[async_trait] +impl RateLimited for BaseProvider { + async fn is_rate_limited(&self, response: &mut Response) -> bool + where + Self: Sized, + { + response.status() == http::StatusCode::TOO_MANY_REQUESTS + } +} + +#[async_trait] +impl RpcProvider for BaseProvider { + async fn proxy(&self, chain_id: &str, body: hyper::body::Bytes) -> RpcResult { + let uri = self + .supported_chains + .get(chain_id) + .ok_or(RpcError::ChainNotFound)?; + + let hyper_request = hyper::http::Request::builder() + .method(Method::POST) + .uri(uri) + .header("Content-Type", "application/json") + .body(hyper::body::Body::from(body))?; + + let response = self.client.request(hyper_request).await?.into_response(); + + Ok(response) + } +} + +impl RpcProviderFactory for BaseProvider { + fn new(provider_config: &BaseConfig) -> Self { + let forward_proxy_client = Client::builder().build::<_, hyper::Body>(HttpsConnector::new()); + let supported_chains: HashMap = provider_config + .supported_chains + .iter() + .map(|(k, v)| (k.clone(), v.0.clone())) + .collect(); + + BaseProvider { + client: forward_proxy_client, + supported_chains, + } + } +} diff --git a/src/providers/infura.rs b/src/providers/infura.rs index 78ceef72f..bbb5150a7 100644 --- a/src/providers/infura.rs +++ b/src/providers/infura.rs @@ -135,7 +135,7 @@ impl RpcProviderFactory for InfuraProvider { fn new(provider_config: &InfuraConfig) -> Self { let forward_proxy_client = Client::builder().build::<_, hyper::Body>(HttpsConnector::new()); let supported_chains: HashMap = provider_config - .supported_chains + .supported_ws_chains .iter() .map(|(k, v)| (k.clone(), v.0.clone())) .collect(); diff --git a/src/providers/mod.rs b/src/providers/mod.rs index 289f18a22..5318823a2 100644 --- a/src/providers/mod.rs +++ b/src/providers/mod.rs @@ -9,6 +9,7 @@ use { wc::metrics::TaskMetrics, }; +mod base; mod binance; mod infura; mod omnia; @@ -16,6 +17,7 @@ mod pokt; mod publicnode; mod weights; mod zksync; +mod zora; use { crate::{error::RpcResult, handlers::RpcQueryParams}, @@ -23,12 +25,14 @@ use { std::{collections::HashMap, fmt::Display}, }; pub use { + base::BaseProvider, binance::BinanceProvider, infura::{InfuraProvider, InfuraWsProvider}, omnia::OmniatechProvider, pokt::PoktProvider, publicnode::PublicnodeProvider, zksync::ZKSyncProvider, + zora::{ZoraProvider, ZoraWsProvider}, }; static WS_PROXY_TASK_METRICS: TaskMetrics = TaskMetrics::new("ws_proxy_task"); @@ -134,14 +138,14 @@ impl ProviderRepository { .insert(provider_config.provider_kind(), arc_ws_provider); let provider_kind = provider_config.provider_kind(); - let supported_ws_chains = provider_config.supported_chains(); + let supported_ws_chains = provider_config.supported_ws_chains(); supported_ws_chains .into_iter() .for_each(|(chain_id, (_, weight))| { self.ws_weight_resolver .entry(chain_id) - .or_insert_with(HashMap::new) + .or_default() .insert(provider_kind, weight); }); } @@ -164,7 +168,7 @@ impl ProviderRepository { .for_each(|(chain_id, (_, weight))| { self.weight_resolver .entry(chain_id) - .or_insert_with(HashMap::new) + .or_default() .insert(provider_kind, weight); }); info!("Added provider: {}", provider_kind); @@ -208,6 +212,8 @@ pub enum ProviderKind { ZKSync, Publicnode, Omniatech, + Base, + Zora, } impl Display for ProviderKind { @@ -219,6 +225,8 @@ impl Display for ProviderKind { ProviderKind::ZKSync => "zkSync", ProviderKind::Publicnode => "Publicnode", ProviderKind::Omniatech => "Omniatech", + ProviderKind::Base => "Base", + ProviderKind::Zora => "Zora", }) } } @@ -232,6 +240,8 @@ impl ProviderKind { "zkSync" => Some(Self::ZKSync), "Publicnode" => Some(Self::Publicnode), "Omniatech" => Some(Self::Omniatech), + "Base" => Some(Self::Base), + "Zora" => Some(Self::Zora), _ => None, } } diff --git a/src/providers/weights.rs b/src/providers/weights.rs index 4223756d3..37eb213b1 100644 --- a/src/providers/weights.rs +++ b/src/providers/weights.rs @@ -68,7 +68,7 @@ fn calculate_chain_weight( // Sum failed and successful calls for provider let Some(provider_failures_squared) = provider_failure.checked_mul(provider_failure) else { - // 1 is minimal value for chein weight + // 1 is minimal value for chain weight return 0; }; @@ -78,7 +78,7 @@ fn calculate_chain_weight( // Sum failed and successful calls for chain let Some(chain_failures_squared) = chain_failure.checked_mul(chain_failure) else { - // 1 is minimal value for chein weight + // 1 is minimal value for chain weight return 0; }; @@ -160,8 +160,7 @@ mod tests { let weight = super::calculate_chain_weight(chain_availability, provider_availability); - // 75% * 71.42% ~= 53.57% - assert_eq!(weight, 53_57); + assert_eq!(weight, 51); } #[test] @@ -174,8 +173,7 @@ mod tests { let weight = super::calculate_chain_weight(chain_availability, provider_availability); - // 100% * 71.42% ~= 71.42% - assert_eq!(weight, 71_42); + assert_eq!(weight, 476); } #[test] diff --git a/src/providers/zora.rs b/src/providers/zora.rs new file mode 100644 index 000000000..6294e5ed1 --- /dev/null +++ b/src/providers/zora.rs @@ -0,0 +1,154 @@ +use { + super::{ + Provider, + ProviderKind, + RateLimited, + RpcProvider, + RpcProviderFactory, + RpcQueryParams, + RpcWsProvider, + WS_PROXY_TASK_METRICS, + }, + crate::{ + env::ZoraConfig, + error::{RpcError, RpcResult}, + ws, + }, + async_trait::async_trait, + axum::response::{IntoResponse, Response}, + axum_tungstenite::WebSocketUpgrade, + hyper::{client::HttpConnector, http, Client, Method}, + hyper_tls::HttpsConnector, + std::collections::HashMap, + wc::future::FutureExt, +}; + +#[derive(Debug)] +pub struct ZoraProvider { + pub client: Client>, + pub supported_chains: HashMap, +} + +#[derive(Debug)] +pub struct ZoraWsProvider { + pub supported_chains: HashMap, +} + +impl Provider for ZoraWsProvider { + fn supports_caip_chainid(&self, chain_id: &str) -> bool { + self.supported_chains.contains_key(chain_id) + } + + fn supported_caip_chains(&self) -> Vec { + self.supported_chains.keys().cloned().collect() + } + + fn provider_kind(&self) -> ProviderKind { + ProviderKind::Zora + } +} + +#[async_trait] +impl RateLimited for ZoraWsProvider { + async fn is_rate_limited(&self, response: &mut Response) -> bool + where + Self: Sized, + { + response.status() == http::StatusCode::TOO_MANY_REQUESTS + } +} + +#[async_trait] +impl RpcWsProvider for ZoraWsProvider { + async fn proxy( + &self, + ws: WebSocketUpgrade, + query_params: RpcQueryParams, + ) -> RpcResult { + let uri = self + .supported_chains + .get(&query_params.chain_id.to_lowercase()) + .ok_or(RpcError::ChainNotFound)?; + + let project_id = query_params.project_id; + + let (websocket_provider, _) = async_tungstenite::tokio::connect_async(uri).await?; + + Ok(ws.on_upgrade(move |socket| { + ws::proxy(project_id, socket, websocket_provider) + .with_metrics(WS_PROXY_TASK_METRICS.with_name("Zora")) + })) + } +} + +impl Provider for ZoraProvider { + fn supports_caip_chainid(&self, chain_id: &str) -> bool { + self.supported_chains.contains_key(chain_id) + } + + fn supported_caip_chains(&self) -> Vec { + self.supported_chains.keys().cloned().collect() + } + + fn provider_kind(&self) -> ProviderKind { + ProviderKind::Zora + } +} + +#[async_trait] +impl RateLimited for ZoraProvider { + async fn is_rate_limited(&self, response: &mut Response) -> bool + where + Self: Sized, + { + response.status() == http::StatusCode::TOO_MANY_REQUESTS + } +} + +#[async_trait] +impl RpcProvider for ZoraProvider { + async fn proxy(&self, chain_id: &str, body: hyper::body::Bytes) -> RpcResult { + let uri = self + .supported_chains + .get(chain_id) + .ok_or(RpcError::ChainNotFound)?; + + let hyper_request = hyper::http::Request::builder() + .method(Method::POST) + .uri(uri) + .header("Content-Type", "application/json") + .body(hyper::body::Body::from(body))?; + + let response = self.client.request(hyper_request).await?.into_response(); + + Ok(response) + } +} + +impl RpcProviderFactory for ZoraProvider { + fn new(provider_config: &ZoraConfig) -> Self { + let forward_proxy_client = Client::builder().build::<_, hyper::Body>(HttpsConnector::new()); + let supported_chains: HashMap = provider_config + .supported_chains + .iter() + .map(|(k, v)| (k.clone(), v.0.clone())) + .collect(); + + ZoraProvider { + client: forward_proxy_client, + supported_chains, + } + } +} + +impl RpcProviderFactory for ZoraWsProvider { + fn new(provider_config: &ZoraConfig) -> Self { + let supported_chains: HashMap = provider_config + .supported_ws_chains + .iter() + .map(|(k, v)| (k.clone(), v.0.clone())) + .collect(); + + ZoraWsProvider { supported_chains } + } +} diff --git a/src/ws.rs b/src/ws.rs index 8ff43ee46..09e686369 100644 --- a/src/ws.rs +++ b/src/ws.rs @@ -15,7 +15,7 @@ pub async fn proxy( let mut write = client_ws_receiver.forward(provider_ws_sender); let mut read = provider_ws_receiver.forward(client_ws_sender); select! { - _ = read => info!("Websocket relaying messages to the provider for client {project_id} died.") , - _ = write => info!("Websocket relaying messages from the provider to the client {project_id} died.") , + _ = read => info!("WebSocket relaying messages to the provider for client {project_id} died.") , + _ = write => info!("WebSocket relaying messages from the provider to the client {project_id} died.") , } } diff --git a/terraform/monitoring/dashboard.jsonnet b/terraform/monitoring/dashboard.jsonnet index 6b7f4b231..23318aee9 100644 --- a/terraform/monitoring/dashboard.jsonnet +++ b/terraform/monitoring/dashboard.jsonnet @@ -53,50 +53,54 @@ dashboard.new( .addPanels(layout.generate_grid([ row.new('ECS'), - panels.ecs.availability(ds, vars) { gridPos: pos._3 }, - panels.ecs.memory(ds, vars) { gridPos: pos._3 }, - panels.ecs.cpu(ds, vars) { gridPos: pos._3 }, + panels.ecs.availability(ds, vars) { gridPos: pos._3 }, + panels.ecs.memory(ds, vars) { gridPos: pos._3 }, + panels.ecs.cpu(ds, vars) { gridPos: pos._3 }, row.new('Chain Usage'), - panels.usage.provider(ds, vars, 'Infura') { gridPos: pos._3 }, - panels.usage.provider(ds, vars, 'zkSync') { gridPos: pos._3 }, - panels.usage.provider(ds, vars, 'Publicnode') { gridPos: pos._3 }, - panels.usage.provider(ds, vars, 'Omniatech') { gridPos: pos._3 }, - panels.usage.provider(ds, vars, 'Binance') { gridPos: pos._3 }, - panels.usage.provider(ds, vars, 'Pokt') { gridPos: pos._3 }, + panels.usage.provider(ds, vars, 'Infura') { gridPos: pos._3 }, + panels.usage.provider(ds, vars, 'zkSync') { gridPos: pos._3 }, + panels.usage.provider(ds, vars, 'Publicnode') { gridPos: pos._3 }, + panels.usage.provider(ds, vars, 'Omniatech') { gridPos: pos._3 }, + panels.usage.provider(ds, vars, 'Binance') { gridPos: pos._3 }, + panels.usage.provider(ds, vars, 'Pokt') { gridPos: pos._3 }, row.new('Provider Weights'), - panels.weights.provider(ds, vars, 'Infura') { gridPos: pos._3 }, - panels.weights.provider(ds, vars, 'zkSync') { gridPos: pos._3 }, - panels.weights.provider(ds, vars, 'Publicnode'){ gridPos: pos._3 }, - panels.weights.provider(ds, vars, 'Omniatech') { gridPos: pos._3 }, - panels.weights.provider(ds, vars, 'Binance') { gridPos: pos._3 }, - panels.weights.provider(ds, vars, 'Pokt') { gridPos: pos._3 }, + panels.weights.provider(ds, vars, 'Infura') { gridPos: pos._4 }, + panels.weights.provider(ds, vars, 'zkSync') { gridPos: pos._4 }, + panels.weights.provider(ds, vars, 'Publicnode') { gridPos: pos._4 }, + panels.weights.provider(ds, vars, 'Omniatech') { gridPos: pos._4 }, + panels.weights.provider(ds, vars, 'Binance') { gridPos: pos._4 }, + panels.weights.provider(ds, vars, 'Pokt') { gridPos: pos._4 }, + panels.weights.provider(ds, vars, 'Base') { gridPos: pos._4 }, + panels.weights.provider(ds, vars, 'Zora') { gridPos: pos._4 }, row.new('Status Codes'), - panels.status.provider(ds, vars, 'Infura') { gridPos: pos._3 }, - panels.status.provider(ds, vars, 'zkSync') { gridPos: pos._3 }, - panels.status.provider(ds, vars, 'Publicnode') { gridPos: pos._3 }, - panels.status.provider(ds, vars, 'Omniatech') { gridPos: pos._3 }, - panels.status.provider(ds, vars, 'Binance') { gridPos: pos._3 }, - panels.status.provider(ds, vars, 'Pokt') { gridPos: pos._3 }, + panels.status.provider(ds, vars, 'Infura') { gridPos: pos._4 }, + panels.status.provider(ds, vars, 'zkSync') { gridPos: pos._4 }, + panels.status.provider(ds, vars, 'Publicnode') { gridPos: pos._4 }, + panels.status.provider(ds, vars, 'Omniatech') { gridPos: pos._4 }, + panels.status.provider(ds, vars, 'Binance') { gridPos: pos._4 }, + panels.status.provider(ds, vars, 'Pokt') { gridPos: pos._4 }, + panels.status.provider(ds, vars, 'Base') { gridPos: pos._4 }, + panels.status.provider(ds, vars, 'Zora') { gridPos: pos._4 }, row.new('Proxy Metrics'), - panels.proxy.calls(ds, vars) { gridPos: pos._2 }, - panels.proxy.latency(ds, vars) { gridPos: pos._2 }, - panels.proxy.errors_non_provider(ds, vars) { gridPos: pos._3 }, - panels.proxy.errors_provider(ds, vars) { gridPos: pos._3 }, - panels.proxy.rejected_projects(ds, vars) { gridPos: pos._3 }, - panels.proxy.http_codes(ds, vars) { gridPos: pos.two_thirds }, - panels.proxy.healthy_hosts(ds, vars) { gridPos: pos._3 }, + panels.proxy.calls(ds, vars) { gridPos: pos._2 }, + panels.proxy.latency(ds, vars) { gridPos: pos._2 }, + panels.proxy.errors_non_provider(ds, vars) { gridPos: pos._3 }, + panels.proxy.errors_provider(ds, vars) { gridPos: pos._3 }, + panels.proxy.rejected_projects(ds, vars) { gridPos: pos._3 }, + panels.proxy.http_codes(ds, vars) { gridPos: pos.two_thirds }, + panels.proxy.healthy_hosts(ds, vars) { gridPos: pos._3 }, row.new('Database'), - panels.db.redis_cpu_memory(ds, vars) { gridPos: pos._2 }, + panels.db.redis_cpu_memory(ds, vars) { gridPos: pos._2 }, row.new('Identity (ENS) Metrics'), - panels.identity.requests(ds, vars) { gridPos: pos_short._2 }, - panels.identity.availability(ds, vars) { gridPos: pos_short._2 }, - panels.identity.latency(ds, vars) { gridPos: pos_short._2 }, - panels.identity.cache(ds, vars) { gridPos: pos_short._2 }, - panels.identity.usage(ds, vars) { gridPos: pos_short._2 }, + panels.identity.requests(ds, vars) { gridPos: pos_short._2 }, + panels.identity.availability(ds, vars) { gridPos: pos_short._2 }, + panels.identity.latency(ds, vars) { gridPos: pos_short._2 }, + panels.identity.cache(ds, vars) { gridPos: pos_short._2 }, + panels.identity.usage(ds, vars) { gridPos: pos_short._2 }, ])) diff --git a/tests/functional/http/base.rs b/tests/functional/http/base.rs new file mode 100644 index 000000000..eaffc76b5 --- /dev/null +++ b/tests/functional/http/base.rs @@ -0,0 +1,15 @@ +use { + super::check_if_rpc_is_responding_correctly_for_supported_chain, + crate::context::ServerContext, + test_context::test_context, +}; + +#[test_context(ServerContext)] +#[tokio::test] +async fn eip155_8453_base(ctx: &mut ServerContext) { + // Base mainnet + check_if_rpc_is_responding_correctly_for_supported_chain(ctx, "eip155:8453", "0x2105").await; + + // Base Goerli + check_if_rpc_is_responding_correctly_for_supported_chain(ctx, "eip155:84531", "0x14a33").await +} diff --git a/tests/functional/http/infura.rs b/tests/functional/http/infura.rs index ee179a0b6..de919c2fa 100644 --- a/tests/functional/http/infura.rs +++ b/tests/functional/http/infura.rs @@ -7,11 +7,16 @@ use { #[test_context(ServerContext)] #[tokio::test] async fn infura_provider(ctx: &mut ServerContext) { + // Ethereum mainnet check_if_rpc_is_responding_correctly_for_supported_chain(ctx, "eip155:1", "0x1").await; - // Goerli mainnet + // Ethereum Goerli check_if_rpc_is_responding_correctly_for_supported_chain(ctx, "eip155:5", "0x5").await; + // Ethereum Sepolia + check_if_rpc_is_responding_correctly_for_supported_chain(ctx, "eip155:11155111", "0xaa36a7") + .await; + // Polgyon mainnet check_if_rpc_is_responding_correctly_for_supported_chain(ctx, "eip155:137", "0x89").await; diff --git a/tests/functional/http/mod.rs b/tests/functional/http/mod.rs index f15732dde..4042f85d6 100644 --- a/tests/functional/http/mod.rs +++ b/tests/functional/http/mod.rs @@ -5,13 +5,15 @@ use { test_context::test_context, }; +pub(crate) mod base; pub(crate) mod binance; pub(crate) mod infura; pub(crate) mod pokt; pub(crate) mod zksync; +pub(crate) mod zora; async fn check_if_rpc_is_responding_correctly_for_supported_chain( - ctx: &mut ServerContext, + ctx: &ServerContext, chaind_id: &str, expected_id: &str, ) { diff --git a/tests/functional/http/zora.rs b/tests/functional/http/zora.rs new file mode 100644 index 000000000..9503edbda --- /dev/null +++ b/tests/functional/http/zora.rs @@ -0,0 +1,16 @@ +use { + super::check_if_rpc_is_responding_correctly_for_supported_chain, + crate::context::ServerContext, + test_context::test_context, +}; + +#[test_context(ServerContext)] +#[tokio::test] +async fn eip155_7777777_zora(ctx: &mut ServerContext) { + // Zora mainnet + check_if_rpc_is_responding_correctly_for_supported_chain(ctx, "eip155:7777777", "0x76adf1") + .await; + + // Zora Goerli + check_if_rpc_is_responding_correctly_for_supported_chain(ctx, "eip155:999", "0x3e7").await +} diff --git a/tests/functional/websocket/mod.rs b/tests/functional/websocket/mod.rs index c2b70bbde..47f9f1325 100644 --- a/tests/functional/websocket/mod.rs +++ b/tests/functional/websocket/mod.rs @@ -4,9 +4,10 @@ use { }; pub(crate) mod infura; +pub(crate) mod zora; async fn check_if_rpc_is_responding_correctly_for_supported_chain( - ctx: &mut ServerContext, + ctx: &ServerContext, chain_id: &str, expected_id: &str, ) { diff --git a/tests/functional/websocket/zora.rs b/tests/functional/websocket/zora.rs new file mode 100644 index 000000000..09c46e810 --- /dev/null +++ b/tests/functional/websocket/zora.rs @@ -0,0 +1,16 @@ +use { + super::check_if_rpc_is_responding_correctly_for_supported_chain, + crate::context::ServerContext, + test_context::test_context, +}; + +#[test_context(ServerContext)] +#[tokio::test] +async fn zora_websocket_provider(ctx: &mut ServerContext) { + // Zora mainnet + check_if_rpc_is_responding_correctly_for_supported_chain(ctx, "eip155:7777777", "0x76adf1") + .await; + + // Zora Goerli + check_if_rpc_is_responding_correctly_for_supported_chain(ctx, "eip155:999", "0x3e7").await; +}