forked from ghe0/brain-mock
Implement app contracts pricing methods with cron job
This commit is contained in:
parent
92a26c5f66
commit
928a7d029b
101
src/data.rs
101
src/data.rs
@ -1,7 +1,6 @@
|
|||||||
use crate::grpc::snp_proto::{self as grpc};
|
use crate::grpc::snp_proto::{self as grpc};
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use detee_shared::sgx::pb::brain::DelAppReq;
|
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@ -14,10 +13,12 @@ use std::{
|
|||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
use tokio::sync::oneshot::Sender as OneshotSender;
|
use tokio::sync::oneshot::Sender as OneshotSender;
|
||||||
|
|
||||||
|
use detee_shared::sgx::pb::brain::brain_message_app;
|
||||||
use detee_shared::sgx::pb::brain::AppContract as AppContractPB;
|
use detee_shared::sgx::pb::brain::AppContract as AppContractPB;
|
||||||
use detee_shared::sgx::pb::brain::AppNodeResources;
|
use detee_shared::sgx::pb::brain::AppNodeResources;
|
||||||
use detee_shared::sgx::pb::brain::AppResource as AppResourcePB;
|
use detee_shared::sgx::pb::brain::AppResource as AppResourcePB;
|
||||||
use detee_shared::sgx::pb::brain::BrainMessageApp;
|
use detee_shared::sgx::pb::brain::BrainMessageApp;
|
||||||
|
use detee_shared::sgx::pb::brain::DelAppReq;
|
||||||
use detee_shared::sgx::pb::brain::MappedPort;
|
use detee_shared::sgx::pb::brain::MappedPort;
|
||||||
use detee_shared::sgx::pb::brain::NewAppReq;
|
use detee_shared::sgx::pb::brain::NewAppReq;
|
||||||
use detee_shared::sgx::pb::brain::NewAppRes;
|
use detee_shared::sgx::pb::brain::NewAppRes;
|
||||||
@ -39,7 +40,7 @@ pub enum Error {
|
|||||||
AccessDenied,
|
AccessDenied,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
#[derive(Clone, Default, Serialize, Deserialize, Debug)]
|
||||||
pub struct AccountData {
|
pub struct AccountData {
|
||||||
pub balance: u64,
|
pub balance: u64,
|
||||||
pub tmp_locked: u64,
|
pub tmp_locked: u64,
|
||||||
@ -193,6 +194,24 @@ pub struct AppContract {
|
|||||||
pub public_package_mr_enclave: Option<Vec<u8>>,
|
pub public_package_mr_enclave: Option<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AppContract {
|
||||||
|
fn total_units(&self) -> u64 {
|
||||||
|
// TODO: Optimize this based on price of hardware.
|
||||||
|
(self.vcpus as u64 * 10)
|
||||||
|
+ (self.memory_mb as u64 / 200)
|
||||||
|
+ (self.disk_size_mb as u64 / 10000)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn price_estimate(vcpus: u32, memory_mb: u32, disk_size_mb: u32) -> u64 {
|
||||||
|
(vcpus as u64 * 10) + (memory_mb as u64 / 200) + (disk_size_mb as u64 / 10000)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns price per minute in nanoLP
|
||||||
|
fn price_per_minute(&self) -> u64 {
|
||||||
|
self.total_units() * self.price_per_unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<AppContract> for AppContractPB {
|
impl From<AppContract> for AppContractPB {
|
||||||
fn from(value: AppContract) -> Self {
|
fn from(value: AppContract) -> Self {
|
||||||
let mapped_ports = value
|
let mapped_ports = value
|
||||||
@ -243,6 +262,8 @@ pub struct AppNode {
|
|||||||
pub max_ports_per_app: u32,
|
pub max_ports_per_app: u32,
|
||||||
// nanotokens per unit per minute
|
// nanotokens per unit per minute
|
||||||
pub price: u64,
|
pub price: u64,
|
||||||
|
|
||||||
|
pub offline_minutes: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
@ -1183,6 +1204,11 @@ impl BrainData {
|
|||||||
contracts.iter().find(|c| c.uuid == uuid).cloned()
|
contracts.iter().find(|c| c.uuid == uuid).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_app_node_by_pubkey(&self, public_key: &str) -> Option<AppNode> {
|
||||||
|
let nodes = self.app_nodes.read().unwrap();
|
||||||
|
nodes.iter().cloned().find(|n| n.node_pubkey == public_key)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_app_contracts_by_admin_pubkey(&self, admin_pubkey: &str) -> Vec<AppContract> {
|
pub fn find_app_contracts_by_admin_pubkey(&self, admin_pubkey: &str) -> Vec<AppContract> {
|
||||||
debug!("Searching contracts for admin pubkey {admin_pubkey}");
|
debug!("Searching contracts for admin pubkey {admin_pubkey}");
|
||||||
let contracts: Vec<AppContract> = self
|
let contracts: Vec<AppContract> = self
|
||||||
@ -1206,6 +1232,60 @@ impl BrainData {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn app_contracts_cron(&self) {
|
||||||
|
let mut deleted_app_contracts: Vec<(String, String)> = Vec::new();
|
||||||
|
log::debug!("Running app contracts cron...");
|
||||||
|
{
|
||||||
|
let mut app_contracts = self.app_contracts.write().unwrap();
|
||||||
|
app_contracts.retain_mut(|c| {
|
||||||
|
let node = self.find_app_node_by_pubkey(&c.node_pubkey).unwrap();
|
||||||
|
if node.offline_minutes == 0 {
|
||||||
|
let operator_wallet = node.operator_wallet.clone();
|
||||||
|
let minutes_to_collect = (Utc::now() - c.collected_at).num_minutes() as u64;
|
||||||
|
c.collected_at = Utc::now();
|
||||||
|
dbg!(&minutes_to_collect);
|
||||||
|
dbg!(&c.price_per_minute());
|
||||||
|
let mut nanolp_to_collect =
|
||||||
|
c.price_per_minute().saturating_mul(minutes_to_collect);
|
||||||
|
if nanolp_to_collect > c.locked_nano {
|
||||||
|
nanolp_to_collect = c.locked_nano;
|
||||||
|
}
|
||||||
|
dbg!(&nanolp_to_collect);
|
||||||
|
log::debug!("Removing {nanolp_to_collect} nanoLP from {}", c.uuid);
|
||||||
|
c.locked_nano -= nanolp_to_collect;
|
||||||
|
let escrow_multiplier = match self.operators.get(&operator_wallet) {
|
||||||
|
Some(op) if op.escrow > 5000 => match self.operators.get(&c.admin_pubkey) {
|
||||||
|
Some(user_is_op) if user_is_op.escrow > 5000 => 1,
|
||||||
|
_ => 5,
|
||||||
|
},
|
||||||
|
_ => 1,
|
||||||
|
};
|
||||||
|
self.add_nano_to_wallet(
|
||||||
|
&operator_wallet,
|
||||||
|
nanolp_to_collect * escrow_multiplier,
|
||||||
|
);
|
||||||
|
if c.locked_nano == 0 {
|
||||||
|
deleted_app_contracts.push((c.uuid.clone(), c.node_pubkey.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.locked_nano > 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// inform daemons of the deletion of the contracts
|
||||||
|
for (uuid, node_pubkey) in deleted_app_contracts.iter() {
|
||||||
|
if let Some(app_daemon_tx) = self.app_daemon_tx.get(&node_pubkey.clone()) {
|
||||||
|
let msg = BrainMessageApp {
|
||||||
|
msg: Some(brain_message_app::Msg::DeleteAppReq(DelAppReq {
|
||||||
|
uuid: uuid.to_string(),
|
||||||
|
admin_pubkey: String::new(),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
let app_daemon_tx = app_daemon_tx.clone();
|
||||||
|
let _ = app_daemon_tx.send(msg).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn submit_app_node_resources(&self, node_resource: AppNodeResources) {
|
pub fn submit_app_node_resources(&self, node_resource: AppNodeResources) {
|
||||||
debug!("{:#?}", &node_resource);
|
debug!("{:#?}", &node_resource);
|
||||||
let mut nodes = self.app_nodes.write().unwrap();
|
let mut nodes = self.app_nodes.write().unwrap();
|
||||||
@ -1231,6 +1311,23 @@ impl BrainData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_new_container_req(&self, mut req: NewAppReq, tx: OneshotSender<NewAppRes>) {
|
pub async fn send_new_container_req(&self, mut req: NewAppReq, tx: OneshotSender<NewAppRes>) {
|
||||||
|
// TODO: make sure locked_nano in cli
|
||||||
|
if req.locked_nano == 0 {
|
||||||
|
let resource = req.resource.clone().unwrap_or_default();
|
||||||
|
req.locked_nano =
|
||||||
|
AppContract::price_estimate(resource.vcpu, resource.memory_mb, resource.disk_mb)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = self.lock_nanotockens(&req.admin_pubkey, req.locked_nano) {
|
||||||
|
let _ = tx.send(NewAppRes {
|
||||||
|
uuid: String::new(),
|
||||||
|
error: e.to_string(),
|
||||||
|
status: "failed".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
req.uuid = uuid::Uuid::new_v4().to_string();
|
req.uuid = uuid::Uuid::new_v4().to_string();
|
||||||
|
|
||||||
info!("Inserting new container request in memory: {req:?}");
|
info!("Inserting new container request in memory: {req:?}");
|
||||||
|
@ -25,6 +25,7 @@ async fn main() {
|
|||||||
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_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() {
|
if let Err(e) = data_clone.save_to_disk() {
|
||||||
log::error!("Could not save data to disk due to error: {e}")
|
log::error!("Could not save data to disk due to error: {e}")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user