Compare commits
1 Commits
af3c3103e2
...
e9f5ae01fb
Author | SHA1 | Date | |
---|---|---|---|
e9f5ae01fb |
91
src/data.rs
91
src/data.rs
@ -18,10 +18,6 @@ pub enum Error {
|
|||||||
InsufficientFunds,
|
InsufficientFunds,
|
||||||
#[error("Could not find contract {0}")]
|
#[error("Could not find contract {0}")]
|
||||||
VmContractNotFound(String),
|
VmContractNotFound(String),
|
||||||
#[error("This error should never happen.")]
|
|
||||||
ImpossibleError,
|
|
||||||
#[error("You don't have the required permissions for this operation.")]
|
|
||||||
AccessDenied,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
@ -30,7 +26,6 @@ pub struct AccountData {
|
|||||||
pub tmp_locked: u64,
|
pub tmp_locked: u64,
|
||||||
// holds reasons why VMs of this account got kicked
|
// holds reasons why VMs of this account got kicked
|
||||||
pub kicked_for: Vec<String>,
|
pub kicked_for: Vec<String>,
|
||||||
pub last_kick: chrono::DateTime<Utc>,
|
|
||||||
// holds accounts that banned this account
|
// holds accounts that banned this account
|
||||||
pub banned_by: HashSet<String>,
|
pub banned_by: HashSet<String>,
|
||||||
}
|
}
|
||||||
@ -104,15 +99,14 @@ pub struct VmContract {
|
|||||||
pub dtrfs_sha: String,
|
pub dtrfs_sha: String,
|
||||||
pub created_at: chrono::DateTime<Utc>,
|
pub created_at: chrono::DateTime<Utc>,
|
||||||
pub updated_at: chrono::DateTime<Utc>,
|
pub updated_at: chrono::DateTime<Utc>,
|
||||||
|
// price per unit per minute
|
||||||
// recommended value is 20000
|
// recommended value is 20000
|
||||||
/// price per unit per minute
|
|
||||||
pub price_per_unit: u64,
|
pub price_per_unit: u64,
|
||||||
pub locked_nano: u64,
|
pub locked_nano: u64,
|
||||||
pub collected_at: chrono::DateTime<Utc>,
|
pub collected_at: chrono::DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VmContract {
|
impl VmContract {
|
||||||
/// total hardware units of this VM
|
|
||||||
fn total_units(&self) -> u64 {
|
fn total_units(&self) -> u64 {
|
||||||
// TODO: Optimize this based on price of hardware.
|
// TODO: Optimize this based on price of hardware.
|
||||||
// I tried, but this can be done better.
|
// I tried, but this can be done better.
|
||||||
@ -123,7 +117,7 @@ impl VmContract {
|
|||||||
+ (!self.public_ipv4.is_empty() as u64 * 10)
|
+ (!self.public_ipv4.is_empty() as u64 * 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns price per minute in nanoLP
|
// Returns price per minute in nanoLP
|
||||||
fn price_per_minute(&self) -> u64 {
|
fn price_per_minute(&self) -> u64 {
|
||||||
self.total_units() * self.price_per_unit
|
self.total_units() * self.price_per_unit
|
||||||
}
|
}
|
||||||
@ -188,7 +182,6 @@ impl BrainData {
|
|||||||
tmp_locked: 0,
|
tmp_locked: 0,
|
||||||
kicked_for: Vec::new(),
|
kicked_for: Vec::new(),
|
||||||
banned_by: HashSet::new(),
|
banned_by: HashSet::new(),
|
||||||
last_kick: chrono::Utc::now(),
|
|
||||||
};
|
};
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
@ -278,63 +271,6 @@ impl BrainData {
|
|||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: this should also support Apps
|
|
||||||
/// Receives: operator, contract uuid, reason of kick
|
|
||||||
pub async fn kick_contract(
|
|
||||||
&self,
|
|
||||||
operator: &str,
|
|
||||||
uuid: &str,
|
|
||||||
reason: &str,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let contract = self.find_contract_by_uuid(uuid)?;
|
|
||||||
let mut operator_data = self
|
|
||||||
.operators
|
|
||||||
.get_mut(operator)
|
|
||||||
.ok_or(Error::AccessDenied)?;
|
|
||||||
if !operator_data.vm_nodes.contains(&contract.node_pubkey) {
|
|
||||||
return Err(Error::AccessDenied);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut minutes_to_refund = chrono::Utc::now()
|
|
||||||
.signed_duration_since(contract.updated_at)
|
|
||||||
.num_minutes()
|
|
||||||
.abs() as u64;
|
|
||||||
// cap refund at 1 week
|
|
||||||
if minutes_to_refund > 10080 {
|
|
||||||
minutes_to_refund = 10080;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut refund_ammount = minutes_to_refund * contract.price_per_minute();
|
|
||||||
let mut user = self
|
|
||||||
.accounts
|
|
||||||
.get_mut(&contract.admin_pubkey)
|
|
||||||
.ok_or(Error::ImpossibleError)?;
|
|
||||||
|
|
||||||
// check if he got kicked within the last day
|
|
||||||
if !chrono::Utc::now()
|
|
||||||
.signed_duration_since(user.last_kick)
|
|
||||||
.gt(&chrono::Duration::days(1))
|
|
||||||
{
|
|
||||||
refund_ammount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if operator_data.escrow < refund_ammount {
|
|
||||||
refund_ammount = operator_data.escrow;
|
|
||||||
}
|
|
||||||
|
|
||||||
user.balance += refund_ammount;
|
|
||||||
user.kicked_for.push(reason.to_string());
|
|
||||||
operator_data.escrow -= refund_ammount;
|
|
||||||
|
|
||||||
self.delete_vm(grpc::DeleteVmReq {
|
|
||||||
uuid: contract.uuid,
|
|
||||||
admin_pubkey: contract.admin_pubkey,
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn report_node(&self, admin_pubkey: String, node: &str, report: String) {
|
pub fn report_node(&self, admin_pubkey: String, node: &str, report: String) {
|
||||||
let mut nodes = self.vm_nodes.write().unwrap();
|
let mut nodes = self.vm_nodes.write().unwrap();
|
||||||
if let Some(node) = nodes.iter_mut().find(|n| n.public_key == node) {
|
if let Some(node) = nodes.iter_mut().find(|n| n.public_key == node) {
|
||||||
@ -427,10 +363,17 @@ impl BrainData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_vm(&self, delete_vm: grpc::DeleteVmReq) -> Result<(), Error> {
|
pub async fn delete_vm(&self, delete_vm: grpc::DeleteVmReq) -> Result<(), Error> {
|
||||||
let contract = self.find_contract_by_uuid(&delete_vm.uuid)?;
|
let contract = match self.find_contract_by_uuid(&delete_vm.uuid) {
|
||||||
|
Some(contract) => {
|
||||||
if contract.admin_pubkey != delete_vm.admin_pubkey {
|
if contract.admin_pubkey != delete_vm.admin_pubkey {
|
||||||
return Err(Error::AccessDenied);
|
return Err(Error::VmContractNotFound(delete_vm.uuid));
|
||||||
}
|
}
|
||||||
|
contract
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(Error::VmContractNotFound(delete_vm.uuid));
|
||||||
|
}
|
||||||
|
};
|
||||||
info!("Found vm {}. Deleting...", delete_vm.uuid);
|
info!("Found vm {}. Deleting...", delete_vm.uuid);
|
||||||
if let Some(daemon_tx) = self.daemon_tx.get(&contract.node_pubkey) {
|
if let Some(daemon_tx) = self.daemon_tx.get(&contract.node_pubkey) {
|
||||||
debug!(
|
debug!(
|
||||||
@ -639,7 +582,7 @@ impl BrainData {
|
|||||||
let uuid = req.uuid.clone();
|
let uuid = req.uuid.clone();
|
||||||
info!("Inserting new vm update request in memory: {req:?}");
|
info!("Inserting new vm update request in memory: {req:?}");
|
||||||
let node_pubkey = match self.find_contract_by_uuid(&req.uuid) {
|
let node_pubkey = match self.find_contract_by_uuid(&req.uuid) {
|
||||||
Ok(contract) => {
|
Some(contract) => {
|
||||||
if contract.admin_pubkey != req.admin_pubkey {
|
if contract.admin_pubkey != req.admin_pubkey {
|
||||||
let _ = tx.send(grpc::UpdateVmResp {
|
let _ = tx.send(grpc::UpdateVmResp {
|
||||||
uuid,
|
uuid,
|
||||||
@ -650,7 +593,7 @@ impl BrainData {
|
|||||||
}
|
}
|
||||||
contract.node_pubkey
|
contract.node_pubkey
|
||||||
}
|
}
|
||||||
Err(_) => {
|
None => {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Received UpdateVMReq for a contract that does not exist: {}",
|
"Received UpdateVMReq for a contract that does not exist: {}",
|
||||||
req.uuid
|
req.uuid
|
||||||
@ -810,13 +753,9 @@ impl BrainData {
|
|||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_contract_by_uuid(&self, uuid: &str) -> Result<VmContract, Error> {
|
pub fn find_contract_by_uuid(&self, uuid: &str) -> Option<VmContract> {
|
||||||
let contracts = self.vm_contracts.read().unwrap();
|
let contracts = self.vm_contracts.read().unwrap();
|
||||||
contracts
|
contracts.iter().cloned().find(|c| c.uuid == uuid)
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.find(|c| c.uuid == uuid)
|
|
||||||
.ok_or(Error::VmContractNotFound(uuid.to_string()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_all_contracts(&self) -> Vec<VmContract> {
|
pub fn list_all_contracts(&self) -> Vec<VmContract> {
|
||||||
|
23
src/grpc.rs
23
src/grpc.rs
@ -216,7 +216,7 @@ impl BrainCli for BrainCliMock {
|
|||||||
async fn report_node(&self, req: Request<ReportNodeReq>) -> Result<Response<Empty>, Status> {
|
async fn report_node(&self, req: Request<ReportNodeReq>) -> Result<Response<Empty>, Status> {
|
||||||
let req = check_sig_from_req(req)?;
|
let req = check_sig_from_req(req)?;
|
||||||
match self.data.find_contract_by_uuid(&req.contract) {
|
match self.data.find_contract_by_uuid(&req.contract) {
|
||||||
Ok(contract)
|
Some(contract)
|
||||||
if contract.admin_pubkey == req.admin_pubkey
|
if contract.admin_pubkey == req.admin_pubkey
|
||||||
&& contract.node_pubkey == req.node_pubkey =>
|
&& contract.node_pubkey == req.node_pubkey =>
|
||||||
{
|
{
|
||||||
@ -238,8 +238,8 @@ impl BrainCli for BrainCliMock {
|
|||||||
info!("CLI {} requested ListVMVmContractsStream", req.admin_pubkey);
|
info!("CLI {} requested ListVMVmContractsStream", req.admin_pubkey);
|
||||||
let contracts = match req.uuid.is_empty() {
|
let contracts = match req.uuid.is_empty() {
|
||||||
false => match self.data.find_contract_by_uuid(&req.uuid) {
|
false => match self.data.find_contract_by_uuid(&req.uuid) {
|
||||||
Ok(contract) => vec![contract],
|
Some(contract) => vec![contract],
|
||||||
_ => Vec::new(),
|
None => Vec::new(),
|
||||||
},
|
},
|
||||||
true => self.data.find_vm_contracts_by_admin(&req.admin_pubkey),
|
true => self.data.find_vm_contracts_by_admin(&req.admin_pubkey),
|
||||||
};
|
};
|
||||||
@ -291,8 +291,8 @@ impl BrainCli for BrainCliMock {
|
|||||||
|
|
||||||
async fn register_operator(
|
async fn register_operator(
|
||||||
&self,
|
&self,
|
||||||
req: Request<RegOperatorReq>,
|
req: tonic::Request<RegOperatorReq>,
|
||||||
) -> Result<Response<Empty>, Status> {
|
) -> std::result::Result<tonic::Response<Empty>, tonic::Status> {
|
||||||
let req = check_sig_from_req(req)?;
|
let req = check_sig_from_req(req)?;
|
||||||
info!("Regitering new operator: {req:?}");
|
info!("Regitering new operator: {req:?}");
|
||||||
match self.data.register_operator(req) {
|
match self.data.register_operator(req) {
|
||||||
@ -301,18 +301,6 @@ impl BrainCli for BrainCliMock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn kick_contract(&self, req: Request<KickReq>) -> Result<Response<Empty>, Status> {
|
|
||||||
let req = check_sig_from_req(req)?;
|
|
||||||
match self
|
|
||||||
.data
|
|
||||||
.kick_contract(&req.operator_wallet, &req.contract_uuid, &req.reason)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(()) => Ok(Response::new(Empty {})),
|
|
||||||
Err(e) => Err(Status::permission_denied(e.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListOperatorsStream =
|
type ListOperatorsStream =
|
||||||
Pin<Box<dyn Stream<Item = Result<ListOperatorsResp, Status>> + Send>>;
|
Pin<Box<dyn Stream<Item = Result<ListOperatorsResp, Status>> + Send>>;
|
||||||
async fn list_operators(
|
async fn list_operators(
|
||||||
@ -431,7 +419,6 @@ impl_pubkey_getter!(ReportNodeReq, admin_pubkey);
|
|||||||
impl_pubkey_getter!(ListVmContractsReq, admin_pubkey);
|
impl_pubkey_getter!(ListVmContractsReq, admin_pubkey);
|
||||||
impl_pubkey_getter!(RegisterVmNodeReq, node_pubkey);
|
impl_pubkey_getter!(RegisterVmNodeReq, node_pubkey);
|
||||||
impl_pubkey_getter!(RegOperatorReq, pubkey);
|
impl_pubkey_getter!(RegOperatorReq, pubkey);
|
||||||
impl_pubkey_getter!(KickReq, operator_wallet);
|
|
||||||
|
|
||||||
impl_pubkey_getter!(VmNodeFilters);
|
impl_pubkey_getter!(VmNodeFilters);
|
||||||
impl_pubkey_getter!(Empty);
|
impl_pubkey_getter!(Empty);
|
||||||
|
5
vm.proto
5
vm.proto
@ -234,9 +234,8 @@ message ReportNodeReq {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message KickReq {
|
message KickReq {
|
||||||
string operator_wallet = 1;
|
string uuid = 1;
|
||||||
string contract_uuid = 2;
|
string reason = 2;
|
||||||
string reason = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
service BrainCli {
|
service BrainCli {
|
||||||
|
Loading…
Reference in New Issue
Block a user