payments on app deployment and refund for vm and app deletion #5
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -1000,7 +1000,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/testnet/proto?branch=surreal_brain_app#694d5811aa0edc9b2b9bdb17c6e972b04a21b96f" | source = "git+ssh://git@gitea.detee.cloud/testnet/proto?branch=surreal_brain_app#005677153b3fcd3251b64111a736c806106fdc04" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "bincode 2.0.1", |  "bincode 2.0.1", | ||||||
|  "prost", |  "prost", | ||||||
|  | |||||||
| @ -295,8 +295,6 @@ impl From<ActiveApp> for DeletedApp { | |||||||
|             disk_size_gb: value.disk_size_gb, |             disk_size_gb: value.disk_size_gb, | ||||||
|             created_at: value.created_at, |             created_at: value.created_at, | ||||||
|             price_per_unit: value.price_per_unit, |             price_per_unit: value.price_per_unit, | ||||||
|             locked_nano: value.locked_nano, |  | ||||||
|             collected_at: value.collected_at, |  | ||||||
|             mr_enclave: value.mr_enclave, |             mr_enclave: value.mr_enclave, | ||||||
|             package_url: value.package_url, |             package_url: value.package_url, | ||||||
|             hratls_pubkey: value.hratls_pubkey, |             hratls_pubkey: value.hratls_pubkey, | ||||||
| @ -359,15 +357,42 @@ impl ActiveApp { | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub async fn delete(db: &Surreal<Client>, id: &str) -> Result<bool, Error> { |     pub async fn delete(db: &Surreal<Client>, admin: &str, id: &str) -> Result<(), Error> { | ||||||
|         let deleted_app: Option<Self> = db.delete((ACTIVE_APP, id)).await?; |         let mut app_del_resp = db | ||||||
|         if let Some(deleted_app) = deleted_app { |             .query( | ||||||
|             let deleted_app: DeletedApp = deleted_app.into(); |                 " | ||||||
|             let _: Vec<DeletedApp> = db.insert(DELETED_APP).relation(deleted_app).await?; |             BEGIN TRANSACTION; | ||||||
|             Ok(true) | 
 | ||||||
|         } else { |                 LET $active_app = $app_id_input; | ||||||
|             Ok(false) |                 LET $admin = $admin_input; | ||||||
|  | 
 | ||||||
|  |                 IF $active_app.in != $admin { | ||||||
|  |                     THROW 'Unauthorized' | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 return fn::delete_app($active_app); | ||||||
|  | 
 | ||||||
|  |             COMMIT TRANSACTION; | ||||||
|  |             ",
 | ||||||
|  |             ) | ||||||
|  |             .bind(("app_id_input", RecordId::from((ACTIVE_APP, id)))) | ||||||
|  |             .bind(("admin_input", RecordId::from((ACCOUNT, admin)))) | ||||||
|  |             .await?; | ||||||
|  | 
 | ||||||
|  |         log::trace!("delete_app query response: {app_del_resp:?}"); | ||||||
|  | 
 | ||||||
|  |         let query_err = app_del_resp.take_errors(); | ||||||
|  |         if !query_err.is_empty() { | ||||||
|  |             log::trace!("errors in delete_app: {query_err:?}"); | ||||||
|  |             let tx_fail_err_str = | ||||||
|  |                 String::from("The query was not executed due to a failed transaction"); | ||||||
|  | 
 | ||||||
|  |             if query_err.contains_key(&2) && query_err[&2].to_string() != tx_fail_err_str { | ||||||
|  |                 log::error!("Unauthorized: {}", query_err[&2]); | ||||||
|  |                 return Err(Error::AccessDenied); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |         Ok(()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -653,9 +678,17 @@ pub struct DeletedApp { | |||||||
|     pub disk_size_gb: u32, |     pub disk_size_gb: u32, | ||||||
|     pub created_at: Datetime, |     pub created_at: Datetime, | ||||||
|     pub price_per_unit: u64, |     pub price_per_unit: u64, | ||||||
|     pub locked_nano: u64, |  | ||||||
|     pub collected_at: Datetime, |  | ||||||
|     pub mr_enclave: String, |     pub mr_enclave: String, | ||||||
|     pub package_url: String, |     pub package_url: String, | ||||||
|     pub hratls_pubkey: String, |     pub hratls_pubkey: String, | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | impl DeletedApp { | ||||||
|  |     pub async fn list_by_node(db: &Surreal<Client>, node_pubkey: &str) -> Result<Vec<Self>, Error> { | ||||||
|  |         let mut result = db | ||||||
|  |             .query(format!("select * from {DELETED_APP} where out = {APP_NODE}:{node_pubkey};")) | ||||||
|  |             .await?; | ||||||
|  |         let contracts: Vec<Self> = result.take(0)?; | ||||||
|  |         Ok(contracts) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										43
									
								
								src/db/vm.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										43
									
								
								src/db/vm.rs
									
									
									
									
									
								
							| @ -546,15 +546,42 @@ impl ActiveVm { | |||||||
|         Ok(false) |         Ok(false) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub async fn delete(db: &Surreal<Client>, id: &str) -> Result<bool, Error> { |     pub async fn delete(db: &Surreal<Client>, admin: &str, id: &str) -> Result<(), Error> { | ||||||
|         let deleted_vm: Option<Self> = db.delete((ACTIVE_VM, id)).await?; |         let mut vm_del_resp = db | ||||||
|         if let Some(deleted_vm) = deleted_vm { |             .query( | ||||||
|             let deleted_vm: DeletedVm = deleted_vm.into(); |                 " | ||||||
|             let _: Vec<DeletedVm> = db.insert(DELETED_VM).relation(deleted_vm).await?; |             BEGIN TRANSACTION; | ||||||
|             Ok(true) | 
 | ||||||
|         } else { |                 LET $active_vm = $vm_id_input; | ||||||
|             Ok(false) |                 LET $admin = $admin_input; | ||||||
|  | 
 | ||||||
|  |                 IF $active_vm.in != $admin { | ||||||
|  |                     THROW 'Unauthorized' | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 return fn::delete_vm($active_vm); | ||||||
|  | 
 | ||||||
|  |             COMMIT TRANSACTION; | ||||||
|  |             ",
 | ||||||
|  |             ) | ||||||
|  |             .bind(("vm_id_input", RecordId::from((ACTIVE_VM, id)))) | ||||||
|  |             .bind(("admin_input", RecordId::from((ACCOUNT, admin)))) | ||||||
|  |             .await?; | ||||||
|  | 
 | ||||||
|  |         log::trace!("delete_vm query response: {vm_del_resp:?}"); | ||||||
|  | 
 | ||||||
|  |         let query_err = vm_del_resp.take_errors(); | ||||||
|  |         if !query_err.is_empty() { | ||||||
|  |             log::trace!("errors in delete_vm: {query_err:?}"); | ||||||
|  |             let tx_fail_err_str = | ||||||
|  |                 String::from("The query was not executed due to a failed transaction"); | ||||||
|  | 
 | ||||||
|  |             if query_err.contains_key(&2) && query_err[&2].to_string() != tx_fail_err_str { | ||||||
|  |                 log::error!("Unauthorized: {}", query_err[&2]); | ||||||
|  |                 return Err(Error::AccessDenied); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub async fn extend_time( |     pub async fn extend_time( | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ impl AppDaemonServer { | |||||||
| 
 | 
 | ||||||
| #[tonic::async_trait] | #[tonic::async_trait] | ||||||
| impl BrainAppDaemon for AppDaemonServer { | impl BrainAppDaemon for AppDaemonServer { | ||||||
|     type RegisterAppNodeStream = Pin<Box<dyn Stream<Item = Result<AppContract, Status>> + Send>>; |     type RegisterAppNodeStream = Pin<Box<dyn Stream<Item = Result<DelAppReq, Status>> + Send>>; | ||||||
|     type BrainMessagesStream = Pin<Box<dyn Stream<Item = Result<BrainMessageApp, Status>> + Send>>; |     type BrainMessagesStream = Pin<Box<dyn Stream<Item = Result<BrainMessageApp, Status>> + Send>>; | ||||||
| 
 | 
 | ||||||
|     async fn register_app_node( |     async fn register_app_node( | ||||||
| @ -59,11 +59,11 @@ impl BrainAppDaemon for AppDaemonServer { | |||||||
|         app_node.register(&self.db).await?; |         app_node.register(&self.db).await?; | ||||||
|         info!("Sending existing contracts to {}", req.node_pubkey); |         info!("Sending existing contracts to {}", req.node_pubkey); | ||||||
| 
 | 
 | ||||||
|         let contracts = db::ActiveAppWithNode::list_by_node(&self.db, &req.node_pubkey).await?; |         let deleted_apps = db::DeletedApp::list_by_node(&self.db, &req.node_pubkey).await?; | ||||||
|         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 deleted_app in deleted_apps { | ||||||
|                 let _ = tx.send(Ok(contract.into())).await; |                 let _ = tx.send(Ok(deleted_app.into())).await; | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
| @ -226,9 +226,15 @@ impl BrainAppCli for AppCliServer { | |||||||
|     async fn delete_app(&self, req: Request<DelAppReq>) -> Result<Response<Empty>, Status> { |     async fn delete_app(&self, req: Request<DelAppReq>) -> Result<Response<Empty>, Status> { | ||||||
|         let req = check_sig_from_req(req)?; |         let req = check_sig_from_req(req)?; | ||||||
|         info!("delete_app process starting for {:?}", req); |         info!("delete_app process starting for {:?}", req); | ||||||
|         match ActiveApp::delete(&self.db, &req.uuid).await? { |         match ActiveApp::delete(&self.db, &req.admin_pubkey, &req.uuid).await { | ||||||
|             true => Ok(Response::new(Empty {})), |             Ok(()) => Ok(Response::new(Empty {})), | ||||||
|             false => Err(Status::not_found(format!("Could not find App contract {}", &req.uuid))), |             Err(db::Error::AccessDenied) => Err(Status::permission_denied("Unauthorized")), | ||||||
|  |             Err(e) => { | ||||||
|  |                 log::error!("Error deleting app contract {}: {e}", &req.uuid); | ||||||
|  |                 Err(Status::unknown( | ||||||
|  |                     "Unknown error. Please try again or contact the DeTEE devs team.", | ||||||
|  |                 )) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -342,9 +342,15 @@ impl BrainVmCli for VmCliServer { | |||||||
| 
 | 
 | ||||||
|     async fn delete_vm(&self, req: Request<DeleteVmReq>) -> Result<Response<Empty>, Status> { |     async fn delete_vm(&self, req: Request<DeleteVmReq>) -> Result<Response<Empty>, Status> { | ||||||
|         let req = check_sig_from_req(req)?; |         let req = check_sig_from_req(req)?; | ||||||
|         match db::ActiveVm::delete(&self.db, &req.uuid).await? { |         match db::ActiveVm::delete(&self.db, &req.admin_pubkey, &req.uuid).await { | ||||||
|             true => Ok(Response::new(Empty {})), |             Ok(()) => Ok(Response::new(Empty {})), | ||||||
|             false => Err(Status::not_found(format!("Could not find VM contract {}", &req.uuid))), |             Err(db::Error::AccessDenied) => Err(Status::permission_denied("Unauthorized")), | ||||||
|  |             Err(e) => { | ||||||
|  |                 log::error!("Error deleting VM contract {}: {e}", &req.uuid); | ||||||
|  |                 Err(Status::unknown( | ||||||
|  |                     "Unknown error. Please try again or contact the DeTEE devs team.", | ||||||
|  |                 )) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ DEFINE FUNCTION OVERWRITE fn::delete_vm( | |||||||
|         UPDATE $account SET balance += $vm.locked_nano; |         UPDATE $account SET balance += $vm.locked_nano; | ||||||
|     }; |     }; | ||||||
|     INSERT RELATION INTO deleted_vm ( $deleted_vm ); |     INSERT RELATION INTO deleted_vm ( $deleted_vm ); | ||||||
|     DELETE $vm.id; |     RETURN DELETE $vm.id RETURN BEFORE; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| DEFINE FUNCTION OVERWRITE fn::app_price_per_minute( | DEFINE FUNCTION OVERWRITE fn::app_price_per_minute( | ||||||
| @ -35,3 +35,20 @@ DEFINE FUNCTION OVERWRITE fn::app_price_per_minute( | |||||||
|         ($app.disk_size_gb / 10)) |         ($app.disk_size_gb / 10)) | ||||||
|     * $app.price_per_unit; |     * $app.price_per_unit; | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | DEFINE FUNCTION OVERWRITE fn::delete_app( | ||||||
|  | 	$app_id: record | ||||||
|  | ) { | ||||||
|  |     LET $app = (select * from $app_id)[0]; | ||||||
|  |     LET $account = $app.in; | ||||||
|  |     LET $deleted_app = $app.patch([{ | ||||||
|  | 		'op': 'replace', | ||||||
|  | 		'path': 'id', | ||||||
|  | 		'value': type::record("deleted_app:" + record::id($app.id)) | ||||||
|  |     }]); | ||||||
|  |     IF $app.locked_nano >= 0 { | ||||||
|  |         UPDATE $account SET balance += $app.locked_nano; | ||||||
|  |     }; | ||||||
|  |     INSERT RELATION INTO deleted_app ( $deleted_app ); | ||||||
|  |     RETURN DELETE $app.id RETURN BEFORE; | ||||||
|  | }; | ||||||
| @ -27,3 +27,5 @@ FOR $contract IN (select * from active_vm fetch out) { | |||||||
|         fn::delete_vm($contract.id); |         fn::delete_vm($contract.id); | ||||||
|     }; |     }; | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | -- TODO: implement for active_app | ||||||
							
								
								
									
										31
									
								
								tests/common/app_cli_utils.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										31
									
								
								tests/common/app_cli_utils.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | |||||||
|  | use anyhow::Result; | ||||||
|  | use detee_shared::app_proto::{ | ||||||
|  |     brain_app_cli_client::BrainAppCliClient, AppResource, NewAppReq, NewAppRes, | ||||||
|  | }; | ||||||
|  | use tonic::transport::Channel; | ||||||
|  | 
 | ||||||
|  | use crate::common::test_utils::Key; | ||||||
|  | 
 | ||||||
|  | pub async fn create_new_app( | ||||||
|  |     key: &Key, | ||||||
|  |     node_pubkey: &str, | ||||||
|  |     brain_channel: &Channel, | ||||||
|  | ) -> Result<NewAppRes> { | ||||||
|  |     let new_app_req = NewAppReq { | ||||||
|  |         admin_pubkey: key.pubkey.clone(), | ||||||
|  |         node_pubkey: node_pubkey.to_string(), | ||||||
|  |         price_per_unit: 1200, | ||||||
|  |         resource: Some(AppResource { ports: vec![8080, 8081], ..Default::default() }), | ||||||
|  |         locked_nano: 100, | ||||||
|  |         ..Default::default() | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let mut client_app_cli = BrainAppCliClient::new(brain_channel.clone()); | ||||||
|  |     let new_app_resp = | ||||||
|  |         client_app_cli.new_app(key.sign_request(new_app_req.clone())?).await?.into_inner(); | ||||||
|  | 
 | ||||||
|  |     assert!(new_app_resp.error.is_empty()); | ||||||
|  |     assert!(new_app_resp.uuid.len() == 40); | ||||||
|  | 
 | ||||||
|  |     Ok(new_app_resp) | ||||||
|  | } | ||||||
| @ -41,7 +41,7 @@ pub async fn register_app_node( | |||||||
|     client: &mut BrainAppDaemonClient<Channel>, |     client: &mut BrainAppDaemonClient<Channel>, | ||||||
|     key: &Key, |     key: &Key, | ||||||
|     operator_wallet: &str, |     operator_wallet: &str, | ||||||
| ) -> Result<Vec<app_proto::AppContract>> { | ) -> Result<Vec<app_proto::DelAppReq>> { | ||||||
|     log::info!("Registering app_node: {}", key.pubkey); |     log::info!("Registering app_node: {}", key.pubkey); | ||||||
|     let node_pubkey = key.pubkey.clone(); |     let node_pubkey = key.pubkey.clone(); | ||||||
| 
 | 
 | ||||||
| @ -133,8 +133,8 @@ pub async fn daemon_engine( | |||||||
|                 }; |                 }; | ||||||
|                 tx.send(res).await?; |                 tx.send(res).await?; | ||||||
|             } |             } | ||||||
|             Some(app_proto::brain_message_app::Msg::DeleteAppReq(_del_app_req)) => { |             Some(app_proto::brain_message_app::Msg::DeleteAppReq(del_app_req)) => { | ||||||
|                 todo!() |                 println!("MOCK_APP_DAEMON:: delete app request for {}", del_app_req.uuid); | ||||||
|             } |             } | ||||||
|             None => todo!(), |             None => todo!(), | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -9,3 +9,6 @@ pub mod vm_daemon_utils; | |||||||
| 
 | 
 | ||||||
| #[allow(dead_code)] | #[allow(dead_code)] | ||||||
| pub mod app_daemon_utils; | pub mod app_daemon_utils; | ||||||
|  | 
 | ||||||
|  | #[allow(dead_code)] | ||||||
|  | pub mod app_cli_utils; | ||||||
|  | |||||||
| @ -1,10 +1,14 @@ | |||||||
| use anyhow::Result; | use anyhow::Result; | ||||||
| use detee_shared::app_proto as sgx_proto; | use detee_shared::app_proto as sgx_proto; | ||||||
|  | use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient; | ||||||
|  | use detee_shared::general_proto::AirdropReq; | ||||||
| use detee_shared::vm_proto as snp_proto; | use detee_shared::vm_proto as snp_proto; | ||||||
| use ed25519_dalek::{Signer, SigningKey}; | use ed25519_dalek::{Signer, SigningKey}; | ||||||
| use itertools::Itertools; | use itertools::Itertools; | ||||||
| use std::sync::OnceLock; | use std::sync::OnceLock; | ||||||
|  | use surreal_brain::constants::TOKEN_DECIMAL; | ||||||
| use tonic::metadata::AsciiMetadataValue; | use tonic::metadata::AsciiMetadataValue; | ||||||
|  | use tonic::transport::Channel; | ||||||
| use tonic::Request; | use tonic::Request; | ||||||
| 
 | 
 | ||||||
| pub static ADMIN_KEYS: OnceLock<Vec<Key>> = OnceLock::new(); | pub static ADMIN_KEYS: OnceLock<Vec<Key>> = OnceLock::new(); | ||||||
| @ -83,3 +87,14 @@ impl Key { | |||||||
|         Ok(sgx_proto::DaemonAuth { timestamp, pubkey, contracts, signature }) |         Ok(sgx_proto::DaemonAuth { timestamp, pubkey, contracts, signature }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | pub async fn airdrop(brain_channel: &Channel, wallet: &str, amount: u64) -> Result<()> { | ||||||
|  |     let mut client = BrainGeneralCliClient::new(brain_channel.clone()); | ||||||
|  |     let airdrop_req = AirdropReq { pubkey: wallet.to_string(), tokens: amount * TOKEN_DECIMAL }; | ||||||
|  | 
 | ||||||
|  |     let admin_key = admin_keys()[0].clone(); | ||||||
|  | 
 | ||||||
|  |     client.airdrop(admin_key.sign_request(airdrop_req.clone())?).await?; | ||||||
|  | 
 | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,29 +1,18 @@ | |||||||
| use super::test_utils::{admin_keys, Key}; | use super::test_utils::Key; | ||||||
| use anyhow::{anyhow, Result}; | use anyhow::{anyhow, Result}; | ||||||
| use detee_shared::app_proto; | use detee_shared::app_proto; | ||||||
| use detee_shared::common_proto::Empty; | use detee_shared::common_proto::Empty; | ||||||
| use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient; | use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient; | ||||||
| use detee_shared::general_proto::{Account, AirdropReq, RegOperatorReq, ReportNodeReq}; | use detee_shared::general_proto::{Account, RegOperatorReq, ReportNodeReq}; | ||||||
| use detee_shared::vm_proto; | use detee_shared::vm_proto; | ||||||
| use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient; | use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient; | ||||||
| use futures::StreamExt; | use futures::StreamExt; | ||||||
| use surreal_brain::constants::{ACTIVE_VM, NEW_VM_REQ, TOKEN_DECIMAL}; | use surreal_brain::constants::{ACTIVE_VM, NEW_VM_REQ}; | ||||||
| use surreal_brain::db::prelude as db; | use surreal_brain::db::prelude as db; | ||||||
| use surrealdb::engine::remote::ws::Client; | use surrealdb::engine::remote::ws::Client; | ||||||
| use surrealdb::Surreal; | use surrealdb::Surreal; | ||||||
| use tonic::transport::Channel; | use tonic::transport::Channel; | ||||||
| 
 | 
 | ||||||
| pub async fn airdrop(brain_channel: &Channel, wallet: &str, amount: u64) -> Result<()> { |  | ||||||
|     let mut client = BrainGeneralCliClient::new(brain_channel.clone()); |  | ||||||
|     let airdrop_req = AirdropReq { pubkey: wallet.to_string(), tokens: amount * TOKEN_DECIMAL }; |  | ||||||
| 
 |  | ||||||
|     let admin_key = admin_keys()[0].clone(); |  | ||||||
| 
 |  | ||||||
|     client.airdrop(admin_key.sign_request(airdrop_req.clone())?).await?; |  | ||||||
| 
 |  | ||||||
|     Ok(()) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub async fn create_new_vm( | pub async fn create_new_vm( | ||||||
|     db: &Surreal<Client>, |     db: &Surreal<Client>, | ||||||
|     key: &Key, |     key: &Key, | ||||||
|  | |||||||
| @ -136,8 +136,8 @@ pub async fn daemon_engine( | |||||||
|             Some(vm_proto::brain_vm_message::Msg::UpdateVmReq(_update_vm_req)) => { |             Some(vm_proto::brain_vm_message::Msg::UpdateVmReq(_update_vm_req)) => { | ||||||
|                 todo!() |                 todo!() | ||||||
|             } |             } | ||||||
|             Some(vm_proto::brain_vm_message::Msg::DeleteVm(_del_vm_req)) => { |             Some(vm_proto::brain_vm_message::Msg::DeleteVm(del_vm_req)) => { | ||||||
|                 todo!() |                 println!("MOCK_VM_DAEMON:: delete vm request for {}", del_vm_req.uuid); | ||||||
|             } |             } | ||||||
|             None => todo!(), |             None => todo!(), | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,13 +1,14 @@ | |||||||
| use common::app_daemon_utils::mock_app_daemon; | use common::app_daemon_utils::mock_app_daemon; | ||||||
| use common::prepare_test_env::{prepare_test_db, run_service_for_stream}; | use common::prepare_test_env::{prepare_test_db, run_service_for_stream}; | ||||||
| use common::test_utils::Key; | use common::test_utils::{airdrop, Key}; | ||||||
| use common::vm_cli_utils::airdrop; |  | ||||||
| use detee_shared::app_proto; |  | ||||||
| use detee_shared::app_proto::brain_app_cli_client::BrainAppCliClient; | use detee_shared::app_proto::brain_app_cli_client::BrainAppCliClient; | ||||||
|  | use detee_shared::app_proto::{self, DelAppReq}; | ||||||
| use std::vec; | use std::vec; | ||||||
| use surreal_brain::constants::{ACCOUNT, ACTIVE_APP, NEW_APP_REQ, TOKEN_DECIMAL}; | use surreal_brain::constants::{ACCOUNT, ACTIVE_APP, DELETED_APP, NEW_APP_REQ, TOKEN_DECIMAL}; | ||||||
| use surreal_brain::db::prelude as db; | use surreal_brain::db::prelude as db; | ||||||
| 
 | 
 | ||||||
|  | use crate::common::app_cli_utils::create_new_app; | ||||||
|  | 
 | ||||||
| mod common; | mod common; | ||||||
| 
 | 
 | ||||||
| #[tokio::test] | #[tokio::test] | ||||||
| @ -89,3 +90,93 @@ async fn test_app_creation() { | |||||||
|     assert_eq!(acc_db.balance, airdrop_amount * TOKEN_DECIMAL - (locking_nano + 100)); |     assert_eq!(acc_db.balance, airdrop_amount * TOKEN_DECIMAL - (locking_nano + 100)); | ||||||
|     assert_eq!(acc_db.tmp_locked, 0); |     assert_eq!(acc_db.tmp_locked, 0); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #[tokio::test] | ||||||
|  | async fn test_timeout_app_creation() { | ||||||
|  |     let _ = prepare_test_db().await.unwrap(); | ||||||
|  |     let brain_channel = run_service_for_stream().await.unwrap(); | ||||||
|  |     let daemon_key = Key::new().pubkey.clone(); | ||||||
|  | 
 | ||||||
|  |     let key = Key::new(); | ||||||
|  | 
 | ||||||
|  |     let new_app_req = app_proto::NewAppReq { | ||||||
|  |         admin_pubkey: key.pubkey.clone(), | ||||||
|  |         node_pubkey: daemon_key.clone(), | ||||||
|  |         price_per_unit: 1200, | ||||||
|  |         resource: Some(app_proto::AppResource { ports: vec![8080, 8081], ..Default::default() }), | ||||||
|  |         locked_nano: 100, | ||||||
|  |         ..Default::default() | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     airdrop(&brain_channel, &key.pubkey, 10).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let mut client_app_cli = BrainAppCliClient::new(brain_channel.clone()); | ||||||
|  |     let timeout_resp = client_app_cli.new_app(key.sign_request(new_app_req.clone()).unwrap()).await; | ||||||
|  |     assert!(timeout_resp.is_err()); | ||||||
|  |     let timeout_err = timeout_resp.err().unwrap(); | ||||||
|  |     assert_eq!( | ||||||
|  |         timeout_err.message(), | ||||||
|  |         "Network timeout. Please try again later or contact the DeTEE devs team." | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[tokio::test] | ||||||
|  | async fn test_app_deletion() { | ||||||
|  |     let db = prepare_test_db().await.unwrap(); | ||||||
|  |     let brain_channel = run_service_for_stream().await.unwrap(); | ||||||
|  |     let daemon_key = mock_app_daemon(&brain_channel, None).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let key = Key::new(); | ||||||
|  |     airdrop(&brain_channel, &key.pubkey, 10).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let new_app_res = create_new_app(&key, &daemon_key, &brain_channel).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let mut client_app_cli = BrainAppCliClient::new(brain_channel.clone()); | ||||||
|  | 
 | ||||||
|  |     let del_app_req = DelAppReq { admin_pubkey: key.pubkey.clone(), uuid: new_app_res.uuid }; | ||||||
|  |     let _ = client_app_cli.delete_app(key.sign_request(del_app_req).unwrap()).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let key_02 = Key::new(); | ||||||
|  | 
 | ||||||
|  |     // delete random app
 | ||||||
|  |     let mut del_app_req = DelAppReq { | ||||||
|  |         admin_pubkey: key_02.pubkey.clone(), | ||||||
|  |         uuid: "9ae3VH8nJg2i8pqTQ6mJtvYuS2kd9n1XLLco8GUPfT95".to_string(), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let del_err = client_app_cli | ||||||
|  |         .delete_app(key_02.sign_request(del_app_req.clone()).unwrap()) | ||||||
|  |         .await | ||||||
|  |         .err() | ||||||
|  |         .unwrap(); | ||||||
|  |     assert_eq!(del_err.message(), "Unauthorized"); | ||||||
|  | 
 | ||||||
|  |     let new_app_res_02 = create_new_app(&key, &daemon_key, &brain_channel).await.unwrap(); | ||||||
|  |     del_app_req.uuid = new_app_res_02.uuid; | ||||||
|  | 
 | ||||||
|  |     let del_err = client_app_cli | ||||||
|  |         .delete_app(key_02.sign_request(del_app_req.clone()).unwrap()) | ||||||
|  |         .await | ||||||
|  |         .err() | ||||||
|  |         .unwrap(); | ||||||
|  |     assert_eq!(del_err.message(), "Unauthorized"); | ||||||
|  | 
 | ||||||
|  |     // test refund
 | ||||||
|  |     let key_03 = Key::new(); | ||||||
|  |     airdrop(&brain_channel, &key_03.pubkey, 10).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let new_app_res_03 = create_new_app(&key_03, &daemon_key, &brain_channel).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let del_app_req = | ||||||
|  |         DelAppReq { admin_pubkey: key_03.pubkey.clone(), uuid: new_app_res_03.uuid.clone() }; | ||||||
|  |     let _ = client_app_cli.delete_app(key_03.sign_request(del_app_req).unwrap()).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let acc: db::Account = db.select((ACCOUNT, key_03.pubkey.clone())).await.unwrap().unwrap(); | ||||||
|  |     assert_eq!(acc.balance, 10 * TOKEN_DECIMAL); | ||||||
|  | 
 | ||||||
|  |     let deleted_app = | ||||||
|  |         db.select::<Option<db::DeletedApp>>((DELETED_APP, new_app_res_03.uuid)).await.unwrap(); | ||||||
|  |     assert!(deleted_app.is_some()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TODO: test register app node, delete app contract while node offline, kick, etc..
 | ||||||
|  | |||||||
| @ -1,10 +1,10 @@ | |||||||
| use common::prepare_test_env::{ | use common::prepare_test_env::{ | ||||||
|     prepare_test_db, run_service_for_stream, run_service_in_background, |     prepare_test_db, run_service_for_stream, run_service_in_background, | ||||||
| }; | }; | ||||||
| use common::test_utils::{admin_keys, Key}; | use common::test_utils::{admin_keys, airdrop, Key}; | ||||||
| use common::vm_cli_utils::{ | use common::vm_cli_utils::{ | ||||||
|     airdrop, create_new_vm, list_accounts, list_all_app_contracts, list_all_vm_contracts, |     create_new_vm, list_accounts, list_all_app_contracts, list_all_vm_contracts, register_operator, | ||||||
|     register_operator, report_node, |     report_node, | ||||||
| }; | }; | ||||||
| use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node}; | use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node}; | ||||||
| use detee_shared::common_proto::{Empty, Pubkey}; | use detee_shared::common_proto::{Empty, Pubkey}; | ||||||
|  | |||||||
| @ -1,14 +1,14 @@ | |||||||
| use common::prepare_test_env::{prepare_test_db, run_service_for_stream}; | use common::prepare_test_env::{prepare_test_db, run_service_for_stream}; | ||||||
| use common::test_utils::Key; | use common::test_utils::{airdrop, Key}; | ||||||
| use common::vm_cli_utils::{airdrop, create_new_vm, user_list_vm_contracts}; | use common::vm_cli_utils::{create_new_vm, user_list_vm_contracts}; | ||||||
| use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node}; | use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node}; | ||||||
| use detee_shared::vm_proto; |  | ||||||
| use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient; | use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient; | ||||||
| use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient; | use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient; | ||||||
|  | use detee_shared::vm_proto::{self, DeleteVmReq}; | ||||||
| use detee_shared::vm_proto::{ExtendVmReq, ListVmContractsReq, NewVmReq}; | use detee_shared::vm_proto::{ExtendVmReq, ListVmContractsReq, NewVmReq}; | ||||||
| use futures::StreamExt; | use futures::StreamExt; | ||||||
| use std::vec; | use std::vec; | ||||||
| use surreal_brain::constants::{ACCOUNT, ACTIVE_VM, NEW_VM_REQ, TOKEN_DECIMAL}; | use surreal_brain::constants::{ACCOUNT, ACTIVE_VM, DELETED_VM, NEW_VM_REQ, TOKEN_DECIMAL}; | ||||||
| use surreal_brain::db::prelude as db; | use surreal_brain::db::prelude as db; | ||||||
| 
 | 
 | ||||||
| mod common; | mod common; | ||||||
| @ -125,6 +125,65 @@ async fn test_timeout_vm_creation() { | |||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[tokio::test] | ||||||
|  | async fn test_vm_deletion() { | ||||||
|  |     let db = prepare_test_db().await.unwrap(); | ||||||
|  |     let brain_channel = run_service_for_stream().await.unwrap(); | ||||||
|  |     let daemon_key = mock_vm_daemon(&brain_channel, None).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let key = Key::new(); | ||||||
|  |     airdrop(&brain_channel, &key.pubkey, 10).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let new_vm_uuid = create_new_vm(&db, &key, &daemon_key, &brain_channel).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let mut client_vm_cli = BrainVmCliClient::new(brain_channel.clone()); | ||||||
|  | 
 | ||||||
|  |     let del_app_req = DeleteVmReq { admin_pubkey: key.pubkey.clone(), uuid: new_vm_uuid }; | ||||||
|  |     let _ = client_vm_cli.delete_vm(key.sign_request(del_app_req).unwrap()).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let key_02 = Key::new(); | ||||||
|  | 
 | ||||||
|  |     // delete random vm
 | ||||||
|  |     let mut del_vm_req = DeleteVmReq { | ||||||
|  |         admin_pubkey: key_02.pubkey.clone(), | ||||||
|  |         uuid: "9ae3VH8nJg2i8pqTQ6mJtvYuS2kd9n1XLLco8GUPfT95".to_string(), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let del_err = client_vm_cli | ||||||
|  |         .delete_vm(key_02.sign_request(del_vm_req.clone()).unwrap()) | ||||||
|  |         .await | ||||||
|  |         .err() | ||||||
|  |         .unwrap(); | ||||||
|  |     assert_eq!(del_err.message(), "Unauthorized"); | ||||||
|  | 
 | ||||||
|  |     let new_vm_uuid_02 = create_new_vm(&db, &key, &daemon_key, &brain_channel).await.unwrap(); | ||||||
|  |     del_vm_req.uuid = new_vm_uuid_02; | ||||||
|  | 
 | ||||||
|  |     let del_err = client_vm_cli | ||||||
|  |         .delete_vm(key_02.sign_request(del_vm_req.clone()).unwrap()) | ||||||
|  |         .await | ||||||
|  |         .err() | ||||||
|  |         .unwrap(); | ||||||
|  |     assert_eq!(del_err.message(), "Unauthorized"); | ||||||
|  | 
 | ||||||
|  |     // test refund
 | ||||||
|  |     let key_03 = Key::new(); | ||||||
|  |     airdrop(&brain_channel, &key_03.pubkey, 10).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let new_vm_uuid_03 = create_new_vm(&db, &key_03, &daemon_key, &brain_channel).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let del_vm_req = | ||||||
|  |         DeleteVmReq { admin_pubkey: key_03.pubkey.clone(), uuid: new_vm_uuid_03.clone() }; | ||||||
|  |     let _ = client_vm_cli.delete_vm(key_03.sign_request(del_vm_req).unwrap()).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     let acc: db::Account = db.select((ACCOUNT, key_03.pubkey.clone())).await.unwrap().unwrap(); | ||||||
|  |     assert_eq!(acc.balance, 10 * TOKEN_DECIMAL); | ||||||
|  | 
 | ||||||
|  |     let deleted_vm = | ||||||
|  |         db.select::<Option<db::DeletedVm>>((DELETED_VM, new_vm_uuid_03)).await.unwrap(); | ||||||
|  |     assert!(deleted_vm.is_some()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[tokio::test] | #[tokio::test] | ||||||
| // TODO: create vm for this user before testing this
 | // TODO: create vm for this user before testing this
 | ||||||
| async fn test_list_vm_contracts() { | async fn test_list_vm_contracts() { | ||||||
| @ -240,3 +299,5 @@ async fn test_extend_vm() { | |||||||
|     let acc: db::Account = db_conn.select((ACCOUNT, key.pubkey.clone())).await.unwrap().unwrap(); |     let acc: db::Account = db_conn.select((ACCOUNT, key.pubkey.clone())).await.unwrap().unwrap(); | ||||||
|     assert_eq!(acc.balance, expected_bal_02); |     assert_eq!(acc.balance, expected_bal_02); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // TODO: test register vm node, delete vm contract while node offline, kick, etc..
 | ||||||
|  | |||||||
| @ -1,8 +1,7 @@ | |||||||
| use common::prepare_test_env::{ | use common::prepare_test_env::{ | ||||||
|     prepare_test_db, run_service_for_stream, run_service_in_background, |     prepare_test_db, run_service_for_stream, run_service_in_background, | ||||||
| }; | }; | ||||||
| use common::test_utils::Key; | use common::test_utils::{airdrop, Key}; | ||||||
| use common::vm_cli_utils::airdrop; |  | ||||||
| use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node}; | use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node}; | ||||||
| use detee_shared::vm_proto; | use detee_shared::vm_proto; | ||||||
| use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient; | use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user