From d64761403bc7007178d0f37b74ab817083dd564b Mon Sep 17 00:00:00 2001 From: Bryan Stitt Date: Tue, 30 May 2023 23:17:05 -0700 Subject: [PATCH] Cow instead of String --- web3_proxy/src/admin_queries.rs | 12 ++-- web3_proxy/src/app/mod.rs | 15 +++-- web3_proxy/src/block_number.rs | 4 +- web3_proxy/src/errors.rs | 2 +- web3_proxy/src/frontend/admin.rs | 32 +++++---- web3_proxy/src/frontend/rpc_proxy_ws.rs | 6 +- .../src/frontend/users/authentication.rs | 11 ++-- web3_proxy/src/frontend/users/payment.rs | 65 +++++++++++-------- web3_proxy/src/frontend/users/subuser.rs | 22 +++---- web3_proxy/src/http_params.rs | 4 +- web3_proxy/src/jsonrpc.rs | 2 +- web3_proxy/src/stats/db_queries.rs | 2 +- web3_proxy/src/stats/influxdb_queries.rs | 21 +++--- 13 files changed, 108 insertions(+), 90 deletions(-) diff --git a/web3_proxy/src/admin_queries.rs b/web3_proxy/src/admin_queries.rs index 08d6e111..017ac155 100644 --- a/web3_proxy/src/admin_queries.rs +++ b/web3_proxy/src/admin_queries.rs @@ -29,18 +29,16 @@ pub async fn query_admin_modify_usertier<'a>( let user_address: Vec = params .get("user_address") .ok_or_else(|| { - Web3ProxyError::BadRequest("Unable to find user_address key in request".to_string()) + Web3ProxyError::BadRequest("Unable to find user_address key in request".into()) })? .parse::
() .map_err(|_| { - Web3ProxyError::BadRequest("Unable to parse user_address as an Address".to_string()) + Web3ProxyError::BadRequest("Unable to parse user_address as an Address".into()) })? .to_fixed_bytes() .into(); let user_tier_title = params.get("user_tier_title").ok_or_else(|| { - Web3ProxyError::BadRequest( - "Unable to get the user_tier_title key from the request".to_string(), - ) + Web3ProxyError::BadRequest("Unable to get the user_tier_title key from the request".into()) })?; // Prepare output body @@ -84,7 +82,7 @@ pub async fn query_admin_modify_usertier<'a>( .one(&db_conn) .await? .ok_or(Web3ProxyError::BadRequest( - "No user with this id found".to_string(), + "No user with this id found".into(), ))?; // Return early if the target user_tier_id is the same as the original user_tier_id response_body.insert( @@ -98,7 +96,7 @@ pub async fn query_admin_modify_usertier<'a>( .one(&db_conn) .await? .ok_or(Web3ProxyError::BadRequest( - "User Tier name was not found".to_string(), + "User Tier name was not found".into(), ))?; if user.user_tier_id == new_user_tier.id { diff --git a/web3_proxy/src/app/mod.rs b/web3_proxy/src/app/mod.rs index b76f06fe..5edad18e 100644 --- a/web3_proxy/src/app/mod.rs +++ b/web3_proxy/src/app/mod.rs @@ -739,6 +739,13 @@ impl Web3ProxyApp { self.watch_consensus_head_receiver.clone() } + /// an ethers provider that you can use with ether's abigen. + /// this works for now, but I don't like it + /// TODO: I would much prefer we figure out the traits and `impl JsonRpcClient for Web3ProxyApp` + pub fn internal_provider(&self) -> &Arc { + &self.internal_provider + } + pub async fn prometheus_metrics(&self) -> String { let globals = HashMap::new(); // TODO: what globals? should this be the hostname or what? @@ -1417,19 +1424,19 @@ impl Web3ProxyApp { .as_array() .ok_or_else(|| { Web3ProxyError::BadRequest( - "Unable to get array from params".to_string(), + "Unable to get array from params".into(), ) })? .get(0) .ok_or_else(|| { Web3ProxyError::BadRequest( - "Unable to get item 0 from params".to_string(), + "Unable to get item 0 from params".into(), ) })? .as_str() .ok_or_else(|| { Web3ProxyError::BadRequest( - "Unable to get string from params item 0".to_string(), + "Unable to get string from params item 0".into(), ) })?; @@ -1546,7 +1553,7 @@ impl Web3ProxyApp { .map_err(|x| { trace!("bad request: {:?}", x); Web3ProxyError::BadRequest( - "param 0 could not be read as H256".to_string(), + "param 0 could not be read as H256".into(), ) })?; diff --git a/web3_proxy/src/block_number.rs b/web3_proxy/src/block_number.rs index f93a904b..999daf78 100644 --- a/web3_proxy/src/block_number.rs +++ b/web3_proxy/src/block_number.rs @@ -174,10 +174,10 @@ pub async fn block_needed( // TODO: jsonrpc has a specific code for this let obj = params .get_mut(0) - .ok_or_else(|| Web3ProxyError::BadRequest("invalid format. no params".to_string()))? + .ok_or_else(|| Web3ProxyError::BadRequest("invalid format. no params".into()))? .as_object_mut() .ok_or_else(|| { - Web3ProxyError::BadRequest("invalid format. params not object".to_string()) + Web3ProxyError::BadRequest("invalid format. params not object".into()) })?; if obj.contains_key("blockHash") { diff --git a/web3_proxy/src/errors.rs b/web3_proxy/src/errors.rs index 8b6fdca2..a8338f55 100644 --- a/web3_proxy/src/errors.rs +++ b/web3_proxy/src/errors.rs @@ -41,7 +41,7 @@ pub enum Web3ProxyError { Anyhow(anyhow::Error), #[error(ignore)] #[from(ignore)] - BadRequest(String), + BadRequest(Cow<'static, str>), #[error(ignore)] #[from(ignore)] BadResponse(String), diff --git a/web3_proxy/src/frontend/admin.rs b/web3_proxy/src/frontend/admin.rs index bb2b82d7..f667ebf9 100644 --- a/web3_proxy/src/frontend/admin.rs +++ b/web3_proxy/src/frontend/admin.rs @@ -67,32 +67,30 @@ pub async fn admin_increase_balance( let user_address: Address = params .get("user_address") .ok_or_else(|| { - Web3ProxyError::BadRequest("Unable to find user_address key in request".to_string()) + Web3ProxyError::BadRequest("Unable to find user_address key in request".into()) })? .parse::
() .map_err(|_| { - Web3ProxyError::BadRequest("Unable to parse user_address as an Address".to_string()) + Web3ProxyError::BadRequest("Unable to parse user_address as an Address".into()) })?; let user_address_bytes: Vec = user_address.to_fixed_bytes().into(); let note: String = params .get("note") - .ok_or_else(|| { - Web3ProxyError::BadRequest("Unable to find 'note' key in request".to_string()) - })? + .ok_or_else(|| Web3ProxyError::BadRequest("Unable to find 'note' key in request".into()))? .parse::() - .map_err(|_| { - Web3ProxyError::BadRequest("Unable to parse 'note' as a String".to_string()) - })?; + .map_err(|_| Web3ProxyError::BadRequest("Unable to parse 'note' as a String".into()))?; // Get the amount from params // Decimal::from_str let amount: Decimal = params .get("amount") .ok_or_else(|| { - Web3ProxyError::BadRequest("Unable to get the amount key from the request".to_string()) + Web3ProxyError::BadRequest("Unable to get the amount key from the request".into()) }) .map(|x| Decimal::from_str(x))? .map_err(|err| { - Web3ProxyError::BadRequest(format!("Unable to parse amount from the request {:?}", err)) + Web3ProxyError::BadRequest( + format!("Unable to parse amount from the request {:?}", err).into(), + ) })?; let user_entry: user::Model = user::Entity::find() @@ -100,7 +98,7 @@ pub async fn admin_increase_balance( .one(&db_conn) .await? .ok_or(Web3ProxyError::BadRequest( - "No user with this id found".to_string(), + "No user with this id found".into(), ))?; let increase_balance_receipt = admin_increase_balance_receipt::ActiveModel { @@ -211,22 +209,22 @@ pub async fn admin_login_get( let admin_address: Address = params .get("admin_address") .ok_or_else(|| { - Web3ProxyError::BadRequest("Unable to find admin_address key in request".to_string()) + Web3ProxyError::BadRequest("Unable to find admin_address key in request".into()) })? .parse::
() .map_err(|_err| { - Web3ProxyError::BadRequest("Unable to parse admin_address as an Address".to_string()) + Web3ProxyError::BadRequest("Unable to parse admin_address as an Address".into()) })?; // Fetch the user_address parameter from the login string ... (as who we want to be logging in ...) let user_address: Vec = params .get("user_address") .ok_or_else(|| { - Web3ProxyError::BadRequest("Unable to find user_address key in request".to_string()) + Web3ProxyError::BadRequest("Unable to find user_address key in request".into()) })? .parse::
() .map_err(|_err| { - Web3ProxyError::BadRequest("Unable to parse user_address as an Address".to_string()) + Web3ProxyError::BadRequest("Unable to parse user_address as an Address".into()) })? .to_fixed_bytes() .into(); @@ -277,7 +275,7 @@ pub async fn admin_login_get( .one(db_replica.as_ref()) .await? .ok_or(Web3ProxyError::BadRequest( - "Could not find user in db".to_string(), + "Could not find user in db".into(), ))?; // TODO: Gotta check if encoding messes up things maybe ... @@ -288,7 +286,7 @@ pub async fn admin_login_get( .one(db_replica.as_ref()) .await? .ok_or(Web3ProxyError::BadRequest( - "Could not find admin in db".to_string(), + "Could not find admin in db".into(), ))?; // Note that the admin is trying to log in as this user diff --git a/web3_proxy/src/frontend/rpc_proxy_ws.rs b/web3_proxy/src/frontend/rpc_proxy_ws.rs index 0880102d..fc376e12 100644 --- a/web3_proxy/src/frontend/rpc_proxy_ws.rs +++ b/web3_proxy/src/frontend/rpc_proxy_ws.rs @@ -415,9 +415,9 @@ async fn handle_socket_payload( Ok(response.into()) } - Err(err) => Err(Web3ProxyError::BadRequest(f!( - "incorrect params given for eth_unsubscribe. {err:?}" - ))), + Err(err) => Err(Web3ProxyError::BadRequest( + f!("incorrect params given for eth_unsubscribe. {err:?}").into(), + )), } } _ => app diff --git a/web3_proxy/src/frontend/users/authentication.rs b/web3_proxy/src/frontend/users/authentication.rs index 805bec0c..3c3321d7 100644 --- a/web3_proxy/src/frontend/users/authentication.rs +++ b/web3_proxy/src/frontend/users/authentication.rs @@ -352,10 +352,13 @@ pub async fn user_login_post( .filter(referrer::Column::ReferralCode.eq(referral_code)) .one(db_replica.as_ref()) .await? - .ok_or(Web3ProxyError::BadRequest(format!( - "The referral_link you provided does not exist {}", - referral_code - )))?; + .ok_or(Web3ProxyError::BadRequest( + format!( + "The referral_link you provided does not exist {}", + referral_code + ) + .into(), + ))?; // Create a new item in the database, // marking this guy as the referrer (and ignoring a duplicate insert, if there is any...) diff --git a/web3_proxy/src/frontend/users/payment.rs b/web3_proxy/src/frontend/users/payment.rs index 98621abc..eb83cfb1 100644 --- a/web3_proxy/src/frontend/users/payment.rs +++ b/web3_proxy/src/frontend/users/payment.rs @@ -38,6 +38,8 @@ abigen!( PaymentFactory, r#"[ event PaymentReceived(address indexed account, address token, uint256 amount) + account_to_payment_address(address) -> address + payment_address_to_account(address) -> address ]"#, ); @@ -137,30 +139,31 @@ pub async fn user_balance_post( // Let's say that for now, 1 credit is equivalent to 1 dollar (assuming any stablecoin has a 1:1 peg) let tx_hash: H256 = params .remove("tx_hash") - // TODO: map_err so this becomes a 500. routing must be bad .ok_or(Web3ProxyError::BadRequest( - "You have not provided the tx_hash in which you paid in".to_string(), + "You have not provided a tx_hash".into(), ))? .parse() - .context("unable to parse tx_hash")?; + .map_err(|err| { + Web3ProxyError::BadRequest(format!("unable to parse tx_hash: {}", err).into()) + })?; let db_conn = app.db_conn().context("query_user_stats needs a db")?; - // let db_replica = app - // .db_replica() - // .context("query_user_stats needs a db replica")?; // Return straight false if the tx was already added ... - // TODO: TxHash being string - let receipt = increase_on_chain_balance_receipt::Entity::find() + if increase_on_chain_balance_receipt::Entity::find() .filter(increase_on_chain_balance_receipt::Column::TxHash.eq(tx_hash.encode_hex())) .one(&db_conn) - .await?; - if receipt.is_some() { - return Err(Web3ProxyError::BadRequest( - "The transaction you provided has already been accounted for!".to_string(), - )); + .await? + .is_some() + { + let response = Json(json!({ + "result": "success", + "message": "this transaction was already in the database", + })) + .into_response(); + + return Ok(response); } - debug!("Receipt: {:?}", receipt); // Iterate through all logs, and add them to the transaction list if there is any // Address will be hardcoded in the config @@ -170,18 +173,32 @@ pub async fn user_balance_post( trace!("Transaction receipt: {:#?}", transaction_receipt); - // there is no need to check accepted tokens. the smart contract already does that + // there is no need to check accepted tokens. the smart contract already reverts if the token isn't accepted - // parse the log from the transaction receipt to get the token address, - /* - event PaymentReceived: - account: indexed(address) - token: address - amount: uint256 - */ + let payment_factory_address = app + .config + .deposit_factory_contract + .context("A deposit_contract must be provided in the config to parse payments")?; + + let payment_factory = + PaymentFactory::new(payment_factory_address, app.internal_provider().clone()); + + // TODO: parse the log from the transaction receipt + + // let deposit_log = payment_factory.payment_received_filter().topic; + + // // // TODO: do a quick check that this transaction contains the required log + // if !transaction_receipt.logs_bloom.contains_input(deposit_log) { + // return Err(Web3ProxyError::BadRequest("no matching logs found".into())); + // } + + // TODO: get the payment token address + // TODO: get the account the payment was received on behalf of (any account could have sent it) // TODO: get the decimals for the token + // TODO: payment_factory.payment_address_to_account(...).call(); + // Go through all logs, this should prob capture it, // At least according to this SE logs are just concatenations of the underlying types (like a struct..) // https://ethereum.stackexchange.com/questions/87653/how-to-decode-log-event-of-my-transaction-log @@ -380,8 +397,4 @@ pub async fn user_balance_post( return Ok(response); } */ - - Err(Web3ProxyError::BadRequest( - "No such transaction was found, or token is not supported!".to_string(), - )) } diff --git a/web3_proxy/src/frontend/users/subuser.rs b/web3_proxy/src/frontend/users/subuser.rs index 56c6ac42..bc59ce1b 100644 --- a/web3_proxy/src/frontend/users/subuser.rs +++ b/web3_proxy/src/frontend/users/subuser.rs @@ -111,7 +111,7 @@ pub async fn get_subusers( .remove("rpc_key") // TODO: map_err so this becomes a 500. routing must be bad .ok_or(Web3ProxyError::BadRequest( - "You have not provided the 'rpc_key' whose access to modify".to_string(), + "You have not provided the 'rpc_key' whose access to modify".into(), ))? .parse() .context(format!("unable to parse rpc_key {:?}", params))?; @@ -122,7 +122,7 @@ pub async fn get_subusers( .one(db_replica.as_ref()) .await? .ok_or(Web3ProxyError::BadRequest( - "The provided RPC key cannot be found".to_string(), + "The provided RPC key cannot be found".into(), ))?; // Get all secondary users that have access to this rpc key @@ -188,7 +188,7 @@ pub async fn modify_subuser( .remove("rpc_key") // TODO: map_err so this becomes a 500. routing must be bad .ok_or(Web3ProxyError::BadRequest( - "You have not provided the 'rpc_key' whose access to modify".to_string(), + "You have not provided the 'rpc_key' whose access to modify".into(), ))? .parse::() .context(format!("unable to parse rpc_key {:?}", params))?; @@ -198,7 +198,7 @@ pub async fn modify_subuser( .remove("subuser_address") // TODO: map_err so this becomes a 500. routing must be bad .ok_or(Web3ProxyError::BadRequest( - "You have not provided the 'user_address' whose access to modify".to_string(), + "You have not provided the 'user_address' whose access to modify".into(), ))? .parse() .context(format!("unable to parse subuser_address {:?}", params))?; @@ -209,14 +209,14 @@ pub async fn modify_subuser( .remove("new_status") // TODO: map_err so this becomes a 500. routing must be bad .ok_or(Web3ProxyError::BadRequest( - "You have not provided the new_stats key in the request".to_string(), + "You have not provided the new_stats key in the request".into(), ))? .as_str() { "upsert" => Ok(true), "remove" => Ok(false), _ => Err(Web3ProxyError::BadRequest( - "'new_status' must be one of 'upsert' or 'remove'".to_string(), + "'new_status' must be one of 'upsert' or 'remove'".into(), )), }?; @@ -224,7 +224,7 @@ pub async fn modify_subuser( .remove("new_role") // TODO: map_err so this becomes a 500. routing must be bad .ok_or(Web3ProxyError::BadRequest( - "You have not provided the new_role key in the request".to_string(), + "You have not provided the new_role key in the request".into(), ))? .as_str() { @@ -235,7 +235,7 @@ pub async fn modify_subuser( "admin" => Ok(Role::Admin), "collaborator" => Ok(Role::Collaborator), _ => Err(Web3ProxyError::BadRequest( - "'new_role' must be one of 'owner', 'admin', 'collaborator'".to_string(), + "'new_role' must be one of 'owner', 'admin', 'collaborator'".into(), )), }?; @@ -253,13 +253,13 @@ pub async fn modify_subuser( .one(db_replica.as_ref()) .await? .ok_or(Web3ProxyError::BadRequest( - "Provided RPC key does not exist!".to_owned(), + "Provided RPC key does not exist!".into(), ))?; // Make sure that the user owns the rpc_key_entity if rpc_key_entity.user_id != user.id { return Err(Web3ProxyError::BadRequest( - "you must own the RPC for which you are giving permissions out".to_string(), + "you must own the RPC for which you are giving permissions out".into(), )); } @@ -308,7 +308,7 @@ pub async fn modify_subuser( Some(subuser) => { if subuser.id == user.id { return Err(Web3ProxyError::BadRequest( - "you cannot make a subuser out of yourself".to_string(), + "you cannot make a subuser out of yourself".into(), )); } diff --git a/web3_proxy/src/http_params.rs b/web3_proxy/src/http_params.rs index aa0a245e..be438545 100644 --- a/web3_proxy/src/http_params.rs +++ b/web3_proxy/src/http_params.rs @@ -224,7 +224,7 @@ pub fn get_query_window_seconds_from_params( |query_window_seconds: &String| { // parse the given timestamp query_window_seconds.parse::().map_err(|_| { - Web3ProxyError::BadRequest("Unable to parse query_window_seconds".to_string()) + Web3ProxyError::BadRequest("Unable to parse query_window_seconds".into()) }) }, ) @@ -259,7 +259,7 @@ pub fn get_stats_column_from_params(params: &HashMap) -> Web3Pro sum_response_millis, \ sum_credits_used, \ balance" - .to_string(), + .into(), )), } }, diff --git a/web3_proxy/src/jsonrpc.rs b/web3_proxy/src/jsonrpc.rs index 1f67de1c..eb7a01a7 100644 --- a/web3_proxy/src/jsonrpc.rs +++ b/web3_proxy/src/jsonrpc.rs @@ -84,7 +84,7 @@ impl JsonRpcRequestEnum { Self::Batch(x) => match x.first() { Some(x) => Ok(x.id.clone()), None => Err(Web3ProxyError::BadRequest( - "no requests in the batch".to_string(), + "no requests in the batch".into(), )), }, Self::Single(x) => Ok(x.id.clone()), diff --git a/web3_proxy/src/stats/db_queries.rs b/web3_proxy/src/stats/db_queries.rs index be9dc511..8a1b0315 100644 --- a/web3_proxy/src/stats/db_queries.rs +++ b/web3_proxy/src/stats/db_queries.rs @@ -208,7 +208,7 @@ pub async fn query_user_stats<'a>( // TODO: move getting the param and checking the bearer token into a helper function if let Some(rpc_key_id) = params.get("rpc_key_id") { let rpc_key_id = rpc_key_id.parse::().map_err(|e| { - Web3ProxyError::BadRequest(format!("Unable to parse rpc_key_id. {:?}", e)) + Web3ProxyError::BadRequest(format!("Unable to parse rpc_key_id. {}", e).into()) })?; response_body.insert("rpc_key_id", serde_json::Value::Number(rpc_key_id.into())); diff --git a/web3_proxy/src/stats/influxdb_queries.rs b/web3_proxy/src/stats/influxdb_queries.rs index cace3d29..e9fda7d2 100644 --- a/web3_proxy/src/stats/influxdb_queries.rs +++ b/web3_proxy/src/stats/influxdb_queries.rs @@ -33,18 +33,18 @@ pub async fn query_user_stats<'a>( params: &'a HashMap, stat_response_type: StatType, ) -> Web3ProxyResponse { - let user_id = match bearer { - Some(inner_bearer) => { - let (user, _semaphore) = app.bearer_is_authorized(inner_bearer.0 .0).await?; - user.id + let (user_id, _semaphore) = match bearer { + Some(TypedHeader(Authorization(bearer))) => { + let (user, semaphore) = app.bearer_is_authorized(bearer).await?; + (user.id, Some(semaphore)) } - None => 0, + None => (0, None), }; - // Return an error if the bearer is set, but the StatType is Detailed + // Return an error if the bearer is **not** set, but the StatType is Detailed if stat_response_type == StatType::Detailed && user_id == 0 { return Err(Web3ProxyError::BadRequest( - "Detailed Stats Response requires you to authorize with a bearer token".to_owned(), + "Detailed Stats Response requires you to authorize with a bearer token".into(), )); } @@ -66,8 +66,7 @@ pub async fn query_user_stats<'a>( // Return a bad request if query_start == query_stop, because then the query is empty basically if query_start == query_stop { return Err(Web3ProxyError::BadRequest( - "Start and Stop date cannot be equal. Please specify a (different) start date." - .to_owned(), + "Start and Stop date cannot be equal. Please specify a (different) start date.".into(), )); } @@ -128,7 +127,7 @@ pub async fn query_user_stats<'a>( if user_rpc_keys.is_empty() { return Err(Web3ProxyError::BadRequest( - "User has no secret RPC keys yet".to_string(), + "User has no secret RPC keys yet".into(), )); } @@ -481,7 +480,7 @@ pub async fn query_user_stats<'a>( if let Some(rpc_key_id) = params.get("rpc_key_id") { let rpc_key_id = rpc_key_id .parse::() - .map_err(|_| Web3ProxyError::BadRequest("Unable to parse rpc_key_id".to_string()))?; + .map_err(|_| Web3ProxyError::BadRequest("Unable to parse rpc_key_id".into()))?; response_body.insert("rpc_key_id", serde_json::Value::Number(rpc_key_id.into())); }