Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
a90a6c0b79 | |||
a46f6ef800 | |||
dcdfe21c57 | |||
127d399670 | |||
467a4f04b9 | |||
675933dd7c | |||
2cada47d24 | |||
784878d0a1 | |||
3b3221099f | |||
f1a527e22d | |||
b22b08799b | |||
f4f16228fc | |||
c7b4d40846 | |||
5ae69dee52 | |||
230eb8cfbd | |||
c6c44da0e8 | |||
8f40adcbf8 | |||
b1258ac7c7 | |||
3e4672e9e4 |
265
Cargo.lock
generated
265
Cargo.lock
generated
@ -82,11 +82,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.6"
|
||||
version = "3.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
||||
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@ -120,9 +121,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.83"
|
||||
version = "0.1.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
||||
checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -217,9 +218,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
@ -237,6 +238,7 @@ dependencies = [
|
||||
"bs58",
|
||||
"chrono",
|
||||
"dashmap",
|
||||
"detee-shared",
|
||||
"ed25519-dalek",
|
||||
"env_logger",
|
||||
"log",
|
||||
@ -244,7 +246,7 @@ dependencies = [
|
||||
"prost-types",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
@ -264,9 +266,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
version = "3.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
@ -276,15 +278,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
||||
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.5"
|
||||
version = "1.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
|
||||
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@ -305,7 +307,6 @@ dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
]
|
||||
@ -402,7 +403,6 @@ dependencies = [
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -415,6 +415,20 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "detee-shared"
|
||||
version = "0.1.0"
|
||||
source = "git+ssh://git@gitea.detee.cloud/noormohammedb/detee-shared?branch=stable_01#b8f37dec1845d29ea0b69035712e6ebb214376f4"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"prost",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"thiserror",
|
||||
"tonic",
|
||||
"tonic-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@ -619,7 +633,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.13.3+wasi-0.2.2",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -640,7 +666,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http",
|
||||
"indexmap 2.7.0",
|
||||
"indexmap 2.7.1",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
@ -707,9 +733,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.9.5"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
|
||||
checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
@ -725,9 +751,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.5.2"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0"
|
||||
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@ -983,9 +1009,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.7.0"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
||||
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
@ -993,9 +1019,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.10.1"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
|
||||
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
@ -1020,9 +1046,9 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.76"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
@ -1030,15 +1056,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.168"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
@ -1058,9 +1084,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
@ -1082,9 +1108,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.0"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
|
||||
checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
@ -1096,7 +1122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
@ -1108,9 +1134,9 @@ checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.12"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
|
||||
checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
@ -1134,24 +1160,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.5"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
version = "1.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.68"
|
||||
version = "0.10.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
|
||||
checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
@ -1175,15 +1201,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.104"
|
||||
version = "0.9.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
||||
checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@ -1217,23 +1243,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap 2.7.0",
|
||||
"indexmap 2.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.7"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95"
|
||||
checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.7"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
|
||||
checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1242,9 +1268,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.15"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
@ -1279,9 +1305,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.25"
|
||||
version = "0.2.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
|
||||
checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
@ -1289,9 +1315,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.92"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -1350,9 +1376,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@ -1384,7 +1410,7 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1427,9 +1453,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.10"
|
||||
version = "0.12.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d3536321cfc54baa8cf3e273d5e1f63f889067829c4b410fcdbac8ca7b80994"
|
||||
checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
@ -1477,7 +1503,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"libc",
|
||||
"spin",
|
||||
"untrusted",
|
||||
@ -1501,9 +1527,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.42"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
@ -1514,9 +1540,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.20"
|
||||
version = "0.23.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
|
||||
checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"rustls-pki-types",
|
||||
@ -1536,9 +1562,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.10.1"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37"
|
||||
checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
@ -1553,15 +1579,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.18"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
|
||||
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
@ -1593,9 +1619,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.13.0"
|
||||
version = "2.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5"
|
||||
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@ -1629,9 +1655,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.134"
|
||||
version = "1.0.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
|
||||
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
@ -1657,7 +1683,7 @@ version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap 2.7.0",
|
||||
"indexmap 2.7.1",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
@ -1745,9 +1771,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.90"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1797,12 +1823,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.14.0"
|
||||
version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
|
||||
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"getrandom 0.3.1",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
@ -1855,9 +1882,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.42.0"
|
||||
version = "1.43.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
|
||||
checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@ -1871,9 +1898,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2060,9 +2087,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
@ -2107,11 +2134,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.11.0"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
|
||||
checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2142,21 +2169,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.99"
|
||||
name = "wasi"
|
||||
version = "0.13.3+wasi-0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
||||
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.99"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
@ -2168,9 +2205,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.49"
|
||||
version = "0.4.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
|
||||
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@ -2181,9 +2218,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.99"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@ -2191,9 +2228,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.99"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2204,15 +2241,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.99"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.76"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
|
||||
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@ -2339,6 +2379,15 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "write16"
|
||||
version = "1.0.0"
|
||||
|
11
Cargo.toml
11
Cargo.toml
@ -5,21 +5,24 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bs58 = "0.5.1"
|
||||
chrono = { version = "0.4.39", features = ["serde"] }
|
||||
dashmap = { version = "6.1.0", features = ["serde"] }
|
||||
chrono = "0.4.39"
|
||||
dashmap = "6.1.0"
|
||||
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.217", features = ["derive"] }
|
||||
serde_yaml = "0.9.34"
|
||||
serde = { version = "1.0.216", features = ["derive"] }
|
||||
serde_json = "1.0.134"
|
||||
thiserror = "2.0.11"
|
||||
tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] }
|
||||
tokio-stream = "0.1.17"
|
||||
tonic = "0.12"
|
||||
uuid = { version = "1.11.0", features = ["v4"] }
|
||||
|
||||
detee-shared = { git = "ssh://git@gitea.detee.cloud/noormohammedb/detee-shared", branch = "stable_01" }
|
||||
# detee-shared = { path = "../detee-shared" }
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.12"
|
||||
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Brain mock
|
||||
|
||||
eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519
|
773
src/data.rs
773
src/data.rs
@ -1,57 +1,39 @@
|
||||
use crate::grpc::snp_proto::{self as grpc};
|
||||
use chrono::Utc;
|
||||
use dashmap::DashMap;
|
||||
use detee_shared::sgx::pb::brain::DelAppReq;
|
||||
use log::{debug, info, warn};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
use std::sync::RwLock;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fs::File,
|
||||
io::Write,
|
||||
};
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use tokio::sync::oneshot::Sender as OneshotSender;
|
||||
|
||||
const DATA_PATH: &str = "/etc/detee/brain-mock/saved_data.yaml";
|
||||
use detee_shared::sgx::pb::brain::AppContract as AppContractPB;
|
||||
use detee_shared::sgx::pb::brain::AppNodeResources;
|
||||
use detee_shared::sgx::pb::brain::AppResource as AppResourcePB;
|
||||
use detee_shared::sgx::pb::brain::BrainMessageApp;
|
||||
use detee_shared::sgx::pb::brain::MappedPort;
|
||||
use detee_shared::sgx::pb::brain::NewAppReq;
|
||||
use detee_shared::sgx::pb::brain::NewAppRes;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("We do not allow locking of more than 100000 LP.")]
|
||||
TxTooBig,
|
||||
#[error("Escrow must be at least 5000 LP.")]
|
||||
MinimalEscrow,
|
||||
#[error("Account has insufficient funds for this operation")]
|
||||
InsufficientFunds,
|
||||
#[error("Could not find contract {0}")]
|
||||
VmContractNotFound(String),
|
||||
#[error("This error should never happen.")]
|
||||
ImpossibleError,
|
||||
#[error("You don't have the required permissions for this operation.")]
|
||||
AccessDenied,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||
pub struct AccountData {
|
||||
#[derive(Clone)]
|
||||
pub struct AccountNanoLP {
|
||||
pub balance: u64,
|
||||
pub tmp_locked: u64,
|
||||
// holds reasons why VMs of this account got kicked
|
||||
pub kicked_for: Vec<String>,
|
||||
pub last_kick: chrono::DateTime<Utc>,
|
||||
// holds accounts that banned this account
|
||||
pub banned_by: HashSet<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||
pub struct OperatorData {
|
||||
pub escrow: u64,
|
||||
pub email: String,
|
||||
pub banned_users: HashSet<String>,
|
||||
pub vm_nodes: HashSet<String>,
|
||||
}
|
||||
|
||||
impl From<AccountData> for grpc::AccountBalance {
|
||||
fn from(value: AccountData) -> Self {
|
||||
impl From<AccountNanoLP> for grpc::AccountBalance {
|
||||
fn from(value: AccountNanoLP) -> Self {
|
||||
grpc::AccountBalance {
|
||||
balance: value.balance,
|
||||
tmp_locked: value.tmp_locked,
|
||||
@ -59,10 +41,10 @@ impl From<AccountData> for grpc::AccountBalance {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Eq, Hash, PartialEq, Clone, Debug, Default)]
|
||||
pub struct VmNode {
|
||||
pub public_key: String,
|
||||
pub operator_wallet: String,
|
||||
pub owner_key: String,
|
||||
pub country: String,
|
||||
pub region: String,
|
||||
pub city: String,
|
||||
@ -76,27 +58,24 @@ pub struct VmNode {
|
||||
pub max_ports_per_vm: u32,
|
||||
// nanoLP per unit per minute
|
||||
pub price: u64,
|
||||
// 1st String is user wallet and 2nd String is report message
|
||||
pub reports: HashMap<String, String>,
|
||||
pub offline_minutes: u64,
|
||||
}
|
||||
|
||||
impl Into<grpc::VmNodeListResp> for VmNode {
|
||||
fn into(self) -> grpc::VmNodeListResp {
|
||||
grpc::VmNodeListResp {
|
||||
operator: self.operator_wallet,
|
||||
node_pubkey: self.public_key,
|
||||
country: self.country,
|
||||
region: self.region,
|
||||
city: self.city,
|
||||
ip: self.ip,
|
||||
server_rating: 0,
|
||||
provider_rating: 0,
|
||||
price: self.price,
|
||||
reports: self.reports.into_values().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct VmContract {
|
||||
pub uuid: String,
|
||||
pub hostname: String,
|
||||
@ -112,15 +91,14 @@ pub struct VmContract {
|
||||
pub dtrfs_sha: String,
|
||||
pub created_at: chrono::DateTime<Utc>,
|
||||
pub updated_at: chrono::DateTime<Utc>,
|
||||
// price per unit per minute
|
||||
// recommended value is 20000
|
||||
/// price per unit per minute
|
||||
pub price_per_unit: u64,
|
||||
pub locked_nano: u64,
|
||||
pub collected_at: chrono::DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl VmContract {
|
||||
/// total hardware units of this VM
|
||||
fn total_units(&self) -> u64 {
|
||||
// TODO: Optimize this based on price of hardware.
|
||||
// I tried, but this can be done better.
|
||||
@ -131,7 +109,7 @@ impl VmContract {
|
||||
+ (!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 {
|
||||
self.total_units() * self.price_per_unit
|
||||
}
|
||||
@ -162,178 +140,162 @@ impl Into<grpc::VmContract> for VmContract {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct AppContract {
|
||||
pub uuid: String,
|
||||
pub package_url: String,
|
||||
pub admin_pubkey: String,
|
||||
pub node_pubkey: String,
|
||||
pub mapped_ports: Vec<(u16, u16)>,
|
||||
pub host_ipv4: String,
|
||||
pub disk_size_mb: u32,
|
||||
pub vcpus: u32,
|
||||
pub memory_mb: u32,
|
||||
pub created_at: chrono::DateTime<Utc>,
|
||||
pub updated_at: chrono::DateTime<Utc>,
|
||||
// price per unit per minute
|
||||
// recommended value is 20000
|
||||
pub price_per_unit: u64,
|
||||
pub locked_nano: u64,
|
||||
pub collected_at: chrono::DateTime<Utc>,
|
||||
pub hratls_pubkey: String,
|
||||
pub public_package_mr_enclave: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl From<AppContract> for AppContractPB {
|
||||
fn from(value: AppContract) -> Self {
|
||||
let mapped_ports = value
|
||||
.mapped_ports
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(MappedPort::from)
|
||||
.collect();
|
||||
|
||||
let resource = Some(AppResourcePB {
|
||||
memory_mb: value.memory_mb,
|
||||
disk_mb: value.disk_size_mb,
|
||||
vcpu: value.vcpus,
|
||||
ports: value.mapped_ports.iter().map(|p| p.1 as u32).collect(),
|
||||
});
|
||||
Self {
|
||||
uuid: value.uuid,
|
||||
package_url: value.package_url,
|
||||
admin_pubkey: value.admin_pubkey,
|
||||
node_pubkey: value.node_pubkey,
|
||||
mapped_ports,
|
||||
public_ipv4: value.host_ipv4,
|
||||
resource,
|
||||
created_at: value.created_at.to_rfc3339(),
|
||||
updated_at: value.updated_at.to_rfc3339(),
|
||||
// TODO: check while implementing pricing
|
||||
nano_per_minute: value.price_per_unit,
|
||||
locked_nano: value.locked_nano,
|
||||
collected_at: value.collected_at.to_rfc3339(),
|
||||
hratls_pubkey: value.hratls_pubkey,
|
||||
public_package_mr_enclave: value.public_package_mr_enclave,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq, Clone, Debug, Default)]
|
||||
pub struct AppNode {
|
||||
pub node_pubkey: String,
|
||||
pub operator_pubkey: String,
|
||||
pub country: String,
|
||||
pub region: String,
|
||||
pub city: String,
|
||||
pub ip: String,
|
||||
pub avail_mem_mb: u32,
|
||||
pub avail_vcpus: u32,
|
||||
pub avail_storage_mb: u32,
|
||||
pub avail_no_of_port: u32,
|
||||
pub max_ports_per_app: u32,
|
||||
// nanotokens per unit per minute
|
||||
pub price: u64,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BrainData {
|
||||
// amount of nanoLP in each account
|
||||
accounts: DashMap<String, AccountData>,
|
||||
operators: DashMap<String, OperatorData>,
|
||||
accounts: DashMap<String, AccountNanoLP>,
|
||||
vm_nodes: RwLock<Vec<VmNode>>,
|
||||
vm_contracts: RwLock<Vec<VmContract>>,
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
tmp_newvm_reqs: DashMap<String, (grpc::NewVmReq, OneshotSender<grpc::NewVmResp>)>,
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
tmp_updatevm_reqs: DashMap<String, (grpc::UpdateVmReq, OneshotSender<grpc::UpdateVmResp>)>,
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
daemon_tx: DashMap<String, Sender<grpc::BrainVmMessage>>,
|
||||
|
||||
app_nodes: RwLock<Vec<AppNode>>,
|
||||
app_daemon_tx: DashMap<String, Sender<BrainMessageApp>>,
|
||||
tmp_new_container_reqs: DashMap<String, (NewAppReq, OneshotSender<NewAppRes>)>,
|
||||
app_contracts: RwLock<Vec<AppContract>>,
|
||||
}
|
||||
|
||||
impl BrainData {
|
||||
pub fn save_to_disk(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut file = File::create(DATA_PATH)?;
|
||||
file.write_all(serde_yaml::to_string(self)?.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_from_disk() -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let content = std::fs::read_to_string(DATA_PATH)?;
|
||||
let data: Self = serde_yaml::from_str(&content)?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
match Self::load_from_disk() {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
warn!("Could not data {DATA_PATH} due to error: {e:?}");
|
||||
info!("Creating new instance of brain.");
|
||||
Self {
|
||||
accounts: DashMap::new(),
|
||||
operators: DashMap::new(),
|
||||
vm_nodes: RwLock::new(Vec::new()),
|
||||
vm_contracts: RwLock::new(Vec::new()),
|
||||
tmp_newvm_reqs: DashMap::new(),
|
||||
tmp_updatevm_reqs: DashMap::new(),
|
||||
daemon_tx: DashMap::new(),
|
||||
}
|
||||
}
|
||||
Self {
|
||||
accounts: DashMap::new(),
|
||||
vm_nodes: RwLock::new(Vec::new()),
|
||||
vm_contracts: RwLock::new(Vec::new()),
|
||||
tmp_newvm_reqs: DashMap::new(),
|
||||
tmp_updatevm_reqs: DashMap::new(),
|
||||
daemon_tx: DashMap::new(),
|
||||
|
||||
app_daemon_tx: DashMap::new(),
|
||||
tmp_new_container_reqs: DashMap::new(),
|
||||
app_contracts: RwLock::new(Vec::new()),
|
||||
app_nodes: RwLock::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_balance(&self, account: &str) -> AccountData {
|
||||
pub fn get_balance(&self, account: &str) -> AccountNanoLP {
|
||||
if let Some(account) = self.accounts.get(account) {
|
||||
return account.value().clone();
|
||||
} else {
|
||||
let balance = AccountData {
|
||||
let balance = AccountNanoLP {
|
||||
balance: 0,
|
||||
tmp_locked: 0,
|
||||
kicked_for: Vec::new(),
|
||||
banned_by: HashSet::new(),
|
||||
last_kick: chrono::Utc::now(),
|
||||
};
|
||||
return balance;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn give_airdrop(&self, account: &str, tokens: u64) {
|
||||
warn!("Airdropping {tokens} to {account}.");
|
||||
self.add_nano_to_wallet(account, tokens.saturating_mul(1_000_000_000));
|
||||
}
|
||||
|
||||
pub fn slash_account(&self, account: &str, tokens: u64) {
|
||||
warn!("Slashing {tokens} from {account}.");
|
||||
self.rm_nano_from_wallet(account, tokens.saturating_mul(1_000_000_000));
|
||||
}
|
||||
|
||||
fn add_nano_to_wallet(&self, account: &str, nano_lp: u64) {
|
||||
log::debug!("Adding {nano_lp} nanoLP to {account}");
|
||||
self.accounts
|
||||
.entry(account.to_string())
|
||||
.and_modify(|d| d.balance += nano_lp)
|
||||
.or_insert(AccountData {
|
||||
.or_insert(AccountNanoLP {
|
||||
balance: nano_lp,
|
||||
..Default::default()
|
||||
tmp_locked: 0,
|
||||
});
|
||||
}
|
||||
|
||||
fn rm_nano_from_wallet(&self, account: &str, nano_lp: u64) {
|
||||
log::debug!("Slashing {nano_lp} nanoLP to {account}");
|
||||
self.accounts.entry(account.to_string()).and_modify(|d| {
|
||||
d.balance = d.balance.saturating_sub(nano_lp);
|
||||
});
|
||||
}
|
||||
|
||||
/// This is written to run every minute
|
||||
pub async fn vm_nodes_cron(&self) {
|
||||
log::debug!("Running vm nodes cron...");
|
||||
let mut nodes = self.vm_nodes.write().unwrap();
|
||||
let mut vm_contracts = self.vm_contracts.write().unwrap();
|
||||
for node in nodes.iter_mut() {
|
||||
if self.daemon_tx.contains_key(&node.public_key) {
|
||||
node.offline_minutes = 0;
|
||||
continue;
|
||||
}
|
||||
let mut operator = match self
|
||||
.operators
|
||||
.iter_mut()
|
||||
.find(|o| o.vm_nodes.contains(&node.public_key))
|
||||
{
|
||||
Some(op) => op,
|
||||
None => continue,
|
||||
};
|
||||
node.offline_minutes += 1;
|
||||
// compensate contract admin if the node is offline more then 5 minutes
|
||||
if node.offline_minutes > 5 {
|
||||
for c in vm_contracts
|
||||
.iter()
|
||||
.filter(|c| c.node_pubkey == node.public_key)
|
||||
{
|
||||
let compensation = c.price_per_minute() * 10;
|
||||
if compensation < operator.escrow {
|
||||
operator.escrow -= compensation;
|
||||
self.add_nano_to_wallet(&c.admin_pubkey, compensation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// delete nodes that are offline more than 3 hours, and clean contracts
|
||||
nodes.retain(|n| {
|
||||
if n.offline_minutes > 1600 {
|
||||
vm_contracts.retain_mut(|c| {
|
||||
if c.node_pubkey == n.public_key {
|
||||
self.add_nano_to_wallet(&c.admin_pubkey, c.locked_nano);
|
||||
}
|
||||
c.node_pubkey != n.public_key
|
||||
});
|
||||
for mut op in self.operators.iter_mut() {
|
||||
op.vm_nodes.remove(&n.public_key);
|
||||
}
|
||||
}
|
||||
n.offline_minutes <= 180
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn vm_contracts_cron(&self) {
|
||||
let mut deleted_contracts: Vec<(String, String)> = Vec::new();
|
||||
log::debug!("Running contracts cron...");
|
||||
{
|
||||
let mut contracts = self.vm_contracts.write().unwrap();
|
||||
contracts.retain_mut(|c| {
|
||||
let node = self.find_node_by_pubkey(&c.node_pubkey).unwrap();
|
||||
if node.offline_minutes == 0 {
|
||||
let operator_wallet = node.operator_wallet.clone();
|
||||
let minutes_to_collect = (Utc::now() - c.collected_at).num_minutes() as u64;
|
||||
c.collected_at = Utc::now();
|
||||
let mut nanolp_to_collect =
|
||||
c.price_per_minute().saturating_mul(minutes_to_collect);
|
||||
if nanolp_to_collect > c.locked_nano {
|
||||
nanolp_to_collect = c.locked_nano;
|
||||
}
|
||||
log::debug!("Removing {nanolp_to_collect} nanoLP from {}", c.uuid);
|
||||
c.locked_nano -= nanolp_to_collect;
|
||||
let escrow_multiplier = match self.operators.get(&operator_wallet) {
|
||||
Some(op) if op.escrow > 5000 => match self.operators.get(&c.admin_pubkey) {
|
||||
Some(user_is_op) if user_is_op.escrow > 5000 => 1,
|
||||
_ => 5,
|
||||
},
|
||||
_ => 1,
|
||||
};
|
||||
self.add_nano_to_wallet(
|
||||
&operator_wallet,
|
||||
nanolp_to_collect * escrow_multiplier,
|
||||
);
|
||||
if c.locked_nano == 0 {
|
||||
deleted_contracts.push((c.uuid.clone(), c.node_pubkey.clone()));
|
||||
}
|
||||
let owner_key = self
|
||||
.find_nodes_by_pubkey(&c.node_pubkey)
|
||||
.unwrap()
|
||||
.owner_key
|
||||
.clone();
|
||||
let minutes_to_collect = (Utc::now() - c.collected_at).num_minutes() as u64;
|
||||
c.collected_at = Utc::now();
|
||||
let mut nanolp_to_collect = c.price_per_minute().saturating_mul(minutes_to_collect);
|
||||
if nanolp_to_collect > c.locked_nano {
|
||||
nanolp_to_collect = c.locked_nano;
|
||||
}
|
||||
log::debug!("Removing {nanolp_to_collect} nanoLP from {}", c.uuid);
|
||||
c.locked_nano -= nanolp_to_collect;
|
||||
self.add_nano_to_wallet(&owner_key, nanolp_to_collect);
|
||||
if c.locked_nano == 0 {
|
||||
deleted_contracts.push((c.uuid.clone(), c.node_pubkey.clone()));
|
||||
}
|
||||
c.locked_nano > 0
|
||||
});
|
||||
@ -353,9 +315,8 @@ impl BrainData {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_node(&self, node: VmNode) {
|
||||
pub fn insert_node(&self, node: VmNode) {
|
||||
info!("Registering node {node:?}");
|
||||
self.add_vmnode_to_operator(&node.operator_wallet, &node.public_key);
|
||||
let mut nodes = self.vm_nodes.write().unwrap();
|
||||
for n in nodes.iter_mut() {
|
||||
if n.public_key == node.public_key {
|
||||
@ -368,101 +329,6 @@ impl BrainData {
|
||||
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<u64, Error> {
|
||||
log::debug!("Operator {operator} requested a kick of {uuid} for reason: {reason}");
|
||||
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_amount = minutes_to_refund * contract.price_per_minute();
|
||||
let mut admin_account = 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(admin_account.last_kick)
|
||||
.gt(&chrono::Duration::days(1))
|
||||
{
|
||||
refund_amount = 0;
|
||||
}
|
||||
|
||||
if operator_data.escrow < refund_amount {
|
||||
refund_amount = operator_data.escrow;
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
"Removing {refund_amount} escrow from {} and giving it to {}",
|
||||
operator_data.key(),
|
||||
admin_account.key()
|
||||
);
|
||||
admin_account.balance += refund_amount;
|
||||
admin_account.kicked_for.push(reason.to_string());
|
||||
operator_data.escrow -= refund_amount;
|
||||
|
||||
let admin_pubkey = contract.admin_pubkey.clone();
|
||||
drop(admin_account);
|
||||
drop(contract);
|
||||
|
||||
self.delete_vm(grpc::DeleteVmReq {
|
||||
uuid: uuid.to_string(),
|
||||
admin_pubkey,
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(refund_amount)
|
||||
}
|
||||
|
||||
pub fn ban_user(&self, operator: &str, user: &str) {
|
||||
self.accounts
|
||||
.entry(user.to_string())
|
||||
.and_modify(|a| {
|
||||
a.banned_by.insert(operator.to_string());
|
||||
})
|
||||
.or_insert(AccountData {
|
||||
banned_by: HashSet::from([operator.to_string()]),
|
||||
..Default::default()
|
||||
});
|
||||
self.operators
|
||||
.entry(operator.to_string())
|
||||
.and_modify(|o| {
|
||||
o.banned_users.insert(user.to_string());
|
||||
})
|
||||
.or_insert(OperatorData {
|
||||
banned_users: HashSet::from([user.to_string()]),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn report_node(&self, admin_pubkey: String, node: &str, report: String) {
|
||||
let mut nodes = self.vm_nodes.write().unwrap();
|
||||
if let Some(node) = nodes.iter_mut().find(|n| n.public_key == node) {
|
||||
node.reports.insert(admin_pubkey, report);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lock_nanotockens(&self, account: &str, nano_lp: u64) -> Result<(), Error> {
|
||||
if nano_lp > 100_000_000_000_000 {
|
||||
return Err(Error::TxTooBig);
|
||||
@ -548,11 +414,17 @@ impl BrainData {
|
||||
}
|
||||
|
||||
pub async fn delete_vm(&self, delete_vm: grpc::DeleteVmReq) -> Result<(), Error> {
|
||||
log::debug!("Starting deletion of VM {}", delete_vm.uuid);
|
||||
let contract = self.find_contract_by_uuid(&delete_vm.uuid)?;
|
||||
if contract.admin_pubkey != delete_vm.admin_pubkey {
|
||||
return Err(Error::AccessDenied);
|
||||
}
|
||||
let contract = match self.find_contract_by_uuid(&delete_vm.uuid) {
|
||||
Some(contract) => {
|
||||
if contract.admin_pubkey != delete_vm.admin_pubkey {
|
||||
return Err(Error::VmContractNotFound(delete_vm.uuid));
|
||||
}
|
||||
contract
|
||||
}
|
||||
None => {
|
||||
return Err(Error::VmContractNotFound(delete_vm.uuid));
|
||||
}
|
||||
};
|
||||
info!("Found vm {}. Deleting...", delete_vm.uuid);
|
||||
if let Some(daemon_tx) = self.daemon_tx.get(&contract.node_pubkey) {
|
||||
debug!(
|
||||
@ -661,11 +533,6 @@ impl BrainData {
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let Err(e) = update_vm_req.1.send(update_vm_resp.clone()) {
|
||||
log::warn!(
|
||||
"CLI RX dropped before receiving UpdateVMResp {update_vm_resp:?}. Error: {e:?}"
|
||||
);
|
||||
}
|
||||
if update_vm_resp.error != "" {
|
||||
return;
|
||||
}
|
||||
@ -702,6 +569,11 @@ impl BrainData {
|
||||
update_vm_resp.error = "VM Contract not found.".to_string();
|
||||
}
|
||||
}
|
||||
if let Err(e) = update_vm_req.1.send(update_vm_resp.clone()) {
|
||||
log::warn!(
|
||||
"CLI RX dropped before receiving UpdateVMResp {update_vm_resp:?}. Error: {e:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn submit_newvm_req(
|
||||
@ -761,7 +633,7 @@ impl BrainData {
|
||||
let uuid = req.uuid.clone();
|
||||
info!("Inserting new vm update request in memory: {req:?}");
|
||||
let node_pubkey = match self.find_contract_by_uuid(&req.uuid) {
|
||||
Ok(contract) => {
|
||||
Some(contract) => {
|
||||
if contract.admin_pubkey != req.admin_pubkey {
|
||||
let _ = tx.send(grpc::UpdateVmResp {
|
||||
uuid,
|
||||
@ -772,7 +644,7 @@ impl BrainData {
|
||||
}
|
||||
contract.node_pubkey
|
||||
}
|
||||
Err(_) => {
|
||||
None => {
|
||||
log::warn!(
|
||||
"Received UpdateVMReq for a contract that does not exist: {}",
|
||||
req.uuid
|
||||
@ -823,81 +695,12 @@ impl BrainData {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_node_by_pubkey(&self, public_key: &str) -> Option<VmNode> {
|
||||
pub fn find_nodes_by_pubkey(&self, public_key: &str) -> Option<VmNode> {
|
||||
let nodes = self.vm_nodes.read().unwrap();
|
||||
nodes.iter().cloned().find(|n| n.public_key == public_key)
|
||||
}
|
||||
|
||||
pub fn is_user_banned_by_node(&self, user_wallet: &str, node_pubkey: &str) -> bool {
|
||||
if let Some(node) = self.find_node_by_pubkey(&node_pubkey) {
|
||||
if let Some(account) = self.accounts.get(user_wallet) {
|
||||
if account.banned_by.contains(&node.operator_wallet) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn add_vmnode_to_operator(&self, operator_wallet: &str, node_pubkey: &str) {
|
||||
self.operators
|
||||
.entry(operator_wallet.to_string())
|
||||
.and_modify(|op| {
|
||||
op.vm_nodes.insert(node_pubkey.to_string());
|
||||
})
|
||||
.or_insert(OperatorData {
|
||||
escrow: 0,
|
||||
email: String::new(),
|
||||
banned_users: HashSet::new(),
|
||||
vm_nodes: HashSet::from([node_pubkey.to_string()]),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn register_operator(&self, req: grpc::RegOperatorReq) -> Result<(), Error> {
|
||||
let mut operator = match self.operators.get(&req.pubkey) {
|
||||
Some(o) => (*(o.value())).clone(),
|
||||
None => OperatorData {
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
if req.escrow < 5000 {
|
||||
return Err(Error::MinimalEscrow);
|
||||
}
|
||||
let escrow = req.escrow * 1_000_000_000;
|
||||
if let Some(mut account) = self.accounts.get_mut(&req.pubkey) {
|
||||
if (account.balance + operator.escrow) < escrow {
|
||||
return Err(Error::InsufficientFunds);
|
||||
}
|
||||
account.balance = account.balance + operator.escrow - escrow;
|
||||
operator.escrow = escrow;
|
||||
} else {
|
||||
return Err(Error::InsufficientFunds);
|
||||
}
|
||||
operator.email = req.email;
|
||||
self.operators.insert(req.pubkey, operator);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn find_vm_nodes_by_operator(&self, operator_wallet: &str) -> Vec<VmNode> {
|
||||
let nodes = self.vm_nodes.read().unwrap();
|
||||
nodes
|
||||
.iter()
|
||||
.filter(|node| node.operator_wallet == operator_wallet)
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn total_operator_reports(&self, operator_wallet: &str) -> usize {
|
||||
let nodes = self.vm_nodes.read().unwrap();
|
||||
nodes
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|n| n.operator_wallet == operator_wallet)
|
||||
.map(|node| node.reports.len())
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub fn find_vm_nodes_by_filters(
|
||||
pub fn find_nodes_by_filters(
|
||||
&self,
|
||||
filters: &crate::grpc::snp_proto::VmNodeFilters,
|
||||
) -> Vec<VmNode> {
|
||||
@ -944,13 +747,9 @@ impl BrainData {
|
||||
.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();
|
||||
contracts
|
||||
.iter()
|
||||
.cloned()
|
||||
.find(|c| c.uuid == uuid)
|
||||
.ok_or(Error::VmContractNotFound(uuid.to_string()))
|
||||
contracts.iter().cloned().find(|c| c.uuid == uuid)
|
||||
}
|
||||
|
||||
pub fn list_all_contracts(&self) -> Vec<VmContract> {
|
||||
@ -969,72 +768,21 @@ impl BrainData {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn list_operators(&self) -> Vec<grpc::ListOperatorsResp> {
|
||||
self.operators
|
||||
.iter()
|
||||
.map(|op| grpc::ListOperatorsResp {
|
||||
pubkey: op.key().to_string(),
|
||||
escrow: op.escrow / 1_000_000_000,
|
||||
email: op.email.clone(),
|
||||
app_nodes: 0,
|
||||
vm_nodes: op.vm_nodes.len() as u64,
|
||||
reports: self.total_operator_reports(op.key()) as u64,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn inspect_operator(&self, wallet: &str) -> Option<grpc::InspectOperatorResp> {
|
||||
self.operators.get(wallet).map(|op| {
|
||||
let nodes = self
|
||||
.find_vm_nodes_by_operator(wallet)
|
||||
.into_iter()
|
||||
.map(|n| n.into())
|
||||
.collect();
|
||||
grpc::InspectOperatorResp {
|
||||
operator: Some(grpc::ListOperatorsResp {
|
||||
pubkey: op.key().to_string(),
|
||||
escrow: op.escrow,
|
||||
email: op.email.clone(),
|
||||
app_nodes: 0,
|
||||
vm_nodes: op.vm_nodes.len() as u64,
|
||||
reports: self.total_operator_reports(op.key()) as u64,
|
||||
}),
|
||||
nodes,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_vm_contracts_by_operator(&self, wallet: &str) -> Vec<VmContract> {
|
||||
debug!("Searching contracts for operator {wallet}");
|
||||
let nodes = match self.operators.get(wallet) {
|
||||
Some(op) => op.vm_nodes.clone(),
|
||||
None => return Vec::new(),
|
||||
};
|
||||
pub fn find_contracts_by_admin_pubkey(&self, admin_pubkey: &str) -> Vec<VmContract> {
|
||||
debug!("Searching contracts for admin pubkey {admin_pubkey}");
|
||||
let contracts: Vec<VmContract> = self
|
||||
.vm_contracts
|
||||
.read()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|c| nodes.contains(&c.node_pubkey))
|
||||
.filter(|c| c.admin_pubkey == admin_pubkey)
|
||||
.cloned()
|
||||
.collect();
|
||||
debug!("Found {} contracts or {admin_pubkey}.", contracts.len());
|
||||
contracts
|
||||
}
|
||||
|
||||
pub fn find_vm_contracts_by_admin(&self, admin_wallet: &str) -> Vec<VmContract> {
|
||||
debug!("Searching contracts for admin pubkey {admin_wallet}");
|
||||
let contracts: Vec<VmContract> = self
|
||||
.vm_contracts
|
||||
.read()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|c| c.admin_pubkey == admin_wallet)
|
||||
.cloned()
|
||||
.collect();
|
||||
contracts
|
||||
}
|
||||
|
||||
pub fn find_vm_contracts_by_node(&self, node_pubkey: &str) -> Vec<VmContract> {
|
||||
pub fn find_contracts_by_node_pubkey(&self, node_pubkey: &str) -> Vec<VmContract> {
|
||||
let contracts = self.vm_contracts.read().unwrap();
|
||||
contracts
|
||||
.iter()
|
||||
@ -1043,3 +791,204 @@ impl BrainData {
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl BrainData {
|
||||
pub fn add_app_daemon_tx(&self, node_pubkey: &str, tx: Sender<BrainMessageApp>) {
|
||||
self.app_daemon_tx.insert(node_pubkey.to_string(), tx);
|
||||
}
|
||||
|
||||
pub fn del_app_daemon_tx(&self, node_pubkey: &str) {
|
||||
self.app_daemon_tx.remove(node_pubkey);
|
||||
}
|
||||
|
||||
pub fn insert_app_node(&self, node: AppNode) {
|
||||
let mut nodes = self.app_nodes.write().unwrap();
|
||||
for n in nodes.iter_mut() {
|
||||
if n.node_pubkey == node.node_pubkey {
|
||||
// TODO: figure what to do in this case.
|
||||
warn!("Node {} already exists. Updating data.", n.node_pubkey);
|
||||
*n = node;
|
||||
return;
|
||||
}
|
||||
}
|
||||
nodes.push(node);
|
||||
}
|
||||
|
||||
pub fn find_app_contract_by_uuid(&self, uuid: &str) -> Option<AppContract> {
|
||||
let contracts = self.app_contracts.read().unwrap();
|
||||
contracts.iter().find(|c| c.uuid == uuid).cloned()
|
||||
}
|
||||
|
||||
pub fn find_app_contracts_by_admin_pubkey(&self, admin_pubkey: &str) -> Vec<AppContract> {
|
||||
debug!("Searching contracts for admin pubkey {admin_pubkey}");
|
||||
let contracts: Vec<AppContract> = self
|
||||
.app_contracts
|
||||
.read()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|c| c.admin_pubkey == admin_pubkey)
|
||||
.cloned()
|
||||
.collect();
|
||||
debug!("Found {} contracts or {admin_pubkey}.", contracts.len());
|
||||
contracts
|
||||
}
|
||||
|
||||
pub fn find_app_contracts_by_node_pubkey(&self, node_pubkey: &str) -> Vec<AppContract> {
|
||||
let app_contracts = self.app_contracts.read().unwrap();
|
||||
app_contracts
|
||||
.iter()
|
||||
.filter(|c| c.node_pubkey == node_pubkey)
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn submit_app_node_resources(&self, node_resource: AppNodeResources) {
|
||||
debug!("{:#?}", &node_resource);
|
||||
let mut nodes = self.app_nodes.write().unwrap();
|
||||
for n in nodes.iter_mut() {
|
||||
if n.node_pubkey == node_resource.node_pubkey {
|
||||
debug!(
|
||||
"Found node {}. Updating resources to {:?}",
|
||||
n.node_pubkey, node_resource
|
||||
);
|
||||
n.avail_vcpus = node_resource.avail_vcpus;
|
||||
n.avail_mem_mb = node_resource.avail_memory_mb;
|
||||
n.avail_storage_mb = node_resource.avail_storage_mb;
|
||||
n.max_ports_per_app = node_resource.max_ports_per_app;
|
||||
n.avail_no_of_port = node_resource.avail_no_of_port;
|
||||
return;
|
||||
}
|
||||
}
|
||||
debug!(
|
||||
"VM Node {} not found when trying to update resources.",
|
||||
node_resource.node_pubkey
|
||||
);
|
||||
debug!("VM Node list:\n{:?}", nodes);
|
||||
}
|
||||
|
||||
pub async fn send_new_container_req(&self, mut req: NewAppReq, tx: OneshotSender<NewAppRes>) {
|
||||
req.uuid = uuid::Uuid::new_v4().to_string();
|
||||
|
||||
info!("Inserting new container request in memory: {req:?}");
|
||||
self.tmp_new_container_reqs
|
||||
.insert(req.uuid.clone(), (req.clone(), tx));
|
||||
|
||||
if let Some(app_daemon_tx) = self.app_daemon_tx.get(&req.node_pubkey) {
|
||||
debug!(
|
||||
"Found daemon TX for {}. Sending newVMReq {}",
|
||||
req.node_pubkey, req.uuid
|
||||
);
|
||||
let msg = BrainMessageApp {
|
||||
msg: Some(
|
||||
detee_shared::sgx::pb::brain::brain_message_app::Msg::NewAppReq(req.clone()),
|
||||
),
|
||||
};
|
||||
if let Err(e) = app_daemon_tx.send(msg).await {
|
||||
warn!(
|
||||
"Failed to send new container request to {} due to error: {e:?}",
|
||||
req.node_pubkey
|
||||
);
|
||||
info!("Deleting daemon TX for {}", req.node_pubkey);
|
||||
self.del_app_daemon_tx(&req.node_pubkey);
|
||||
self.send_new_container_resp(NewAppRes {
|
||||
uuid: req.uuid,
|
||||
status: "failed".to_string(),
|
||||
error: "Daemon is offline.".to_string(),
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
// TODO: implement daemon offline handling
|
||||
}
|
||||
|
||||
pub async fn send_del_container_req(
|
||||
&self,
|
||||
req: DelAppReq,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if let Some(app_contract) = self.find_app_contract_by_uuid(&req.uuid) {
|
||||
info!("Found app contract {}. Deleting...", &req.uuid);
|
||||
if let Some(app_daemon_tx) = self.app_daemon_tx.get(&app_contract.node_pubkey) {
|
||||
debug!(
|
||||
"TX for daemon {} found. Informing daemon about deletion of {}.",
|
||||
app_contract.node_pubkey, &req.uuid
|
||||
);
|
||||
let msg = BrainMessageApp {
|
||||
msg: Some(
|
||||
detee_shared::sgx::pb::brain::brain_message_app::Msg::DeleteAppReq(
|
||||
req.clone(),
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
if let Err(e) = app_daemon_tx.send(msg).await {
|
||||
warn!(
|
||||
"Failed to send deletion request to {} due to error: {e:?}",
|
||||
app_contract.node_pubkey
|
||||
);
|
||||
info!("Deleting daemon TX for {}", app_contract.node_pubkey);
|
||||
self.del_app_daemon_tx(&app_contract.node_pubkey);
|
||||
}
|
||||
}
|
||||
|
||||
let mut app_contracts = self.app_contracts.write().unwrap();
|
||||
app_contracts.retain(|c| c.uuid != req.uuid);
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err("Contract not found".into())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_new_container_resp(&self, new_container_resp: NewAppRes) {
|
||||
let new_container_req = match self.tmp_new_container_reqs.remove(&new_container_resp.uuid) {
|
||||
Some((_, r)) => r,
|
||||
None => {
|
||||
log::error!(
|
||||
"Received confirmation for ghost new container req {}",
|
||||
new_container_resp.uuid
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let Err(err) = new_container_req.1.send(new_container_resp.clone()) {
|
||||
log::error!(
|
||||
"CLI RX for {} dropped before receiving confirmation {:?}.\n{:?}",
|
||||
&new_container_req.0.admin_pubkey,
|
||||
new_container_resp,
|
||||
err
|
||||
);
|
||||
}
|
||||
|
||||
if new_container_resp.error != "" {
|
||||
return;
|
||||
}
|
||||
|
||||
let requested_resource = new_container_req.0.resource.clone().unwrap_or_default();
|
||||
|
||||
let app_contracts = AppContract {
|
||||
uuid: new_container_req.0.uuid,
|
||||
package_url: new_container_req.0.package_url,
|
||||
admin_pubkey: new_container_req.0.admin_pubkey,
|
||||
node_pubkey: new_container_req.0.node_pubkey.clone(),
|
||||
mapped_ports: new_container_resp
|
||||
.mapped_ports
|
||||
.iter()
|
||||
.map(|p| (p.host_port as u16, p.app_port as u16))
|
||||
.collect::<Vec<(u16, u16)>>(),
|
||||
host_ipv4: new_container_resp.ip_address,
|
||||
disk_size_mb: requested_resource.disk_mb,
|
||||
vcpus: requested_resource.vcpu,
|
||||
memory_mb: requested_resource.memory_mb,
|
||||
created_at: Utc::now(),
|
||||
updated_at: Utc::now(),
|
||||
price_per_unit: new_container_req.0.price_per_unit,
|
||||
locked_nano: new_container_req.0.locked_nano,
|
||||
collected_at: Utc::now(),
|
||||
hratls_pubkey: new_container_req.0.hratls_pubkey,
|
||||
public_package_mr_enclave: new_container_req.0.public_package_mr_enclave,
|
||||
};
|
||||
log::info!("Created new app contract: {app_contracts:?}");
|
||||
self.app_contracts.write().unwrap().push(app_contracts);
|
||||
}
|
||||
}
|
||||
|
479
src/grpc.rs
479
src/grpc.rs
@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod snp_proto {
|
||||
tonic::include_proto!("vm_proto");
|
||||
}
|
||||
@ -14,10 +16,15 @@ use tokio::sync::mpsc;
|
||||
use tokio_stream::{wrappers::ReceiverStream, Stream, StreamExt};
|
||||
use tonic::{Request, Response, Status, Streaming};
|
||||
|
||||
use detee_shared::sgx::pb::brain::brain_app_cli_server::BrainAppCli;
|
||||
use detee_shared::sgx::pb::brain::brain_app_daemon_server::BrainAppDaemon;
|
||||
use detee_shared::sgx::pb::brain::{
|
||||
AppContract, BrainMessageApp, DaemonMessageApp, DelAppReq, ListAppContractsReq, NewAppReq,
|
||||
NewAppRes, RegisterAppNodeReq,
|
||||
};
|
||||
const ADMIN_ACCOUNTS: &[&str] = &[
|
||||
"x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK",
|
||||
"FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL",
|
||||
"H21Shi4iE7vgfjWEQNvzmpmBMJSaiZ17PYUcdNoAoKNc",
|
||||
];
|
||||
|
||||
pub struct BrainDaemonMock {
|
||||
@ -40,6 +47,26 @@ impl BrainCliMock {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BrainAppCliMock {
|
||||
data: Arc<BrainData>,
|
||||
}
|
||||
|
||||
impl BrainAppCliMock {
|
||||
pub fn new(data: Arc<BrainData>) -> Self {
|
||||
Self { data }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BrainAppDaemonMock {
|
||||
data: Arc<BrainData>,
|
||||
}
|
||||
|
||||
impl BrainAppDaemonMock {
|
||||
pub fn new(data: Arc<BrainData>) -> Self {
|
||||
Self { data }
|
||||
}
|
||||
}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl BrainVmDaemon for BrainDaemonMock {
|
||||
type RegisterVmNodeStream = Pin<Box<dyn Stream<Item = Result<VmContract, Status>> + Send>>;
|
||||
@ -51,7 +78,7 @@ impl BrainVmDaemon for BrainDaemonMock {
|
||||
info!("Starting registration process for {:?}", req);
|
||||
let node = crate::data::VmNode {
|
||||
public_key: req.node_pubkey.clone(),
|
||||
operator_wallet: req.operator_wallet,
|
||||
owner_key: req.owner_pubkey,
|
||||
country: req.country,
|
||||
region: req.region,
|
||||
city: req.city,
|
||||
@ -59,10 +86,10 @@ impl BrainVmDaemon for BrainDaemonMock {
|
||||
price: req.price,
|
||||
..Default::default()
|
||||
};
|
||||
self.data.register_node(node);
|
||||
self.data.insert_node(node);
|
||||
|
||||
info!("Sending existing contracts to {}", req.node_pubkey);
|
||||
let contracts = self.data.find_vm_contracts_by_node(&req.node_pubkey);
|
||||
let contracts = self.data.find_contracts_by_node_pubkey(&req.node_pubkey);
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
tokio::spawn(async move {
|
||||
for contract in contracts {
|
||||
@ -160,14 +187,6 @@ impl BrainCli for BrainCliMock {
|
||||
async fn new_vm(&self, req: Request<NewVmReq>) -> Result<Response<NewVmResp>, Status> {
|
||||
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;
|
||||
@ -195,9 +214,9 @@ impl BrainCli for BrainCliMock {
|
||||
info!("Sending UpdateVMResp: {response:?}");
|
||||
Ok(Response::new(response))
|
||||
}
|
||||
Err(e) => Err(Status::unknown(format!(
|
||||
"Update VM request failed due to error: {e}"
|
||||
))),
|
||||
Err(_) => Err(Status::unknown(
|
||||
"Update VM request failed due to error: {e}",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,55 +231,20 @@ impl BrainCli for BrainCliMock {
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
info!("CLI {} requested ListVMVmContractsStream", 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),
|
||||
};
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
tokio::spawn(async move {
|
||||
for contract in contracts {
|
||||
@ -280,7 +264,7 @@ impl BrainCli for BrainCliMock {
|
||||
) -> 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 nodes = self.data.find_nodes_by_filters(&req);
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
tokio::spawn(async move {
|
||||
for node in nodes {
|
||||
@ -307,65 +291,12 @@ impl BrainCli for BrainCliMock {
|
||||
}
|
||||
}
|
||||
|
||||
async fn register_operator(
|
||||
&self,
|
||||
req: Request<RegOperatorReq>,
|
||||
) -> Result<Response<Empty>, Status> {
|
||||
async fn delete_vm(&self, req: Request<DeleteVmReq>) -> Result<Response<Empty>, Status> {
|
||||
let req = check_sig_from_req(req)?;
|
||||
info!("Regitering new operator: {req:?}");
|
||||
match self.data.register_operator(req) {
|
||||
info!("Unknown CLI requested to delete vm {}", req.uuid);
|
||||
match self.data.delete_vm(req).await {
|
||||
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",
|
||||
)),
|
||||
Err(e) => Err(Status::not_found(e.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,13 +307,6 @@ impl BrainCli for BrainCliMock {
|
||||
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,
|
||||
@ -428,39 +352,280 @@ 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 PubkeyGetter for Pubkey {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
Some(self.pubkey.clone())
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
#[tonic::async_trait]
|
||||
impl BrainAppCli for BrainAppCliMock {
|
||||
type ListAppContractsStream = Pin<Box<dyn Stream<Item = Result<AppContract, Status>> + Send>>;
|
||||
|
||||
impl_pubkey_getter!(VmNodeFilters);
|
||||
impl_pubkey_getter!(Empty);
|
||||
impl_pubkey_getter!(AirdropReq);
|
||||
impl_pubkey_getter!(SlashReq);
|
||||
async fn create_app(
|
||||
&self,
|
||||
req: tonic::Request<NewAppReq>,
|
||||
) -> Result<tonic::Response<NewAppRes>, Status> {
|
||||
let req_data = check_sig_from_req(req)?;
|
||||
log::info!("Creating new container: {req_data:?}");
|
||||
let admin_pubkey = req_data.admin_pubkey.clone();
|
||||
let (oneshot_tx, oneshot_rx) = tokio::sync::oneshot::channel();
|
||||
self.data.send_new_container_req(req_data, oneshot_tx).await;
|
||||
|
||||
match oneshot_rx.await {
|
||||
Ok(response) => {
|
||||
info!("responding container confirmation to {admin_pubkey}: {response:?}");
|
||||
Ok(Response::new(response))
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Something went wrong. Reached error {e:?}");
|
||||
Err(Status::unknown(
|
||||
"Request failed due to unknown error. Please try again or contact the DeTEE devs team.",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn delete_app(
|
||||
&self,
|
||||
req: tonic::Request<DelAppReq>,
|
||||
) -> Result<tonic::Response<detee_shared::sgx::pb::brain::Empty>, Status> {
|
||||
let req_data = check_sig_from_req(req)?;
|
||||
log::info!("deleting container: {}", req_data.uuid.clone());
|
||||
if let Err(er) = self.data.send_del_container_req(req_data).await {
|
||||
info!("Could not delete container: {er}");
|
||||
return Err(Status::not_found("Could not find container"));
|
||||
};
|
||||
|
||||
Ok(Response::new(detee_shared::sgx::pb::brain::Empty {}))
|
||||
}
|
||||
|
||||
async fn list_app_contracts(
|
||||
&self,
|
||||
req: tonic::Request<ListAppContractsReq>,
|
||||
) -> Result<tonic::Response<Self::ListAppContractsStream>, Status> {
|
||||
let req_data = check_sig_from_req(req)?;
|
||||
let app_contracts = self
|
||||
.data
|
||||
.find_app_contracts_by_admin_pubkey(&req_data.admin_pubkey);
|
||||
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
tokio::spawn(async move {
|
||||
for contract in app_contracts {
|
||||
let _ = tx.send(contract.into()).await;
|
||||
}
|
||||
});
|
||||
let output_stream = ReceiverStream::new(rx).map(Ok);
|
||||
Ok(Response::new(
|
||||
Box::pin(output_stream) as Self::ListAppContractsStream
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl BrainAppDaemon for BrainAppDaemonMock {
|
||||
type RegisterAppNodeStream = Pin<Box<dyn Stream<Item = Result<AppContract, Status>> + Send>>;
|
||||
type BrainMessagesStream = Pin<Box<dyn Stream<Item = Result<BrainMessageApp, Status>> + Send>>;
|
||||
|
||||
async fn register_app_node(
|
||||
&self,
|
||||
req: tonic::Request<RegisterAppNodeReq>,
|
||||
) -> Result<tonic::Response<Self::RegisterAppNodeStream>, Status> {
|
||||
let req_data = check_sig_from_req(req)?;
|
||||
log::info!(
|
||||
"registering app node_key : {}, operator_key: {}",
|
||||
&req_data.node_pubkey,
|
||||
&req_data.operator_pubkey
|
||||
);
|
||||
|
||||
let app_node = crate::data::AppNode {
|
||||
node_pubkey: req_data.node_pubkey.clone(),
|
||||
operator_pubkey: req_data.operator_pubkey,
|
||||
ip: req_data.main_ip,
|
||||
city: req_data.city,
|
||||
region: req_data.region,
|
||||
country: req_data.country,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
self.data.insert_app_node(app_node);
|
||||
log::info!("Sending existing contracts to {}", &req_data.node_pubkey);
|
||||
|
||||
let app_contracts = self
|
||||
.data
|
||||
.find_app_contracts_by_node_pubkey(&req_data.node_pubkey);
|
||||
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
tokio::spawn(async move {
|
||||
for contract in app_contracts {
|
||||
let _ = tx.send(contract.into()).await;
|
||||
}
|
||||
});
|
||||
let output_stream = ReceiverStream::new(rx).map(Ok);
|
||||
Ok(Response::new(Box::pin(output_stream)))
|
||||
}
|
||||
|
||||
async fn brain_messages(
|
||||
&self,
|
||||
req: tonic::Request<detee_shared::sgx::pb::brain::DaemonAuth>,
|
||||
) -> Result<tonic::Response<Self::BrainMessagesStream>, Status> {
|
||||
let req_data = req.into_inner();
|
||||
let pubkey = req_data.pubkey.clone();
|
||||
check_sig_from_parts(
|
||||
&pubkey,
|
||||
&req_data.timestamp,
|
||||
&format!("{:?}", req_data.contracts),
|
||||
&req_data.signature,
|
||||
)?;
|
||||
|
||||
info!(
|
||||
"Daemon {} connected to receive brain messages",
|
||||
req_data.pubkey
|
||||
);
|
||||
let (tx, rx) = mpsc::channel(6);
|
||||
self.data.add_app_daemon_tx(&req_data.pubkey, tx);
|
||||
let output_stream = ReceiverStream::new(rx).map(Ok);
|
||||
Ok(Response::new(
|
||||
Box::pin(output_stream) as Self::BrainMessagesStream
|
||||
))
|
||||
}
|
||||
|
||||
async fn daemon_messages(
|
||||
&self,
|
||||
req: tonic::Request<Streaming<DaemonMessageApp>>,
|
||||
) -> Result<tonic::Response<detee_shared::sgx::pb::brain::Empty>, Status> {
|
||||
let mut req_stream = req.into_inner();
|
||||
let mut pubkey;
|
||||
|
||||
if let Some(Ok(msg)) = req_stream.next().await {
|
||||
log::debug!(
|
||||
"demon_messages received the following auth message: {:?}",
|
||||
msg.msg
|
||||
);
|
||||
if let Some(detee_shared::sgx::pb::brain::daemon_message_app::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"));
|
||||
}
|
||||
|
||||
while let Some(daemon_message) = req_stream.next().await {
|
||||
match daemon_message {
|
||||
Ok(msg) => match msg.msg {
|
||||
Some(detee_shared::sgx::pb::brain::daemon_message_app::Msg::Auth(
|
||||
daemon_auth,
|
||||
)) => pubkey = daemon_auth.pubkey,
|
||||
Some(detee_shared::sgx::pb::brain::daemon_message_app::Msg::NewAppRes(
|
||||
new_app_res,
|
||||
)) => self.data.send_new_container_resp(new_app_res).await,
|
||||
Some(
|
||||
detee_shared::sgx::pb::brain::daemon_message_app::Msg::AppNodeResources(
|
||||
node_resource,
|
||||
),
|
||||
) => self.data.submit_app_node_resources(node_resource),
|
||||
_ => {
|
||||
dbg!("None");
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::warn!("Daemon disconnected: {e:?}");
|
||||
self.data.del_app_daemon_tx(&pubkey);
|
||||
}
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
Ok(Response::new(detee_shared::sgx::pb::brain::Empty {}))
|
||||
}
|
||||
}
|
||||
impl PubkeyGetter for NewVmReq {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
Some(self.admin_pubkey.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for DeleteVmReq {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
Some(self.admin_pubkey.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for UpdateVmReq {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
Some(self.admin_pubkey.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for ExtendVmReq {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
Some(self.admin_pubkey.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for ListVmContractsReq {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
Some(self.admin_pubkey.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for VmNodeFilters {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for RegisterVmNodeReq {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
Some(self.node_pubkey.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for Empty {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for AirdropReq {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for RegisterAppNodeReq {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for NewAppReq {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
Some(self.admin_pubkey.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for DelAppReq {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
Some(self.admin_pubkey.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl PubkeyGetter for ListAppContractsReq {
|
||||
fn get_pubkey(&self) -> Option<String> {
|
||||
Some(self.admin_pubkey.clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) -> Result<T, Status> {
|
||||
let time = match req.metadata().get("timestamp") {
|
||||
@ -475,9 +640,9 @@ fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) -> Res
|
||||
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 {
|
||||
if seconds_elapsed > 1 || seconds_elapsed < -1 {
|
||||
return Err(Status::unauthenticated(format!(
|
||||
"Date is not within 4 sec of the time of the server: CLI {} vs Server {}",
|
||||
"Date is not within 1 sec of the time of the server: CLI {} vs Server {}",
|
||||
parsed_time, now
|
||||
)));
|
||||
}
|
||||
@ -530,9 +695,9 @@ fn check_sig_from_parts(pubkey: &str, time: &str, msg: &str, sig: &str) -> Resul
|
||||
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 {
|
||||
if seconds_elapsed > 1 || seconds_elapsed < -1 {
|
||||
return Err(Status::unauthenticated(format!(
|
||||
"Date is not within 4 sec of the time of the server: CLI {} vs Server {}",
|
||||
"Date is not within 1 sec of the time of the server: CLI {} vs Server {}",
|
||||
parsed_time, now
|
||||
)));
|
||||
}
|
||||
|
13
src/main.rs
13
src/main.rs
@ -2,8 +2,12 @@ mod data;
|
||||
mod grpc;
|
||||
|
||||
use data::BrainData;
|
||||
use detee_shared::sgx::pb::brain::brain_app_cli_server::BrainAppCliServer;
|
||||
use detee_shared::sgx::pb::brain::brain_app_daemon_server::BrainAppDaemonServer;
|
||||
use grpc::snp_proto::brain_cli_server::BrainCliServer;
|
||||
use grpc::snp_proto::brain_vm_daemon_server::BrainVmDaemonServer;
|
||||
use grpc::BrainAppCliMock;
|
||||
use grpc::BrainAppDaemonMock;
|
||||
use grpc::BrainCliMock;
|
||||
use grpc::BrainDaemonMock;
|
||||
use std::sync::Arc;
|
||||
@ -19,11 +23,7 @@ async fn main() {
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(60)).await;
|
||||
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();
|
||||
@ -31,9 +31,14 @@ async fn main() {
|
||||
let daemon_server = BrainVmDaemonServer::new(BrainDaemonMock::new(data.clone()));
|
||||
let cli_server = BrainCliServer::new(BrainCliMock::new(data.clone()));
|
||||
|
||||
let sgx_cli_server = BrainAppCliServer::new(BrainAppCliMock::new(data.clone()));
|
||||
let sgx_daemon_server = BrainAppDaemonServer::new(BrainAppDaemonMock::new(data.clone()));
|
||||
|
||||
Server::builder()
|
||||
.add_service(daemon_server)
|
||||
.add_service(cli_server)
|
||||
.add_service(sgx_cli_server)
|
||||
.add_service(sgx_daemon_server)
|
||||
.serve(addr)
|
||||
.await
|
||||
.unwrap();
|
||||
|
77
vm.proto
77
vm.proto
@ -55,7 +55,7 @@ message MeasurementIP {
|
||||
// This should also include a block hash or similar, for auth
|
||||
message RegisterVmNodeReq {
|
||||
string node_pubkey = 1;
|
||||
string operator_wallet = 2;
|
||||
string owner_pubkey = 2;
|
||||
string main_ip = 3;
|
||||
string country = 4;
|
||||
string region = 5;
|
||||
@ -154,8 +154,8 @@ service BrainVmDaemon {
|
||||
}
|
||||
|
||||
message ListVmContractsReq {
|
||||
string wallet = 1;
|
||||
bool as_operator = 2;
|
||||
string admin_pubkey = 1;
|
||||
string node_pubkey = 2;
|
||||
string uuid = 3;
|
||||
}
|
||||
|
||||
@ -174,14 +174,15 @@ message VmNodeFilters {
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
// nanoLP per unit per minute
|
||||
uint64 price = 8;
|
||||
}
|
||||
|
||||
message ExtendVmReq {
|
||||
@ -195,59 +196,12 @@ message AirdropReq {
|
||||
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 GetBalance (Pubkey) returns (AccountBalance);
|
||||
rpc NewVm (NewVmReq) returns (NewVmResp);
|
||||
@ -257,15 +211,8 @@ service BrainCli {
|
||||
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