forked from ghe0/brain-to-surreal
added report and airdrop
This commit is contained in:
parent
71cc0a8d82
commit
a8cf515061
64
src/db.rs
64
src/db.rs
@ -51,36 +51,6 @@ pub async fn migration0(old_data: &old_brain::BrainData) -> surrealdb::Result<()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn account(address: &str) -> Result<Account, Error> {
|
||||
let id = (ACCOUNT, address);
|
||||
let account: Option<Account> = DB.select(id).await?;
|
||||
let account = match account {
|
||||
Some(account) => account,
|
||||
None => {
|
||||
Account { id: id.into(), balance: 0, tmp_locked: 0, escrow: 0, email: String::new() }
|
||||
}
|
||||
};
|
||||
Ok(account)
|
||||
}
|
||||
|
||||
// I am not deleting this example cause I might need it later.
|
||||
//
|
||||
// async fn get_wallet_contracts() -> surrealdb::Result<Vec<Wallet>> {
|
||||
// let mut result = DB
|
||||
// .query("select *, ->contract.* from wallet:address1;")
|
||||
// .await?;
|
||||
// let wallets: Vec<Wallet> = result.take(0)?;
|
||||
// Ok(wallets)
|
||||
// }
|
||||
//
|
||||
// #[derive(Debug, Serialize, Deserialize)]
|
||||
// pub struct Wallet {
|
||||
// balance: u64,
|
||||
// id: RecordId,
|
||||
// #[serde(rename = "->contract", default)]
|
||||
// contracts: Vec<Contract>,
|
||||
// }
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Account {
|
||||
pub id: RecordId,
|
||||
@ -90,6 +60,28 @@ pub struct Account {
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
impl Account {
|
||||
pub async fn get(address: &str) -> Result<Self, Error> {
|
||||
let id = (ACCOUNT, address);
|
||||
let account: Option<Self> = DB.select(id).await?;
|
||||
let account = match account {
|
||||
Some(account) => account,
|
||||
None => {
|
||||
Self { id: id.into(), balance: 0, tmp_locked: 0, escrow: 0, email: String::new() }
|
||||
}
|
||||
};
|
||||
Ok(account)
|
||||
}
|
||||
|
||||
pub async fn airdrop(account: &str, tokens: u64) -> Result<(), Error> {
|
||||
let tokens = tokens.saturating_mul(1_000_000_000);
|
||||
let _ = DB
|
||||
.query(format!("upsert account:{account} SET balance = (balance || 0) + {tokens};"))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct VmNode {
|
||||
pub id: RecordId,
|
||||
@ -291,7 +283,6 @@ pub struct Kick {
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Report {
|
||||
id: RecordId,
|
||||
#[serde(rename = "in")]
|
||||
from_account: RecordId,
|
||||
#[serde(rename = "out")]
|
||||
@ -300,6 +291,17 @@ pub struct Report {
|
||||
reason: String,
|
||||
}
|
||||
|
||||
impl Report {
|
||||
// TODO: test this functionality and remove this comment
|
||||
pub async fn create(from_account: RecordId, to_node: RecordId, reason: String) -> Result<(), Error> {
|
||||
let _: Vec<Self> = DB
|
||||
.insert("report")
|
||||
.relation(Report { from_account, to_node, created_at: Datetime::default(), reason })
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct OperatorRelation {
|
||||
#[serde(rename = "in")]
|
||||
|
84
src/grpc.rs
84
src/grpc.rs
@ -95,29 +95,25 @@ impl BrainGeneralCli for BrainGeneralCliMock {
|
||||
|
||||
async fn get_balance(&self, req: Request<Pubkey>) -> Result<Response<AccountBalance>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
Ok(Response::new(db::account(&req.pubkey).await?.into()))
|
||||
Ok(Response::new(db::Account::get(&req.pubkey).await?.into()))
|
||||
}
|
||||
|
||||
async fn report_node(&self, req: Request<ReportNodeReq>) -> Result<Response<Empty>, Status> {
|
||||
let _req = check_sig_from_req(req)?;
|
||||
todo!();
|
||||
// match self.data.find_any_contract_by_uuid(&req.contract) {
|
||||
// Ok((Some(vm_contract), _))
|
||||
// if vm_contract.admin_pubkey == req.admin_pubkey
|
||||
// && vm_contract.node_pubkey == req.node_pubkey =>
|
||||
// {
|
||||
// ()
|
||||
// }
|
||||
// Ok((_, Some(app_contract)))
|
||||
// if app_contract.admin_pubkey == req.admin_pubkey
|
||||
// && app_contract.node_pubkey == req.node_pubkey =>
|
||||
// {
|
||||
// ()
|
||||
// }
|
||||
// _ => return Err(Status::unauthenticated("No contract found by this ID.")),
|
||||
// };
|
||||
// self.data.report_any_node(req.admin_pubkey, &req.node_pubkey, req.reason);
|
||||
// Ok(Response::new(Empty {}))
|
||||
let req = check_sig_from_req(req)?;
|
||||
let (account, node) = match db::VmContractWithNode::get_by_uuid(&req.contract).await? {
|
||||
Some(vm_contract)
|
||||
if vm_contract.admin.key().to_string() == req.admin_pubkey
|
||||
&& vm_contract.vm_node.id.key().to_string() == req.node_pubkey =>
|
||||
{
|
||||
(vm_contract.admin, vm_contract.vm_node.id)
|
||||
}
|
||||
_ => {
|
||||
// TODO: Hey, Noor! Please add app contract here.
|
||||
return Err(Status::unauthenticated("No contract found by this ID."));
|
||||
}
|
||||
};
|
||||
db::Report::create(account, node, req.reason).await?;
|
||||
Ok(Response::new(Empty {}))
|
||||
}
|
||||
|
||||
async fn list_operators(
|
||||
@ -178,12 +174,11 @@ impl BrainGeneralCli for BrainGeneralCliMock {
|
||||
|
||||
// admin commands
|
||||
|
||||
async fn airdrop(&self, _req: Request<AirdropReq>) -> Result<Response<Empty>, Status> {
|
||||
todo!();
|
||||
// check_admin_key(&req)?;
|
||||
// let req = check_sig_from_req(req)?;
|
||||
// self.data.give_airdrop(&req.pubkey, req.tokens);
|
||||
// Ok(Response::new(Empty {}))
|
||||
async fn airdrop(&self, req: Request<AirdropReq>) -> Result<Response<Empty>, Status> {
|
||||
check_admin_key(&req)?;
|
||||
let req = check_sig_from_req(req)?;
|
||||
db::Account::airdrop(&req.pubkey, req.tokens).await?;
|
||||
Ok(Response::new(Empty {}))
|
||||
}
|
||||
|
||||
async fn slash(&self, _req: Request<SlashReq>) -> Result<Response<Empty>, Status> {
|
||||
@ -420,13 +415,26 @@ macro_rules! impl_pubkey_getter {
|
||||
impl_pubkey_getter!(Pubkey, pubkey);
|
||||
impl_pubkey_getter!(NewVmReq, admin_pubkey);
|
||||
impl_pubkey_getter!(DeleteVmReq, admin_pubkey);
|
||||
impl_pubkey_getter!(ReportNodeReq, admin_pubkey);
|
||||
impl_pubkey_getter!(UpdateVmReq, admin_pubkey);
|
||||
impl_pubkey_getter!(ExtendVmReq, admin_pubkey);
|
||||
impl_pubkey_getter!(ReportNodeReq, admin_pubkey);
|
||||
impl_pubkey_getter!(ListVmContractsReq, wallet);
|
||||
impl_pubkey_getter!(RegisterVmNodeReq, node_pubkey);
|
||||
impl_pubkey_getter!(RegOperatorReq, pubkey);
|
||||
impl_pubkey_getter!(KickReq, operator_wallet);
|
||||
impl_pubkey_getter!(BanUserReq, operator_wallet);
|
||||
|
||||
impl_pubkey_getter!(VmNodeFilters);
|
||||
impl_pubkey_getter!(Empty);
|
||||
impl_pubkey_getter!(AirdropReq);
|
||||
impl_pubkey_getter!(SlashReq);
|
||||
|
||||
// impl_pubkey_getter!(NewAppReq, admin_pubkey);
|
||||
// impl_pubkey_getter!(DelAppReq, admin_pubkey);
|
||||
// impl_pubkey_getter!(ListAppContractsReq, admin_pubkey);
|
||||
//
|
||||
// impl_pubkey_getter!(RegisterAppNodeReq);
|
||||
// impl_pubkey_getter!(AppNodeFilters);
|
||||
|
||||
fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) -> Result<T, Status> {
|
||||
let time = match req.metadata().get("timestamp") {
|
||||
@ -490,3 +498,25 @@ fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) -> Res
|
||||
}
|
||||
Ok(req)
|
||||
}
|
||||
|
||||
const ADMIN_ACCOUNTS: &[&str] = &[
|
||||
"x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK",
|
||||
"FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL",
|
||||
"H21Shi4iE7vgfjWEQNvzmpmBMJSaiZ17PYUcdNoAoKNc",
|
||||
];
|
||||
|
||||
fn check_admin_key<T>(req: &Request<T>) -> Result<(), Status> {
|
||||
let pubkey = match req.metadata().get("pubkey") {
|
||||
Some(p) => p.clone(),
|
||||
None => return Err(Status::unauthenticated("pubkey not found in metadata.")),
|
||||
};
|
||||
let pubkey = pubkey
|
||||
.to_str()
|
||||
.map_err(|_| Status::unauthenticated("could not parse pubkey metadata to str"))?;
|
||||
|
||||
if !ADMIN_ACCOUNTS.contains(&pubkey) {
|
||||
return Err(Status::unauthenticated("This operation is reserved to admin accounts"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user