Compare commits
2 Commits
8226f03e7c
...
f67146aa13
Author | SHA1 | Date | |
---|---|---|---|
f67146aa13 | |||
5514f7b794 |
@ -2,6 +2,7 @@ use crate::persistence::{SealError, SealedFile};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::{serde_as, TimestampSeconds};
|
use serde_with::{serde_as, TimestampSeconds};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
@ -95,6 +96,7 @@ pub struct State {
|
|||||||
nodes: RwLock<HashMap<IP, NodeInfo>>,
|
nodes: RwLock<HashMap<IP, NodeInfo>>,
|
||||||
conns: RwLock<HashSet<IP>>,
|
conns: RwLock<HashSet<IP>>,
|
||||||
timeout: u64,
|
timeout: u64,
|
||||||
|
is_minting: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
@ -102,7 +104,13 @@ impl State {
|
|||||||
let mut nodes = HashMap::new();
|
let mut nodes = HashMap::new();
|
||||||
let my_info = NodeInfo::load();
|
let my_info = NodeInfo::load();
|
||||||
nodes.insert(my_ip.clone(), my_info);
|
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) {
|
pub async fn add_conn(&self, ip: &str) {
|
||||||
@ -203,6 +211,14 @@ impl State {
|
|||||||
Duration::from_secs(self.timeout)
|
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 {
|
pub async fn get_my_info(&self) -> NodeInfo {
|
||||||
let nodes = self.nodes.read().await;
|
let nodes = self.nodes.read().await;
|
||||||
nodes.get(&self.my_ip).cloned().unwrap_or(NodeInfo::new_empty())
|
nodes.get(&self.my_ip).cloned().unwrap_or(NodeInfo::new_empty())
|
||||||
@ -245,10 +261,8 @@ impl State {
|
|||||||
pub async fn process_node_update(&self, (node_ip, node_info): (String, NodeInfo)) -> bool {
|
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 is_update_mine = node_ip.eq(&self.my_ip);
|
||||||
let mut nodes = self.nodes.write().await;
|
let mut nodes = self.nodes.write().await;
|
||||||
let is_update_new = nodes
|
let is_update_new =
|
||||||
.get(&node_ip)
|
nodes.get(&node_ip).map(|curr_info| node_info.is_newer_than(curr_info)).unwrap_or(true);
|
||||||
.map(|curr_info| node_info.is_newer_than(&curr_info))
|
|
||||||
.unwrap_or(true);
|
|
||||||
if is_update_new {
|
if is_update_new {
|
||||||
println!("Inserting: {}, {}", node_ip, node_info.to_json());
|
println!("Inserting: {}, {}", node_ip, node_info.to_json());
|
||||||
let _ = nodes.insert(node_ip, node_info);
|
let _ = nodes.insert(node_ip, node_info);
|
||||||
|
@ -2,6 +2,7 @@ use crate::{datastore, datastore::State, solana::SolClient};
|
|||||||
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
|
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::json;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
const HOMEPAGE: &str = include_str!("HOMEPAGE.md");
|
const HOMEPAGE: &str = include_str!("HOMEPAGE.md");
|
||||||
@ -66,15 +67,20 @@ async fn mint(
|
|||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let recipient = req.into_inner().wallet;
|
let recipient = req.into_inner().wallet;
|
||||||
state.increase_mint_requests().await;
|
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 {
|
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) => {
|
Ok(s) => {
|
||||||
state.increase_mints().await;
|
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() })),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use crate::{grpc::challenge::Keys, persistence::KeysFile};
|
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_program::program_pack::Pack;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
pubkey::Pubkey, signature::keypair::Keypair, signer::Signer, system_instruction,
|
pubkey::Pubkey, signature::keypair::Keypair, signer::Signer, system_instruction,
|
||||||
@ -28,7 +28,7 @@ pub struct SolClient {
|
|||||||
|
|
||||||
impl SolClient {
|
impl SolClient {
|
||||||
pub async fn create_new_token() -> Self {
|
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 keypair = Keypair::new();
|
||||||
let token = create_token(&client, &keypair).await;
|
let token = create_token(&client, &keypair).await;
|
||||||
Self { client, keypair, token }
|
Self { client, keypair, token }
|
||||||
@ -42,10 +42,10 @@ impl SolClient {
|
|||||||
self.get_keys().into()
|
self.get_keys().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mint(&self, recipient: &str) -> Result<String, Box<dyn std::error::Error>> {
|
pub async fn mint(&self, recipient: &str) -> Result<String, Box<dyn std::error::Error>> {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
let recipient = solana_sdk::pubkey::Pubkey::from_str(recipient)?;
|
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(
|
let mint_to_instruction = mint_to(
|
||||||
&spl_token::id(),
|
&spl_token::id(),
|
||||||
&self.token,
|
&self.token,
|
||||||
@ -59,32 +59,32 @@ impl SolClient {
|
|||||||
&[mint_to_instruction],
|
&[mint_to_instruction],
|
||||||
Some(&self.keypair.pubkey()),
|
Some(&self.keypair.pubkey()),
|
||||||
&[&self.keypair],
|
&[&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())
|
Ok(signature.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_token_account(
|
async fn create_token_account(
|
||||||
&self,
|
&self,
|
||||||
recipient: &Pubkey,
|
recipient: &Pubkey,
|
||||||
) -> Result<Pubkey, Box<dyn std::error::Error>> {
|
) -> Result<Pubkey, Box<dyn std::error::Error>> {
|
||||||
let address = get_associated_token_address(recipient, &self.token);
|
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(
|
let create_token_account_instruction = create_associated_token_account(
|
||||||
&self.keypair.pubkey(),
|
&self.keypair.pubkey(),
|
||||||
recipient,
|
recipient,
|
||||||
&self.token,
|
&self.token,
|
||||||
&spl_token::id(),
|
&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(
|
let tx = Transaction::new_signed_with_payer(
|
||||||
&[create_token_account_instruction],
|
&[create_token_account_instruction],
|
||||||
Some(&self.keypair.pubkey()),
|
Some(&self.keypair.pubkey()),
|
||||||
&[&self.keypair],
|
&[&self.keypair],
|
||||||
recent_blockhash,
|
recent_blockhash,
|
||||||
);
|
);
|
||||||
self.client.send_and_confirm_transaction(&tx)?;
|
self.client.send_and_confirm_transaction(&tx).await?;
|
||||||
}
|
}
|
||||||
Ok(address)
|
Ok(address)
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ impl TryFrom<Keys> for SolClient {
|
|||||||
};
|
};
|
||||||
let token = Pubkey::from_str(&keys.token_address)
|
let token = Pubkey::from_str(&keys.token_address)
|
||||||
.map_err(|_| "Could not parse wallet address.".to_string())?;
|
.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}");
|
println!("Waiting to receive 0.01 SOL in address {pubkey}");
|
||||||
loop {
|
loop {
|
||||||
sleep(Duration::from_secs(30)).await;
|
sleep(Duration::from_secs(30)).await;
|
||||||
match client.get_balance(pubkey) {
|
match client.get_balance(pubkey).await {
|
||||||
Ok(balance) => {
|
Ok(balance) => {
|
||||||
println!("Got {balance} lamports.");
|
println!("Got {balance} lamports.");
|
||||||
if balance > 10_000_000 {
|
if balance > 10_000_000 {
|
||||||
@ -148,7 +148,7 @@ async fn create_token(client: &RpcClient, keypair: &Keypair) -> Pubkey {
|
|||||||
|
|
||||||
let mint_keypair = Keypair::new();
|
let mint_keypair = Keypair::new();
|
||||||
let payer = Keypair::from_base58_string(&keypair.to_base58_string());
|
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(
|
let create_mint_account_ix = system_instruction::create_account(
|
||||||
&payer.pubkey(),
|
&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)
|
initialize_mint(&spl_token::id(), &mint_keypair.pubkey(), &payer.pubkey(), None, 9)
|
||||||
.unwrap();
|
.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(
|
let tx = Transaction::new_signed_with_payer(
|
||||||
&[create_mint_account_ix, init_mint_ix],
|
&[create_mint_account_ix, init_mint_ix],
|
||||||
Some(&payer.pubkey()),
|
Some(&payer.pubkey()),
|
||||||
@ -170,7 +170,7 @@ async fn create_token(client: &RpcClient, keypair: &Keypair) -> Pubkey {
|
|||||||
recent_blockhash,
|
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!("Mint created: {}", mint_keypair.pubkey());
|
||||||
println!("Transaction signature: {}", signature);
|
println!("Transaction signature: {}", signature);
|
||||||
|
Loading…
Reference in New Issue
Block a user