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