From 1a4cec421b78593379dd33f9541d0e69b288c79b Mon Sep 17 00:00:00 2001 From: ghe0 Date: Thu, 23 Jan 2025 01:38:19 +0200 Subject: [PATCH] added payments for VM creation --- Cargo.lock | 35 +++++++++++++++++++++++++---------- Cargo.toml | 3 ++- scripts/start_qemu_vm.sh | 2 +- snp.proto | 16 +++++++++++++--- src/config.rs | 2 ++ src/global.rs | 27 +++++++++++---------------- src/grpc.rs | 5 +++-- src/main.rs | 2 +- src/state.rs | 8 +++++++- 9 files changed, 65 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7e8466..6cb831b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,6 +215,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -329,7 +338,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", - "pem-rfc7468", "zeroize", ] @@ -338,6 +346,7 @@ name = "detee-snp-daemon" version = "0.1.0" dependencies = [ "anyhow", + "bs58", "ed25519-dalek", "env_logger", "lazy_static", @@ -1103,15 +1112,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -1712,6 +1712,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.42.0" diff --git a/Cargo.toml b/Cargo.toml index 4c3c33a..cf07e2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -ed25519-dalek = { version = "2.1.1", default-features = false, features = ["std", "alloc", "rand_core", "pem"] } +ed25519-dalek = { version = "2.1.1", features = [ "rand_core" ] } rand_core = { version = "0.6.4", features = ["alloc", "getrandom", "std"] } anyhow = "1.0.94" env_logger = "0.11.6" @@ -21,6 +21,7 @@ tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] } tokio-stream = "0.1.17" tonic = "0.12" serde_json = "1.0.135" +bs58 = "0.5.1" [build-dependencies] tonic-build = "0.12" diff --git a/scripts/start_qemu_vm.sh b/scripts/start_qemu_vm.sh index ecbddb8..779c86d 100755 --- a/scripts/start_qemu_vm.sh +++ b/scripts/start_qemu_vm.sh @@ -109,4 +109,4 @@ qemu-system-x86_64 $qemu_device_params \ -object memory-backend-memfd,id=ram1,size=$MEMORY,share=true,prealloc=false \ -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,kernel-hashes=on \ -kernel $KERNEL -append "$PARAMS" -initrd $INITRD \ - -nographic -monitor pty -serial mon:stdio -monitor unix:monitor,server,nowait + -nographic diff --git a/snp.proto b/snp.proto index 89f637b..528573f 100644 --- a/snp.proto +++ b/snp.proto @@ -23,6 +23,10 @@ message Contract { string dtrfs_sha = 12; string created_at = 13; string updated_at = 14; + // total nanotoken cost per minute (for all units) + uint64 nano_per_minute = 15; + uint64 locked_nano = 16; + string collected_at = 17; } message MeasurementArgs { @@ -47,9 +51,11 @@ message RegisterNodeReq { string node_pubkey = 1; string owner_pubkey = 2; string main_ip = 3; - string country = 7; - string region = 8; - string city = 9; + string country = 4; + string region = 5; + string city = 6; + // nanotokens per unit per minute + uint64 price = 7; } message NodeResources { @@ -78,6 +84,8 @@ message NewVmReq { string kernel_sha = 12; string dtrfs_url = 13; string dtrfs_sha = 14; + uint64 price_per_unit = 15; + uint64 locked_nano = 16; } message NewVmResp { @@ -157,6 +165,8 @@ message NodeListResp { string ip = 5; // required for latency test uint32 server_rating = 6; uint32 provider_rating = 7; + // nanotokens per unit per minute + uint64 price = 8; } service BrainCli { diff --git a/src/config.rs b/src/config.rs index 0dc7664..04527a6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -53,6 +53,8 @@ pub struct Config { #[serde(with = "range_format")] pub public_port_range: Range, pub max_ports_per_vm: u16, + // price per unit per minute + pub price: u64, } mod range_format { diff --git a/src/global.rs b/src/global.rs index c3fff0c..511144d 100644 --- a/src/global.rs +++ b/src/global.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use ed25519_dalek::SigningKey; use lazy_static::lazy_static; use log::{info, warn}; use std::{fs::File, io::Write}; @@ -23,39 +24,33 @@ lazy_static! { } fn create_secret_key() -> Result { - use ed25519_dalek::pkcs8::{spki::der::pem::LineEnding, EncodePrivateKey}; let key_path = SECRET_KEY_PATH; info!("Creating new secret key at {}", key_path); let sk = ed25519_dalek::SigningKey::generate(&mut rand_core::OsRng); - let sk_pem = sk.to_pkcs8_pem(LineEnding::default()).unwrap(); + let private_key_string = bs58::encode(sk.to_bytes()).into_string(); let mut file = File::create(key_path)?; - file.write_all(sk_pem.as_bytes())?; + file.write_all(private_key_string.as_bytes())?; Ok(sk) } fn load_secret_key() -> Result { - use ed25519_dalek::pkcs8::DecodePrivateKey; - let secret_key_pem = match std::fs::read_to_string(SECRET_KEY_PATH) { + let secret_key_string = match std::fs::read_to_string(SECRET_KEY_PATH) { Ok(secret_key_pem) => secret_key_pem, Err(e) => { warn!("Could not load secret key due to error: {e:?}"); return Ok(create_secret_key()?); } }; - Ok(ed25519_dalek::SigningKey::from_pkcs8_pem(&secret_key_pem)?) + Ok(SigningKey::from_bytes( + &bs58::decode(secret_key_string) + .into_vec()? + .try_into() + .map_err(|_| bs58::decode::Error::BufferTooSmall)?, + )) } pub fn get_public_key() -> String { - use ed25519_dalek::pkcs8::{spki::der::pem::LineEnding, EncodePublicKey}; - let pubkey = load_secret_key() - .unwrap() - .verifying_key() - .to_public_key_pem(LineEnding::default()) - .unwrap() - .lines() - .nth(1) - .unwrap() - .to_string(); + let pubkey = bs58::encode(load_secret_key().unwrap().verifying_key().to_bytes()).into_string(); log::info!("Loaded the following public key: {pubkey}"); pubkey } diff --git a/src/grpc.rs b/src/grpc.rs index 81be01a..32cad9a 100644 --- a/src/grpc.rs +++ b/src/grpc.rs @@ -34,8 +34,8 @@ impl From for snp_proto::DaemonMessage { } } -pub async fn register_node(brain_url: String) -> Result> { - let mut client = BrainDaemonClient::connect(brain_url).await?; +pub async fn register_node(config: &crate::config::Config) -> Result> { + let mut client = BrainDaemonClient::connect(config.brain_url.clone()).await?; debug!("Starting node registration..."); let ip_info = IP_INFO.clone(); let req = RegisterNodeReq { @@ -45,6 +45,7 @@ pub async fn register_node(brain_url: String) -> Result> { country: ip_info.country, region: ip_info.region, city: ip_info.city, + price: config.price, }; let mut contracts = Vec::new(); let mut grpc_stream = client.register_node(req).await?.into_inner(); diff --git a/src/main.rs b/src/main.rs index 2e2a898..8b91716 100644 --- a/src/main.rs +++ b/src/main.rs @@ -243,7 +243,7 @@ async fn main() { let brain_url = vm_handler.config.brain_url.clone(); info!("Registering with the brain and getting back VM Contracts (if they exist)."); - match grpc::register_node(brain_url.clone()).await { + match grpc::register_node(&vm_handler.config).await { Ok(contracts) => vm_handler.clear_deleted_contracts(contracts), Err(e) => log::error!("Could not get contracts from brain: {e:?}"), }; diff --git a/src/state.rs b/src/state.rs index 9bbff8f..9dbdcad 100644 --- a/src/state.rs +++ b/src/state.rs @@ -76,7 +76,7 @@ impl Resources { } volumes.sort_by_key(|v| v.max_reservation_gb); if let Some(biggest_volume) = volumes.last() { - if biggest_volume.max_reservation_gb > required_gb { + if biggest_volume.max_reservation_gb >= required_gb { return Some(biggest_volume.path.clone()); } } @@ -435,6 +435,7 @@ pub struct NewVMRequest { kernel_sha: String, dtrfs_url: String, dtrfs_sha: String, + price: u64, } impl From for NewVMRequest { @@ -453,6 +454,7 @@ impl From for NewVMRequest { kernel_sha: req.kernel_sha, dtrfs_url: req.dtrfs_url, dtrfs_sha: req.dtrfs_sha, + price: req.price_per_unit, } } } @@ -487,6 +489,7 @@ impl From for UpdateVMReq { #[derive(Debug)] pub enum VMCreationErrors { + PriceIsTooLow, VMAlreadyExists(VM), NATandIPv4Conflict, TooManyCores, @@ -508,6 +511,9 @@ impl VM { config: &Config, res: &mut Resources, ) -> Result { + if req.price < config.price { + return Err(VMCreationErrors::PriceIsTooLow); + } if res.existing_vms.contains(&req.uuid) { let content = std::fs::read_to_string(VM_CONFIG_DIR.to_string() + &req.uuid + ".yaml") .map_err(|e| VMCreationErrors::ServerDiskError(e.to_string()))?;