From f51e29fc4bf8665a7c4b4698d2207aff0a43f3ac Mon Sep 17 00:00:00 2001 From: ghe0 Date: Wed, 23 Apr 2025 04:12:35 +0300 Subject: [PATCH] inspecting and listing contracts with node info --- Cargo.lock | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 2 +- src/db.rs | 108 +++++++++++++++++++++++++++++++++------------- src/grpc.rs | 56 ++++++++++++++---------- 4 files changed, 229 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b4828d..42912f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -482,6 +482,26 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -652,6 +672,8 @@ version = "1.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -978,15 +1000,17 @@ dependencies = [ [[package]] name = "detee-shared" version = "0.1.0" -source = "git+ssh://git@gitea.detee.cloud/testnet/proto?branch=main#3024c00b8e1c93e70902793385b92bc0a8d1f26a" +source = "git+ssh://git@gitea.detee.cloud/testnet/proto?branch=surreal_brain#fb38352e1b47837b14f32d8df5ae7f6b17202aae" dependencies = [ - "base64 0.22.1", + "bincode 2.0.1", "prost", "serde", "serde_yaml", + "tar", "thiserror 2.0.12", "tonic", "tonic-build", + "zstd", ] [[package]] @@ -1190,6 +1214,18 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1959,6 +1995,16 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.2", + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -2050,6 +2096,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags", "libc", + "redox_syscall", ] [[package]] @@ -2606,6 +2653,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "portable-atomic" version = "1.11.0" @@ -3744,7 +3797,7 @@ checksum = "cd369a114a892aa1d0851d743f35c4c48672d6b0fb5aaf2b3e4dcacfac68a070" dependencies = [ "arrayvec", "async-channel", - "bincode", + "bincode 1.3.3", "chrono", "dmp", "futures", @@ -3793,7 +3846,7 @@ dependencies = [ "async-graphql", "base64 0.21.7", "bcrypt", - "bincode", + "bincode 1.3.3", "blake3", "bytes", "castaway", @@ -3926,6 +3979,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.19.1" @@ -4417,6 +4481,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + [[package]] name = "url" version = "2.5.4" @@ -4482,6 +4552,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + [[package]] name = "walkdir" version = "2.5.0" @@ -5009,6 +5085,16 @@ dependencies = [ "tap", ] +[[package]] +name = "xattr" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" +dependencies = [ + "libc", + "rustix", +] + [[package]] name = "yoke" version = "0.7.5" @@ -5121,3 +5207,31 @@ dependencies = [ "quote", "syn 2.0.100", ] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.15+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index bfdce67..96832e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ serde_yaml = "0.9.34" surrealdb = "2.2.2" tokio = { version = "1.44.2", features = ["macros", "rt-multi-thread"] } tonic = { version = "0.12", features = ["tls"] } -detee-shared = { git = "ssh://git@gitea.detee.cloud/testnet/proto", branch = "main" } +detee-shared = { git = "ssh://git@gitea.detee.cloud/testnet/proto", branch = "surreal_brain" } ed25519-dalek = "2.1.1" bs58 = "0.5.1" tokio-stream = "0.1.17" diff --git a/src/db.rs b/src/db.rs index acfd965..620d8a5 100644 --- a/src/db.rs +++ b/src/db.rs @@ -63,37 +63,6 @@ pub async fn account(address: &str) -> Result { Ok(account) } -pub async fn vm_contract_by_uuid(uuid: &str) -> Result, Error> { - let id = (VM_CONTRACT, uuid); - let contract: Option = DB.select(id).await?; - Ok(contract) -} - -pub async fn vm_contracts_by_admin(admin: &str) -> Result, Error> { - let mut result = - DB.query(format!("select * from {VM_CONTRACT} where in = {ACCOUNT}:{admin};")).await?; - let contracts: Vec = result.take(0)?; - Ok(contracts) -} - -pub async fn vm_contracts_by_operator(operator: &str) -> Result, Error> { - let mut result = DB - .query(format!( - "select ->{OPERATOR}->{VM_NODE}<-{VM_CONTRACT}.* as contracts from {ACCOUNT}:{operator};" - )) - .await?; - - #[derive(Deserialize)] - struct Wrapper { - contracts: Vec, - } - let c: Option = result.take(0)?; - match c { - Some(c) => Ok(c.contracts), - None => Ok(Vec::new()), - } -} - // I am not deleting this example cause I might need it later. // // async fn get_wallet_contracts() -> surrealdb::Result> { @@ -181,6 +150,83 @@ impl VmContract { } } +#[derive(Debug, Serialize, Deserialize)] +pub struct VmContractWithNode { + pub id: RecordId, + #[serde(rename = "in")] + pub admin: RecordId, + #[serde(rename = "out")] + pub vm_node: VmNode, + pub state: String, + pub hostname: String, + pub mapped_ports: Vec<(u32, u32)>, + pub public_ipv4: String, + pub public_ipv6: String, + pub disk_size_gb: u32, + pub vcpus: u32, + pub memory_mb: u32, + pub dtrfs_sha: String, + pub kernel_sha: String, + pub created_at: Datetime, + pub updated_at: Datetime, + pub price_per_unit: u64, + pub locked_nano: u64, + pub collected_at: Datetime, +} + +impl VmContractWithNode { + pub async fn by_uuid(uuid: &str) -> Result, Error> { + let contract: Option = + DB.query(format!("select * from {VM_CONTRACT}:{uuid} fetch out;")).await?.take(0)?; + Ok(contract) + } + + pub async fn by_admin(admin: &str) -> Result, Error> { + let mut result = DB + .query(format!("select * from {VM_CONTRACT} where in = {ACCOUNT}:{admin} fetch out;")) + .await?; + let contracts: Vec = result.take(0)?; + Ok(contracts) + } + + pub async fn by_operator(operator: &str) -> Result, Error> { + let mut result = DB + .query(format!( + "select + (select * from ->operator->vm_node<-vm_contract fetch out) as contracts + from {ACCOUNT}:{operator};" + )) + .await?; + + #[derive(Deserialize)] + struct Wrapper { + contracts: Vec, + } + + let c: Option = result.take(0)?; + match c { + Some(c) => Ok(c.contracts), + None => Ok(Vec::new()), + } + } + + /// total hardware units of this VM + fn total_units(&self) -> u64 { + // TODO: Optimize this based on price of hardware. + // I tried, but this can be done better. + // Storage cost should also be based on tier + (self.vcpus as u64 * 10) + + ((self.memory_mb + 256) as u64 / 200) + + (self.disk_size_gb as u64 / 10) + + (!self.public_ipv4.is_empty() as u64 * 10) + } + + /// Returns price per minute in nanoLP + pub fn price_per_minute(&self) -> u64 { + self.total_units() * self.price_per_unit + } +} + #[derive(Debug, Serialize, Deserialize)] pub struct AppNode { id: RecordId, diff --git a/src/grpc.rs b/src/grpc.rs index 5acb32e..079c73d 100644 --- a/src/grpc.rs +++ b/src/grpc.rs @@ -28,30 +28,39 @@ impl From for AccountBalance { } } -impl From for VmContract { - fn from(contract: db::VmContract) -> Self { +impl From for VmContract { + fn from(db_c: db::VmContractWithNode) -> Self { let mut exposed_ports = Vec::new(); - for port in contract.mapped_ports.iter() { + for port in db_c.mapped_ports.iter() { exposed_ports.push(port.0); } VmContract { - uuid: contract.id.key().to_string(), - dtrfs_sha: contract.dtrfs_sha.clone(), - kernel_sha: contract.kernel_sha.clone(), - memory_mb: contract.memory_mb, - vcpus: contract.vcpus, - created_at: contract.created_at.to_string(), - disk_size_gb: contract.disk_size_gb, - public_ipv6: contract.public_ipv6.clone(), - public_ipv4: contract.public_ipv4.clone(), - updated_at: contract.updated_at.to_string(), - exposed_ports, - node_pubkey: contract.vm_node.key().to_string(), - nano_per_minute: contract.price_per_minute(), - locked_nano: contract.locked_nano, - admin_pubkey: contract.admin.key().to_string(), - hostname: contract.hostname.clone(), - collected_at: contract.hostname.clone(), + uuid: db_c.id.key().to_string(), + hostname: db_c.hostname.clone(), + admin_pubkey: db_c.admin.key().to_string(), + node_pubkey: db_c.vm_node.id.key().to_string(), + node_ip: db_c.vm_node.ip.clone(), + location: format!( + "{}, {}, {}", + db_c.vm_node.city, db_c.vm_node.region, db_c.vm_node.country + ), + memory_mb: db_c.memory_mb, + vcpus: db_c.vcpus, + disk_size_gb: db_c.disk_size_gb, + mapped_ports: db_c + .mapped_ports + .iter() + .map(|(h, g)| MappedPort { host_port: *h, guest_port: *g }) + .collect(), + vm_public_ipv6: db_c.public_ipv6.clone(), + vm_public_ipv4: db_c.public_ipv4.clone(), + locked_nano: db_c.locked_nano, + dtrfs_sha: db_c.dtrfs_sha.clone(), + kernel_sha: db_c.kernel_sha.clone(), + nano_per_minute: db_c.price_per_minute(), + created_at: db_c.created_at.to_rfc3339(), + updated_at: db_c.updated_at.to_rfc3339(), + collected_at: db_c.collected_at.to_rfc3339(), } } } @@ -313,7 +322,7 @@ impl BrainVmCli for BrainVmCliMock { ); let mut contracts = Vec::new(); if !req.uuid.is_empty() { - if let Some(specific_contract) = db::vm_contract_by_uuid(&req.uuid).await? { + if let Some(specific_contract) = db::VmContractWithNode::by_uuid(&req.uuid).await? { if specific_contract.admin.key().to_string() == req.wallet { contracts.push(specific_contract.into()); } @@ -321,9 +330,10 @@ impl BrainVmCli for BrainVmCliMock { } } else { if req.as_operator { - contracts.append(&mut db::vm_contracts_by_operator(&req.wallet).await?.into()); + contracts + .append(&mut db::VmContractWithNode::by_operator(&req.wallet).await?.into()); } else { - contracts.append(&mut db::vm_contracts_by_admin(&req.wallet).await?.into()); + contracts.append(&mut db::VmContractWithNode::by_admin(&req.wallet).await?.into()); } } let (tx, rx) = mpsc::channel(6);