From 5514f7b794cf61bec9721c26db7e3422e44b673b Mon Sep 17 00:00:00 2001 From: Noor Date: Mon, 30 Dec 2024 22:47:45 +0000 Subject: [PATCH 1/2] async solana client remove blocking on actix handler asynchronous mint method fix clippy on node comparison --- src/datastore.rs | 6 ++---- src/http_server.rs | 4 +--- src/solana.rs | 30 +++++++++++++++--------------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/datastore.rs b/src/datastore.rs index 9026611..22c29f7 100644 --- a/src/datastore.rs +++ b/src/datastore.rs @@ -245,10 +245,8 @@ impl State { pub async fn process_node_update(&self, (node_ip, node_info): (String, NodeInfo)) -> bool { let is_update_mine = node_ip.eq(&self.my_ip); let mut nodes = self.nodes.write().await; - let is_update_new = nodes - .get(&node_ip) - .map(|curr_info| node_info.is_newer_than(&curr_info)) - .unwrap_or(true); + let is_update_new = + nodes.get(&node_ip).map(|curr_info| node_info.is_newer_than(curr_info)).unwrap_or(true); if is_update_new { println!("Inserting: {}, {}", node_ip, node_info.to_json()); let _ = nodes.insert(node_ip, node_info); diff --git a/src/http_server.rs b/src/http_server.rs index 44e4caf..92b0f9e 100644 --- a/src/http_server.rs +++ b/src/http_server.rs @@ -66,10 +66,8 @@ async fn mint( ) -> impl Responder { let recipient = req.into_inner().wallet; state.increase_mint_requests().await; - let result = - web::block(move || sol_client.mint(&recipient).map_err(|e| e.to_string())).await.unwrap(); // TODO: check if this can get a BlockingError - match result { + match sol_client.mint(&recipient).await { Ok(s) => { state.increase_mints().await; HttpResponse::Ok().body(format!(r#"{{" signature": "{s} "}}"#)) diff --git a/src/solana.rs b/src/solana.rs index 39a0610..dd97d7b 100644 --- a/src/solana.rs +++ b/src/solana.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] use crate::{grpc::challenge::Keys, persistence::KeysFile}; -use solana_client::rpc_client::RpcClient; +use solana_client::nonblocking::rpc_client::RpcClient; use solana_program::program_pack::Pack; use solana_sdk::{ pubkey::Pubkey, signature::keypair::Keypair, signer::Signer, system_instruction, @@ -28,7 +28,7 @@ pub struct SolClient { impl SolClient { pub async fn create_new_token() -> Self { - let client = RpcClient::new(RPC_URL); + let client = RpcClient::new(RPC_URL.to_string()); let keypair = Keypair::new(); let token = create_token(&client, &keypair).await; Self { client, keypair, token } @@ -42,10 +42,10 @@ impl SolClient { self.get_keys().into() } - pub fn mint(&self, recipient: &str) -> Result> { + pub async fn mint(&self, recipient: &str) -> Result> { use std::str::FromStr; let recipient = solana_sdk::pubkey::Pubkey::from_str(recipient)?; - let associated_token_address = self.create_token_account(&recipient)?; + let associated_token_address = self.create_token_account(&recipient).await?; let mint_to_instruction = mint_to( &spl_token::id(), &self.token, @@ -59,32 +59,32 @@ impl SolClient { &[mint_to_instruction], Some(&self.keypair.pubkey()), &[&self.keypair], - self.client.get_latest_blockhash()?, + self.client.get_latest_blockhash().await?, ); - let signature = self.client.send_and_confirm_transaction(&transaction)?; + let signature = self.client.send_and_confirm_transaction(&transaction).await?; Ok(signature.to_string()) } - fn create_token_account( + async fn create_token_account( &self, recipient: &Pubkey, ) -> Result> { let address = get_associated_token_address(recipient, &self.token); - if self.client.get_account(&address).is_err() { + if self.client.get_account(&address).await.is_err() { let create_token_account_instruction = create_associated_token_account( &self.keypair.pubkey(), recipient, &self.token, &spl_token::id(), ); - let recent_blockhash = self.client.get_latest_blockhash()?; + let recent_blockhash = self.client.get_latest_blockhash().await?; let tx = Transaction::new_signed_with_payer( &[create_token_account_instruction], Some(&self.keypair.pubkey()), &[&self.keypair], recent_blockhash, ); - self.client.send_and_confirm_transaction(&tx)?; + self.client.send_and_confirm_transaction(&tx).await?; } Ok(address) } @@ -114,7 +114,7 @@ impl TryFrom for SolClient { }; let token = Pubkey::from_str(&keys.token_address) .map_err(|_| "Could not parse wallet address.".to_string())?; - Ok(Self { client: RpcClient::new(RPC_URL), keypair, token }) + Ok(Self { client: RpcClient::new(RPC_URL.to_string()), keypair, token }) } } @@ -131,7 +131,7 @@ async fn wait_for_sol(client: &RpcClient, pubkey: &Pubkey) { println!("Waiting to receive 0.01 SOL in address {pubkey}"); loop { sleep(Duration::from_secs(30)).await; - match client.get_balance(pubkey) { + match client.get_balance(pubkey).await { Ok(balance) => { println!("Got {balance} lamports."); if balance > 10_000_000 { @@ -148,7 +148,7 @@ async fn create_token(client: &RpcClient, keypair: &Keypair) -> Pubkey { let mint_keypair = Keypair::new(); let payer = Keypair::from_base58_string(&keypair.to_base58_string()); - let mint_rent = client.get_minimum_balance_for_rent_exemption(Mint::LEN).unwrap(); + let mint_rent = client.get_minimum_balance_for_rent_exemption(Mint::LEN).await.unwrap(); let create_mint_account_ix = system_instruction::create_account( &payer.pubkey(), @@ -162,7 +162,7 @@ async fn create_token(client: &RpcClient, keypair: &Keypair) -> Pubkey { initialize_mint(&spl_token::id(), &mint_keypair.pubkey(), &payer.pubkey(), None, 9) .unwrap(); - let recent_blockhash = client.get_latest_blockhash().unwrap(); + let recent_blockhash = client.get_latest_blockhash().await.unwrap(); let tx = Transaction::new_signed_with_payer( &[create_mint_account_ix, init_mint_ix], Some(&payer.pubkey()), @@ -170,7 +170,7 @@ async fn create_token(client: &RpcClient, keypair: &Keypair) -> Pubkey { recent_blockhash, ); - let signature = client.send_and_confirm_transaction(&tx).unwrap(); + let signature = client.send_and_confirm_transaction(&tx).await.unwrap(); println!("Mint created: {}", mint_keypair.pubkey()); println!("Transaction signature: {}", signature); -- 2.43.0 From f67146aa13677045b08f13baeb235f5a9f307a99 Mon Sep 17 00:00:00 2001 From: Noor Date: Tue, 31 Dec 2024 12:43:12 +0000 Subject: [PATCH 2/2] minting state implement 1 minting at a time to prevent ddos enhanced json response --- src/datastore.rs | 18 +++++++++++++++++- src/http_server.rs | 14 +++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/datastore.rs b/src/datastore.rs index 22c29f7..37c3aaa 100644 --- a/src/datastore.rs +++ b/src/datastore.rs @@ -2,6 +2,7 @@ use crate::persistence::{SealError, SealedFile}; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, TimestampSeconds}; use std::collections::{HashMap, HashSet}; +use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use tokio::sync::RwLock; @@ -95,6 +96,7 @@ pub struct State { nodes: RwLock>, conns: RwLock>, timeout: u64, + is_minting: AtomicBool, } impl State { @@ -102,7 +104,13 @@ impl State { let mut nodes = HashMap::new(); let my_info = NodeInfo::load(); nodes.insert(my_ip.clone(), my_info); - Self { my_ip, timeout, nodes: RwLock::new(nodes), conns: RwLock::new(HashSet::new()) } + Self { + my_ip, + timeout, + nodes: RwLock::new(nodes), + conns: RwLock::new(HashSet::new()), + is_minting: AtomicBool::new(false), + } } pub async fn add_conn(&self, ip: &str) { @@ -203,6 +211,14 @@ impl State { Duration::from_secs(self.timeout) } + pub fn is_minting(&self) -> bool { + self.is_minting.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst).is_err() + } + + pub fn release_minting(&self) { + self.is_minting.store(false, Ordering::SeqCst); + } + pub async fn get_my_info(&self) -> NodeInfo { let nodes = self.nodes.read().await; nodes.get(&self.my_ip).cloned().unwrap_or(NodeInfo::new_empty()) diff --git a/src/http_server.rs b/src/http_server.rs index 92b0f9e..dccc585 100644 --- a/src/http_server.rs +++ b/src/http_server.rs @@ -2,6 +2,7 @@ use crate::{datastore, datastore::State, solana::SolClient}; use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; +use serde_json::json; use std::sync::Arc; const HOMEPAGE: &str = include_str!("HOMEPAGE.md"); @@ -67,12 +68,19 @@ async fn mint( let recipient = req.into_inner().wallet; state.increase_mint_requests().await; - match sol_client.mint(&recipient).await { + if state.is_minting() { + return HttpResponse::TooManyRequests().json(json!({ "error": "already mint processing" })); + } + + let mint_res = sol_client.mint(&recipient).await; + + state.release_minting(); + match mint_res { Ok(s) => { state.increase_mints().await; - HttpResponse::Ok().body(format!(r#"{{" signature": "{s} "}}"#)) + HttpResponse::Ok().json(json!({"signature": s})) } - Err(e) => HttpResponse::InternalServerError().body(format!(r#"{{ "error": "{e}" }}"#)), + Err(e) => HttpResponse::InternalServerError().json(json!({ "error": e.to_string() })), } } -- 2.43.0