Compare commits

..

1 Commits

Author SHA1 Message Date
6ca02e91b9
added app code from noor 2025-03-14 16:32:54 +02:00
6 changed files with 949 additions and 251 deletions

6
Cargo.lock generated

@ -246,7 +246,7 @@ dependencies = [
"prost-types", "prost-types",
"reqwest", "reqwest",
"serde", "serde",
"serde_json", "serde_yaml",
"thiserror", "thiserror",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
@ -307,6 +307,7 @@ dependencies = [
"iana-time-zone", "iana-time-zone",
"js-sys", "js-sys",
"num-traits", "num-traits",
"serde",
"wasm-bindgen", "wasm-bindgen",
"windows-targets", "windows-targets",
] ]
@ -403,6 +404,7 @@ dependencies = [
"lock_api", "lock_api",
"once_cell", "once_cell",
"parking_lot_core", "parking_lot_core",
"serde",
] ]
[[package]] [[package]]
@ -418,7 +420,7 @@ dependencies = [
[[package]] [[package]]
name = "detee-shared" name = "detee-shared"
version = "0.1.0" version = "0.1.0"
source = "git+ssh://git@gitea.detee.cloud/noormohammedb/detee-shared?branch=stable_01#b8f37dec1845d29ea0b69035712e6ebb214376f4" source = "git+ssh://git@gitea.detee.cloud/noormohammedb/detee-shared?branch=stable_01#099f0a0488bce8e59c9c9e9a5e9b1f24998f1633"
dependencies = [ dependencies = [
"base64", "base64",
"prost", "prost",

@ -5,16 +5,16 @@ edition = "2021"
[dependencies] [dependencies]
bs58 = "0.5.1" bs58 = "0.5.1"
chrono = "0.4.39" chrono = { version = "0.4.39", features = ["serde"] }
dashmap = "6.1.0" dashmap = { version = "6.1.0", features = ["serde"] }
ed25519-dalek = "2.1.1" ed25519-dalek = "2.1.1"
env_logger = "0.11.6" env_logger = "0.11.6"
log = "0.4.22" log = "0.4.22"
prost = "0.13.4" prost = "0.13.4"
prost-types = "0.13.4" prost-types = "0.13.4"
reqwest = "0.12.10" reqwest = "0.12.10"
serde = { version = "1.0.216", features = ["derive"] } serde = { version = "1.0.217", features = ["derive"] }
serde_json = "1.0.134" serde_yaml = "0.9.34"
thiserror = "2.0.11" thiserror = "2.0.11"
tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] }
tokio-stream = "0.1.17" tokio-stream = "0.1.17"

File diff suppressed because it is too large Load Diff

@ -1,5 +1,3 @@
#![allow(dead_code)]
pub mod snp_proto { pub mod snp_proto {
tonic::include_proto!("vm_proto"); tonic::include_proto!("vm_proto");
} }
@ -19,12 +17,13 @@ use tonic::{Request, Response, Status, Streaming};
use detee_shared::sgx::pb::brain::brain_app_cli_server::BrainAppCli; use detee_shared::sgx::pb::brain::brain_app_cli_server::BrainAppCli;
use detee_shared::sgx::pb::brain::brain_app_daemon_server::BrainAppDaemon; use detee_shared::sgx::pb::brain::brain_app_daemon_server::BrainAppDaemon;
use detee_shared::sgx::pb::brain::{ use detee_shared::sgx::pb::brain::{
AppContract, BrainMessageApp, DaemonMessageApp, DelAppReq, ListAppContractsReq, NewAppReq, AppContract, AppNodeFilters, AppNodeListResp, BrainMessageApp, DaemonMessageApp, DelAppReq,
NewAppRes, RegisterAppNodeReq, ListAppContractsReq, NewAppReq, NewAppRes, RegisterAppNodeReq,
}; };
const ADMIN_ACCOUNTS: &[&str] = &[ const ADMIN_ACCOUNTS: &[&str] = &[
"x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK", "x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK",
"FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL", "FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL",
"H21Shi4iE7vgfjWEQNvzmpmBMJSaiZ17PYUcdNoAoKNc",
]; ];
pub struct BrainDaemonMock { pub struct BrainDaemonMock {
@ -78,7 +77,7 @@ impl BrainVmDaemon for BrainDaemonMock {
info!("Starting registration process for {:?}", req); info!("Starting registration process for {:?}", req);
let node = crate::data::VmNode { let node = crate::data::VmNode {
public_key: req.node_pubkey.clone(), public_key: req.node_pubkey.clone(),
owner_key: req.owner_pubkey, operator_wallet: req.operator_wallet,
country: req.country, country: req.country,
region: req.region, region: req.region,
city: req.city, city: req.city,
@ -86,10 +85,10 @@ impl BrainVmDaemon for BrainDaemonMock {
price: req.price, price: req.price,
..Default::default() ..Default::default()
}; };
self.data.insert_node(node); self.data.register_node(node);
info!("Sending existing contracts to {}", req.node_pubkey); info!("Sending existing contracts to {}", req.node_pubkey);
let contracts = self.data.find_contracts_by_node_pubkey(&req.node_pubkey); let contracts = self.data.find_vm_contracts_by_node(&req.node_pubkey);
let (tx, rx) = mpsc::channel(6); let (tx, rx) = mpsc::channel(6);
tokio::spawn(async move { tokio::spawn(async move {
for contract in contracts { for contract in contracts {
@ -187,6 +186,14 @@ impl BrainCli for BrainCliMock {
async fn new_vm(&self, req: Request<NewVmReq>) -> Result<Response<NewVmResp>, Status> { async fn new_vm(&self, req: Request<NewVmReq>) -> Result<Response<NewVmResp>, Status> {
let req = check_sig_from_req(req)?; let req = check_sig_from_req(req)?;
info!("New VM requested via CLI: {req:?}"); info!("New VM requested via CLI: {req:?}");
if self
.data
.is_user_banned_by_node(&req.admin_pubkey, &req.node_pubkey)
{
return Err(Status::permission_denied(
"This operator banned you. What did you do?",
));
}
let admin_pubkey = req.admin_pubkey.clone(); let admin_pubkey = req.admin_pubkey.clone();
let (oneshot_tx, oneshot_rx) = tokio::sync::oneshot::channel(); let (oneshot_tx, oneshot_rx) = tokio::sync::oneshot::channel();
self.data.submit_newvm_req(req, oneshot_tx).await; self.data.submit_newvm_req(req, oneshot_tx).await;
@ -214,9 +221,9 @@ impl BrainCli for BrainCliMock {
info!("Sending UpdateVMResp: {response:?}"); info!("Sending UpdateVMResp: {response:?}");
Ok(Response::new(response)) Ok(Response::new(response))
} }
Err(_) => Err(Status::unknown( Err(e) => Err(Status::unknown(format!(
"Update VM request failed due to error: {e}", "Update VM request failed due to error: {e}"
)), ))),
} }
} }
@ -231,20 +238,55 @@ impl BrainCli for BrainCliMock {
} }
} }
async fn delete_vm(&self, req: Request<DeleteVmReq>) -> Result<Response<Empty>, Status> {
let req = check_sig_from_req(req)?;
match self.data.delete_vm(req).await {
Ok(()) => Ok(Response::new(Empty {})),
Err(e) => Err(Status::not_found(e.to_string())),
}
}
async fn report_node(&self, req: Request<ReportNodeReq>) -> Result<Response<Empty>, Status> {
let req = check_sig_from_req(req)?;
match self.data.find_contract_by_uuid(&req.contract) {
Ok(contract)
if contract.admin_pubkey == req.admin_pubkey
&& contract.node_pubkey == req.node_pubkey =>
{
()
}
_ => return Err(Status::unauthenticated("No contract found by this ID.")),
};
self.data
.report_node(req.admin_pubkey, &req.node_pubkey, req.reason);
Ok(Response::new(Empty {}))
}
type ListVmContractsStream = Pin<Box<dyn Stream<Item = Result<VmContract, Status>> + Send>>; type ListVmContractsStream = Pin<Box<dyn Stream<Item = Result<VmContract, Status>> + Send>>;
async fn list_vm_contracts( async fn list_vm_contracts(
&self, &self,
req: Request<ListVmContractsReq>, req: Request<ListVmContractsReq>,
) -> Result<Response<Self::ListVmContractsStream>, Status> { ) -> Result<Response<Self::ListVmContractsStream>, Status> {
let req = check_sig_from_req(req)?; let req = check_sig_from_req(req)?;
info!("CLI {} requested ListVMVmContractsStream", req.admin_pubkey); info!(
let contracts = match req.uuid.is_empty() { "CLI {} requested ListVMVmContractsStream. As operator: {}",
false => match self.data.find_contract_by_uuid(&req.uuid) { req.wallet, req.as_operator
Some(contract) => vec![contract], );
None => Vec::new(), let mut contracts = Vec::new();
}, if !req.uuid.is_empty() {
true => self.data.find_contracts_by_admin_pubkey(&req.admin_pubkey), if let Ok(specific_contract) = self.data.find_contract_by_uuid(&req.uuid) {
}; if specific_contract.admin_pubkey == req.wallet {
contracts.push(specific_contract);
}
// TODO: allow operator to inspect contracts
}
} else {
if req.as_operator {
contracts.append(&mut self.data.find_vm_contracts_by_operator(&req.wallet));
} else {
contracts.append(&mut self.data.find_vm_contracts_by_admin(&req.wallet));
}
}
let (tx, rx) = mpsc::channel(6); let (tx, rx) = mpsc::channel(6);
tokio::spawn(async move { tokio::spawn(async move {
for contract in contracts { for contract in contracts {
@ -264,7 +306,7 @@ impl BrainCli for BrainCliMock {
) -> Result<Response<Self::ListVmNodesStream>, tonic::Status> { ) -> Result<Response<Self::ListVmNodesStream>, tonic::Status> {
let req = check_sig_from_req(req)?; let req = check_sig_from_req(req)?;
info!("CLI requested ListVmNodesStream: {req:?}"); info!("CLI requested ListVmNodesStream: {req:?}");
let nodes = self.data.find_nodes_by_filters(&req); let nodes = self.data.find_vm_nodes_by_filters(&req);
let (tx, rx) = mpsc::channel(6); let (tx, rx) = mpsc::channel(6);
tokio::spawn(async move { tokio::spawn(async move {
for node in nodes { for node in nodes {
@ -291,12 +333,65 @@ impl BrainCli for BrainCliMock {
} }
} }
async fn delete_vm(&self, req: Request<DeleteVmReq>) -> Result<Response<Empty>, Status> { async fn register_operator(
&self,
req: Request<RegOperatorReq>,
) -> Result<Response<Empty>, Status> {
let req = check_sig_from_req(req)?; let req = check_sig_from_req(req)?;
info!("Unknown CLI requested to delete vm {}", req.uuid); info!("Regitering new operator: {req:?}");
match self.data.delete_vm(req).await { match self.data.register_operator(req) {
Ok(()) => Ok(Response::new(Empty {})), Ok(()) => Ok(Response::new(Empty {})),
Err(e) => Err(Status::not_found(e.to_string())), Err(e) => Err(Status::failed_precondition(e.to_string())),
}
}
async fn kick_contract(&self, req: Request<KickReq>) -> Result<Response<KickResp>, Status> {
let req = check_sig_from_req(req)?;
match self
.data
.kick_contract(&req.operator_wallet, &req.contract_uuid, &req.reason)
.await
{
Ok(nano_lp) => Ok(Response::new(KickResp { nano_lp })),
Err(e) => Err(Status::permission_denied(e.to_string())),
}
}
async fn ban_user(&self, req: Request<BanUserReq>) -> Result<Response<Empty>, Status> {
let req = check_sig_from_req(req)?;
self.data.ban_user(&req.operator_wallet, &req.user_wallet);
Ok(Response::new(Empty {}))
}
type ListOperatorsStream =
Pin<Box<dyn Stream<Item = Result<ListOperatorsResp, Status>> + Send>>;
async fn list_operators(
&self,
req: Request<Empty>,
) -> Result<Response<Self::ListOperatorsStream>, Status> {
let _ = check_sig_from_req(req)?;
let operators = self.data.list_operators();
let (tx, rx) = mpsc::channel(6);
tokio::spawn(async move {
for op in operators {
let _ = tx.send(Ok(op.into())).await;
}
});
let output_stream = ReceiverStream::new(rx);
Ok(Response::new(
Box::pin(output_stream) as Self::ListOperatorsStream
))
}
async fn inspect_operator(
&self,
req: Request<Pubkey>,
) -> Result<Response<InspectOperatorResp>, Status> {
match self.data.inspect_operator(&req.into_inner().pubkey) {
Some(op) => Ok(Response::new(op.into())),
None => Err(Status::not_found(
"The wallet you specified is not an operator",
)),
} }
} }
@ -307,6 +402,13 @@ impl BrainCli for BrainCliMock {
Ok(Response::new(Empty {})) Ok(Response::new(Empty {}))
} }
async fn slash(&self, req: Request<SlashReq>) -> Result<Response<Empty>, Status> {
check_admin_key(&req)?;
let req = check_sig_from_req(req)?;
self.data.slash_account(&req.pubkey, req.tokens);
Ok(Response::new(Empty {}))
}
type ListAllVmContractsStream = Pin<Box<dyn Stream<Item = Result<VmContract, Status>> + Send>>; type ListAllVmContractsStream = Pin<Box<dyn Stream<Item = Result<VmContract, Status>> + Send>>;
async fn list_all_vm_contracts( async fn list_all_vm_contracts(
&self, &self,
@ -352,17 +454,14 @@ trait PubkeyGetter {
fn get_pubkey(&self) -> Option<String>; fn get_pubkey(&self) -> Option<String>;
} }
impl PubkeyGetter for Pubkey {
fn get_pubkey(&self) -> Option<String> {
Some(self.pubkey.clone())
}
}
#[tonic::async_trait] #[tonic::async_trait]
impl BrainAppCli for BrainAppCliMock { impl BrainAppCli for BrainAppCliMock {
type ListAppContractsStream = Pin<Box<dyn Stream<Item = Result<AppContract, Status>> + Send>>; type ListAppContractsStream = Pin<Box<dyn Stream<Item = Result<AppContract, Status>> + Send>>;
type ListAppNodesStream = Pin<Box<dyn Stream<Item = Result<AppNodeListResp, Status>> + Send>>;
type ListAllAppContractsStream =
Pin<Box<dyn Stream<Item = Result<AppContract, Status>> + Send>>;
async fn create_app( async fn deploy_app(
&self, &self,
req: tonic::Request<NewAppReq>, req: tonic::Request<NewAppReq>,
) -> Result<tonic::Response<NewAppRes>, Status> { ) -> Result<tonic::Response<NewAppRes>, Status> {
@ -420,6 +519,54 @@ impl BrainAppCli for BrainAppCliMock {
Box::pin(output_stream) as Self::ListAppContractsStream Box::pin(output_stream) as Self::ListAppContractsStream
)) ))
} }
async fn list_app_nodes(
&self,
req: tonic::Request<AppNodeFilters>,
) -> Result<tonic::Response<Self::ListAppNodesStream>, Status> {
let req = check_sig_from_req(req)?;
info!("CLI requested ListAppNodes: {req:?}");
let nodes = self.data.find_app_nodes_by_filters(&req);
let (tx, rx) = mpsc::channel(6);
tokio::spawn(async move {
for node in nodes {
let _ = tx.send(Ok(node.into())).await;
}
});
let output_stream = ReceiverStream::new(rx);
Ok(Response::new(Box::pin(output_stream)))
}
async fn get_one_app_node(
&self,
req: tonic::Request<AppNodeFilters>,
) -> Result<tonic::Response<AppNodeListResp>, Status> {
let req = check_sig_from_req(req)?;
info!("CLI requested GetOneAppNode: {req:?}");
match self.data.get_one_app_node_by_filters(&req) {
Some(node) => Ok(Response::new(node.into())),
None => Err(Status::not_found(
"Could not find any node based on your search criteria",
)),
}
}
async fn list_all_app_contracts(
&self,
req: tonic::Request<detee_shared::sgx::pb::brain::Empty>,
) -> Result<tonic::Response<Self::ListAllAppContractsStream>, Status> {
check_admin_key(&req)?;
let _ = check_sig_from_req(req)?;
let contracts = self.data.list_all_app_contracts();
let (tx, rx) = mpsc::channel(6);
tokio::spawn(async move {
for contract in contracts {
let _ = tx.send(Ok(contract.into())).await;
}
});
let output_stream = ReceiverStream::new(rx);
Ok(Response::new(Box::pin(output_stream)))
}
} }
#[tonic::async_trait] #[tonic::async_trait]
@ -435,26 +582,22 @@ impl BrainAppDaemon for BrainAppDaemonMock {
log::info!( log::info!(
"registering app node_key : {}, operator_key: {}", "registering app node_key : {}, operator_key: {}",
&req_data.node_pubkey, &req_data.node_pubkey,
&req_data.operator_pubkey &req_data.operator_wallet
); );
let app_node = crate::data::AppNode { let app_node = crate::data::AppNode {
node_pubkey: req_data.node_pubkey.clone(), node_pubkey: req_data.node_pubkey.clone(),
operator_pubkey: req_data.operator_pubkey, operator_wallet: req_data.operator_wallet,
ip: req_data.main_ip, ip: req_data.main_ip,
city: req_data.city, city: req_data.city,
region: req_data.region, region: req_data.region,
country: req_data.country, country: req_data.country,
..Default::default() ..Default::default()
}; };
self.data.register_app_node(app_node);
self.data.insert_app_node(app_node);
log::info!("Sending existing contracts to {}", &req_data.node_pubkey); log::info!("Sending existing contracts to {}", &req_data.node_pubkey);
let app_contracts = self.data.find_app_contracts_by_node(&req_data.node_pubkey);
let app_contracts = self
.data
.find_app_contracts_by_node_pubkey(&req_data.node_pubkey);
let (tx, rx) = mpsc::channel(6); let (tx, rx) = mpsc::channel(6);
tokio::spawn(async move { tokio::spawn(async move {
for contract in app_contracts { for contract in app_contracts {
@ -549,83 +692,48 @@ impl BrainAppDaemon for BrainAppDaemonMock {
Ok(Response::new(detee_shared::sgx::pb::brain::Empty {})) Ok(Response::new(detee_shared::sgx::pb::brain::Empty {}))
} }
} }
impl PubkeyGetter for NewVmReq {
fn get_pubkey(&self) -> Option<String> {
Some(self.admin_pubkey.clone())
}
}
impl PubkeyGetter for DeleteVmReq { macro_rules! impl_pubkey_getter {
($t:ty, $field:ident) => {
impl PubkeyGetter for $t {
fn get_pubkey(&self) -> Option<String> { fn get_pubkey(&self) -> Option<String> {
Some(self.admin_pubkey.clone()) Some(self.$field.clone())
} }
} }
};
impl PubkeyGetter for UpdateVmReq { ($t:ty) => {
fn get_pubkey(&self) -> Option<String> { impl PubkeyGetter for $t {
Some(self.admin_pubkey.clone())
}
}
impl PubkeyGetter for ExtendVmReq {
fn get_pubkey(&self) -> Option<String> {
Some(self.admin_pubkey.clone())
}
}
impl PubkeyGetter for ListVmContractsReq {
fn get_pubkey(&self) -> Option<String> {
Some(self.admin_pubkey.clone())
}
}
impl PubkeyGetter for VmNodeFilters {
fn get_pubkey(&self) -> Option<String> { fn get_pubkey(&self) -> Option<String> {
None None
} }
} }
};
impl PubkeyGetter for RegisterVmNodeReq {
fn get_pubkey(&self) -> Option<String> {
Some(self.node_pubkey.clone())
}
} }
impl PubkeyGetter for Empty { impl_pubkey_getter!(Pubkey, pubkey);
fn get_pubkey(&self) -> Option<String> { impl_pubkey_getter!(NewVmReq, admin_pubkey);
None impl_pubkey_getter!(DeleteVmReq, admin_pubkey);
} impl_pubkey_getter!(UpdateVmReq, admin_pubkey);
} impl_pubkey_getter!(ExtendVmReq, admin_pubkey);
impl_pubkey_getter!(ReportNodeReq, admin_pubkey);
impl_pubkey_getter!(ListVmContractsReq, wallet);
impl_pubkey_getter!(RegisterVmNodeReq, node_pubkey);
impl_pubkey_getter!(RegOperatorReq, pubkey);
impl_pubkey_getter!(KickReq, operator_wallet);
impl_pubkey_getter!(BanUserReq, operator_wallet);
impl PubkeyGetter for AirdropReq { impl_pubkey_getter!(VmNodeFilters);
fn get_pubkey(&self) -> Option<String> { impl_pubkey_getter!(Empty);
None impl_pubkey_getter!(AirdropReq);
} impl_pubkey_getter!(SlashReq);
}
impl PubkeyGetter for RegisterAppNodeReq { impl_pubkey_getter!(NewAppReq, admin_pubkey);
fn get_pubkey(&self) -> Option<String> { impl_pubkey_getter!(DelAppReq, admin_pubkey);
None impl_pubkey_getter!(ListAppContractsReq, admin_pubkey);
}
}
impl PubkeyGetter for NewAppReq { impl_pubkey_getter!(RegisterAppNodeReq);
fn get_pubkey(&self) -> Option<String> { impl_pubkey_getter!(detee_shared::sgx::pb::brain::Empty);
Some(self.admin_pubkey.clone()) impl_pubkey_getter!(AppNodeFilters);
}
}
impl PubkeyGetter for DelAppReq {
fn get_pubkey(&self) -> Option<String> {
Some(self.admin_pubkey.clone())
}
}
impl PubkeyGetter for ListAppContractsReq {
fn get_pubkey(&self) -> Option<String> {
Some(self.admin_pubkey.clone())
}
}
fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) -> Result<T, Status> { fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) -> Result<T, Status> {
let time = match req.metadata().get("timestamp") { let time = match req.metadata().get("timestamp") {
@ -640,9 +748,9 @@ fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) -> Res
let parsed_time = chrono::DateTime::parse_from_rfc3339(time) let parsed_time = chrono::DateTime::parse_from_rfc3339(time)
.map_err(|_| Status::unauthenticated("Coult not parse timestamp"))?; .map_err(|_| Status::unauthenticated("Coult not parse timestamp"))?;
let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds(); let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds();
if seconds_elapsed > 1 || seconds_elapsed < -1 { if seconds_elapsed > 4 || seconds_elapsed < -4 {
return Err(Status::unauthenticated(format!( return Err(Status::unauthenticated(format!(
"Date is not within 1 sec of the time of the server: CLI {} vs Server {}", "Date is not within 4 sec of the time of the server: CLI {} vs Server {}",
parsed_time, now parsed_time, now
))); )));
} }
@ -695,9 +803,9 @@ fn check_sig_from_parts(pubkey: &str, time: &str, msg: &str, sig: &str) -> Resul
let parsed_time = chrono::DateTime::parse_from_rfc3339(time) let parsed_time = chrono::DateTime::parse_from_rfc3339(time)
.map_err(|_| Status::unauthenticated("Coult not parse timestamp"))?; .map_err(|_| Status::unauthenticated("Coult not parse timestamp"))?;
let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds(); let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds();
if seconds_elapsed > 1 || seconds_elapsed < -1 { if seconds_elapsed > 4 || seconds_elapsed < -4 {
return Err(Status::unauthenticated(format!( return Err(Status::unauthenticated(format!(
"Date is not within 1 sec of the time of the server: CLI {} vs Server {}", "Date is not within 4 sec of the time of the server: CLI {} vs Server {}",
parsed_time, now parsed_time, now
))); )));
} }

@ -23,7 +23,12 @@ async fn main() {
tokio::spawn(async move { tokio::spawn(async move {
loop { loop {
tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; tokio::time::sleep(tokio::time::Duration::from_secs(60)).await;
data_clone.vm_nodes_cron().await;
data_clone.vm_contracts_cron().await; data_clone.vm_contracts_cron().await;
data_clone.app_contracts_cron().await;
if let Err(e) = data_clone.save_to_disk() {
log::error!("Could not save data to disk due to error: {e}")
}
} }
}); });
let addr = "0.0.0.0:31337".parse().unwrap(); let addr = "0.0.0.0:31337".parse().unwrap();

@ -55,7 +55,7 @@ message MeasurementIP {
// This should also include a block hash or similar, for auth // This should also include a block hash or similar, for auth
message RegisterVmNodeReq { message RegisterVmNodeReq {
string node_pubkey = 1; string node_pubkey = 1;
string owner_pubkey = 2; string operator_wallet = 2;
string main_ip = 3; string main_ip = 3;
string country = 4; string country = 4;
string region = 5; string region = 5;
@ -154,8 +154,8 @@ service BrainVmDaemon {
} }
message ListVmContractsReq { message ListVmContractsReq {
string admin_pubkey = 1; string wallet = 1;
string node_pubkey = 2; bool as_operator = 2;
string uuid = 3; string uuid = 3;
} }
@ -174,15 +174,14 @@ message VmNodeFilters {
} }
message VmNodeListResp { message VmNodeListResp {
string node_pubkey = 1; string operator = 1;
string country = 2; string node_pubkey = 2;
string region = 3; string country = 3;
string city = 4; string region = 4;
string ip = 5; // required for latency test string city = 5;
uint32 server_rating = 6; string ip = 6; // required for latency test
uint32 provider_rating = 7; repeated string reports = 7; // TODO: this will become an enum
// nanoLP per unit per minute uint64 price = 8; // nanoLP per unit per minute
uint64 price = 8;
} }
message ExtendVmReq { message ExtendVmReq {
@ -196,12 +195,59 @@ message AirdropReq {
uint64 tokens = 2; uint64 tokens = 2;
} }
message SlashReq {
string pubkey = 1;
uint64 tokens = 2;
}
message Account { message Account {
string pubkey = 1; string pubkey = 1;
uint64 balance = 2; uint64 balance = 2;
uint64 tmp_locked = 3; uint64 tmp_locked = 3;
} }
message RegOperatorReq {
string pubkey = 1;
uint64 escrow = 2;
string email = 3;
}
message ListOperatorsResp {
string pubkey = 1;
uint64 escrow = 2;
string email = 3;
uint64 app_nodes = 4;
uint64 vm_nodes = 5;
uint64 reports = 6;
}
message InspectOperatorResp {
ListOperatorsResp operator = 1;
repeated VmNodeListResp nodes = 2;
}
message ReportNodeReq {
string admin_pubkey = 1;
string node_pubkey = 2;
string contract = 3;
string reason = 4;
}
message KickReq {
string operator_wallet = 1;
string contract_uuid = 2;
string reason = 3;
}
message BanUserReq {
string operator_wallet = 1;
string user_wallet = 2;
}
message KickResp {
uint64 nano_lp = 1;
}
service BrainCli { service BrainCli {
rpc GetBalance (Pubkey) returns (AccountBalance); rpc GetBalance (Pubkey) returns (AccountBalance);
rpc NewVm (NewVmReq) returns (NewVmResp); rpc NewVm (NewVmReq) returns (NewVmResp);
@ -211,8 +257,15 @@ service BrainCli {
rpc DeleteVm (DeleteVmReq) returns (Empty); rpc DeleteVm (DeleteVmReq) returns (Empty);
rpc UpdateVm (UpdateVmReq) returns (UpdateVmResp); rpc UpdateVm (UpdateVmReq) returns (UpdateVmResp);
rpc ExtendVm (ExtendVmReq) returns (Empty); rpc ExtendVm (ExtendVmReq) returns (Empty);
rpc ReportNode (ReportNodeReq) returns (Empty);
rpc ListOperators (Empty) returns (stream ListOperatorsResp);
rpc InspectOperator (Pubkey) returns (InspectOperatorResp);
rpc RegisterOperator (RegOperatorReq) returns (Empty);
rpc KickContract (KickReq) returns (KickResp);
rpc BanUser (BanUserReq) returns (Empty);
// admin commands // admin commands
rpc Airdrop (AirdropReq) returns (Empty); rpc Airdrop (AirdropReq) returns (Empty);
rpc Slash (SlashReq) returns (Empty);
rpc ListAllVmContracts (Empty) returns (stream VmContract); rpc ListAllVmContracts (Empty) returns (stream VmContract);
rpc ListAccounts (Empty) returns (stream Account); rpc ListAccounts (Empty) returns (stream Account);
} }