From 4a9c1a0ce64655b3f10204be4e271d36ad868bbd Mon Sep 17 00:00:00 2001 From: Bryan Stitt Date: Fri, 9 Jun 2023 18:31:47 -0700 Subject: [PATCH] move user registration into a dedicated function --- Cargo.lock | 12 +- web3_proxy/Cargo.toml | 2 +- web3_proxy/src/app/mod.rs | 13 +- web3_proxy/src/errors.rs | 154 +++++++++--------- web3_proxy/src/frontend/rpc_proxy_ws.rs | 6 +- .../src/frontend/users/authentication.rs | 102 ++++++------ web3_proxy/src/frontend/users/payment.rs | 12 +- web3_proxy/src/jsonrpc.rs | 13 +- web3_proxy/src/response_cache.rs | 8 +- web3_proxy/src/rpcs/many.rs | 3 +- web3_proxy/src/stats/mod.rs | 3 +- 11 files changed, 164 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ef88d72..def87e87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4107,9 +4107,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ "unicode-ident", ] @@ -4304,9 +4304,9 @@ dependencies = [ [[package]] name = "rdkafka" -version = "0.31.0" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88383df3a85a38adfa2aa447d3ab6eb9cedcb49613adcf18e7e7ebb3b62e9b03" +checksum = "f8733bc5dc0b192d1a4b28073f9bff1326ad9e4fecd4d9b025d6fc358d1c3e79" dependencies = [ "futures-channel", "futures-util", @@ -4322,9 +4322,9 @@ dependencies = [ [[package]] name = "rdkafka-sys" -version = "4.4.0+1.9.2" +version = "4.5.0+1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ac9d87c3aba1748e3112318459f2ac8bff80bfff7359e338e0463549590249" +checksum = "1bb0676c2112342ac7165decdedbc4e7086c0af384479ccce534546b10687a5d" dependencies = [ "cmake", "libc", diff --git a/web3_proxy/Cargo.toml b/web3_proxy/Cargo.toml index 91b4275e..723bedf0 100644 --- a/web3_proxy/Cargo.toml +++ b/web3_proxy/Cargo.toml @@ -76,7 +76,7 @@ pagerduty-rs = { version = "0.1.6", default-features = false, features = ["async parking_lot = { version = "0.12.1", features = ["arc_lock", "nightly", "serde"] } prettytable = "0.10.0" proctitle = "0.1.1" -rdkafka = { version = "0.31.0" } +rdkafka = { version = "0.32.2" } regex = "1.8.4" reqwest = { version = "0.11.18", default-features = false, features = ["deflate", "gzip", "json", "tokio-rustls"] } rmp-serde = "1.1.1" diff --git a/web3_proxy/src/app/mod.rs b/web3_proxy/src/app/mod.rs index 664c0c26..b8388567 100644 --- a/web3_proxy/src/app/mod.rs +++ b/web3_proxy/src/app/mod.rs @@ -49,7 +49,6 @@ use redis_rate_limiter::{redis, DeadpoolRuntime, RedisConfig, RedisPool, RedisRa use serde::Serialize; use serde_json::json; use serde_json::value::RawValue; -use std::borrow::Cow; use std::fmt; use std::net::IpAddr; use std::num::NonZeroU64; @@ -1512,15 +1511,13 @@ impl Web3ProxyApp { JsonRpcResponseEnum::from(serde_json::Value::Bool(false)) } "eth_subscribe" => JsonRpcErrorData { - message: Cow::Borrowed( - "notifications not supported. eth_subscribe is only available over a websocket", - ), + message: "notifications not supported. eth_subscribe is only available over a websocket".into(), code: -32601, data: None, } .into(), "eth_unsubscribe" => JsonRpcErrorData { - message: Cow::Borrowed("notifications not supported. eth_unsubscribe is only available over a websocket"), + message: "notifications not supported. eth_unsubscribe is only available over a websocket".into(), code: -32601, data: None, }.into(), @@ -1547,7 +1544,7 @@ impl Web3ProxyApp { // TODO: what error code? // TODO: use Web3ProxyError::BadRequest JsonRpcErrorData { - message: Cow::Borrowed("Invalid request"), + message: "Invalid request".into(), code: -32600, data: None }.into() @@ -1575,7 +1572,7 @@ impl Web3ProxyApp { // TODO: this needs the correct error code in the response // TODO: Web3ProxyError::BadRequest instead? JsonRpcErrorData { - message: Cow::Borrowed("invalid request"), + message: "invalid request".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }.into() @@ -1583,7 +1580,7 @@ impl Web3ProxyApp { } } "test" => JsonRpcErrorData { - message: Cow::Borrowed("The method test does not exist/is not available."), + message: "The method test does not exist/is not available.".into(), code: -32601, data: None, }.into(), diff --git a/web3_proxy/src/errors.rs b/web3_proxy/src/errors.rs index 1a4678cb..ecc0f66b 100644 --- a/web3_proxy/src/errors.rs +++ b/web3_proxy/src/errors.rs @@ -49,7 +49,7 @@ pub enum Web3ProxyError { BadRequest(Cow<'static, str>), #[error(ignore)] #[from(ignore)] - BadResponse(String), + BadResponse(Cow<'static, str>), BadRouting, Contract(ContractError), Database(DbErr), @@ -134,7 +134,7 @@ pub enum Web3ProxyError { SerdeJson(serde_json::Error), /// simple way to return an error message to the user and an anyhow to our logs #[display(fmt = "{}, {}, {:?}", _0, _1, _2)] - StatusCode(StatusCode, String, Option), + StatusCode(StatusCode, Cow<'static, str>, Option), /// TODO: what should be attached to the timout? #[display(fmt = "{:?}", _0)] #[error(ignore)] @@ -153,7 +153,7 @@ pub enum Web3ProxyError { WebsocketOnly, #[display(fmt = "{:?}, {}", _0, _1)] #[error(ignore)] - WithContext(Option>, String), + WithContext(Option>, Cow<'static, str>), } impl Web3ProxyError { @@ -165,7 +165,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Owned(err.to_string()), + message: err.to_string().into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -177,7 +177,7 @@ impl Web3ProxyError { ( StatusCode::FORBIDDEN, JsonRpcErrorData { - message: Cow::Borrowed("FORBIDDEN"), + message: "FORBIDDEN".into(), code: StatusCode::FORBIDDEN.as_u16().into(), data: None, }, @@ -189,7 +189,7 @@ impl Web3ProxyError { StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { // TODO: is it safe to expose all of our anyhow strings? - message: Cow::Owned(err.to_string()), + message: err.to_string().into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -204,7 +204,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Owned(format!("bad request: {}", err)), + message: format!("bad request: {}", err).into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -216,7 +216,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Owned(format!("bad response: {}", err)), + message: format!("bad response: {}", err).into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -227,7 +227,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("bad routing"), + message: "bad routing".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -238,7 +238,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("database error!"), + message: "database error!".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -249,7 +249,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Owned(format!("contract error: {}", err)), + message: format!("contract error: {}", err).into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -260,7 +260,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Owned(format!("decimal error: {}", err)), + message: format!("decimal error: {}", err).into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -274,10 +274,11 @@ impl Web3ProxyError { ( StatusCode::UNAUTHORIZED, JsonRpcErrorData { - message: Cow::Owned(format!( + message: format!( "both the primary and eip191 verification failed: {:#?}; {:#?}", err_1, err_191 - )), + ) + .into(), code: StatusCode::UNAUTHORIZED.as_u16().into(), data: None, }, @@ -288,7 +289,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("ether http client error"), + message: "ether http client error".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -299,7 +300,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("ether provider error"), + message: "ether provider error".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -310,7 +311,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("ether ws client error"), + message: "ether ws client error".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -321,7 +322,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("flume recv error!"), + message: "flume recv error!".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -333,7 +334,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("gas estimate result is not an U256"), + message: "gas estimate result is not an U256".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -344,7 +345,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: format!("{}", err).into(), + message: err.to_string().into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -355,7 +356,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Owned(format!("{}", err)), + message: err.to_string().into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -367,7 +368,7 @@ impl Web3ProxyError { StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { // TODO: is it safe to expose these error strings? - message: Cow::Owned(err.to_string()), + message: err.to_string().into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -379,7 +380,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("influxdb2 error!"), + message: "influxdb2 error!".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -390,10 +391,11 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Owned(format!( + message: format!( "Invalid blocks bounds requested. min ({}) > max ({})", min, max - )), + ) + .into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -404,7 +406,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Owned(err.to_string()), + message: err.to_string().into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -415,7 +417,7 @@ impl Web3ProxyError { ( StatusCode::FORBIDDEN, JsonRpcErrorData { - message: Cow::Owned(format!("IP ({}) is not allowed!", ip)), + message: format!("IP ({}) is not allowed!", ip).into(), code: StatusCode::FORBIDDEN.as_u16().into(), data: None, }, @@ -426,7 +428,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Owned(format!("{}", err)), + message: err.to_string().into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -437,7 +439,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("invalid message eip given"), + message: "invalid message eip given".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -448,7 +450,7 @@ impl Web3ProxyError { ( StatusCode::UNAUTHORIZED, JsonRpcErrorData { - message: Cow::Borrowed("invalid invite code"), + message: "invalid invite code".into(), code: StatusCode::UNAUTHORIZED.as_u16().into(), data: None, }, @@ -460,7 +462,7 @@ impl Web3ProxyError { StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { // TODO: is it safe to expose our io error strings? - message: Cow::Owned(err.to_string()), + message: err.to_string().into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -471,7 +473,7 @@ impl Web3ProxyError { ( StatusCode::UNAUTHORIZED, JsonRpcErrorData { - message: Cow::Borrowed("invalid referral code"), + message: "invalid referral code".into(), code: StatusCode::UNAUTHORIZED.as_u16().into(), data: None, }, @@ -482,7 +484,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("invalid referer!"), + message: "invalid referer!".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -493,7 +495,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("invalid signature length"), + message: "invalid signature length".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -504,7 +506,7 @@ impl Web3ProxyError { ( StatusCode::FORBIDDEN, JsonRpcErrorData { - message: Cow::Borrowed("invalid user agent!"), + message: "invalid user agent!".into(), code: StatusCode::FORBIDDEN.as_u16().into(), data: None, }, @@ -515,7 +517,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("UserKey was not a ULID or UUID"), + message: "UserKey was not a ULID or UUID".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -526,7 +528,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("UserTier is not valid!"), + message: "UserTier is not valid!".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -545,7 +547,7 @@ impl Web3ProxyError { code, JsonRpcErrorData { // TODO: different messages of cancelled or not? - message: Cow::Borrowed("Unable to complete request"), + message: "Unable to complete request".into(), code: code.as_u16().into(), data: None, }, @@ -560,7 +562,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Owned(format!("msgpack encode error: {}", err)), + message: format!("msgpack encode error: {}", err).into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -571,7 +573,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("Blocks here must have a number or hash"), + message: "Blocks here must have a number or hash".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -582,7 +584,7 @@ impl Web3ProxyError { ( StatusCode::BAD_GATEWAY, JsonRpcErrorData { - message: Cow::Borrowed("no blocks known"), + message: "no blocks known".into(), code: StatusCode::BAD_GATEWAY.as_u16().into(), data: None, }, @@ -593,7 +595,7 @@ impl Web3ProxyError { ( StatusCode::BAD_GATEWAY, JsonRpcErrorData { - message: Cow::Borrowed("no consensus head block"), + message: "no consensus head block".into(), code: StatusCode::BAD_GATEWAY.as_u16().into(), data: None, }, @@ -604,7 +606,7 @@ impl Web3ProxyError { ( StatusCode::BAD_GATEWAY, JsonRpcErrorData { - message: Cow::Borrowed("unable to retry for request handle"), + message: "unable to retry for request handle".into(), code: StatusCode::BAD_GATEWAY.as_u16().into(), data: None, }, @@ -615,7 +617,7 @@ impl Web3ProxyError { ( StatusCode::BAD_GATEWAY, JsonRpcErrorData { - message: Cow::Borrowed("no servers synced"), + message: "no servers synced".into(), code: StatusCode::BAD_GATEWAY.as_u16().into(), data: None, }, @@ -629,10 +631,11 @@ impl Web3ProxyError { ( StatusCode::BAD_GATEWAY, JsonRpcErrorData { - message: Cow::Owned(format!( + message: format!( "not enough rpcs connected {}/{}", num_known, min_head_rpcs - )), + ) + .into(), code: StatusCode::BAD_GATEWAY.as_u16().into(), data: None, }, @@ -643,10 +646,11 @@ impl Web3ProxyError { ( StatusCode::BAD_GATEWAY, JsonRpcErrorData { - message: Cow::Owned(format!( + message: format!( "not enough soft limit available {}/{}", available, needed - )), + ) + .into(), code: StatusCode::BAD_GATEWAY.as_u16().into(), data: None, }, @@ -658,7 +662,7 @@ impl Web3ProxyError { ( StatusCode::NOT_FOUND, JsonRpcErrorData { - message: Cow::Borrowed("not found!"), + message: "not found!".into(), code: StatusCode::NOT_FOUND.as_u16().into(), data: None, }, @@ -669,7 +673,7 @@ impl Web3ProxyError { ( StatusCode::NOT_IMPLEMENTED, JsonRpcErrorData { - message: Cow::Borrowed("work in progress"), + message: "work in progress".into(), code: StatusCode::NOT_IMPLEMENTED.as_u16().into(), data: None, }, @@ -680,7 +684,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("Origin required"), + message: "Origin required".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -691,7 +695,7 @@ impl Web3ProxyError { ( StatusCode::FORBIDDEN, JsonRpcErrorData { - message: Cow::Owned(format!("Origin ({}) is not allowed!", origin)), + message: format!("Origin ({}) is not allowed!", origin).into(), code: StatusCode::FORBIDDEN.as_u16().into(), data: None, }, @@ -702,7 +706,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("parse bytes error!"), + message: "parse bytes error!".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -713,7 +717,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("parse message error!"), + message: "parse message error!".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -724,7 +728,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("unable to parse address"), + message: "unable to parse address".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -735,7 +739,7 @@ impl Web3ProxyError { ( StatusCode::PAYMENT_REQUIRED, JsonRpcErrorData { - message: Cow::Borrowed("Payment is required and user is not premium"), + message: "Payment is required and user is not premium".into(), code: StatusCode::PAYMENT_REQUIRED.as_u16().into(), data: None, }, @@ -767,7 +771,7 @@ impl Web3ProxyError { ( StatusCode::TOO_MANY_REQUESTS, JsonRpcErrorData { - message: Cow::Owned(msg), + message: msg.into(), code: StatusCode::TOO_MANY_REQUESTS.as_u16().into(), data: None, }, @@ -778,7 +782,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("redis error!"), + message: "redis error!".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -789,7 +793,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("Referer required"), + message: "Referer required".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -800,7 +804,7 @@ impl Web3ProxyError { ( StatusCode::FORBIDDEN, JsonRpcErrorData { - message: Cow::Owned(format!("Referer ({:?}) is not allowed", referer)), + message: format!("Referer ({:?}) is not allowed", referer).into(), code: StatusCode::FORBIDDEN.as_u16().into(), data: None, }, @@ -812,7 +816,7 @@ impl Web3ProxyError { StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { // TODO: is it safe to expose all of our anyhow strings? - message: Cow::Borrowed("semaphore acquire error"), + message: "semaphore acquire error".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -823,7 +827,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("error stat_sender sending response_stat"), + message: "error stat_sender sending response_stat".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -834,7 +838,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Owned(format!("de/serialization error! {}", err)), + message: format!("de/serialization error! {}", err).into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -852,7 +856,7 @@ impl Web3ProxyError { ( *status_code, JsonRpcErrorData { - message: err_msg.to_owned().into(), + message: err_msg.clone(), code: code.into(), data: None, }, @@ -904,7 +908,7 @@ impl Web3ProxyError { Self::UnknownKey => ( StatusCode::UNAUTHORIZED, JsonRpcErrorData { - message: Cow::Borrowed("unknown api key!"), + message: "unknown api key!".into(), code: StatusCode::UNAUTHORIZED.as_u16().into(), data: None, }, @@ -914,7 +918,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("User agent required"), + message: "User agent required".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -925,7 +929,7 @@ impl Web3ProxyError { ( StatusCode::FORBIDDEN, JsonRpcErrorData { - message: Cow::Owned(format!("User agent ({}) is not allowed!", ua)), + message: format!("User agent ({}) is not allowed!", ua).into(), code: StatusCode::FORBIDDEN.as_u16().into(), data: None, }, @@ -937,7 +941,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("user ids should always be non-zero"), + message: "user ids should always be non-zero".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -948,7 +952,7 @@ impl Web3ProxyError { ( StatusCode::BAD_REQUEST, JsonRpcErrorData { - message: Cow::Borrowed("verification error!"), + message: "verification error!".into(), code: StatusCode::BAD_REQUEST.as_u16().into(), data: None, }, @@ -959,7 +963,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("watch recv error!"), + message: "watch recv error!".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -970,7 +974,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: Cow::Borrowed("watch send error!"), + message: "watch send error!".into(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -997,7 +1001,7 @@ impl Web3ProxyError { ( StatusCode::INTERNAL_SERVER_ERROR, JsonRpcErrorData { - message: msg.to_owned().into(), + message: msg.clone(), code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(), data: None, }, @@ -1038,11 +1042,11 @@ impl IntoResponse for Web3ProxyError { } pub trait Web3ProxyErrorContext { - fn web3_context>(self, msg: S) -> Result; + fn web3_context>>(self, msg: S) -> Result; } impl Web3ProxyErrorContext for Option { - fn web3_context>(self, msg: S) -> Result { + fn web3_context>>(self, msg: S) -> Result { self.ok_or(Web3ProxyError::WithContext(None, msg.into())) } } @@ -1051,7 +1055,7 @@ impl Web3ProxyErrorContext for Result where E: Into, { - fn web3_context>(self, msg: S) -> Result { + fn web3_context>>(self, msg: S) -> Result { self.map_err(|err| Web3ProxyError::WithContext(Some(Box::new(err.into())), msg.into())) } } diff --git a/web3_proxy/src/frontend/rpc_proxy_ws.rs b/web3_proxy/src/frontend/rpc_proxy_ws.rs index dee85ee5..cc8a3225 100644 --- a/web3_proxy/src/frontend/rpc_proxy_ws.rs +++ b/web3_proxy/src/frontend/rpc_proxy_ws.rs @@ -264,7 +264,7 @@ async fn _websocket_handler_with_key( ) { (None, None, _) => Err(Web3ProxyError::StatusCode( StatusCode::BAD_REQUEST, - "this page is for rpcs".to_string(), + "this page is for rpcs".into(), None, )), (Some(redirect_public_url), _, None) => { @@ -277,7 +277,7 @@ async fn _websocket_handler_with_key( // i don't think this is possible Err(Web3ProxyError::StatusCode( StatusCode::UNAUTHORIZED, - "AUTHORIZATION header required".to_string(), + "AUTHORIZATION header required".into(), None, )) } else { @@ -295,7 +295,7 @@ async fn _websocket_handler_with_key( // any other combinations get a simple error _ => Err(Web3ProxyError::StatusCode( StatusCode::BAD_REQUEST, - "this page is for rpcs".to_string(), + "this page is for rpcs".into(), None, )), } diff --git a/web3_proxy/src/frontend/users/authentication.rs b/web3_proxy/src/frontend/users/authentication.rs index 44cfde21..c283d979 100644 --- a/web3_proxy/src/frontend/users/authentication.rs +++ b/web3_proxy/src/frontend/users/authentication.rs @@ -18,11 +18,11 @@ use entities::{balance, login, pending_login, referee, referrer, rpc_key, user}; use ethers::{prelude::Address, types::Bytes}; use hashbrown::HashMap; use http::StatusCode; -use log::{debug, warn, trace}; +use log::{debug, trace, warn}; use migration::sea_orm::prelude::{Decimal, Uuid}; use migration::sea_orm::{ - self, ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, QueryFilter, - TransactionTrait, + self, ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, IntoActiveModel, + QueryFilter, TransactionTrait, }; use serde_json::json; use siwe::{Message, VerificationOpts}; @@ -143,6 +143,54 @@ pub async fn user_login_get( Ok(message.into_response()) } +pub async fn register_new_user( + db_conn: &DatabaseConnection, + address: Address, +) -> anyhow::Result<(user::Model, rpc_key::Model, balance::Model)> { + // all or nothing + let txn = db_conn.begin().await?; + + // the only thing we need from them is an address + // everything else is optional + // TODO: different invite codes should allow different levels + // TODO: maybe decrement a count on the invite code? + // TODO: There will be two different transactions. The first one inserts the user, the second one marks the user as being referred + let new_user = user::ActiveModel { + address: sea_orm::Set(address.to_fixed_bytes().into()), + ..Default::default() + }; + + let new_user = new_user.insert(&txn).await?; + + // create the user's first api key + let rpc_secret_key = RpcSecretKey::new(); + + let user_rpc_key = rpc_key::ActiveModel { + user_id: sea_orm::Set(new_user.id), + secret_key: sea_orm::Set(rpc_secret_key.into()), + description: sea_orm::Set(None), + ..Default::default() + }; + + let user_rpc_key = user_rpc_key + .insert(&txn) + .await + .web3_context("Failed saving new user key")?; + + // create an empty balance entry + let user_balance = balance::ActiveModel { + user_id: sea_orm::Set(new_user.id), + ..Default::default() + }; + + let user_balance = user_balance.insert(&txn).await?; + + // save the user and key and balance to the database + txn.commit().await?; + + Ok((new_user, user_rpc_key, user_balance)) +} + /// `POST /user/login` - Register or login by posting a signed "siwe" message. /// It is recommended to save the returned bearer token in a cookie. /// The bearer token can be used to authenticate other requests, such as getting the user's stats or modifying the user's profile. @@ -264,50 +312,8 @@ pub async fn user_login_post( } } - let txn = db_conn.begin().await?; - - // First add a user - - // the only thing we need from them is an address - // everything else is optional - // TODO: different invite codes should allow different levels - // TODO: maybe decrement a count on the invite code? - // TODO: There will be two different transactions. The first one inserts the user, the second one marks the user as being referred - let caller = user::ActiveModel { - address: sea_orm::Set(our_msg.address.into()), - ..Default::default() - }; - - let caller = caller.insert(&txn).await?; - - // create the user's first api key - let rpc_secret_key = RpcSecretKey::new(); - - let user_rpc_key = rpc_key::ActiveModel { - user_id: sea_orm::Set(caller.id), - secret_key: sea_orm::Set(rpc_secret_key.into()), - description: sea_orm::Set(None), - ..Default::default() - }; - - let user_rpc_key = user_rpc_key - .insert(&txn) - .await - .web3_context("Failed saving new user key")?; - - // We should also create the balance entry ... - let user_balance = balance::ActiveModel { - user_id: sea_orm::Set(caller.id), - ..Default::default() - }; - user_balance.insert(&txn).await?; - - let user_rpc_keys = vec![user_rpc_key]; - - // Also add a part for the invite code, i.e. who invited this guy - - // save the user and key to the database - txn.commit().await?; + let (caller, caller_key, _) = + register_new_user(&db_conn, our_msg.address.into()).await?; let txn = db_conn.begin().await?; // First, optionally catch a referral code from the parameters if there is any @@ -336,7 +342,7 @@ pub async fn user_login_post( } txn.commit().await?; - (caller, user_rpc_keys, StatusCode::CREATED) + (caller, vec![caller_key], StatusCode::CREATED) } Some(caller) => { // Let's say that a user that exists can actually also redeem a key in retrospect... diff --git a/web3_proxy/src/frontend/users/payment.rs b/web3_proxy/src/frontend/users/payment.rs index f471d28d..cd5a9a33 100644 --- a/web3_proxy/src/frontend/users/payment.rs +++ b/web3_proxy/src/frontend/users/payment.rs @@ -1,6 +1,7 @@ use crate::app::Web3ProxyApp; use crate::errors::{Web3ProxyError, Web3ProxyResponse}; use crate::frontend::authorization::login_is_authorized; +use crate::frontend::users::authentication::register_new_user; use anyhow::Context; use axum::{ extract::Path, @@ -169,7 +170,7 @@ pub async fn user_balance_post( PaymentFactory::new(payment_factory_address, app.internal_provider().clone()); debug!( - "Payment Factor Filter is: {:?}", + "Payment Factory Filter: {:?}", payment_factory_contract.payment_received_filter() ); @@ -251,12 +252,13 @@ pub async fn user_balance_post( .one(&db_conn) .await? { - Some(x) => Ok(x), + Some(x) => x, None => { - // todo!("make their account"); - Err(Web3ProxyError::AccessDenied) + let (user, _, _) = register_new_user(&db_conn, recipient_account).await?; + + user } - }?; + }; // For now we only accept stablecoins // And we hardcode the peg (later we would have to depeg this, for example diff --git a/web3_proxy/src/jsonrpc.rs b/web3_proxy/src/jsonrpc.rs index 9b67c508..42fcc2ae 100644 --- a/web3_proxy/src/jsonrpc.rs +++ b/web3_proxy/src/jsonrpc.rs @@ -211,7 +211,7 @@ impl From<&'static str> for JsonRpcErrorData { fn from(value: &'static str) -> Self { Self { code: -32000, - message: Cow::Borrowed(value), + message: value.into(), data: None, } } @@ -221,7 +221,7 @@ impl From for JsonRpcErrorData { fn from(value: String) -> Self { Self { code: -32000, - message: Cow::Owned(value), + message: value.into(), data: None, } } @@ -273,7 +273,7 @@ impl JsonRpcForwardedResponse { result: None, error: Some(JsonRpcErrorData { code: code.unwrap_or(-32099), - message: Cow::Owned(message), + message: message.into(), // TODO: accept data as an argument data: None, }), @@ -319,10 +319,7 @@ impl JsonRpcForwardedResponse { data = err.data.clone(); } else if let Some(err) = err.as_serde_error() { // this is not an rpc error. keep it as an error - return Err(Web3ProxyError::BadResponse(format!( - "bad response: {}", - err - ))); + return Err(Web3ProxyError::BadResponse(err.to_string().into())); } else { return Err(anyhow::anyhow!("unexpected ethers error! {:?}", err).into()); } @@ -336,7 +333,7 @@ impl JsonRpcForwardedResponse { result: None, error: Some(JsonRpcErrorData { code, - message: Cow::Owned(message), + message: message.into(), data, }), }) diff --git a/web3_proxy/src/response_cache.rs b/web3_proxy/src/response_cache.rs index f9541672..3e68267c 100644 --- a/web3_proxy/src/response_cache.rs +++ b/web3_proxy/src/response_cache.rs @@ -5,7 +5,6 @@ use hashbrown::hash_map::DefaultHashBuilder; use moka::future::Cache; use serde_json::value::RawValue; use std::{ - borrow::Cow, hash::{BuildHasher, Hash, Hasher}, sync::Arc, }; @@ -211,10 +210,7 @@ impl TryFrom for JsonRpcErrorData { data = err.data.clone(); } else if let Some(err) = err.as_serde_error() { // this is not an rpc error. keep it as an error - return Err(Web3ProxyError::BadResponse(format!( - "bad response: {}", - err - ))); + return Err(Web3ProxyError::BadResponse(err.to_string().into())); } else { return Err(anyhow::anyhow!("unexpected ethers error! {:?}", err).into()); } @@ -224,7 +220,7 @@ impl TryFrom for JsonRpcErrorData { Ok(JsonRpcErrorData { code, - message: Cow::Owned(message), + message: message.into(), data, }) } diff --git a/web3_proxy/src/rpcs/many.rs b/web3_proxy/src/rpcs/many.rs index 5d0f2694..f47da3a7 100644 --- a/web3_proxy/src/rpcs/many.rs +++ b/web3_proxy/src/rpcs/many.rs @@ -27,7 +27,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; use serde_json::json; use serde_json::value::RawValue; -use std::borrow::Cow; use std::cmp::min_by_key; use std::fmt::{self, Display}; use std::sync::atomic::Ordering; @@ -1079,7 +1078,7 @@ impl Web3Rpcs { // TODO: what error code? // cloudflare gives {"jsonrpc":"2.0","error":{"code":-32043,"message":"Requested data cannot be older than 128 blocks."},"id":1} Err(JsonRpcErrorData { - message: Cow::Borrowed("Requested data is not available"), + message: "Requested data is not available".into(), code: -32043, data: None, } diff --git a/web3_proxy/src/stats/mod.rs b/web3_proxy/src/stats/mod.rs index 6409aead..8b1740f2 100644 --- a/web3_proxy/src/stats/mod.rs +++ b/web3_proxy/src/stats/mod.rs @@ -605,8 +605,7 @@ impl BufferedRpcQueryStats { // ================== let sender_latest_balance = match NonZeroU64::try_from(sender_rpc_entity.user_id) { Err(_) => Err(Web3ProxyError::BadResponse( - "Balance is not positive, although it was previously checked to be as such!" - .to_string(), + "Balance is not positive, although it was previously checked to be as such!".into(), )), // We don't do an get_or_insert, because technically we don't have the most up to date balance // Also let's keep things simple in terms of writing and getting. A single place writes it, multiple places can remove / poll it