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