metrics and refactoring
Signed-off-by: Valentyn Faychuk <valy@detee.ltd>
This commit is contained in:
		
							parent
							
								
									3c93b258f5
								
							
						
					
					
						commit
						2a87efacc1
					
				
							
								
								
									
										40
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										40
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -1490,6 +1490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||||
| checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "powerfmt", |  "powerfmt", | ||||||
|  |  "serde", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| @ -1525,7 +1526,7 @@ dependencies = [ | |||||||
| [[package]] | [[package]] | ||||||
| name = "detee-sgx" | name = "detee-sgx" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| source = "git+ssh://git@gitea.detee.cloud/SGX/detee-sgx#a47753a8e07ef533cca5df41bea4893c9eeb133e" | source = "git+ssh://git@gitea.detee.cloud/SGX/detee-sgx?branch=hacker-challenge#2f032b5c5448be40feda466bb457821ef814f959" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "aes-gcm", |  "aes-gcm", | ||||||
|  "base64 0.22.1", |  "base64 0.22.1", | ||||||
| @ -2042,6 +2043,7 @@ dependencies = [ | |||||||
|  "rustls 0.23.14", |  "rustls 0.23.14", | ||||||
|  "serde", |  "serde", | ||||||
|  "serde_json", |  "serde_json", | ||||||
|  |  "serde_with 3.11.0", | ||||||
|  "solana-client", |  "solana-client", | ||||||
|  "solana-program", |  "solana-program", | ||||||
|  "solana-sdk", |  "solana-sdk", | ||||||
| @ -2418,6 +2420,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "autocfg", |  "autocfg", | ||||||
|  "hashbrown 0.12.3", |  "hashbrown 0.12.3", | ||||||
|  |  "serde", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| @ -2428,6 +2431,7 @@ checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "equivalent", |  "equivalent", | ||||||
|  "hashbrown 0.15.0", |  "hashbrown 0.15.0", | ||||||
|  |  "serde", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| @ -3893,7 +3897,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||||
| checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" | checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "serde", |  "serde", | ||||||
|  "serde_with_macros", |  "serde_with_macros 2.3.3", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "serde_with" | ||||||
|  | version = "3.11.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" | ||||||
|  | dependencies = [ | ||||||
|  |  "base64 0.22.1", | ||||||
|  |  "chrono", | ||||||
|  |  "hex", | ||||||
|  |  "indexmap 1.9.3", | ||||||
|  |  "indexmap 2.6.0", | ||||||
|  |  "serde", | ||||||
|  |  "serde_derive", | ||||||
|  |  "serde_json", | ||||||
|  |  "serde_with_macros 3.11.0", | ||||||
|  |  "time", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| @ -3908,6 +3930,18 @@ dependencies = [ | |||||||
|  "syn 2.0.79", |  "syn 2.0.79", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "serde_with_macros" | ||||||
|  | version = "3.11.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" | ||||||
|  | dependencies = [ | ||||||
|  |  "darling", | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "syn 2.0.79", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "sha1" | name = "sha1" | ||||||
| version = "0.10.6" | version = "0.10.6" | ||||||
| @ -4510,7 +4544,7 @@ dependencies = [ | |||||||
|  "serde_bytes", |  "serde_bytes", | ||||||
|  "serde_derive", |  "serde_derive", | ||||||
|  "serde_json", |  "serde_json", | ||||||
|  "serde_with", |  "serde_with 2.3.3", | ||||||
|  "sha2 0.10.8", |  "sha2 0.10.8", | ||||||
|  "sha3 0.10.8", |  "sha3 0.10.8", | ||||||
|  "siphasher", |  "siphasher", | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ prost = "0.13" | |||||||
| prost-types = "0.13" | prost-types = "0.13" | ||||||
| rand = "0.8" | rand = "0.8" | ||||||
| serde = { version = "1.0", features = ["derive"] } | serde = { version = "1.0", features = ["derive"] } | ||||||
|  | serde_with = { version = "3.11", features = ["macros", "base64"] } | ||||||
| serde_json = "1.0" | serde_json = "1.0" | ||||||
| solana-client = "2.0" | solana-client = "2.0" | ||||||
| solana-program = "2.0" | solana-program = "2.0" | ||||||
| @ -36,8 +37,7 @@ hyper-util = "0.1.7" | |||||||
| hyper-rustls = { version = "0.27", features = ["http2"] } | hyper-rustls = { version = "0.27", features = ["http2"] } | ||||||
| base64 = "0.22" | base64 = "0.22" | ||||||
| lazy_static = "1.5" | lazy_static = "1.5" | ||||||
| # TODO: create a feature for testing, make occlum feature optional and added only if not compiling for testing | detee-sgx = { git = "ssh://git@gitea.detee.cloud/SGX/detee-sgx", branch = "hacker-challenge", features = ["tonic", "occlum", "sealing"] } | ||||||
| detee-sgx = { git = "ssh://git@gitea.detee.cloud/SGX/detee-sgx", features = ["tonic", "occlum", "sealing"] } |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| env_logger = "0.11" | env_logger = "0.11" | ||||||
|  | |||||||
| @ -1,8 +1,6 @@ | |||||||
| #![allow(dead_code)] | use crate::persistence::Logfile; | ||||||
| use crate::solana::Client as SolClient; |  | ||||||
| use dashmap::{DashMap, DashSet}; | use dashmap::{DashMap, DashSet}; | ||||||
| use std::time::{Duration, SystemTime}; | use std::time::{Duration, SystemTime}; | ||||||
| use crate::persistence::Logfile; |  | ||||||
| 
 | 
 | ||||||
| type IP = String; | type IP = String; | ||||||
| pub const LOCALHOST: &str = "localhost"; | pub const LOCALHOST: &str = "localhost"; | ||||||
| @ -14,7 +12,7 @@ pub struct NodeInfo { | |||||||
|     pub mint_requests: u64, |     pub mint_requests: u64, | ||||||
|     pub mints: u64, |     pub mints: u64, | ||||||
|     pub mratls_conns: u64, |     pub mratls_conns: u64, | ||||||
|     pub quote_attacks: u64, |     pub net_attacks: u64, | ||||||
|     pub public: bool, |     pub public: bool, | ||||||
|     pub restarts: u64, |     pub restarts: u64, | ||||||
|     pub disk_attacks: u64, |     pub disk_attacks: u64, | ||||||
| @ -28,7 +26,8 @@ impl NodeInfo { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if self.mint_requests > other_node.mint_requests |         if self.mint_requests > other_node.mint_requests | ||||||
|             || self.quote_attacks > other_node.quote_attacks |             || self.net_attacks > other_node.net_attacks | ||||||
|  |             || self.disk_attacks > other_node.disk_attacks | ||||||
|             || self.mratls_conns > other_node.mratls_conns |             || self.mratls_conns > other_node.mratls_conns | ||||||
|             || self.mints > other_node.mints |             || self.mints > other_node.mints | ||||||
|             || (self.public && !other_node.public) |             || (self.public && !other_node.public) | ||||||
| @ -45,19 +44,17 @@ impl NodeInfo { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Keypair must already be known when creating a Store
 | /// Multithreaded state, designed to be
 | ||||||
| /// This means the first node of the network creates the key
 | /// shared everywhere in the code
 | ||||||
| /// Second node will grab the key from the first node
 | pub struct State { | ||||||
| pub struct Store { |  | ||||||
|     sol_client: SolClient, |  | ||||||
|     nodes: DashMap<IP, NodeInfo>, |     nodes: DashMap<IP, NodeInfo>, | ||||||
|     conns: DashSet<IP>, |     conns: DashSet<IP>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Store { | impl State { | ||||||
|     pub fn init(sol_client: SolClient) -> Self { |     pub fn new() -> Self { | ||||||
|         let store = Self { sol_client, nodes: DashMap::new(), conns: DashSet::new() }; |         let state = Self { nodes: DashMap::new(), conns: DashSet::new() }; | ||||||
|         store.nodes.insert( |         state.nodes.insert( | ||||||
|             LOCALHOST.to_string(), |             LOCALHOST.to_string(), | ||||||
|             NodeInfo { |             NodeInfo { | ||||||
|                 started_at: SystemTime::now(), |                 started_at: SystemTime::now(), | ||||||
| @ -65,25 +62,13 @@ impl Store { | |||||||
|                 mint_requests: 0, |                 mint_requests: 0, | ||||||
|                 mints: 0, |                 mints: 0, | ||||||
|                 mratls_conns: 0, |                 mratls_conns: 0, | ||||||
|                 quote_attacks: 0, |                 net_attacks: 0, | ||||||
|                 public: false, |                 public: false, | ||||||
|                 restarts: 0, |                 restarts: 0, | ||||||
|                 disk_attacks: 0, |                 disk_attacks: 0, | ||||||
|             }, |             }, | ||||||
|         ); |         ); | ||||||
|         store |         state | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn get_token_address(&self) -> String { |  | ||||||
|         self.sol_client.token_address() |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn get_pubkey_base58(&self) -> String { |  | ||||||
|         self.sol_client.wallet_address() |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn get_keypair_bytes(&self) -> Vec<u8> { |  | ||||||
|         self.sol_client.get_keypair_bytes() |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn add_conn(&self, ip: &str) { |     pub fn add_conn(&self, ip: &str) { | ||||||
| @ -122,12 +107,11 @@ impl Store { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn mint(&self, recipient: &str) -> Result<String, Box<dyn std::error::Error>> { |     pub fn increase_net_attacks(&self) { | ||||||
|         use std::str::FromStr; |         if let Some(mut localhost_info) = self.nodes.get_mut(LOCALHOST) { | ||||||
|         let recipient = solana_sdk::pubkey::Pubkey::from_str(recipient)?; |             localhost_info.net_attacks += 1; | ||||||
|         let sig = self.sol_client.mint(&recipient)?; |             localhost_info.log(localhost_info.key()); | ||||||
|         self.increase_mints(); |         } | ||||||
|         Ok(sig) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_localhost(&self) -> NodeInfo { |     pub fn get_localhost(&self) -> NodeInfo { | ||||||
|  | |||||||
| @ -1,10 +1,9 @@ | |||||||
| #![allow(dead_code)] | use super::challenge::{Keys, NodeUpdate}; | ||||||
| use super::challenge::NodeUpdate; |  | ||||||
| use crate::{ | use crate::{ | ||||||
|     datastore::{Store, LOCALHOST}, |     datastore::{State, LOCALHOST}, | ||||||
|     grpc::challenge::{update_client::UpdateClient, Empty}, |     grpc::challenge::{update_client::UpdateClient, Empty}, | ||||||
| }; | }; | ||||||
| use solana_sdk::{pubkey::Pubkey, signature::keypair::Keypair}; | use detee_sgx::RaTlsConfig; | ||||||
| use std::{str::FromStr, sync::Arc}; | use std::{str::FromStr, sync::Arc}; | ||||||
| use tokio::{ | use tokio::{ | ||||||
|     sync::broadcast::Sender, |     sync::broadcast::Sender, | ||||||
| @ -14,13 +13,14 @@ use tokio_stream::{wrappers::BroadcastStream, StreamExt}; | |||||||
| 
 | 
 | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| pub struct ConnManager { | pub struct ConnManager { | ||||||
|     ds: Arc<Store>, |     state: Arc<State>, | ||||||
|     tx: Sender<NodeUpdate>, |     tx: Sender<NodeUpdate>, | ||||||
|  |     ratls_config: RaTlsConfig, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl ConnManager { | impl ConnManager { | ||||||
|     pub fn init(ds: Arc<Store>, tx: Sender<NodeUpdate>) -> Self { |     pub fn init(state: Arc<State>, ratls_config: RaTlsConfig, tx: Sender<NodeUpdate>) -> Self { | ||||||
|         Self { ds, tx } |         Self { state, ratls_config, tx } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub async fn start_with_node(self, node_ip: String) { |     pub async fn start_with_node(self, node_ip: String) { | ||||||
| @ -29,7 +29,7 @@ impl ConnManager { | |||||||
| 
 | 
 | ||||||
|     pub async fn start(self) { |     pub async fn start(self) { | ||||||
|         loop { |         loop { | ||||||
|             if let Some(node) = self.ds.get_random_node() { |             if let Some(node) = self.state.get_random_node() { | ||||||
|                 if node != LOCALHOST { |                 if node != LOCALHOST { | ||||||
|                     self.connect_wrapper(node.clone()).await; |                     self.connect_wrapper(node.clone()).await; | ||||||
|                 } |                 } | ||||||
| @ -39,7 +39,7 @@ impl ConnManager { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async fn connect_wrapper(&self, node_ip: String) { |     async fn connect_wrapper(&self, node_ip: String) { | ||||||
|         let ds = self.ds.clone(); |         let ds = self.state.clone(); | ||||||
|         ds.add_conn(&node_ip); |         ds.add_conn(&node_ip); | ||||||
|         if let Err(e) = self.connect(node_ip.clone()).await { |         if let Err(e) = self.connect(node_ip.clone()).await { | ||||||
|             println!("Client connection for {node_ip} failed: {e:?}"); |             println!("Client connection for {node_ip} failed: {e:?}"); | ||||||
| @ -48,20 +48,14 @@ impl ConnManager { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async fn connect(&self, node_ip: String) -> Result<(), Box<dyn std::error::Error>> { |     async fn connect(&self, node_ip: String) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|         use detee_sgx::{prelude::*, RaTlsConfigBuilder}; |         use detee_sgx::RaTlsConfigBuilder; | ||||||
|         use hyper::Uri; |         use hyper::Uri; | ||||||
|         use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor}; |         use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor}; | ||||||
|         use tokio_rustls::rustls::ClientConfig; |         use tokio_rustls::rustls::ClientConfig; | ||||||
| 
 | 
 | ||||||
|         println!("Connecting to {node_ip}..."); |         println!("Connecting to {node_ip}..."); | ||||||
| 
 | 
 | ||||||
|         let mrsigner_hex = "83E8A0C3ED045D9747ADE06C3BFC70FCA661A4A65FF79A800223621162A88B76"; |         let tls = ClientConfig::from_ratls_config(self.ratls_config.clone()) | ||||||
|         let mrsigner = |  | ||||||
|             crate::sgx::mrsigner_from_hex(mrsigner_hex).expect("mrsigner decoding failed"); |  | ||||||
|         let config = RaTlsConfig::new() |  | ||||||
|             .allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(vec![mrsigner])); |  | ||||||
| 
 |  | ||||||
|         let tls = ClientConfig::from_ratls_config(config) |  | ||||||
|             .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?; |             .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?; | ||||||
| 
 | 
 | ||||||
|         let mut http = HttpConnector::new(); |         let mut http = HttpConnector::new(); | ||||||
| @ -93,10 +87,14 @@ impl ConnManager { | |||||||
| 
 | 
 | ||||||
|         let rx = self.tx.subscribe(); |         let rx = self.tx.subscribe(); | ||||||
|         let rx_stream = BroadcastStream::new(rx).filter_map(|n| n.ok()); |         let rx_stream = BroadcastStream::new(rx).filter_map(|n| n.ok()); | ||||||
|         let response = client.get_updates(rx_stream).await?; |         let response = client.get_updates(rx_stream).await.map_err(|e| { | ||||||
|  |             println!("Error connecting to {node_ip}: {e}"); | ||||||
|  |             self.state.increase_net_attacks(); | ||||||
|  |             e | ||||||
|  |         })?; | ||||||
|         let mut resp_stream = response.into_inner(); |         let mut resp_stream = response.into_inner(); | ||||||
| 
 | 
 | ||||||
|         let _ = self.tx.send((LOCALHOST.to_string(), self.ds.get_localhost()).into()); |         let _ = self.tx.send((LOCALHOST.to_string(), self.state.get_localhost()).into()); | ||||||
| 
 | 
 | ||||||
|         while let Some(mut update) = resp_stream.message().await? { |         while let Some(mut update) = resp_stream.message().await? { | ||||||
|             // "localhost" IPs need to be changed to the real IP of the counterpart
 |             // "localhost" IPs need to be changed to the real IP of the counterpart
 | ||||||
| @ -108,7 +106,7 @@ impl ConnManager { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // update the entire network in case the information is new
 |             // update the entire network in case the information is new
 | ||||||
|             if self.ds.process_node_update(update.clone().into()) |             if self.state.process_node_update(update.clone().into()) | ||||||
|                 && self.tx.send(update.clone()).is_err() |                 && self.tx.send(update.clone()).is_err() | ||||||
|             { |             { | ||||||
|                 println!("tokio broadcast receivers had an issue consuming the channel"); |                 println!("tokio broadcast receivers had an issue consuming the channel"); | ||||||
| @ -119,20 +117,19 @@ impl ConnManager { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub async fn key_grabber(node_ip: String) -> Result<(Keypair, Pubkey), Box<dyn std::error::Error>> { | pub async fn key_grabber( | ||||||
|     use detee_sgx::{prelude::*, RaTlsConfigBuilder}; |     state: Arc<State>, | ||||||
|  |     node_ip: String, | ||||||
|  |     ratls_config: RaTlsConfig, | ||||||
|  | ) -> Result<Keys, Box<dyn std::error::Error>> { | ||||||
|  |     use detee_sgx::RaTlsConfigBuilder; | ||||||
|     use hyper::Uri; |     use hyper::Uri; | ||||||
|     use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor}; |     use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor}; | ||||||
|     use tokio_rustls::rustls::ClientConfig; |     use tokio_rustls::rustls::ClientConfig; | ||||||
| 
 | 
 | ||||||
|     println!("Getting key from {node_ip}..."); |     println!("Getting key from {node_ip}..."); | ||||||
| 
 | 
 | ||||||
|     let mrsigner_hex = "83E8A0C3ED045D9747ADE06C3BFC70FCA661A4A65FF79A800223621162A88B76"; |     let tls = ClientConfig::from_ratls_config(ratls_config) | ||||||
|     let mrsigner = crate::sgx::mrsigner_from_hex(mrsigner_hex).expect("mrsigner decoding failed"); |  | ||||||
|     let config = RaTlsConfig::new() |  | ||||||
|         .allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(vec![mrsigner])); |  | ||||||
| 
 |  | ||||||
|     let tls = ClientConfig::from_ratls_config(config) |  | ||||||
|         .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?; |         .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?; | ||||||
| 
 | 
 | ||||||
|     let mut http = HttpConnector::new(); |     let mut http = HttpConnector::new(); | ||||||
| @ -160,14 +157,10 @@ pub async fn key_grabber(node_ip: String) -> Result<(Keypair, Pubkey), Box<dyn s | |||||||
|     let uri = Uri::from_static("https://example.com"); |     let uri = Uri::from_static("https://example.com"); | ||||||
|     let mut client = UpdateClient::with_origin(client, uri); |     let mut client = UpdateClient::with_origin(client, uri); | ||||||
| 
 | 
 | ||||||
|     let response = client.get_keys(tonic::Request::new(Empty {})).await?; |     let response = client.get_keys(tonic::Request::new(Empty {})).await.map_err(|e| { | ||||||
|     let response = &response.into_inner(); |         println!("Error getting keys from {node_ip}: {e}"); | ||||||
|     let keypair = response.keypair.clone(); |         state.increase_net_attacks(); | ||||||
|     let keypair = match Keypair::from_bytes(&keypair) { |         e | ||||||
|         Ok(k) => k, |     })?; | ||||||
|         Err(_) => return Err("Could not parse keypair.".into()), |     Ok(response.into_inner()) | ||||||
|     }; |  | ||||||
|     let token_address = Pubkey::from_str(&response.token_address) |  | ||||||
|         .map_err(|_| "Could not parse wallet address.".to_string())?; |  | ||||||
|     Ok((keypair, token_address)) |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,10 +16,10 @@ impl From<(String, NodeInfo)> for NodeUpdate { | |||||||
|             mint_requests: info.mint_requests, |             mint_requests: info.mint_requests, | ||||||
|             mints: info.mints, |             mints: info.mints, | ||||||
|             mratls_conns: info.mratls_conns, |             mratls_conns: info.mratls_conns, | ||||||
|             quote_attacks: info.quote_attacks, |             quote_attacks: info.net_attacks, | ||||||
|             public: info.public, |             public: info.public, | ||||||
|             restarts: info.restarts, |             restarts: info.restarts, | ||||||
|             disk_attacks: info.disk_attacks |             disk_attacks: info.disk_attacks, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -47,10 +47,10 @@ impl From<NodeUpdate> for (String, NodeInfo) { | |||||||
|             mint_requests: val.mint_requests, |             mint_requests: val.mint_requests, | ||||||
|             mints: val.mints, |             mints: val.mints, | ||||||
|             mratls_conns: val.mratls_conns, |             mratls_conns: val.mratls_conns, | ||||||
|             quote_attacks: val.quote_attacks, |             net_attacks: val.quote_attacks, | ||||||
|             public: val.public, |             public: val.public, | ||||||
|             restarts: val.restarts, |             restarts: val.restarts, | ||||||
|             disk_attacks: val.disk_attacks |             disk_attacks: val.disk_attacks, | ||||||
|         }; |         }; | ||||||
|         (ip, self_info) |         (ip, self_info) | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,23 +1,30 @@ | |||||||
| #![allow(dead_code)] |  | ||||||
| 
 |  | ||||||
| use super::challenge::{update_server::UpdateServer, Empty, Keys, NodeUpdate}; | use super::challenge::{update_server::UpdateServer, Empty, Keys, NodeUpdate}; | ||||||
| use crate::{datastore::Store, grpc::challenge::update_server::Update}; | use crate::{datastore::State, grpc::challenge::update_server::Update}; | ||||||
|  | use detee_sgx::RaTlsConfig; | ||||||
| use std::{pin::Pin, sync::Arc}; | use std::{pin::Pin, sync::Arc}; | ||||||
| use tokio::sync::broadcast::Sender; | use tokio::sync::broadcast::Sender; | ||||||
| use tokio_stream::{Stream, StreamExt}; | use tokio_stream::{Stream, StreamExt}; | ||||||
| use tonic::{Request, Response, Status, Streaming}; | use tonic::{Request, Response, Status, Streaming}; | ||||||
| 
 | 
 | ||||||
| pub struct MyServer { | pub struct MyServer { | ||||||
|     ds: Arc<Store>, |     state: Arc<State>, | ||||||
|     tx: Sender<NodeUpdate>, |     tx: Sender<NodeUpdate>, | ||||||
|  |     ratls_config: RaTlsConfig, | ||||||
|  |     keys: Keys, // For sending secret keys to new nodes ;)
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl MyServer { | impl MyServer { | ||||||
|     pub fn init(ds: Arc<Store>, tx: Sender<NodeUpdate>) -> Self { |     pub fn init( | ||||||
|         Self { ds, tx } |         state: Arc<State>, | ||||||
|  |         keys: Keys, | ||||||
|  |         ratls_config: RaTlsConfig, | ||||||
|  |         tx: Sender<NodeUpdate>, | ||||||
|  |     ) -> Self { | ||||||
|  |         Self { state, tx, keys, ratls_config } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub async fn start(self) { |     pub async fn start(self) { | ||||||
|  |         use detee_sgx::RaTlsConfigBuilder; | ||||||
|         use hyper::server::conn::http2::Builder; |         use hyper::server::conn::http2::Builder; | ||||||
|         use hyper_util::{ |         use hyper_util::{ | ||||||
|             rt::{TokioExecutor, TokioIo}, |             rt::{TokioExecutor, TokioIo}, | ||||||
| @ -29,22 +36,12 @@ impl MyServer { | |||||||
|         use tonic::{body::boxed, service::Routes}; |         use tonic::{body::boxed, service::Routes}; | ||||||
|         use tower::{ServiceBuilder, ServiceExt}; |         use tower::{ServiceBuilder, ServiceExt}; | ||||||
| 
 | 
 | ||||||
|         use detee_sgx::{prelude::*, RaTlsConfigBuilder}; |  | ||||||
| 
 |  | ||||||
|         // TODO: ratls config should be global
 |  | ||||||
|         // TODO: error handling, shouldn't have expects
 |         // TODO: error handling, shouldn't have expects
 | ||||||
| 
 | 
 | ||||||
|         let mrsigner_hex = "83E8A0C3ED045D9747ADE06C3BFC70FCA661A4A65FF79A800223621162A88B76"; |         let mut tls = ServerConfig::from_ratls_config(self.ratls_config.clone()).unwrap(); | ||||||
|         let mrsigner = |  | ||||||
|             crate::sgx::mrsigner_from_hex(mrsigner_hex).expect("mrsigner decoding failed"); |  | ||||||
|         let config = RaTlsConfig::new() |  | ||||||
|             .allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(vec![mrsigner])); |  | ||||||
| 
 |  | ||||||
|         let mut tls = ServerConfig::from_ratls_config(config) |  | ||||||
|             .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e))) |  | ||||||
|             .expect("failed to create server config"); |  | ||||||
|         tls.alpn_protocols = vec![b"h2".to_vec()]; |         tls.alpn_protocols = vec![b"h2".to_vec()]; | ||||||
| 
 | 
 | ||||||
|  |         let state = self.state.clone(); | ||||||
|         let svc = Routes::new(UpdateServer::new(self)).prepare(); |         let svc = Routes::new(UpdateServer::new(self)).prepare(); | ||||||
| 
 | 
 | ||||||
|         let http = Builder::new(TokioExecutor::new()); |         let http = Builder::new(TokioExecutor::new()); | ||||||
| @ -53,10 +50,11 @@ impl MyServer { | |||||||
|         let tls_acceptor = TlsAcceptor::from(Arc::new(tls)); |         let tls_acceptor = TlsAcceptor::from(Arc::new(tls)); | ||||||
| 
 | 
 | ||||||
|         loop { |         loop { | ||||||
|             let (conn, addr) = match listener.accept().await { |             let (conn, _addr) = match listener.accept().await { | ||||||
|                 Ok(incoming) => incoming, |                 Ok(incoming) => incoming, | ||||||
|                 Err(e) => { |                 Err(e) => { | ||||||
|                     eprintln!("Error accepting connection: {}", e); |                     println!("Error accepting connection: {}", e); | ||||||
|  |                     state.increase_net_attacks(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
| @ -65,6 +63,7 @@ impl MyServer { | |||||||
|             let tls_acceptor = tls_acceptor.clone(); |             let tls_acceptor = tls_acceptor.clone(); | ||||||
|             let svc = svc.clone(); |             let svc = svc.clone(); | ||||||
| 
 | 
 | ||||||
|  |             let state = state.clone(); | ||||||
|             tokio::spawn(async move { |             tokio::spawn(async move { | ||||||
|                 let mut certificates = Vec::new(); |                 let mut certificates = Vec::new(); | ||||||
| 
 | 
 | ||||||
| @ -76,30 +75,29 @@ impl MyServer { | |||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     }) |                     }) | ||||||
|                     .await |                     .await; | ||||||
|                     .unwrap(); |  | ||||||
| 
 | 
 | ||||||
|                 #[derive(Debug)] |                 let conn = if let Err(e) = conn { | ||||||
|                 pub struct ConnInfo { |                     println!("Error accepting TLS connection: {}", e); | ||||||
|                     pub addr: std::net::SocketAddr, |                     state.increase_net_attacks(); | ||||||
|                     pub certificates: Vec<rustls::pki_types::CertificateDer<'static>>, |                     return; | ||||||
|                 } |                 } else { | ||||||
|  |                     conn.unwrap() | ||||||
|  |                 }; | ||||||
| 
 | 
 | ||||||
|                 let extension_layer = |                 let svc = ServiceBuilder::new().service(svc); | ||||||
|                     tower_http::add_extension::AddExtensionLayer::new(Arc::new(ConnInfo { |  | ||||||
|                         addr, |  | ||||||
|                         certificates, |  | ||||||
|                     })); |  | ||||||
|                 let svc = ServiceBuilder::new().layer(extension_layer).service(svc); |  | ||||||
| 
 | 
 | ||||||
|                 http.serve_connection( |                 if let Err(e) = http | ||||||
|  |                     .serve_connection( | ||||||
|                         TokioIo::new(conn), |                         TokioIo::new(conn), | ||||||
|                         TowerToHyperService::new( |                         TowerToHyperService::new( | ||||||
|                             svc.map_request(|req: hyper::Request<_>| req.map(boxed)), |                             svc.map_request(|req: hyper::Request<_>| req.map(boxed)), | ||||||
|                         ), |                         ), | ||||||
|                     ) |                     ) | ||||||
|                     .await |                     .await | ||||||
|                 .unwrap(); |                 { | ||||||
|  |                     println!("Error serving connection: {}", e); | ||||||
|  |                 } | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -109,16 +107,20 @@ impl MyServer { | |||||||
| impl Update for MyServer { | impl Update for MyServer { | ||||||
|     type GetUpdatesStream = Pin<Box<dyn Stream<Item = Result<NodeUpdate, Status>> + Send>>; |     type GetUpdatesStream = Pin<Box<dyn Stream<Item = Result<NodeUpdate, Status>> + Send>>; | ||||||
| 
 | 
 | ||||||
|  |     async fn get_keys(&self, _request: Request<Empty>) -> Result<Response<Keys>, Status> { | ||||||
|  |         Ok(Response::new(self.keys.clone())) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     async fn get_updates( |     async fn get_updates( | ||||||
|         &self, |         &self, | ||||||
|         req: Request<Streaming<NodeUpdate>>, |         req: Request<Streaming<NodeUpdate>>, | ||||||
|     ) -> Result<Response<Self::GetUpdatesStream>, Status> { |     ) -> Result<Response<Self::GetUpdatesStream>, Status> { | ||||||
|         self.ds.increase_mratls_conns(); |         self.state.increase_mratls_conns(); | ||||||
|         let remote_ip = req.remote_addr().unwrap().ip().to_string(); |         let remote_ip = req.remote_addr().unwrap().ip().to_string(); | ||||||
|         let tx = self.tx.clone(); |         let tx = self.tx.clone(); | ||||||
|         let mut rx = self.tx.subscribe(); |         let mut rx = self.tx.subscribe(); | ||||||
|         let mut inbound = req.into_inner(); |         let mut inbound = req.into_inner(); | ||||||
|         let ds = self.ds.clone(); |         let ds = self.state.clone(); | ||||||
| 
 | 
 | ||||||
|         let stream = async_stream::stream! { |         let stream = async_stream::stream! { | ||||||
|             let full_update_list: Vec<NodeUpdate> = ds.get_node_list().into_iter().map(Into::<NodeUpdate>::into).collect(); |             let full_update_list: Vec<NodeUpdate> = ds.get_node_list().into_iter().map(Into::<NodeUpdate>::into).collect(); | ||||||
| @ -161,12 +163,4 @@ impl Update for MyServer { | |||||||
| 
 | 
 | ||||||
|         Ok(Response::new(Box::pin(stream) as Self::GetUpdatesStream)) |         Ok(Response::new(Box::pin(stream) as Self::GetUpdatesStream)) | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     async fn get_keys(&self, _request: Request<Empty>) -> Result<Response<Keys>, Status> { |  | ||||||
|         let reply = Keys { |  | ||||||
|             keypair: self.ds.get_keypair_bytes(), |  | ||||||
|             token_address: self.ds.get_token_address(), |  | ||||||
|         }; |  | ||||||
|         Ok(Response::new(reply)) |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #![allow(dead_code)] | use crate::{datastore, datastore::State, solana::SolClient}; | ||||||
| use crate::{datastore, datastore::Store}; |  | ||||||
| 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}; | ||||||
| @ -8,11 +7,11 @@ use std::sync::Arc; | |||||||
| const HOMEPAGE: &str = include_str!("HOMEPAGE.md"); | const HOMEPAGE: &str = include_str!("HOMEPAGE.md"); | ||||||
| 
 | 
 | ||||||
| #[get("/")] | #[get("/")] | ||||||
| async fn homepage(ds: web::Data<Arc<Store>>) -> impl Responder { | async fn homepage(sol_client: web::Data<Arc<SolClient>>) -> impl Responder { | ||||||
|     let text = HOMEPAGE |     let text = HOMEPAGE | ||||||
|         .to_string() |         .to_string() | ||||||
|         .replace("TOKEN_ADDRESS", &ds.get_token_address()) |         .replace("TOKEN_ADDRESS", &sol_client.get_token_address()) | ||||||
|         .replace("MINT_AUTHORITY", &ds.get_pubkey_base58()); |         .replace("MINT_AUTHORITY", &sol_client.get_wallet_pubkey()); | ||||||
|     HttpResponse::Ok().body(text) |     HttpResponse::Ok().body(text) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -40,7 +39,7 @@ impl From<(String, datastore::NodeInfo)> for NodesResp { | |||||||
|             last_keepalive, |             last_keepalive, | ||||||
|             mints: node_info.mints, |             mints: node_info.mints, | ||||||
|             total_ratls_conns: node_info.mratls_conns, |             total_ratls_conns: node_info.mratls_conns, | ||||||
|             ratls_attacks: node_info.quote_attacks, |             ratls_attacks: node_info.net_attacks, | ||||||
|             public: node_info.public, |             public: node_info.public, | ||||||
|             mint_requests: node_info.mint_requests, |             mint_requests: node_info.mint_requests, | ||||||
|         } |         } | ||||||
| @ -48,7 +47,7 @@ impl From<(String, datastore::NodeInfo)> for NodesResp { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[get("/nodes")] | #[get("/nodes")] | ||||||
| async fn get_nodes(ds: web::Data<Arc<Store>>) -> HttpResponse { | async fn get_nodes(ds: web::Data<Arc<State>>) -> HttpResponse { | ||||||
|     HttpResponse::Ok().json( |     HttpResponse::Ok().json( | ||||||
|         ds.get_node_list().into_iter().map(Into::<NodesResp>::into).collect::<Vec<NodesResp>>(), |         ds.get_node_list().into_iter().map(Into::<NodesResp>::into).collect::<Vec<NodesResp>>(), | ||||||
|     ) |     ) | ||||||
| @ -60,22 +59,30 @@ struct MintReq { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[post("/mint")] | #[post("/mint")] | ||||||
| async fn mint(ds: web::Data<Arc<Store>>, req: web::Json<MintReq>) -> impl Responder { | async fn mint( | ||||||
|     ds.increase_mint_requests(); |     state: web::Data<Arc<State>>, | ||||||
|  |     sol_client: web::Data<Arc<SolClient>>, | ||||||
|  |     req: web::Json<MintReq>, | ||||||
|  | ) -> impl Responder { | ||||||
|  |     let recipient = req.into_inner().wallet; | ||||||
|  |     state.increase_mint_requests(); | ||||||
|     let result = |     let result = | ||||||
|         web::block(move || ds.mint(&req.into_inner().wallet).map_err(|e| e.to_string())) |         web::block(move || sol_client.mint(&recipient).map_err(|e| e.to_string())).await.unwrap(); // TODO: check if this can get a BlockingError
 | ||||||
|             .await | 
 | ||||||
|             .unwrap(); // TODO: check if this can get a BlockingError
 |  | ||||||
|     match result { |     match result { | ||||||
|         Ok(s) => HttpResponse::Ok().body(format!(r#"{{" signature": "{s} "}}"#)), |         Ok(s) => { | ||||||
|  |             state.increase_mints(); | ||||||
|  |             HttpResponse::Ok().body(format!(r#"{{" signature": "{s} "}}"#)) | ||||||
|  |         } | ||||||
|         Err(e) => HttpResponse::InternalServerError().body(format!(r#"{{ "error": "{e}" }}"#)), |         Err(e) => HttpResponse::InternalServerError().body(format!(r#"{{ "error": "{e}" }}"#)), | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub async fn init(ds: Arc<Store>) { | pub async fn init(state: Arc<State>, sol_client: Arc<SolClient>) { | ||||||
|     HttpServer::new(move || { |     HttpServer::new(move || { | ||||||
|         App::new() |         App::new() | ||||||
|             .app_data(web::Data::new(ds.clone())) |             .app_data(web::Data::new(state.clone())) | ||||||
|  |             .app_data(web::Data::new(sol_client.clone())) | ||||||
|             .service(homepage) |             .service(homepage) | ||||||
|             .service(get_nodes) |             .service(get_nodes) | ||||||
|             .service(mint) |             .service(mint) | ||||||
|  | |||||||
							
								
								
									
										104
									
								
								src/main.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										104
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -5,9 +5,11 @@ mod persistence; | |||||||
| mod sgx; | mod sgx; | ||||||
| mod solana; | mod solana; | ||||||
| 
 | 
 | ||||||
| use crate::{datastore::LOCALHOST, grpc::challenge::NodeUpdate, solana::Client as SolClient}; | use crate::{ | ||||||
| use datastore::Store; |     datastore::LOCALHOST, grpc::challenge::NodeUpdate, persistence::KeysFile, solana::SolClient, | ||||||
| use solana_sdk::signer::Signer; | }; | ||||||
|  | use datastore::State; | ||||||
|  | use detee_sgx::{InstanceMeasurement, RaTlsConfig}; | ||||||
| use std::{ | use std::{ | ||||||
|     fs::File, |     fs::File, | ||||||
|     io::{BufRead, BufReader}, |     io::{BufRead, BufReader}, | ||||||
| @ -19,52 +21,61 @@ use tokio::{ | |||||||
|     time::{sleep, Duration}, |     time::{sleep, Duration}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const INIT_NODES: &str = "/host/detee_challenge_nodes"; | const INIT_NODES_FILE: &str = "/host/detee_challenge_nodes"; | ||||||
| const DISK_PERSISTENCE: &str = "/host/main/TRY_TO_HACK_THIS"; | const KEYS_FILE: &str = "/host/TRY_TO_HACK_THIS"; | ||||||
| const MAINTAINED_CONNECTIONS: usize = 3; | const MAX_CONNECTIONS: usize = 3; | ||||||
| 
 | 
 | ||||||
| pub async fn localhost_cron(ds: Arc<Store>, tx: Sender<NodeUpdate>) { | pub async fn localhost_cron(state: Arc<State>, tx: Sender<NodeUpdate>) { | ||||||
|     loop { |     loop { | ||||||
|         sleep(Duration::from_secs(60)).await; |         sleep(Duration::from_secs(60)).await; | ||||||
|         let _ = tx.send((LOCALHOST.to_string(), ds.get_localhost()).into()); |         let _ = tx.send((LOCALHOST.to_string(), state.get_localhost()).into()); | ||||||
|         ds.remove_inactive_nodes(); |         state.remove_inactive_nodes(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async fn get_sol_client() -> SolClient { | async fn get_sol_client(state: Arc<State>, ratls_config: RaTlsConfig) -> SolClient { | ||||||
|     match crate::persistence::Data::read(DISK_PERSISTENCE).await { |     match KeysFile::read(KEYS_FILE, &state).await { | ||||||
|         Ok(data) => { |         Ok(keys_file) => { | ||||||
|             let (keypair, token) = data.parse(); |             let sol_client = SolClient::try_from(keys_file).unwrap(); | ||||||
|             println!("Found the following wallet saved to disk: {}", keypair.pubkey()); |             println!( | ||||||
|             println!("Loading token mint address {}", token); |                 "Found the following wallet saved to disk: {}", | ||||||
|             return SolClient::from(keypair, token); |                 sol_client.get_wallet_pubkey() | ||||||
|  |             ); | ||||||
|  |             println!("Loading token mint address {}", sol_client.get_token_address()); | ||||||
|  |             return sol_client; | ||||||
|         } |         } | ||||||
|         Err(e) => println!("Did not find old pubkeys saved to disk: {e}"), |         Err(e) => println!("Can't initialize using sealed keys: {e}"), | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     let input = match File::open(INIT_NODES) { |     let init_nodes = match File::open(INIT_NODES_FILE) { | ||||||
|         Ok(i) => i, |         Ok(init_nodes) => init_nodes, | ||||||
|         Err(_) => { |         Err(_) => { | ||||||
|             println!("Could not find remote nodes in the file {INIT_NODES}"); |             println!("Can't initialize using init nodes from {INIT_NODES_FILE}"); | ||||||
|             println!("Starting a new network with a new key..."); |             println!("Starting a new network with a new key..."); | ||||||
|             return SolClient::new().await; |             return SolClient::new().await; | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|     let buffered = BufReader::new(input); | 
 | ||||||
|     for line in buffered.lines() { |     let init_nodes_reader = BufReader::new(init_nodes); | ||||||
|         match grpc::client::key_grabber(line.unwrap()).await { |     for init_node_ip in init_nodes_reader.lines().map(|l| l.unwrap()) { | ||||||
|             Ok(bundle) => { |         match grpc::client::key_grabber(state.clone(), init_node_ip, ratls_config.clone()).await { | ||||||
|  |             Ok(keys) => { | ||||||
|  |                 let sol_client = SolClient::try_from(keys.clone()) | ||||||
|  |                     .map_err(|e| { | ||||||
|  |                         println!("Received malformed keys from the network: {e}"); | ||||||
|  |                         state.increase_net_attacks(); | ||||||
|  |                     }) | ||||||
|  |                     .unwrap(); | ||||||
|                 println!( |                 println!( | ||||||
|                     "Got keypair from the network. Joining the network using wallet {}", |                     "Got keypair from the network. Joining the network using wallet {}", | ||||||
|                     bundle.0.pubkey() |                     sol_client.get_wallet_pubkey() | ||||||
|                 ); |                 ); | ||||||
|                 println!("The address of the Token is {}", bundle.1); |                 println!("The address of the Token is {}", sol_client.get_token_address()); | ||||||
|                 println!("Saving this data to disk in the file {DISK_PERSISTENCE}"); |                 println!("Saving this data to disk in the file {KEYS_FILE}"); | ||||||
|                 let disk_data = crate::persistence::Data::init_from(&bundle.0, &bundle.1).await; |                 if let Err(e) = sol_client.get_keys_file().write(KEYS_FILE).await { | ||||||
|                 if let Err(e) = disk_data.write(DISK_PERSISTENCE).await { |                     println!("Could not save data to disk: {e}"); | ||||||
|                     println!("Could not save data to disk due to: {e}"); |  | ||||||
|                 } |                 } | ||||||
|                 return SolClient::from(bundle.0, bundle.1); |                 return sol_client; | ||||||
|             } |             } | ||||||
|             Err(e) => { |             Err(e) => { | ||||||
|                 println!("Could not get keypair: {e:?}"); |                 println!("Could not get keypair: {e:?}"); | ||||||
| @ -77,29 +88,42 @@ async fn get_sol_client() -> SolClient { | |||||||
| #[tokio::main] | #[tokio::main] | ||||||
| async fn main() { | async fn main() { | ||||||
|     env_logger::init_from_env(env_logger::Env::default().default_filter_or("trace")); |     env_logger::init_from_env(env_logger::Env::default().default_filter_or("trace")); | ||||||
|  |     let ratls_config = RaTlsConfig::new() | ||||||
|  |         .allow_instance_measurement(InstanceMeasurement::new().with_current_mrenclave().unwrap()); | ||||||
| 
 | 
 | ||||||
|     let sol_client = get_sol_client().await; |     let state = Arc::new(State::new()); | ||||||
|     let ds = Arc::new(Store::init(sol_client)); |     let sol_client = Arc::new(get_sol_client(state.clone(), ratls_config.clone()).await); | ||||||
| 
 | 
 | ||||||
|     let (tx, _) = broadcast::channel(500); |     let (tx, _) = broadcast::channel(500); | ||||||
| 
 | 
 | ||||||
|     let mut tasks = JoinSet::new(); |     let mut tasks = JoinSet::new(); | ||||||
| 
 | 
 | ||||||
|     tasks.spawn(localhost_cron(ds.clone(), tx.clone())); |     tasks.spawn(localhost_cron(state.clone(), tx.clone())); | ||||||
|     tasks.spawn(http_server::init(ds.clone())); |     tasks.spawn(http_server::init(state.clone(), sol_client.clone())); | ||||||
|     tasks.spawn(grpc::server::MyServer::init(ds.clone(), tx.clone()).start()); |     tasks.spawn( | ||||||
|  |         grpc::server::MyServer::init( | ||||||
|  |             state.clone(), | ||||||
|  |             sol_client.get_keys(), | ||||||
|  |             ratls_config.clone(), | ||||||
|  |             tx.clone(), | ||||||
|  |         ) | ||||||
|  |         .start(), | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     if let Ok(input) = std::fs::read_to_string(INIT_NODES) { |     if let Ok(input) = std::fs::read_to_string(INIT_NODES_FILE) { | ||||||
|         for line in input.lines() { |         for line in input.lines() { | ||||||
|             tasks.spawn( |             tasks.spawn( | ||||||
|                 grpc::client::ConnManager::init(ds.clone(), tx.clone()) |                 grpc::client::ConnManager::init(state.clone(), ratls_config.clone(), tx.clone()) | ||||||
|                     .start_with_node(line.to_string()), |                     .start_with_node(line.to_string()), | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for _ in 0..MAINTAINED_CONNECTIONS { |     for _ in 0..MAX_CONNECTIONS { | ||||||
|         tasks.spawn(grpc::client::ConnManager::init(ds.clone(), tx.clone()).start()); |         tasks.spawn( | ||||||
|  |             grpc::client::ConnManager::init(state.clone(), ratls_config.clone(), tx.clone()) | ||||||
|  |                 .start(), | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     while let Some(Ok(_)) = tasks.join_next().await {} |     while let Some(Ok(_)) = tasks.join_next().await {} | ||||||
|  | |||||||
| @ -1,43 +1,52 @@ | |||||||
|  | use crate::{datastore::State, grpc::challenge::Keys}; | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| use solana_sdk::{pubkey::Pubkey, signature::keypair::Keypair}; | use serde_with::base64::Base64; | ||||||
| use std::str::FromStr; |  | ||||||
| 
 | 
 | ||||||
|  | #[serde_with::serde_as] | ||||||
| #[derive(Serialize, Deserialize)] | #[derive(Serialize, Deserialize)] | ||||||
| pub struct Data { | pub struct KeysFile { | ||||||
|     random: String, |     random: String, | ||||||
|     keypair: String, |     #[serde_as(as = "Base64")] | ||||||
|  |     keypair: Vec<u8>, | ||||||
|     token: String, |     token: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Data { | impl From<Keys> for KeysFile { | ||||||
|     pub async fn init_from(keypair: &Keypair, token: &Pubkey) -> Self { |     fn from(keys: Keys) -> Self { | ||||||
|         use rand::{distributions::Alphanumeric, Rng}; |         use rand::{distributions::Alphanumeric, Rng}; | ||||||
|         let random_string: String = |         let random: String = | ||||||
|             rand::thread_rng().sample_iter(&Alphanumeric).take(128).map(char::from).collect(); |             rand::thread_rng().sample_iter(&Alphanumeric).take(128).map(char::from).collect(); | ||||||
| 
 | 
 | ||||||
|         Self { |         Self { keypair: keys.keypair, token: keys.token_address, random } | ||||||
|             random: random_string, |  | ||||||
|             keypair: keypair.to_base58_string(), |  | ||||||
|             token: token.to_string(), |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl Into<Keys> for KeysFile { | ||||||
|  |     fn into(self) -> Keys { | ||||||
|  |         Keys { keypair: self.keypair, token_address: self.token } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl KeysFile { | ||||||
|     pub async fn write(self, path: &str) -> Result<(), Box<dyn std::error::Error>> { |     pub async fn write(self, path: &str) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|         let serialized = serde_json::to_string(&self)?; |         let serialized = serde_json::to_string(&self)?; | ||||||
|         let sealed = detee_sgx::SealingConfig::new()?.seal_data(serialized.into_bytes())?; |         let sealed = detee_sgx::SealingConfig::new()?.seal_data(serialized.into_bytes())?; | ||||||
|         tokio::fs::write(path, sealed).await.map_err(Into::into) |         tokio::fs::write(path, sealed).await.map_err(Into::into) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub async fn read(path: &str) -> Result<Self, Box<dyn std::error::Error>> { |     pub async fn read(path: &str, state: &State) -> Result<Self, Box<dyn std::error::Error>> { | ||||||
|         let sealed = tokio::fs::read(path).await?; |         let sealed = tokio::fs::read(path).await?; | ||||||
|         let serialized = detee_sgx::SealingConfig::new()?.un_seal_data(sealed)?; |         let serialized = detee_sgx::SealingConfig::new()?.un_seal_data(sealed).map_err(|e| { | ||||||
|         Ok(serde_json::from_str(&String::from_utf8(serialized)?)?) |             match e { | ||||||
|  |                 detee_sgx::SgxError::UnSealingError(ref ue) => { | ||||||
|  |                     state.increase_disk_attacks(); | ||||||
|  |                     println!("The disk data is corrupted: {ue}"); | ||||||
|                 } |                 } | ||||||
| 
 |                 _ => println!("Failed to unseal data: {e}"), | ||||||
|     pub fn parse(self) -> (Keypair, Pubkey) { |             }; | ||||||
|         let keypair = Keypair::from_base58_string(&self.keypair); |             e | ||||||
|         let pubkey = Pubkey::from_str(&self.token).unwrap(); |         })?; | ||||||
|         (keypair, pubkey) |         Ok(serde_json::from_str(&String::from_utf8(serialized)?)?) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -48,9 +57,7 @@ pub struct Logfile {} | |||||||
| impl Logfile { | impl Logfile { | ||||||
|     pub fn append(msg: &str) -> Result<(), Box<dyn std::error::Error>> { |     pub fn append(msg: &str) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|         use std::io::Write; |         use std::io::Write; | ||||||
|         let mut file = std::fs::OpenOptions::new() |         let mut file = std::fs::OpenOptions::new().append(true).open(LOG_PATH)?; | ||||||
|             .append(true) |  | ||||||
|             .open(LOG_PATH)?; |  | ||||||
|         file.write_all(msg.as_bytes())?; |         file.write_all(msg.as_bytes())?; | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #![allow(dead_code)] | #![allow(dead_code)] | ||||||
|  | use crate::{grpc::challenge::Keys, persistence::KeysFile}; | ||||||
| use solana_client::rpc_client::RpcClient; | use solana_client::rpc_client::RpcClient; | ||||||
| use solana_program::program_pack::Pack; | use solana_program::program_pack::Pack; | ||||||
| use solana_sdk::{ | use solana_sdk::{ | ||||||
| @ -12,18 +13,17 @@ use spl_token::{ | |||||||
|     instruction::{initialize_mint, mint_to}, |     instruction::{initialize_mint, mint_to}, | ||||||
|     state::Mint, |     state::Mint, | ||||||
| }; | }; | ||||||
| use std::error::Error; |  | ||||||
| use tokio::time::{sleep, Duration}; | use tokio::time::{sleep, Duration}; | ||||||
| 
 | 
 | ||||||
| const RPC_URL: &str = "https://api.devnet.solana.com"; | const RPC_URL: &str = "https://api.devnet.solana.com"; | ||||||
| 
 | 
 | ||||||
| pub struct Client { | pub struct SolClient { | ||||||
|     client: RpcClient, |     client: RpcClient, | ||||||
|     keypair: Keypair, |     keypair: Keypair, | ||||||
|     token: Pubkey, |     token: Pubkey, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Client { | impl SolClient { | ||||||
|     pub async fn new() -> Self { |     pub async fn new() -> Self { | ||||||
|         let client = RpcClient::new(RPC_URL); |         let client = RpcClient::new(RPC_URL); | ||||||
|         let keypair = Keypair::new(); |         let keypair = Keypair::new(); | ||||||
| @ -31,12 +31,18 @@ impl Client { | |||||||
|         Self { client, keypair, token } |         Self { client, keypair, token } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn from(keypair: Keypair, token: Pubkey) -> Self { |     pub fn get_keys(&self) -> Keys { | ||||||
|         Self { client: RpcClient::new(RPC_URL), keypair, token } |         Keys { keypair: self.get_keypair_bytes(), token_address: self.get_token_address() } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn mint(&self, recipient: &Pubkey) -> Result<String, Box<dyn std::error::Error>> { |     pub fn get_keys_file(&self) -> KeysFile { | ||||||
|         let associated_token_address = self.create_token_account(recipient)?; |         self.get_keys().into() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn mint(&self, recipient: &str) -> Result<String, Box<dyn std::error::Error>> { | ||||||
|  |         use std::str::FromStr; | ||||||
|  |         let recipient = solana_sdk::pubkey::Pubkey::from_str(recipient)?; | ||||||
|  |         let associated_token_address = self.create_token_account(&recipient)?; | ||||||
|         let mint_to_instruction = mint_to( |         let mint_to_instruction = mint_to( | ||||||
|             &spl_token::id(), |             &spl_token::id(), | ||||||
|             &self.token, |             &self.token, | ||||||
| @ -56,7 +62,10 @@ impl Client { | |||||||
|         Ok(signature.to_string()) |         Ok(signature.to_string()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn create_token_account(&self, recipient: &Pubkey) -> Result<Pubkey, Box<dyn Error>> { |     fn create_token_account( | ||||||
|  |         &self, | ||||||
|  |         recipient: &Pubkey, | ||||||
|  |     ) -> 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).is_err() { | ||||||
|             let create_token_account_instruction = create_associated_token_account( |             let create_token_account_instruction = create_associated_token_account( | ||||||
| @ -77,11 +86,12 @@ impl Client { | |||||||
|         Ok(address) |         Ok(address) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn wallet_address(&self) -> String { |     pub fn get_wallet_pubkey(&self) -> String { | ||||||
|  |         // Return the base58 string representation of the public key
 | ||||||
|         self.keypair.pubkey().to_string() |         self.keypair.pubkey().to_string() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn token_address(&self) -> String { |     pub fn get_token_address(&self) -> String { | ||||||
|         self.token.to_string() |         self.token.to_string() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -90,6 +100,30 @@ impl Client { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl TryFrom<Keys> for SolClient { | ||||||
|  |     type Error = String; | ||||||
|  | 
 | ||||||
|  |     fn try_from(keys: Keys) -> Result<Self, Self::Error> { | ||||||
|  |         use std::str::FromStr; | ||||||
|  |         let keypair = match Keypair::from_bytes(&keys.keypair) { | ||||||
|  |             Ok(k) => k, | ||||||
|  |             Err(_) => return Err("Could not parse keypair.".into()), | ||||||
|  |         }; | ||||||
|  |         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 }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl TryFrom<KeysFile> for SolClient { | ||||||
|  |     type Error = String; | ||||||
|  | 
 | ||||||
|  |     fn try_from(keys_file: KeysFile) -> Result<Self, Self::Error> { | ||||||
|  |         let keys: Keys = keys_file.into(); | ||||||
|  |         Self::try_from(keys) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| async fn wait_for_sol(client: &RpcClient, pubkey: &Pubkey) { | 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 { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user