added payments for VM creation

This commit is contained in:
ghe0 2025-01-23 01:38:19 +02:00
parent 1e893b49c0
commit 1a4cec421b
Signed by: ghe0
GPG Key ID: 451028EE56A0FBB4
9 changed files with 65 additions and 35 deletions

35
Cargo.lock generated

@ -215,6 +215,15 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "bs58"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
dependencies = [
"tinyvec",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.16.0" version = "3.16.0"
@ -329,7 +338,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
dependencies = [ dependencies = [
"const-oid", "const-oid",
"pem-rfc7468",
"zeroize", "zeroize",
] ]
@ -338,6 +346,7 @@ name = "detee-snp-daemon"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bs58",
"ed25519-dalek", "ed25519-dalek",
"env_logger", "env_logger",
"lazy_static", "lazy_static",
@ -1103,15 +1112,6 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
dependencies = [
"base64ct",
]
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.1" version = "2.3.1"
@ -1712,6 +1712,21 @@ dependencies = [
"zerovec", "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]] [[package]]
name = "tokio" name = "tokio"
version = "1.42.0" version = "1.42.0"

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [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"] } rand_core = { version = "0.6.4", features = ["alloc", "getrandom", "std"] }
anyhow = "1.0.94" anyhow = "1.0.94"
env_logger = "0.11.6" env_logger = "0.11.6"
@ -21,6 +21,7 @@ tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] }
tokio-stream = "0.1.17" tokio-stream = "0.1.17"
tonic = "0.12" tonic = "0.12"
serde_json = "1.0.135" serde_json = "1.0.135"
bs58 = "0.5.1"
[build-dependencies] [build-dependencies]
tonic-build = "0.12" tonic-build = "0.12"

@ -109,4 +109,4 @@ qemu-system-x86_64 $qemu_device_params \
-object memory-backend-memfd,id=ram1,size=$MEMORY,share=true,prealloc=false \ -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 \ -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,kernel-hashes=on \
-kernel $KERNEL -append "$PARAMS" -initrd $INITRD \ -kernel $KERNEL -append "$PARAMS" -initrd $INITRD \
-nographic -monitor pty -serial mon:stdio -monitor unix:monitor,server,nowait -nographic

@ -23,6 +23,10 @@ message Contract {
string dtrfs_sha = 12; string dtrfs_sha = 12;
string created_at = 13; string created_at = 13;
string updated_at = 14; 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 { message MeasurementArgs {
@ -47,9 +51,11 @@ message RegisterNodeReq {
string node_pubkey = 1; string node_pubkey = 1;
string owner_pubkey = 2; string owner_pubkey = 2;
string main_ip = 3; string main_ip = 3;
string country = 7; string country = 4;
string region = 8; string region = 5;
string city = 9; string city = 6;
// nanotokens per unit per minute
uint64 price = 7;
} }
message NodeResources { message NodeResources {
@ -78,6 +84,8 @@ message NewVmReq {
string kernel_sha = 12; string kernel_sha = 12;
string dtrfs_url = 13; string dtrfs_url = 13;
string dtrfs_sha = 14; string dtrfs_sha = 14;
uint64 price_per_unit = 15;
uint64 locked_nano = 16;
} }
message NewVmResp { message NewVmResp {
@ -157,6 +165,8 @@ message NodeListResp {
string ip = 5; // required for latency test string ip = 5; // required for latency test
uint32 server_rating = 6; uint32 server_rating = 6;
uint32 provider_rating = 7; uint32 provider_rating = 7;
// nanotokens per unit per minute
uint64 price = 8;
} }
service BrainCli { service BrainCli {

@ -53,6 +53,8 @@ pub struct Config {
#[serde(with = "range_format")] #[serde(with = "range_format")]
pub public_port_range: Range<u16>, pub public_port_range: Range<u16>,
pub max_ports_per_vm: u16, pub max_ports_per_vm: u16,
// price per unit per minute
pub price: u64,
} }
mod range_format { mod range_format {

@ -1,4 +1,5 @@
use anyhow::Result; use anyhow::Result;
use ed25519_dalek::SigningKey;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use log::{info, warn}; use log::{info, warn};
use std::{fs::File, io::Write}; use std::{fs::File, io::Write};
@ -23,39 +24,33 @@ lazy_static! {
} }
fn create_secret_key() -> Result<ed25519_dalek::SigningKey> { fn create_secret_key() -> Result<ed25519_dalek::SigningKey> {
use ed25519_dalek::pkcs8::{spki::der::pem::LineEnding, EncodePrivateKey};
let key_path = SECRET_KEY_PATH; let key_path = SECRET_KEY_PATH;
info!("Creating new secret key at {}", key_path); info!("Creating new secret key at {}", key_path);
let sk = ed25519_dalek::SigningKey::generate(&mut rand_core::OsRng); 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)?; let mut file = File::create(key_path)?;
file.write_all(sk_pem.as_bytes())?; file.write_all(private_key_string.as_bytes())?;
Ok(sk) Ok(sk)
} }
fn load_secret_key() -> Result<ed25519_dalek::SigningKey> { fn load_secret_key() -> Result<ed25519_dalek::SigningKey> {
use ed25519_dalek::pkcs8::DecodePrivateKey; let secret_key_string = match std::fs::read_to_string(SECRET_KEY_PATH) {
let secret_key_pem = match std::fs::read_to_string(SECRET_KEY_PATH) {
Ok(secret_key_pem) => secret_key_pem, Ok(secret_key_pem) => secret_key_pem,
Err(e) => { Err(e) => {
warn!("Could not load secret key due to error: {e:?}"); warn!("Could not load secret key due to error: {e:?}");
return Ok(create_secret_key()?); 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 { pub fn get_public_key() -> String {
use ed25519_dalek::pkcs8::{spki::der::pem::LineEnding, EncodePublicKey}; let pubkey = bs58::encode(load_secret_key().unwrap().verifying_key().to_bytes()).into_string();
let pubkey = load_secret_key()
.unwrap()
.verifying_key()
.to_public_key_pem(LineEnding::default())
.unwrap()
.lines()
.nth(1)
.unwrap()
.to_string();
log::info!("Loaded the following public key: {pubkey}"); log::info!("Loaded the following public key: {pubkey}");
pubkey pubkey
} }

@ -34,8 +34,8 @@ impl From<snp_proto::NodeResources> for snp_proto::DaemonMessage {
} }
} }
pub async fn register_node(brain_url: String) -> Result<Vec<Contract>> { pub async fn register_node(config: &crate::config::Config) -> Result<Vec<Contract>> {
let mut client = BrainDaemonClient::connect(brain_url).await?; let mut client = BrainDaemonClient::connect(config.brain_url.clone()).await?;
debug!("Starting node registration..."); debug!("Starting node registration...");
let ip_info = IP_INFO.clone(); let ip_info = IP_INFO.clone();
let req = RegisterNodeReq { let req = RegisterNodeReq {
@ -45,6 +45,7 @@ pub async fn register_node(brain_url: String) -> Result<Vec<Contract>> {
country: ip_info.country, country: ip_info.country,
region: ip_info.region, region: ip_info.region,
city: ip_info.city, city: ip_info.city,
price: config.price,
}; };
let mut contracts = Vec::new(); let mut contracts = Vec::new();
let mut grpc_stream = client.register_node(req).await?.into_inner(); let mut grpc_stream = client.register_node(req).await?.into_inner();

@ -243,7 +243,7 @@ async fn main() {
let brain_url = vm_handler.config.brain_url.clone(); let brain_url = vm_handler.config.brain_url.clone();
info!("Registering with the brain and getting back VM Contracts (if they exist)."); 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), Ok(contracts) => vm_handler.clear_deleted_contracts(contracts),
Err(e) => log::error!("Could not get contracts from brain: {e:?}"), Err(e) => log::error!("Could not get contracts from brain: {e:?}"),
}; };

@ -76,7 +76,7 @@ impl Resources {
} }
volumes.sort_by_key(|v| v.max_reservation_gb); volumes.sort_by_key(|v| v.max_reservation_gb);
if let Some(biggest_volume) = volumes.last() { 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()); return Some(biggest_volume.path.clone());
} }
} }
@ -435,6 +435,7 @@ pub struct NewVMRequest {
kernel_sha: String, kernel_sha: String,
dtrfs_url: String, dtrfs_url: String,
dtrfs_sha: String, dtrfs_sha: String,
price: u64,
} }
impl From<snp_proto::NewVmReq> for NewVMRequest { impl From<snp_proto::NewVmReq> for NewVMRequest {
@ -453,6 +454,7 @@ impl From<snp_proto::NewVmReq> for NewVMRequest {
kernel_sha: req.kernel_sha, kernel_sha: req.kernel_sha,
dtrfs_url: req.dtrfs_url, dtrfs_url: req.dtrfs_url,
dtrfs_sha: req.dtrfs_sha, dtrfs_sha: req.dtrfs_sha,
price: req.price_per_unit,
} }
} }
} }
@ -487,6 +489,7 @@ impl From<snp_proto::UpdateVmReq> for UpdateVMReq {
#[derive(Debug)] #[derive(Debug)]
pub enum VMCreationErrors { pub enum VMCreationErrors {
PriceIsTooLow,
VMAlreadyExists(VM), VMAlreadyExists(VM),
NATandIPv4Conflict, NATandIPv4Conflict,
TooManyCores, TooManyCores,
@ -508,6 +511,9 @@ impl VM {
config: &Config, config: &Config,
res: &mut Resources, res: &mut Resources,
) -> Result<Self, VMCreationErrors> { ) -> Result<Self, VMCreationErrors> {
if req.price < config.price {
return Err(VMCreationErrors::PriceIsTooLow);
}
if res.existing_vms.contains(&req.uuid) { if res.existing_vms.contains(&req.uuid) {
let content = std::fs::read_to_string(VM_CONFIG_DIR.to_string() + &req.uuid + ".yaml") let content = std::fs::read_to_string(VM_CONFIG_DIR.to_string() + &req.uuid + ".yaml")
.map_err(|e| VMCreationErrors::ServerDiskError(e.to_string()))?; .map_err(|e| VMCreationErrors::ServerDiskError(e.to_string()))?;