forked from ghe0/brain-mock
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
cc027d2cc1 | |||
64b65d7ecd | |||
02be48fd96 | |||
5c213f2eb4 | |||
df805ea291 | |||
c98db7f8c3 | |||
64f892c174 | |||
5359ba039b | |||
7dfdf4844e | |||
928c68f550 | |||
9fa62a1978 |
253
Cargo.lock
generated
253
Cargo.lock
generated
@ -209,25 +209,42 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brain-mock"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"chrono",
|
||||
"dashmap",
|
||||
"ed25519-dalek",
|
||||
"env_logger",
|
||||
"log",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
@ -236,6 +253,15 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[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"
|
||||
@ -279,6 +305,7 @@ dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
]
|
||||
@ -289,6 +316,12 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
@ -305,12 +338,58 @@ version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "4.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"curve25519-dalek-derive",
|
||||
"digest",
|
||||
"fiat-crypto",
|
||||
"rustc_version",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek-derive"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "6.1.0"
|
||||
@ -323,6 +402,27 @@ dependencies = [
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -336,6 +436,30 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519"
|
||||
version = "2.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||
dependencies = [
|
||||
"pkcs8",
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519-dalek"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"ed25519",
|
||||
"serde",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
@ -396,6 +520,12 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "fiat-crypto"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.2"
|
||||
@ -471,6 +601,16 @@ dependencies = [
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
@ -1112,6 +1252,16 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
||||
dependencies = [
|
||||
"der",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.31"
|
||||
@ -1340,6 +1490,15 @@ version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.42"
|
||||
@ -1443,19 +1602,25 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.216"
|
||||
name = "semver"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
|
||||
checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.216"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1486,12 +1651,45 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap 2.7.0",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
@ -1523,6 +1721,16 @@ version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
@ -1630,6 +1838,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"
|
||||
@ -1829,12 +2052,24 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
@ -1885,6 +2120,12 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
|
10
Cargo.toml
10
Cargo.toml
@ -4,15 +4,17 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.39"
|
||||
dashmap = "6.1.0"
|
||||
bs58 = "0.5.1"
|
||||
chrono = { version = "0.4.39", features = ["serde"] }
|
||||
dashmap = { version = "6.1.0", features = ["serde"] }
|
||||
ed25519-dalek = "2.1.1"
|
||||
env_logger = "0.11.6"
|
||||
log = "0.4.22"
|
||||
prost = "0.13.4"
|
||||
prost-types = "0.13.4"
|
||||
reqwest = "0.12.10"
|
||||
serde = { version = "1.0.216", features = ["derive"] }
|
||||
serde_json = "1.0.134"
|
||||
serde = { version = "1.0.217", features = ["derive"] }
|
||||
serde_yaml = "0.9.34"
|
||||
thiserror = "2.0.11"
|
||||
tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] }
|
||||
tokio-stream = "0.1.17"
|
||||
|
2
build.rs
2
build.rs
@ -1,6 +1,6 @@
|
||||
fn main() {
|
||||
tonic_build::configure()
|
||||
.build_server(true)
|
||||
.compile_protos(&["snp.proto"], &["proto"])
|
||||
.compile_protos(&["vm.proto"], &["proto"])
|
||||
.unwrap_or_else(|e| panic!("Failed to compile protos {:?}", e));
|
||||
}
|
||||
|
744
src/data.rs
744
src/data.rs
File diff suppressed because it is too large
Load Diff
490
src/grpc.rs
490
src/grpc.rs
@ -1,13 +1,12 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod snp_proto {
|
||||
tonic::include_proto!("snp_proto");
|
||||
tonic::include_proto!("vm_proto");
|
||||
}
|
||||
|
||||
use crate::data::BrainData;
|
||||
use crate::grpc::vm_daemon_message;
|
||||
use log::info;
|
||||
use snp_proto::brain_cli_server::BrainCli;
|
||||
use snp_proto::brain_daemon_server::BrainDaemon;
|
||||
use snp_proto::brain_vm_daemon_server::BrainVmDaemon;
|
||||
use snp_proto::*;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
@ -15,6 +14,12 @@ use tokio::sync::mpsc;
|
||||
use tokio_stream::{wrappers::ReceiverStream, Stream, StreamExt};
|
||||
use tonic::{Request, Response, Status, Streaming};
|
||||
|
||||
const ADMIN_ACCOUNTS: &[&str] = &[
|
||||
"x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK",
|
||||
"FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL",
|
||||
"H21Shi4iE7vgfjWEQNvzmpmBMJSaiZ17PYUcdNoAoKNc",
|
||||
];
|
||||
|
||||
pub struct BrainDaemonMock {
|
||||
data: Arc<BrainData>,
|
||||
}
|
||||
@ -36,17 +41,17 @@ impl BrainCliMock {
|
||||
}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl BrainDaemon for BrainDaemonMock {
|
||||
type RegisterNodeStream = Pin<Box<dyn Stream<Item = Result<Contract, Status>> + Send>>;
|
||||
async fn register_node(
|
||||
impl BrainVmDaemon for BrainDaemonMock {
|
||||
type RegisterVmNodeStream = Pin<Box<dyn Stream<Item = Result<VmContract, Status>> + Send>>;
|
||||
async fn register_vm_node(
|
||||
&self,
|
||||
req: Request<RegisterNodeReq>,
|
||||
) -> Result<Response<Self::RegisterNodeStream>, Status> {
|
||||
let req = req.into_inner();
|
||||
req: Request<RegisterVmNodeReq>,
|
||||
) -> Result<Response<Self::RegisterVmNodeStream>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
info!("Starting registration process for {:?}", req);
|
||||
let node = crate::data::Node {
|
||||
let node = crate::data::VmNode {
|
||||
public_key: req.node_pubkey.clone(),
|
||||
owner_key: req.owner_pubkey,
|
||||
operator_wallet: req.operator_wallet,
|
||||
country: req.country,
|
||||
region: req.region,
|
||||
city: req.city,
|
||||
@ -54,10 +59,10 @@ impl BrainDaemon for BrainDaemonMock {
|
||||
price: req.price,
|
||||
..Default::default()
|
||||
};
|
||||
self.data.insert_node(node);
|
||||
self.data.register_node(node);
|
||||
|
||||
info!("Sending existing contracts to {}", req.node_pubkey);
|
||||
let contracts = self.data.find_contracts_by_node_pubkey(&req.node_pubkey);
|
||||
let contracts = self.data.find_vm_contracts_by_node(&req.node_pubkey);
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
tokio::spawn(async move {
|
||||
for contract in contracts {
|
||||
@ -66,19 +71,26 @@ impl BrainDaemon for BrainDaemonMock {
|
||||
});
|
||||
let output_stream = ReceiverStream::new(rx);
|
||||
Ok(Response::new(
|
||||
Box::pin(output_stream) as Self::RegisterNodeStream
|
||||
Box::pin(output_stream) as Self::RegisterVmNodeStream
|
||||
))
|
||||
}
|
||||
|
||||
type BrainMessagesStream = Pin<Box<dyn Stream<Item = Result<BrainMessage, Status>> + Send>>;
|
||||
type BrainMessagesStream = Pin<Box<dyn Stream<Item = Result<BrainVmMessage, Status>> + Send>>;
|
||||
async fn brain_messages(
|
||||
&self,
|
||||
req: Request<Pubkey>,
|
||||
req: Request<DaemonStreamAuth>,
|
||||
) -> Result<Response<Self::BrainMessagesStream>, Status> {
|
||||
let req = req.into_inner();
|
||||
info!("Daemon {} connected to receive brain messages", req.pubkey);
|
||||
let auth = req.into_inner();
|
||||
let pubkey = auth.pubkey.clone();
|
||||
check_sig_from_parts(
|
||||
&pubkey,
|
||||
&auth.timestamp,
|
||||
&format!("{:?}", auth.contracts),
|
||||
&auth.signature,
|
||||
)?;
|
||||
info!("Daemon {} connected to receive brain messages", pubkey);
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
self.data.add_daemon_tx(&req.pubkey, tx);
|
||||
self.data.add_daemon_tx(&pubkey, tx);
|
||||
let output_stream = ReceiverStream::new(rx).map(|msg| Ok(msg));
|
||||
Ok(Response::new(
|
||||
Box::pin(output_stream) as Self::BrainMessagesStream
|
||||
@ -87,27 +99,46 @@ impl BrainDaemon for BrainDaemonMock {
|
||||
|
||||
async fn daemon_messages(
|
||||
&self,
|
||||
req: Request<Streaming<DaemonMessage>>,
|
||||
req: Request<Streaming<VmDaemonMessage>>,
|
||||
) -> Result<Response<Empty>, Status> {
|
||||
let mut req_stream = req.into_inner();
|
||||
let mut pubkey = String::new();
|
||||
let pubkey: String;
|
||||
if let Some(Ok(msg)) = req_stream.next().await {
|
||||
log::debug!(
|
||||
"demon_messages received the following auth message: {:?}",
|
||||
msg.msg
|
||||
);
|
||||
if let Some(vm_daemon_message::Msg::Auth(auth)) = msg.msg {
|
||||
pubkey = auth.pubkey.clone();
|
||||
check_sig_from_parts(
|
||||
&pubkey,
|
||||
&auth.timestamp,
|
||||
&format!("{:?}", auth.contracts),
|
||||
&auth.signature,
|
||||
)?;
|
||||
} else {
|
||||
return Err(Status::unauthenticated(
|
||||
"Could not authenticate the daemon: could not extract auth signature",
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(Status::unauthenticated("Could not authenticate the daemon"));
|
||||
}
|
||||
|
||||
// info!("Received a message from daemon {pubkey}: {daemon_message:?}");
|
||||
while let Some(daemon_message) = req_stream.next().await {
|
||||
info!("Received a message from daemon {pubkey}: {daemon_message:?}");
|
||||
match daemon_message {
|
||||
Ok(msg) => match msg.msg {
|
||||
Some(daemon_message::Msg::Pubkey(p)) => {
|
||||
pubkey = p.pubkey;
|
||||
}
|
||||
Some(daemon_message::Msg::NewVmResp(new_vm_resp)) => {
|
||||
Some(vm_daemon_message::Msg::NewVmResp(new_vm_resp)) => {
|
||||
self.data.submit_newvm_resp(new_vm_resp).await;
|
||||
}
|
||||
Some(daemon_message::Msg::UpdateVmResp(update_vm_resp)) => {
|
||||
Some(vm_daemon_message::Msg::UpdateVmResp(update_vm_resp)) => {
|
||||
self.data.submit_updatevm_resp(update_vm_resp).await;
|
||||
}
|
||||
Some(daemon_message::Msg::NodeResources(node_resources)) => {
|
||||
Some(vm_daemon_message::Msg::VmNodeResources(node_resources)) => {
|
||||
self.data.submit_node_resources(node_resources);
|
||||
}
|
||||
None => {}
|
||||
_ => {}
|
||||
},
|
||||
Err(e) => {
|
||||
log::warn!("Daemon disconnected: {e:?}");
|
||||
@ -122,19 +153,21 @@ impl BrainDaemon for BrainDaemonMock {
|
||||
#[tonic::async_trait]
|
||||
impl BrainCli for BrainCliMock {
|
||||
async fn get_balance(&self, req: Request<Pubkey>) -> Result<Response<AccountBalance>, Status> {
|
||||
Ok(Response::new(
|
||||
self.data.get_balance(&req.into_inner().pubkey).into(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn get_airdrop(&self, req: Request<Pubkey>) -> Result<Response<Empty>, Status> {
|
||||
self.data.get_airdrop(&req.into_inner().pubkey);
|
||||
Ok(Response::new(Empty {}))
|
||||
let req = check_sig_from_req(req)?;
|
||||
Ok(Response::new(self.data.get_balance(&req.pubkey).into()))
|
||||
}
|
||||
|
||||
async fn new_vm(&self, req: Request<NewVmReq>) -> Result<Response<NewVmResp>, Status> {
|
||||
let req = req.into_inner();
|
||||
let req = check_sig_from_req(req)?;
|
||||
info!("New VM requested via CLI: {req:?}");
|
||||
if self
|
||||
.data
|
||||
.is_user_banned_by_node(&req.admin_pubkey, &req.node_pubkey)
|
||||
{
|
||||
return Err(Status::permission_denied(
|
||||
"This operator banned you. What did you do?",
|
||||
));
|
||||
}
|
||||
let admin_pubkey = req.admin_pubkey.clone();
|
||||
let (oneshot_tx, oneshot_rx) = tokio::sync::oneshot::channel();
|
||||
self.data.submit_newvm_req(req, oneshot_tx).await;
|
||||
@ -153,7 +186,7 @@ impl BrainCli for BrainCliMock {
|
||||
}
|
||||
|
||||
async fn update_vm(&self, req: Request<UpdateVmReq>) -> Result<Response<UpdateVmResp>, Status> {
|
||||
let req = req.into_inner();
|
||||
let req = check_sig_from_req(req)?;
|
||||
info!("Update VM requested via CLI: {req:?}");
|
||||
let (oneshot_tx, oneshot_rx) = tokio::sync::oneshot::channel();
|
||||
self.data.submit_updatevm_req(req, oneshot_tx).await;
|
||||
@ -162,39 +195,72 @@ impl BrainCli for BrainCliMock {
|
||||
info!("Sending UpdateVMResp: {response:?}");
|
||||
Ok(Response::new(response))
|
||||
}
|
||||
Err(e) => {
|
||||
Err(Status::unknown(
|
||||
"Update VM request failed due to error: {e}",
|
||||
))
|
||||
}
|
||||
Err(e) => Err(Status::unknown(format!(
|
||||
"Update VM request failed due to error: {e}"
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
async fn extend_vm(&self, req: Request<ExtendVmReq>) -> Result<Response<Empty>, Status> {
|
||||
let req = req.into_inner();
|
||||
let req = check_sig_from_req(req)?;
|
||||
match self
|
||||
.data
|
||||
.extend_contract_time(&req.uuid, &req.admin_pubkey, req.locked_nano)
|
||||
.extend_vm_contract_time(&req.uuid, &req.admin_pubkey, req.locked_nano)
|
||||
{
|
||||
Ok(()) => Ok(Response::new(Empty {})),
|
||||
Err(e) => Err(Status::unknown(format!("Could not extend contract: {e}"))),
|
||||
}
|
||||
}
|
||||
|
||||
type ListContractsStream = Pin<Box<dyn Stream<Item = Result<Contract, Status>> + Send>>;
|
||||
async fn list_contracts(
|
||||
&self,
|
||||
req: Request<ListContractsReq>,
|
||||
) -> Result<Response<Self::ListContractsStream>, Status> {
|
||||
let req = req.into_inner();
|
||||
info!("CLI {} requested ListVMContractsStream", req.admin_pubkey);
|
||||
let contracts = match req.uuid.is_empty() {
|
||||
false => match self.data.find_contract_by_uuid(&req.uuid) {
|
||||
Some(contract) => vec![contract],
|
||||
None => Vec::new(),
|
||||
},
|
||||
true => self.data.find_contracts_by_admin_pubkey(&req.admin_pubkey),
|
||||
async fn delete_vm(&self, req: Request<DeleteVmReq>) -> Result<Response<Empty>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
match self.data.delete_vm(req).await {
|
||||
Ok(()) => Ok(Response::new(Empty {})),
|
||||
Err(e) => Err(Status::not_found(e.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
async fn report_node(&self, req: Request<ReportNodeReq>) -> Result<Response<Empty>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
match self.data.find_contract_by_uuid(&req.contract) {
|
||||
Ok(contract)
|
||||
if contract.admin_pubkey == req.admin_pubkey
|
||||
&& contract.node_pubkey == req.node_pubkey =>
|
||||
{
|
||||
()
|
||||
}
|
||||
_ => return Err(Status::unauthenticated("No contract found by this ID.")),
|
||||
};
|
||||
self.data
|
||||
.report_node(req.admin_pubkey, &req.node_pubkey, req.reason);
|
||||
Ok(Response::new(Empty {}))
|
||||
}
|
||||
|
||||
type ListVmContractsStream = Pin<Box<dyn Stream<Item = Result<VmContract, Status>> + Send>>;
|
||||
async fn list_vm_contracts(
|
||||
&self,
|
||||
req: Request<ListVmContractsReq>,
|
||||
) -> Result<Response<Self::ListVmContractsStream>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
info!(
|
||||
"CLI {} requested ListVMVmContractsStream. As operator: {}",
|
||||
req.wallet, req.as_operator
|
||||
);
|
||||
let mut contracts = Vec::new();
|
||||
if !req.uuid.is_empty() {
|
||||
if let Ok(specific_contract) = self.data.find_contract_by_uuid(&req.uuid) {
|
||||
if specific_contract.admin_pubkey == req.wallet {
|
||||
contracts.push(specific_contract);
|
||||
}
|
||||
// TODO: allow operator to inspect contracts
|
||||
}
|
||||
} else {
|
||||
if req.as_operator {
|
||||
contracts.append(&mut self.data.find_vm_contracts_by_operator(&req.wallet));
|
||||
} else {
|
||||
contracts.append(&mut self.data.find_vm_contracts_by_admin(&req.wallet));
|
||||
}
|
||||
}
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
tokio::spawn(async move {
|
||||
for contract in contracts {
|
||||
@ -203,18 +269,18 @@ impl BrainCli for BrainCliMock {
|
||||
});
|
||||
let output_stream = ReceiverStream::new(rx);
|
||||
Ok(Response::new(
|
||||
Box::pin(output_stream) as Self::ListContractsStream
|
||||
Box::pin(output_stream) as Self::ListVmContractsStream
|
||||
))
|
||||
}
|
||||
|
||||
type ListNodesStream = Pin<Box<dyn Stream<Item = Result<NodeListResp, Status>> + Send>>;
|
||||
async fn list_nodes(
|
||||
type ListVmNodesStream = Pin<Box<dyn Stream<Item = Result<VmNodeListResp, Status>> + Send>>;
|
||||
async fn list_vm_nodes(
|
||||
&self,
|
||||
req: Request<NodeFilters>,
|
||||
) -> Result<Response<Self::ListNodesStream>, tonic::Status> {
|
||||
let req = req.into_inner();
|
||||
info!("Unknown CLI requested ListNodesStream: {req:?}");
|
||||
let nodes = self.data.find_nodes_by_filters(&req);
|
||||
req: Request<VmNodeFilters>,
|
||||
) -> Result<Response<Self::ListVmNodesStream>, tonic::Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
info!("CLI requested ListVmNodesStream: {req:?}");
|
||||
let nodes = self.data.find_vm_nodes_by_filters(&req);
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
tokio::spawn(async move {
|
||||
for node in nodes {
|
||||
@ -223,16 +289,16 @@ impl BrainCli for BrainCliMock {
|
||||
});
|
||||
let output_stream = ReceiverStream::new(rx);
|
||||
Ok(Response::new(
|
||||
Box::pin(output_stream) as Self::ListNodesStream
|
||||
Box::pin(output_stream) as Self::ListVmNodesStream
|
||||
))
|
||||
}
|
||||
|
||||
async fn get_one_node(
|
||||
async fn get_one_vm_node(
|
||||
&self,
|
||||
req: Request<NodeFilters>,
|
||||
) -> Result<Response<NodeListResp>, Status> {
|
||||
let req = req.into_inner();
|
||||
info!("Unknown CLI requested ListNodesStream: {req:?}");
|
||||
req: Request<VmNodeFilters>,
|
||||
) -> Result<Response<VmNodeListResp>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
info!("Unknown CLI requested ListVmNodesStream: {req:?}");
|
||||
match self.data.get_one_node_by_filters(&req) {
|
||||
Some(node) => Ok(Response::new(node.into())),
|
||||
None => Err(Status::not_found(
|
||||
@ -241,10 +307,278 @@ impl BrainCli for BrainCliMock {
|
||||
}
|
||||
}
|
||||
|
||||
async fn delete_vm(&self, req: Request<DeleteVmReq>) -> Result<Response<Empty>, Status> {
|
||||
let req = req.into_inner();
|
||||
info!("Unknown CLI requested to delete vm {}", req.uuid);
|
||||
self.data.delete_vm(req).await;
|
||||
async fn register_operator(
|
||||
&self,
|
||||
req: Request<RegOperatorReq>,
|
||||
) -> Result<Response<Empty>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
info!("Regitering new operator: {req:?}");
|
||||
match self.data.register_operator(req) {
|
||||
Ok(()) => Ok(Response::new(Empty {})),
|
||||
Err(e) => Err(Status::failed_precondition(e.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
async fn kick_contract(&self, req: Request<KickReq>) -> Result<Response<KickResp>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
match self
|
||||
.data
|
||||
.kick_contract(&req.operator_wallet, &req.contract_uuid, &req.reason)
|
||||
.await
|
||||
{
|
||||
Ok(nano_lp) => Ok(Response::new(KickResp { nano_lp })),
|
||||
Err(e) => Err(Status::permission_denied(e.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
async fn ban_user(&self, req: Request<BanUserReq>) -> Result<Response<Empty>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
self.data.ban_user(&req.operator_wallet, &req.user_wallet);
|
||||
Ok(Response::new(Empty {}))
|
||||
}
|
||||
|
||||
type ListOperatorsStream =
|
||||
Pin<Box<dyn Stream<Item = Result<ListOperatorsResp, Status>> + Send>>;
|
||||
async fn list_operators(
|
||||
&self,
|
||||
req: Request<Empty>,
|
||||
) -> Result<Response<Self::ListOperatorsStream>, Status> {
|
||||
let _ = check_sig_from_req(req)?;
|
||||
let operators = self.data.list_operators();
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
tokio::spawn(async move {
|
||||
for op in operators {
|
||||
let _ = tx.send(Ok(op.into())).await;
|
||||
}
|
||||
});
|
||||
let output_stream = ReceiverStream::new(rx);
|
||||
Ok(Response::new(
|
||||
Box::pin(output_stream) as Self::ListOperatorsStream
|
||||
))
|
||||
}
|
||||
|
||||
async fn inspect_operator(
|
||||
&self,
|
||||
req: Request<Pubkey>,
|
||||
) -> Result<Response<InspectOperatorResp>, Status> {
|
||||
match self.data.inspect_operator(&req.into_inner().pubkey) {
|
||||
Some(op) => Ok(Response::new(op.into())),
|
||||
None => Err(Status::not_found(
|
||||
"The wallet you specified is not an operator",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn airdrop(&self, req: Request<AirdropReq>) -> Result<Response<Empty>, Status> {
|
||||
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 slash(&self, req: Request<SlashReq>) -> Result<Response<Empty>, Status> {
|
||||
check_admin_key(&req)?;
|
||||
let req = check_sig_from_req(req)?;
|
||||
self.data.slash_account(&req.pubkey, req.tokens);
|
||||
Ok(Response::new(Empty {}))
|
||||
}
|
||||
|
||||
type ListAllVmContractsStream = Pin<Box<dyn Stream<Item = Result<VmContract, Status>> + Send>>;
|
||||
async fn list_all_vm_contracts(
|
||||
&self,
|
||||
req: Request<Empty>,
|
||||
) -> Result<Response<Self::ListVmContractsStream>, Status> {
|
||||
check_admin_key(&req)?;
|
||||
let _ = check_sig_from_req(req)?;
|
||||
let contracts = self.data.list_all_contracts();
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
tokio::spawn(async move {
|
||||
for contract in contracts {
|
||||
let _ = tx.send(Ok(contract.into())).await;
|
||||
}
|
||||
});
|
||||
let output_stream = ReceiverStream::new(rx);
|
||||
Ok(Response::new(
|
||||
Box::pin(output_stream) as Self::ListVmContractsStream
|
||||
))
|
||||
}
|
||||
|
||||
type ListAccountsStream = Pin<Box<dyn Stream<Item = Result<Account, Status>> + Send>>;
|
||||
async fn list_accounts(
|
||||
&self,
|
||||
req: Request<Empty>,
|
||||
) -> Result<Response<Self::ListAccountsStream>, Status> {
|
||||
check_admin_key(&req)?;
|
||||
let _ = check_sig_from_req(req)?;
|
||||
let accounts = self.data.list_accounts();
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
tokio::spawn(async move {
|
||||
for account in accounts {
|
||||
let _ = tx.send(Ok(account.into())).await;
|
||||
}
|
||||
});
|
||||
let output_stream = ReceiverStream::new(rx);
|
||||
Ok(Response::new(
|
||||
Box::pin(output_stream) as Self::ListAccountsStream
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
trait PubkeyGetter {
|
||||
fn get_pubkey(&self) -> Option<String>;
|
||||
}
|
||||
|
||||
macro_rules! impl_pubkey_getter {
|
||||
($t:ty, $field:ident) => {
|
||||
impl PubkeyGetter for $t {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
Some(self.$field.clone())
|
||||
}
|
||||
}
|
||||
};
|
||||
($t:ty) => {
|
||||
impl PubkeyGetter for $t {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_pubkey_getter!(Pubkey, pubkey);
|
||||
impl_pubkey_getter!(NewVmReq, admin_pubkey);
|
||||
impl_pubkey_getter!(DeleteVmReq, 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);
|
||||
|
||||
fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) -> Result<T, Status> {
|
||||
let time = match req.metadata().get("timestamp") {
|
||||
Some(t) => t.clone(),
|
||||
None => return Err(Status::unauthenticated("Timestamp not found in metadata.")),
|
||||
};
|
||||
let time = time
|
||||
.to_str()
|
||||
.map_err(|_| Status::unauthenticated("Timestamp in metadata is not a string"))?;
|
||||
|
||||
let now = chrono::Utc::now();
|
||||
let parsed_time = chrono::DateTime::parse_from_rfc3339(time)
|
||||
.map_err(|_| Status::unauthenticated("Coult not parse timestamp"))?;
|
||||
let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds();
|
||||
if seconds_elapsed > 4 || seconds_elapsed < -4 {
|
||||
return Err(Status::unauthenticated(format!(
|
||||
"Date is not within 4 sec of the time of the server: CLI {} vs Server {}",
|
||||
parsed_time, now
|
||||
)));
|
||||
}
|
||||
|
||||
let signature = match req.metadata().get("request-signature") {
|
||||
Some(t) => t,
|
||||
None => return Err(Status::unauthenticated("signature not found in metadata.")),
|
||||
};
|
||||
let signature = bs58::decode(signature)
|
||||
.into_vec()
|
||||
.map_err(|_| Status::unauthenticated("signature is not a bs58 string"))?;
|
||||
let signature = ed25519_dalek::Signature::from_bytes(
|
||||
signature
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| Status::unauthenticated("could not parse ed25519 signature"))?,
|
||||
);
|
||||
|
||||
let pubkey_value = match req.metadata().get("pubkey") {
|
||||
Some(p) => p.clone(),
|
||||
None => return Err(Status::unauthenticated("pubkey not found in metadata.")),
|
||||
};
|
||||
let pubkey = ed25519_dalek::VerifyingKey::from_bytes(
|
||||
&bs58::decode(&pubkey_value)
|
||||
.into_vec()
|
||||
.map_err(|_| Status::unauthenticated("pubkey is not a bs58 string"))?
|
||||
.try_into()
|
||||
.map_err(|_| Status::unauthenticated("pubkey does not have the correct size."))?,
|
||||
)
|
||||
.map_err(|_| Status::unauthenticated("could not parse ed25519 pubkey"))?;
|
||||
|
||||
let req = req.into_inner();
|
||||
let message = format!("{time}{req:?}");
|
||||
use ed25519_dalek::Verifier;
|
||||
pubkey
|
||||
.verify(message.as_bytes(), &signature)
|
||||
.map_err(|_| Status::unauthenticated("the signature is not valid"))?;
|
||||
if let Some(req_pubkey) = req.get_pubkey() {
|
||||
if pubkey_value.to_str().unwrap().to_string() != req_pubkey {
|
||||
return Err(Status::unauthenticated(
|
||||
"pubkey of signature does not match pubkey of request",
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(req)
|
||||
}
|
||||
|
||||
fn check_sig_from_parts(pubkey: &str, time: &str, msg: &str, sig: &str) -> Result<(), Status> {
|
||||
let now = chrono::Utc::now();
|
||||
let parsed_time = chrono::DateTime::parse_from_rfc3339(time)
|
||||
.map_err(|_| Status::unauthenticated("Coult not parse timestamp"))?;
|
||||
let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds();
|
||||
if seconds_elapsed > 4 || seconds_elapsed < -4 {
|
||||
return Err(Status::unauthenticated(format!(
|
||||
"Date is not within 4 sec of the time of the server: CLI {} vs Server {}",
|
||||
parsed_time, now
|
||||
)));
|
||||
}
|
||||
|
||||
let signature = bs58::decode(sig)
|
||||
.into_vec()
|
||||
.map_err(|_| Status::unauthenticated("signature is not a bs58 string"))?;
|
||||
let signature = ed25519_dalek::Signature::from_bytes(
|
||||
signature
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| Status::unauthenticated("could not parse ed25519 signature"))?,
|
||||
);
|
||||
|
||||
let pubkey = ed25519_dalek::VerifyingKey::from_bytes(
|
||||
&bs58::decode(&pubkey)
|
||||
.into_vec()
|
||||
.map_err(|_| Status::unauthenticated("pubkey is not a bs58 string"))?
|
||||
.try_into()
|
||||
.map_err(|_| Status::unauthenticated("pubkey does not have the correct size."))?,
|
||||
)
|
||||
.map_err(|_| Status::unauthenticated("could not parse ed25519 pubkey"))?;
|
||||
|
||||
let msg = time.to_string() + msg;
|
||||
use ed25519_dalek::Verifier;
|
||||
pubkey
|
||||
.verify(msg.as_bytes(), &signature)
|
||||
.map_err(|_| Status::unauthenticated("the signature is not valid"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
|
10
src/main.rs
10
src/main.rs
@ -3,7 +3,7 @@ mod grpc;
|
||||
|
||||
use data::BrainData;
|
||||
use grpc::snp_proto::brain_cli_server::BrainCliServer;
|
||||
use grpc::snp_proto::brain_daemon_server::BrainDaemonServer;
|
||||
use grpc::snp_proto::brain_vm_daemon_server::BrainVmDaemonServer;
|
||||
use grpc::BrainCliMock;
|
||||
use grpc::BrainDaemonMock;
|
||||
use std::sync::Arc;
|
||||
@ -19,12 +19,16 @@ async fn main() {
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(60)).await;
|
||||
data_clone.contracts_cron();
|
||||
data_clone.vm_nodes_cron().await;
|
||||
data_clone.vm_contracts_cron().await;
|
||||
if let Err(e) = data_clone.save_to_disk() {
|
||||
log::error!("Could not save data to disk due to error: {e}")
|
||||
}
|
||||
}
|
||||
});
|
||||
let addr = "0.0.0.0:31337".parse().unwrap();
|
||||
|
||||
let daemon_server = BrainDaemonServer::new(BrainDaemonMock::new(data.clone()));
|
||||
let daemon_server = BrainVmDaemonServer::new(BrainDaemonMock::new(data.clone()));
|
||||
let cli_server = BrainCliServer::new(BrainCliMock::new(data.clone()));
|
||||
|
||||
Server::builder()
|
||||
|
@ -1,5 +1,5 @@
|
||||
syntax = "proto3";
|
||||
package snp_proto;
|
||||
package vm_proto;
|
||||
|
||||
message Empty {
|
||||
}
|
||||
@ -13,7 +13,7 @@ message AccountBalance {
|
||||
uint64 tmp_locked = 2;
|
||||
}
|
||||
|
||||
message Contract {
|
||||
message VmContract {
|
||||
string uuid = 1;
|
||||
string hostname = 2;
|
||||
string admin_pubkey = 3;
|
||||
@ -28,7 +28,7 @@ message Contract {
|
||||
string dtrfs_sha = 12;
|
||||
string created_at = 13;
|
||||
string updated_at = 14;
|
||||
// total nanotoken cost per minute (for all units)
|
||||
// total nanoLP cost per minute (for all units)
|
||||
uint64 nano_per_minute = 15;
|
||||
uint64 locked_nano = 16;
|
||||
string collected_at = 17;
|
||||
@ -52,18 +52,19 @@ message MeasurementIP {
|
||||
string gateway = 4;
|
||||
}
|
||||
|
||||
message RegisterNodeReq {
|
||||
// This should also include a block hash or similar, for auth
|
||||
message RegisterVmNodeReq {
|
||||
string node_pubkey = 1;
|
||||
string owner_pubkey = 2;
|
||||
string operator_wallet = 2;
|
||||
string main_ip = 3;
|
||||
string country = 4;
|
||||
string region = 5;
|
||||
string city = 6;
|
||||
// nanotokens per unit per minute
|
||||
// nanoLP per unit per minute
|
||||
uint64 price = 7;
|
||||
}
|
||||
|
||||
message NodeResources {
|
||||
message VmNodeResources {
|
||||
string node_pubkey = 1;
|
||||
uint32 avail_ports = 2;
|
||||
uint32 avail_ipv4 = 3;
|
||||
@ -101,13 +102,14 @@ message NewVmResp {
|
||||
|
||||
message UpdateVmReq {
|
||||
string uuid = 1;
|
||||
uint32 disk_size_gb = 2;
|
||||
uint32 vcpus = 3;
|
||||
uint32 memory_mb = 4;
|
||||
string kernel_url = 5;
|
||||
string kernel_sha = 6;
|
||||
string dtrfs_url = 7;
|
||||
string dtrfs_sha = 8;
|
||||
string admin_pubkey = 2;
|
||||
uint32 disk_size_gb = 3;
|
||||
uint32 vcpus = 4;
|
||||
uint32 memory_mb = 5;
|
||||
string kernel_url = 6;
|
||||
string kernel_sha = 7;
|
||||
string dtrfs_url = 8;
|
||||
string dtrfs_sha = 9;
|
||||
}
|
||||
|
||||
message UpdateVmResp {
|
||||
@ -118,9 +120,10 @@ message UpdateVmResp {
|
||||
|
||||
message DeleteVmReq {
|
||||
string uuid = 1;
|
||||
string admin_pubkey = 2;
|
||||
}
|
||||
|
||||
message BrainMessage {
|
||||
message BrainVmMessage {
|
||||
oneof Msg {
|
||||
NewVmReq new_vm_req = 1;
|
||||
UpdateVmReq update_vm_req = 2;
|
||||
@ -128,28 +131,35 @@ message BrainMessage {
|
||||
}
|
||||
}
|
||||
|
||||
message DaemonMessage {
|
||||
message DaemonStreamAuth {
|
||||
string timestamp = 1;
|
||||
string pubkey = 2;
|
||||
repeated string contracts = 3;
|
||||
string signature = 4;
|
||||
}
|
||||
|
||||
message VmDaemonMessage {
|
||||
oneof Msg {
|
||||
Pubkey pubkey = 1;
|
||||
DaemonStreamAuth auth = 1;
|
||||
NewVmResp new_vm_resp = 2;
|
||||
UpdateVmResp update_vm_resp = 3;
|
||||
NodeResources node_resources = 4;
|
||||
VmNodeResources vm_node_resources = 4;
|
||||
}
|
||||
}
|
||||
|
||||
service BrainDaemon {
|
||||
rpc RegisterNode (RegisterNodeReq) returns (stream Contract);
|
||||
rpc BrainMessages (Pubkey) returns (stream BrainMessage);
|
||||
rpc DaemonMessages (stream DaemonMessage) returns (Empty);
|
||||
service BrainVmDaemon {
|
||||
rpc RegisterVmNode (RegisterVmNodeReq) returns (stream VmContract);
|
||||
rpc BrainMessages (DaemonStreamAuth) returns (stream BrainVmMessage);
|
||||
rpc DaemonMessages (stream VmDaemonMessage) returns (Empty);
|
||||
}
|
||||
|
||||
message ListContractsReq {
|
||||
string admin_pubkey = 1;
|
||||
string node_pubkey = 2;
|
||||
message ListVmContractsReq {
|
||||
string wallet = 1;
|
||||
bool as_operator = 2;
|
||||
string uuid = 3;
|
||||
}
|
||||
|
||||
message NodeFilters {
|
||||
message VmNodeFilters {
|
||||
uint32 free_ports = 1;
|
||||
bool offers_ipv4 = 2;
|
||||
bool offers_ipv6 = 3;
|
||||
@ -163,16 +173,15 @@ message NodeFilters {
|
||||
string node_pubkey = 11;
|
||||
}
|
||||
|
||||
message NodeListResp {
|
||||
string node_pubkey = 1;
|
||||
string country = 2;
|
||||
string region = 3;
|
||||
string city = 4;
|
||||
string ip = 5; // required for latency test
|
||||
uint32 server_rating = 6;
|
||||
uint32 provider_rating = 7;
|
||||
// nanotokens per unit per minute
|
||||
uint64 price = 8;
|
||||
message VmNodeListResp {
|
||||
string operator = 1;
|
||||
string node_pubkey = 2;
|
||||
string country = 3;
|
||||
string region = 4;
|
||||
string city = 5;
|
||||
string ip = 6; // required for latency test
|
||||
repeated string reports = 7; // TODO: this will become an enum
|
||||
uint64 price = 8; // nanoLP per unit per minute
|
||||
}
|
||||
|
||||
message ExtendVmReq {
|
||||
@ -181,14 +190,82 @@ message ExtendVmReq {
|
||||
uint64 locked_nano = 3;
|
||||
}
|
||||
|
||||
message AirdropReq {
|
||||
string pubkey = 1;
|
||||
uint64 tokens = 2;
|
||||
}
|
||||
|
||||
message SlashReq {
|
||||
string pubkey = 1;
|
||||
uint64 tokens = 2;
|
||||
}
|
||||
|
||||
message Account {
|
||||
string pubkey = 1;
|
||||
uint64 balance = 2;
|
||||
uint64 tmp_locked = 3;
|
||||
}
|
||||
|
||||
message RegOperatorReq {
|
||||
string pubkey = 1;
|
||||
uint64 escrow = 2;
|
||||
string email = 3;
|
||||
}
|
||||
|
||||
message ListOperatorsResp {
|
||||
string pubkey = 1;
|
||||
uint64 escrow = 2;
|
||||
string email = 3;
|
||||
uint64 app_nodes = 4;
|
||||
uint64 vm_nodes = 5;
|
||||
uint64 reports = 6;
|
||||
}
|
||||
|
||||
message InspectOperatorResp {
|
||||
ListOperatorsResp operator = 1;
|
||||
repeated VmNodeListResp nodes = 2;
|
||||
}
|
||||
|
||||
message ReportNodeReq {
|
||||
string admin_pubkey = 1;
|
||||
string node_pubkey = 2;
|
||||
string contract = 3;
|
||||
string reason = 4;
|
||||
}
|
||||
|
||||
message KickReq {
|
||||
string operator_wallet = 1;
|
||||
string contract_uuid = 2;
|
||||
string reason = 3;
|
||||
}
|
||||
|
||||
message BanUserReq {
|
||||
string operator_wallet = 1;
|
||||
string user_wallet = 2;
|
||||
}
|
||||
|
||||
message KickResp {
|
||||
uint64 nano_lp = 1;
|
||||
}
|
||||
|
||||
service BrainCli {
|
||||
rpc GetAirdrop (Pubkey) returns (Empty);
|
||||
rpc GetBalance (Pubkey) returns (AccountBalance);
|
||||
rpc NewVm (NewVmReq) returns (NewVmResp);
|
||||
rpc ListContracts (ListContractsReq) returns (stream Contract);
|
||||
rpc ListNodes (NodeFilters) returns (stream NodeListResp);
|
||||
rpc GetOneNode (NodeFilters) returns (NodeListResp);
|
||||
rpc ListVmContracts (ListVmContractsReq) returns (stream VmContract);
|
||||
rpc ListVmNodes (VmNodeFilters) returns (stream VmNodeListResp);
|
||||
rpc GetOneVmNode (VmNodeFilters) returns (VmNodeListResp);
|
||||
rpc DeleteVm (DeleteVmReq) returns (Empty);
|
||||
rpc UpdateVm (UpdateVmReq) returns (UpdateVmResp);
|
||||
rpc ExtendVm (ExtendVmReq) returns (Empty);
|
||||
rpc ReportNode (ReportNodeReq) returns (Empty);
|
||||
rpc ListOperators (Empty) returns (stream ListOperatorsResp);
|
||||
rpc InspectOperator (Pubkey) returns (InspectOperatorResp);
|
||||
rpc RegisterOperator (RegOperatorReq) returns (Empty);
|
||||
rpc KickContract (KickReq) returns (KickResp);
|
||||
rpc BanUser (BanUserReq) returns (Empty);
|
||||
// admin commands
|
||||
rpc Airdrop (AirdropReq) returns (Empty);
|
||||
rpc Slash (SlashReq) returns (Empty);
|
||||
rpc ListAllVmContracts (Empty) returns (stream VmContract);
|
||||
rpc ListAccounts (Empty) returns (stream Account);
|
||||
}
|
Loading…
Reference in New Issue
Block a user