default to less detailed stats

This commit is contained in:
Bryan Stitt 2022-12-11 20:39:54 -08:00
parent 86f6b16761
commit 4c2d3634c5
14 changed files with 94 additions and 42 deletions

6
Cargo.lock generated
View File

@ -1347,7 +1347,7 @@ dependencies = [
[[package]] [[package]]
name = "entities" name = "entities"
version = "0.10.0" version = "0.11.0"
dependencies = [ dependencies = [
"sea-orm", "sea-orm",
"serde", "serde",
@ -2720,7 +2720,7 @@ dependencies = [
[[package]] [[package]]
name = "migration" name = "migration"
version = "0.10.0" version = "0.11.0"
dependencies = [ dependencies = [
"sea-orm-migration", "sea-orm-migration",
"tokio", "tokio",
@ -5499,7 +5499,7 @@ dependencies = [
[[package]] [[package]]
name = "web3_proxy" name = "web3_proxy"
version = "0.10.0" version = "0.11.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "entities" name = "entities"
version = "0.10.0" version = "0.11.0"
edition = "2021" edition = "2021"
[lib] [lib]

View File

@ -10,7 +10,7 @@ pub struct Model {
pub id: u64, pub id: u64,
pub rpc_key_id: Option<u64>, pub rpc_key_id: Option<u64>,
pub chain_id: u64, pub chain_id: u64,
pub method: String, pub method: Option<String>,
pub archive_request: bool, pub archive_request: bool,
pub error_response: bool, pub error_response: bool,
pub period_datetime: DateTimeUtc, pub period_datetime: DateTimeUtc,

View File

@ -1,5 +1,6 @@
//! SeaORM Entity. Generated by sea-orm-codegen 0.10.1 //! SeaORM Entity. Generated by sea-orm-codegen 0.10.1
use super::sea_orm_active_enums::LogLevel;
use sea_orm::entity::prelude::*; use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -14,6 +15,8 @@ pub struct Model {
pub description: Option<String>, pub description: Option<String>,
pub private_txs: bool, pub private_txs: bool,
pub active: bool, pub active: bool,
pub log_level: LogLevel,
pub log_revert_chance: f64,
#[sea_orm(column_type = "Text", nullable)] #[sea_orm(column_type = "Text", nullable)]
pub allowed_ips: Option<String>, pub allowed_ips: Option<String>,
#[sea_orm(column_type = "Text", nullable)] #[sea_orm(column_type = "Text", nullable)]
@ -22,7 +25,12 @@ pub struct Model {
pub allowed_referers: Option<String>, pub allowed_referers: Option<String>,
#[sea_orm(column_type = "Text", nullable)] #[sea_orm(column_type = "Text", nullable)]
pub allowed_user_agents: Option<String>, pub allowed_user_agents: Option<String>,
pub log_revert_chance: f64, }
pub enum RpcKeyLogLevels {
None,
Basic,
Detailed,
} }
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

View File

@ -3,6 +3,34 @@
use sea_orm::entity::prelude::*; use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "log_level")]
pub enum LogLevel {
#[sea_orm(string_value = "none")]
None,
#[sea_orm(string_value = "aggregate")]
Aggregate,
#[sea_orm(string_value = "detailed")]
Detailed,
}
impl Default for LogLevel {
fn default() -> Self {
Self::None
}
}
#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "method")]
pub enum Method {
#[sea_orm(string_value = "eth_call")]
EthCall,
#[sea_orm(string_value = "eth_estimateGas")]
EthEstimateGas,
#[sea_orm(string_value = "eth_sendRawTransaction")]
EthSendRawTransaction,
}
#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "role")] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "role")]
pub enum Role { pub enum Role {
@ -13,13 +41,3 @@ pub enum Role {
#[sea_orm(string_value = "collaborator")] #[sea_orm(string_value = "collaborator")]
Collaborator, Collaborator,
} }
#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "method")]
pub enum Method {
#[sea_orm(string_value = "eth_call")]
EthCall,
#[sea_orm(string_value = "eth_estimateGas")]
EthEstimateGas,
#[sea_orm(string_value = "eth_sendRawTransaction")]
EthSendRawTransaction,
}

View File

@ -1,6 +1,6 @@
[package] [package]
name = "migration" name = "migration"
version = "0.10.0" version = "0.11.0"
edition = "2021" edition = "2021"
publish = false publish = false

View File

@ -10,6 +10,7 @@ mod m20221027_002407_user_tiers;
mod m20221031_211916_clean_up; mod m20221031_211916_clean_up;
mod m20221101_222349_archive_request; mod m20221101_222349_archive_request;
mod m20221108_200345_save_anon_stats; mod m20221108_200345_save_anon_stats;
mod m20221211_124002_request_method_privacy;
pub struct Migrator; pub struct Migrator;
@ -27,6 +28,7 @@ impl MigratorTrait for Migrator {
Box::new(m20221031_211916_clean_up::Migration), Box::new(m20221031_211916_clean_up::Migration),
Box::new(m20221101_222349_archive_request::Migration), Box::new(m20221101_222349_archive_request::Migration),
Box::new(m20221108_200345_save_anon_stats::Migration), Box::new(m20221108_200345_save_anon_stats::Migration),
Box::new(m20221211_124002_request_method_privacy::Migration),
] ]
} }
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "web3_proxy" name = "web3_proxy"
version = "0.10.0" version = "0.11.0"
edition = "2021" edition = "2021"
default-run = "web3_proxy" default-run = "web3_proxy"

View File

@ -17,6 +17,7 @@ use anyhow::Context;
use axum::headers::{Origin, Referer, UserAgent}; use axum::headers::{Origin, Referer, UserAgent};
use deferred_rate_limiter::DeferredRateLimiter; use deferred_rate_limiter::DeferredRateLimiter;
use derive_more::From; use derive_more::From;
use entities::sea_orm_active_enums::LogLevel;
use ethers::core::utils::keccak256; use ethers::core::utils::keccak256;
use ethers::prelude::{Address, Block, Bytes, TxHash, H256, U64}; use ethers::prelude::{Address, Block, Bytes, TxHash, H256, U64};
use futures::future::join_all; use futures::future::join_all;
@ -84,6 +85,7 @@ pub struct AuthorizationChecks {
pub allowed_user_agents: Option<Vec<UserAgent>>, pub allowed_user_agents: Option<Vec<UserAgent>>,
/// if None, allow any IP Address /// if None, allow any IP Address
pub allowed_ips: Option<Vec<IpNet>>, pub allowed_ips: Option<Vec<IpNet>>,
pub log_level: LogLevel,
/// Chance to save reverting eth_call, eth_estimateGas, and eth_sendRawTransaction to the database. /// Chance to save reverting eth_call, eth_estimateGas, and eth_sendRawTransaction to the database.
/// TODO: f32 would be fine /// TODO: f32 would be fine
pub log_revert_chance: f64, pub log_revert_chance: f64,
@ -180,6 +182,8 @@ pub async fn drop_migration_lock(db_conn: &DatabaseConnection) -> Result<(), DbE
db_conn.execute(drop_lock_statment).await?; db_conn.execute(drop_lock_statment).await?;
debug!("migration lock unlocked");
Ok(()) Ok(())
} }

View File

@ -3,6 +3,7 @@ use axum::headers::Origin;
use chrono::{TimeZone, Utc}; use chrono::{TimeZone, Utc};
use derive_more::From; use derive_more::From;
use entities::rpc_accounting; use entities::rpc_accounting;
use entities::sea_orm_active_enums::LogLevel;
use hashbrown::HashMap; use hashbrown::HashMap;
use hdrhistogram::{Histogram, RecordError}; use hdrhistogram::{Histogram, RecordError};
use log::{error, info}; use log::{error, info};
@ -34,7 +35,7 @@ impl ProxyResponseStat {
/// TODO: think more about this. probably rename it /// TODO: think more about this. probably rename it
fn key(&self) -> ProxyResponseAggregateKey { fn key(&self) -> ProxyResponseAggregateKey {
// include either the rpc_key_id or the origin // include either the rpc_key_id or the origin
let (rpc_key_id, origin) = match ( let (mut rpc_key_id, origin) = match (
self.authorization.checks.rpc_key_id, self.authorization.checks.rpc_key_id,
&self.authorization.origin, &self.authorization.origin,
) { ) {
@ -52,10 +53,27 @@ impl ProxyResponseStat {
} }
}; };
let method = match self.authorization.checks.log_level {
LogLevel::None => {
// No rpc_key logging. Only save fully anonymized metric
rpc_key_id = None;
// keep the method since the rpc key is not attached
Some(self.method.clone())
}
LogLevel::Aggregate => {
// Lose the method
None
}
LogLevel::Detailed => {
// include the method
Some(self.method.clone())
}
};
ProxyResponseAggregateKey { ProxyResponseAggregateKey {
archive_request: self.archive_request, archive_request: self.archive_request,
error_response: self.error_response, error_response: self.error_response,
method: self.method.clone(), method,
origin, origin,
rpc_key_id, rpc_key_id,
} }
@ -89,7 +107,7 @@ struct ProxyResponseAggregateKey {
archive_request: bool, archive_request: bool,
error_response: bool, error_response: bool,
rpc_key_id: Option<NonZeroU64>, rpc_key_id: Option<NonZeroU64>,
method: String, method: Option<String>,
/// TODO: should this be Origin or String? /// TODO: should this be Origin or String?
origin: Option<Origin>, origin: Option<Origin>,
} }

View File

@ -46,7 +46,7 @@ pub enum RateLimitResult {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum AuthorizatioType { pub enum AuthorizationType {
Internal, Internal,
Frontend, Frontend,
} }
@ -60,7 +60,7 @@ pub struct Authorization {
pub origin: Option<Origin>, pub origin: Option<Origin>,
pub referer: Option<Referer>, pub referer: Option<Referer>,
pub user_agent: Option<UserAgent>, pub user_agent: Option<UserAgent>,
pub authorization_type: AuthorizatioType, pub authorization_type: AuthorizationType,
} }
#[derive(Debug)] #[derive(Debug)]
@ -188,7 +188,7 @@ impl Authorization {
None, None,
None, None,
user_agent, user_agent,
AuthorizatioType::Internal, AuthorizationType::Internal,
) )
} }
@ -223,7 +223,7 @@ impl Authorization {
origin, origin,
referer, referer,
user_agent, user_agent,
AuthorizatioType::Frontend, AuthorizationType::Frontend,
) )
} }
@ -234,7 +234,7 @@ impl Authorization {
origin: Option<Origin>, origin: Option<Origin>,
referer: Option<Referer>, referer: Option<Referer>,
user_agent: Option<UserAgent>, user_agent: Option<UserAgent>,
authorization_type: AuthorizatioType, authorization_type: AuthorizationType,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
// check ip // check ip
match &authorization_checks.allowed_ips { match &authorization_checks.allowed_ips {
@ -664,6 +664,7 @@ impl Web3ProxyApp {
allowed_origins, allowed_origins,
allowed_referers, allowed_referers,
allowed_user_agents, allowed_user_agents,
log_level: rpc_key_model.log_level,
log_revert_chance: rpc_key_model.log_revert_chance, log_revert_chance: rpc_key_model.log_revert_chance,
max_concurrent_requests: user_tier_model.max_concurrent_requests, max_concurrent_requests: user_tier_model.max_concurrent_requests,
max_requests_per_period: user_tier_model.max_requests_per_period, max_requests_per_period: user_tier_model.max_requests_per_period,
@ -705,7 +706,7 @@ impl Web3ProxyApp {
origin, origin,
referer, referer,
user_agent, user_agent,
AuthorizatioType::Frontend, AuthorizationType::Frontend,
)?; )?;
let user_max_requests_per_period = match authorization.checks.max_requests_per_period { let user_max_requests_per_period = match authorization.checks.max_requests_per_period {

View File

@ -18,6 +18,7 @@ use axum::{
}; };
use axum_client_ip::ClientIp; use axum_client_ip::ClientIp;
use axum_macros::debug_handler; use axum_macros::debug_handler;
use entities::sea_orm_active_enums::LogLevel;
use entities::{revert_log, rpc_key, user}; use entities::{revert_log, rpc_key, user};
use ethers::{prelude::Address, types::Bytes}; use ethers::{prelude::Address, types::Bytes};
use hashbrown::HashMap; use hashbrown::HashMap;
@ -26,8 +27,8 @@ use ipnet::IpNet;
use itertools::Itertools; use itertools::Itertools;
use log::warn; use log::warn;
use migration::sea_orm::{ use migration::sea_orm::{
self, ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, self, ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, PaginatorTrait, QueryFilter,
TransactionTrait, TryIntoModel, QueryOrder, TransactionTrait, TryIntoModel,
}; };
use redis_rate_limiter::redis::AsyncCommands; use redis_rate_limiter::redis::AsyncCommands;
use serde::Deserialize; use serde::Deserialize;
@ -502,23 +503,24 @@ pub async fn rpc_keys_delete(
/// the JSON input to the `rpc_keys_management` handler. /// the JSON input to the `rpc_keys_management` handler.
/// If `key_id` is set, it updates an existing key. /// If `key_id` is set, it updates an existing key.
/// If `key_id` is not set, it creates a new key. /// If `key_id` is not set, it creates a new key.
/// `log_request_method` cannot be change once the key is created
/// `user_tier` cannot be changed here
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct UserKeyManagement { pub struct UserKeyManagement {
key_id: Option<u64>, key_id: Option<u64>,
description: Option<String>,
private_txs: Option<bool>,
active: Option<bool>, active: Option<bool>,
// TODO: enable log_revert_trace: Option<f64>,
allowed_ips: Option<String>, allowed_ips: Option<String>,
allowed_origins: Option<String>, allowed_origins: Option<String>,
allowed_referers: Option<String>, allowed_referers: Option<String>,
allowed_user_agents: Option<String>, allowed_user_agents: Option<String>,
// do not allow! `user_tier: Option<u64>,` description: Option<String>,
log_level: Option<LogLevel>,
// TODO: enable log_revert_trace: Option<f64>,
private_txs: Option<bool>,
} }
/// `POST /user/keys` or `PUT /user/keys` -- Use a bearer token to create or update an existing key. /// `POST /user/keys` or `PUT /user/keys` -- Use a bearer token to create or update an existing key.
#[debug_handler] #[debug_handler]
pub async fn rpc_keys_management( pub async fn rpc_keys_management(
Extension(app): Extension<Arc<Web3ProxyApp>>, Extension(app): Extension<Arc<Web3ProxyApp>>,
TypedHeader(Authorization(bearer)): TypedHeader<Authorization<Bearer>>, TypedHeader(Authorization(bearer)): TypedHeader<Authorization<Bearer>>,
@ -532,15 +534,14 @@ pub async fn rpc_keys_management(
let mut uk = if let Some(existing_key_id) = payload.key_id { let mut uk = if let Some(existing_key_id) = payload.key_id {
// get the key and make sure it belongs to the user // get the key and make sure it belongs to the user
let uk = rpc_key::Entity::find() rpc_key::Entity::find()
.filter(rpc_key::Column::UserId.eq(user.id)) .filter(rpc_key::Column::UserId.eq(user.id))
.filter(rpc_key::Column::Id.eq(existing_key_id)) .filter(rpc_key::Column::Id.eq(existing_key_id))
.one(&db_conn) .one(&db_conn)
.await .await
.context("failed loading user's key")? .context("failed loading user's key")?
.context("key does not exist or is not controlled by this bearer token")?; .context("key does not exist or is not controlled by this bearer token")?
.into_active_model()
uk.try_into().unwrap()
} else { } else {
// make a new key // make a new key
// TODO: limit to 10 keys? // TODO: limit to 10 keys?
@ -549,6 +550,7 @@ pub async fn rpc_keys_management(
rpc_key::ActiveModel { rpc_key::ActiveModel {
user_id: sea_orm::Set(user.id), user_id: sea_orm::Set(user.id),
secret_key: sea_orm::Set(secret_key.into()), secret_key: sea_orm::Set(secret_key.into()),
log_level: sea_orm::Set(payload.log_level.unwrap_or(LogLevel::None)),
..Default::default() ..Default::default()
} }
}; };

View File

@ -10,7 +10,6 @@ use crate::config::{BlockAndRpc, TxHashAndRpc, Web3ConnectionConfig};
use crate::frontend::authorization::{Authorization, RequestMetadata}; use crate::frontend::authorization::{Authorization, RequestMetadata};
use crate::jsonrpc::{JsonRpcForwardedResponse, JsonRpcRequest}; use crate::jsonrpc::{JsonRpcForwardedResponse, JsonRpcRequest};
use crate::rpcs::transactions::TxStatus; use crate::rpcs::transactions::TxStatus;
use anyhow::Context;
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use counter::Counter; use counter::Counter;
use derive_more::From; use derive_more::From;

View File

@ -1,6 +1,6 @@
use super::connection::Web3Connection; use super::connection::Web3Connection;
use super::provider::Web3Provider; use super::provider::Web3Provider;
use crate::frontend::authorization::{AuthorizatioType, Authorization}; use crate::frontend::authorization::{Authorization, AuthorizationType};
use crate::metered::{JsonRpcErrorCount, ProviderErrorCount}; use crate::metered::{JsonRpcErrorCount, ProviderErrorCount};
use anyhow::Context; use anyhow::Context;
use chrono::Utc; use chrono::Utc;
@ -173,11 +173,11 @@ impl OpenRequestHandle {
// TODO: handle overflows? // TODO: handle overflows?
// TODO: what ordering? // TODO: what ordering?
match authorization.as_ref().authorization_type { match authorization.as_ref().authorization_type {
AuthorizatioType::Frontend => { AuthorizationType::Frontend => {
conn.frontend_requests conn.frontend_requests
.fetch_add(1, atomic::Ordering::Relaxed); .fetch_add(1, atomic::Ordering::Relaxed);
} }
AuthorizatioType::Internal => { AuthorizationType::Internal => {
conn.internal_requests conn.internal_requests
.fetch_add(1, atomic::Ordering::Relaxed); .fetch_add(1, atomic::Ordering::Relaxed);
} }