From 6ded25e7b9f4fab7a47390177a0f07992e6b05f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Thu, 2 Nov 2023 12:07:07 +0100 Subject: [PATCH 01/12] POST certifier service --- Cargo.lock | 536 ++++++++++++++++++++++++++++++--- Cargo.toml | 12 +- certifier/Cargo.toml | 26 ++ certifier/Dockerfile | 28 ++ certifier/mainnet.yml | 11 + certifier/proof.json | 14 + certifier/src/certifier.rs | 76 +++++ certifier/src/configuration.rs | 25 ++ certifier/src/lib.rs | 2 + certifier/src/main.rs | 83 +++++ src/config.rs | 12 +- src/metadata.rs | 6 +- src/prove.rs | 6 +- 13 files changed, 796 insertions(+), 41 deletions(-) create mode 100644 certifier/Cargo.toml create mode 100644 certifier/Dockerfile create mode 100644 certifier/mainnet.yml create mode 100644 certifier/proof.json create mode 100644 certifier/src/certifier.rs create mode 100644 certifier/src/configuration.rs create mode 100644 certifier/src/lib.rs create mode 100644 certifier/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index aba687ad..e48b3b63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,6 +28,17 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "ahash" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.3" @@ -72,9 +83,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.5.0" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ "anstyle", "anstyle-parse", @@ -110,9 +121,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "2.1.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", "windows-sys", @@ -208,7 +219,11 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", "sync_wrapper", + "tokio", "tower", "tower-layer", "tower-service", @@ -258,6 +273,12 @@ version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bindgen" version = "0.66.1" @@ -416,6 +437,27 @@ dependencies = [ "libc", ] +[[package]] +name = "certifier" +version = "0.1.0" +dependencies = [ + "axum", + "clap 4.4.7", + "config", + "ed25519-dalek", + "hex", + "post-rs", + "rand", + "secrecy", + "serde", + "serde_json", + "serde_with 3.4.0", + "tokio", + "tracing", + "tracing-log 0.2.0", + "tracing-subscriber", +] + [[package]] name = "cexpr" version = "0.6.0" @@ -518,9 +560,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.4" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ "clap_builder", "clap_derive", @@ -528,21 +570,21 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.4" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstream", "anstyle", - "clap_lex 0.5.1", + "clap_lex 0.6.0", "strsim", ] [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", @@ -561,9 +603,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "colorchoice" @@ -571,6 +613,31 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "config" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d379af7f68bfc21714c6c7dea883544201741d2ce8274bb12fa54f89507f52a7" +dependencies = [ + "async-trait", + "json5", + "lazy_static", + "nom", + "pathdiff", + "ron", + "rust-ini", + "serde", + "serde_json", + "toml", + "yaml-rust", +] + +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + [[package]] name = "constant_time_eq" version = "0.3.0" @@ -610,7 +677,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.4", + "clap 4.4.7", "criterion-plot", "is-terminal", "itertools", @@ -720,6 +787,34 @@ dependencies = [ "typenum", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "platforms", + "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 2.0.29", +] + [[package]] name = "darling" version = "0.20.3" @@ -764,6 +859,16 @@ dependencies = [ "uuid", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.8" @@ -790,12 +895,42 @@ dependencies = [ "subtle", ] +[[package]] +name = "dlv-list" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" + [[package]] name = "downcast" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" +[[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.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "serde", + "sha2", + "zeroize", +] + [[package]] name = "either" version = "1.9.0" @@ -867,6 +1002,12 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +[[package]] +name = "fiat-crypto" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a481586acf778f1b1455424c343f71124b048ffa5f4fc3f8f6ae9dc432dcb3c7" + [[package]] name = "findshlibs" version = "0.10.2" @@ -912,6 +1053,15 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fragile" version = "2.0.0" @@ -1088,6 +1238,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.7", +] [[package]] name = "hashbrown" @@ -1272,6 +1425,7 @@ checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", "hashbrown 0.14.0", + "serde", ] [[package]] @@ -1280,7 +1434,7 @@ version = "0.11.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73c0fefcb6d409a6587c07515951495d482006f89a21daa0f2f783aa4fd5e027" dependencies = [ - "ahash", + "ahash 0.8.3", "indexmap 2.0.0", "is-terminal", "itoa", @@ -1297,7 +1451,7 @@ name = "initializer" version = "0.5.2" dependencies = [ "base64 0.21.3", - "clap 4.4.4", + "clap 4.4.7", "env_logger", "eyre", "post-rs", @@ -1351,6 +1505,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1385,6 +1550,12 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.10" @@ -1407,6 +1578,15 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matchit" version = "0.7.2" @@ -1544,6 +1724,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-complex" version = "0.4.4" @@ -1652,12 +1842,28 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "ordered-multimap" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" +dependencies = [ + "dlv-list", + "hashbrown 0.12.3", +] + [[package]] name = "os_str_bytes" version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parity-scale-codec" version = "3.6.5" @@ -1707,6 +1913,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -1729,6 +1941,51 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "pest" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "pest_meta" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "petgraph" version = "0.6.4" @@ -1771,6 +2028,22 @@ 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 = "platforms" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" + [[package]] name = "plotters" version = "0.3.5" @@ -1835,7 +2108,7 @@ dependencies = [ "scrypt-jane", "serde", "serde_json", - "serde_with", + "serde_with 2.3.3", "tempfile", "thiserror", "thread_local", @@ -1943,7 +2216,7 @@ dependencies = [ name = "profiler" version = "0.5.2" dependencies = [ - "clap 4.4.4", + "clap 4.4.7", "env_logger", "eyre", "hex", @@ -2170,10 +2443,19 @@ checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", - "regex-automata", + "regex-automata 0.3.7", "regex-syntax 0.7.5", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + [[package]] name = "regex-automata" version = "0.3.7" @@ -2227,6 +2509,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "ron" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" +dependencies = [ + "base64 0.13.1", + "bitflags 1.3.2", + "serde", +] + [[package]] name = "rstest" version = "0.17.0" @@ -2282,6 +2575,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "rust-ini" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -2432,6 +2735,16 @@ dependencies = [ "untrusted", ] +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "serde", + "zeroize", +] + [[package]] name = "semver" version = "1.0.18" @@ -2440,18 +2753,18 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", @@ -2460,10 +2773,32 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ + "form_urlencoded", "itoa", "ryu", "serde", @@ -2481,7 +2816,24 @@ dependencies = [ "indexmap 1.9.3", "serde", "serde_json", - "serde_with_macros", + "serde_with_macros 2.3.3", + "time", +] + +[[package]] +name = "serde_with" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +dependencies = [ + "base64 0.21.3", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.0.0", + "serde", + "serde_json", + "serde_with_macros 3.4.0", "time", ] @@ -2497,12 +2849,24 @@ dependencies = [ "syn 2.0.29", ] +[[package]] +name = "serde_with_macros" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "service" version = "0.5.2" dependencies = [ "async-stream", - "clap 4.4.4", + "clap 4.4.7", "env_logger", "eyre", "hex", @@ -2520,12 +2884,38 @@ dependencies = [ "tonic-build", ] +[[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 = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" + [[package]] name = "slab" version = "0.4.9" @@ -2567,6 +2957,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -2946,11 +3346,11 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2958,9 +3358,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", @@ -2969,11 +3369,52 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log 0.1.4", ] [[package]] @@ -2988,6 +3429,12 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "uint" version = "0.9.5" @@ -3030,6 +3477,12 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" @@ -3269,6 +3722,15 @@ dependencies = [ "tap", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yasna" version = "0.5.2" @@ -3277,3 +3739,9 @@ checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ "time", ] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/Cargo.toml b/Cargo.toml index a7fd192c..6872c271 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,13 @@ [workspace] -members = [".", "ffi", "scrypt-ocl", "initializer", "profiler", "service"] +members = [ + ".", + "ffi", + "scrypt-ocl", + "initializer", + "profiler", + "service", + "certifier", +] [package] name = "post-rs" @@ -20,7 +28,7 @@ itertools = "0.10.5" serde = { version = "1.0.152", features = ["derive"] } serde_json = "1.0.93" bytemuck = "1.13.0" -serde_with = { version = "2.2.0", features = ["base64"] } +serde_with = { version = "2.2.0", features = ["base64", "hex"] } scrypt-jane = { git = "https://github.com/spacemeshos/scrypt-jane-rs", branch = "main" } blake3 = "1.3.3" diff --git a/certifier/Cargo.toml b/certifier/Cargo.toml new file mode 100644 index 00000000..55bbe582 --- /dev/null +++ b/certifier/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "certifier" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = "0.6.20" +serde = { version = "1.0.190", features = ["derive"] } +tokio = { version = "1.0", features = [ + "rt-multi-thread", + "macros", + "sync", + "time", +] } +post-rs = { path = "../" } +serde_with = { version = "3.4.0", features = ["base64", "hex"] } +ed25519-dalek = { version = "2.0.0", features = ["rand_core"] } +clap = { version = "4.4.7", features = ["derive", "env"] } +hex = "0.4.3" +config = "0.13.3" +secrecy = { version = "0.8.0", features = ["serde"] } +tracing = { version = "0.1.40", features = ["log"] } +tracing-log = "0.2.0" +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } +rand = "0.8.5" +serde_json = "1.0.108" diff --git a/certifier/Dockerfile b/certifier/Dockerfile new file mode 100644 index 00000000..5e69f515 --- /dev/null +++ b/certifier/Dockerfile @@ -0,0 +1,28 @@ +FROM rust:1 AS chef + +RUN cargo install cargo-chef +RUN apt-get update && apt-get install -y\ + llvm-dev \ + libclang-dev \ + clang \ + cmake \ + protobuf-compiler \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /certifier + +FROM chef AS planner +COPY . . +RUN cargo chef prepare --recipe-path recipe.json + +FROM chef AS builder +COPY --from=planner /certifier/recipe.json recipe.json +RUN cargo chef cook --release -p certifier --recipe-path recipe.json + +COPY . . +RUN cargo build --release -p certifier --bin certifier + +FROM debian:bookworm-slim AS runtime +WORKDIR /certifier +COPY --from=builder /certifier/target/release/certifier /usr/local/bin +ENTRYPOINT ["/usr/local/bin/certifier"] \ No newline at end of file diff --git a/certifier/mainnet.yml b/certifier/mainnet.yml new file mode 100644 index 00000000..14a3ee91 --- /dev/null +++ b/certifier/mainnet.yml @@ -0,0 +1,11 @@ +# Mainnet configuration +listen: "0.0.0.0:80" +post_cfg: + k1: 26 + k2: 37 + k3: 37 + pow_difficulty: "000dfb23b0979b4b000000000000000000000000000000000000000000000000" + scrypt: + n: 8192 + r: 1 + p: 1 diff --git a/certifier/proof.json b/certifier/proof.json new file mode 100644 index 00000000..9a2315f0 --- /dev/null +++ b/certifier/proof.json @@ -0,0 +1,14 @@ +{ + "proof": { + "nonce": 77, + "pow": 1234, + "indices": "hBGTHs44tav7YR87sRVafuzZwObCZnK1Z/exYpxwqSQ=" + }, + "metadata": { + "node_id": "hBGTHs44tav7YR87sRVafuzZwObCZnK1Z/exYpxwqSQ=", + "challenge": "hBGTHs44tav7YR87sRVafuzZwObCZnK1Z/exYpxwqSQ=", + "commitment_atx_id": "ZuxocVjIYWfv7A/K1Lmm8+mNsHzAZaWVpbl5+KINx+I=", + "num_units": 1, + "labels_per_unit": 65536 + } +} \ No newline at end of file diff --git a/certifier/src/certifier.rs b/certifier/src/certifier.rs new file mode 100644 index 00000000..5f5a78c0 --- /dev/null +++ b/certifier/src/certifier.rs @@ -0,0 +1,76 @@ +use std::sync::Arc; + +use axum::{extract::State, Json}; +use axum::{routing::post, Router}; +use ed25519_dalek::{Signer, SigningKey}; +use post::pow::randomx::{PoW, RandomXFlag}; +use post::verification::{Verifier, VerifyingParams}; +use serde::{Deserialize, Serialize}; +use serde_with::{base64::Base64, serde_as}; +use tracing::instrument; + +#[derive(Debug, Deserialize)] +struct CertifyRequest { + proof: post::prove::Proof<'static>, + metadata: post::metadata::ProofMetadata, +} + +#[serde_as] +#[derive(Debug, Serialize)] +struct CertifyResponse { + #[serde_as(as = "Base64")] + signature: Vec, + #[serde_as(as = "Base64")] + pub_key: Vec, +} + +#[instrument(skip(state))] +async fn certify( + State(state): State>, + Json(request): Json, +) -> Result, String> { + tracing::debug!("certifying"); + + let pub_key = request.metadata.node_id; + let s = state.clone(); + let result = tokio::task::spawn_blocking(move || { + s.verifier.verify( + &request.proof, + &request.metadata, + VerifyingParams::new(&request.metadata, &s.cfg).unwrap(), + ) + }) + .await; + match result { + Err(e) => return Err(format!("internal error verifying proof: {e:?}")), + Ok(Err(e)) => return Err(format!("invalid proof: {e:?}")), + _ => {} + } + + // Sign the nodeID + let response = CertifyResponse { + signature: state.signer.sign(&pub_key).to_vec(), + pub_key: state.signer.verifying_key().to_bytes().to_vec(), + }; + Ok(Json(response)) +} + +struct AppState { + verifier: Verifier, + cfg: post::config::Config, + signer: SigningKey, +} + +pub fn new(cfg: post::config::Config, signer: SigningKey) -> Router { + let state = AppState { + verifier: Verifier::new(Box::new( + PoW::new(RandomXFlag::get_recommended_flags()).expect("creating RandomX PoW verifier"), + )), + cfg, + signer, + }; + + Router::new() + .route("/certify", post(certify)) + .with_state(Arc::new(state)) +} diff --git a/certifier/src/configuration.rs b/certifier/src/configuration.rs new file mode 100644 index 00000000..dd3c3ead --- /dev/null +++ b/certifier/src/configuration.rs @@ -0,0 +1,25 @@ +use std::path::Path; + +use ed25519_dalek::SecretKey; +use serde_with::{base64::Base64, serde_as}; +use tracing::info; + +#[serde_as] +#[derive(serde::Deserialize, Clone)] +pub struct Config { + pub listen: std::net::SocketAddr, + #[serde_as(as = "Base64")] + pub signing_key: SecretKey, + pub post_cfg: post::config::Config, +} + +pub fn get_configuration(config_path: &Path) -> Result { + info!("loading configuration from {config_path:?}"); + + let config = config::Config::builder() + .add_source(config::File::from(config_path).required(true)) + .add_source(config::Environment::with_prefix("CERTIFIER").try_parsing(true)) + .build()?; + + config.try_deserialize() +} diff --git a/certifier/src/lib.rs b/certifier/src/lib.rs new file mode 100644 index 00000000..4b79f41b --- /dev/null +++ b/certifier/src/lib.rs @@ -0,0 +1,2 @@ +pub mod certifier; +pub mod configuration; diff --git a/certifier/src/main.rs b/certifier/src/main.rs new file mode 100644 index 00000000..2541483a --- /dev/null +++ b/certifier/src/main.rs @@ -0,0 +1,83 @@ +use std::path::PathBuf; + +use clap::{arg, Parser, Subcommand}; +use ed25519_dalek::SigningKey; +use tracing::info; +use tracing_log::LogTracer; +use tracing_subscriber::{EnvFilter, FmtSubscriber}; + +#[derive(Parser, Debug)] +#[command(version)] +struct Cli { + #[arg( + short, + long, + default_value = "config.yml", + env("CERTIFIER_CONFIG_PATH") + )] + config_path: PathBuf, + + #[command(subcommand)] + cmd: Option, +} + +#[derive(Subcommand, Debug)] +enum Commands { + /// generate keypair and write it to standard out. + /// the keypair is encoded as json + GenerateKeys, +} + +fn generate_keys() -> Result<(), Box> { + let signing_key: SigningKey = SigningKey::generate(&mut rand::rngs::OsRng); + + #[serde_with::serde_as] + #[derive(serde::Serialize)] + struct KeyPair { + #[serde_as(as = "serde_with::base64::Base64")] + public_key: [u8; ed25519_dalek::PUBLIC_KEY_LENGTH], + #[serde_as(as = "serde_with::base64::Base64")] + secret_key: [u8; ed25519_dalek::SECRET_KEY_LENGTH], + } + + let keypair = KeyPair { + public_key: signing_key.verifying_key().to_bytes(), + secret_key: signing_key.to_bytes(), + }; + + serde_json::to_writer_pretty(std::io::stdout(), &keypair)?; + Ok(()) +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let args = Cli::parse(); + + if let Some(Commands::GenerateKeys) = args.cmd { + return generate_keys(); + } + + LogTracer::init()?; + let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("INFO")); + let subscriber = FmtSubscriber::builder() + .with_env_filter(env_filter) + .finish(); + tracing::subscriber::set_global_default(subscriber)?; + + let config = certifier::configuration::get_configuration(&args.config_path)?; + let signer = SigningKey::from_bytes(&config.signing_key); + + info!( + "listening on: {:?}, pubkey: {:?}", + config.listen, + signer.verifying_key() + ); + info!("using POST configuration: {:?}", config.post_cfg); + + let app: axum::Router = certifier::certifier::new(config.post_cfg, signer); + + axum::Server::bind(&config.listen) + .serve(app.into_make_service()) + .await?; + Ok(()) +} diff --git a/src/config.rs b/src/config.rs index 65519eaf..2096df1f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,9 @@ +use serde::Deserialize; + +/// POST configuration (network parameter) #[repr(C)] -#[derive(Debug, Clone, Copy)] +#[serde_with::serde_as] +#[derive(Debug, Clone, Copy, Deserialize)] pub struct InitConfig { /// The minimal number of units that must be initialized. pub min_num_units: u32, @@ -12,7 +16,8 @@ pub struct InitConfig { } #[repr(C)] -#[derive(Debug, Clone, Copy)] +#[serde_with::serde_as] +#[derive(Debug, Clone, Copy, Deserialize)] pub struct ProofConfig { /// K1 specifies the difficulty for a label to be a candidate for a proof. pub k1: u32, @@ -22,11 +27,12 @@ pub struct ProofConfig { pub k3: u32, /// Difficulty for the nonce proof of work. Lower values increase difficulty of finding /// `pow` for [Proof][crate::prove::Proof]. + #[serde_as(as = "serde_with::hex::Hex")] pub pow_difficulty: [u8; 32], } #[repr(C)] -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Deserialize)] pub struct ScryptParams { pub n: usize, pub r: usize, diff --git a/src/metadata.rs b/src/metadata.rs index 4ef3502f..fb84521d 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -61,10 +61,14 @@ pub fn load(datadir: &Path) -> eyre::Result { } #[repr(C)] -#[derive(Debug, Clone)] +#[serde_as] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct ProofMetadata { + #[serde_as(as = "Base64")] pub node_id: [u8; 32], + #[serde_as(as = "Base64")] pub commitment_atx_id: [u8; 32], + #[serde_as(as = "Base64")] pub challenge: [u8; 32], pub num_units: u32, pub labels_per_unit: u64, diff --git a/src/prove.rs b/src/prove.rs index d74b8eda..cebcc57e 100644 --- a/src/prove.rs +++ b/src/prove.rs @@ -21,6 +21,8 @@ use eyre::Context; use primitive_types::U256; use randomx_rs::RandomXFlag; use rayon::prelude::{ParallelBridge, ParallelIterator}; +use serde::{Deserialize, Serialize}; +use serde_with::{base64::Base64, serde_as}; use crate::{ cipher::AesCipher, @@ -37,9 +39,11 @@ const BLOCK_SIZE: usize = 16; // size of the aes block const AES_BATCH: usize = 8; // will use encrypt8 asm method const CHUNK_SIZE: usize = BLOCK_SIZE * AES_BATCH; -#[derive(Debug, Clone, PartialEq, Eq)] +#[serde_as] +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] pub struct Proof<'a> { pub nonce: u32, + #[serde_as(as = "Base64")] pub indices: Cow<'a, [u8]>, pub pow: u64, } From 68b0f120ab149032327b63848bd51b73d3b9ea3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Thu, 2 Nov 2023 12:23:02 +0100 Subject: [PATCH 02/12] Build certifier-service docker image in CI --- .github/workflows/docker.yml | 12 ++++++++++-- certifier/proof.json | 14 -------------- 2 files changed, 10 insertions(+), 16 deletions(-) delete mode 100644 certifier/proof.json diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8afd8bab..a1c367ee 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -7,6 +7,14 @@ on: jobs: docker-build: + strategy: + matrix: + include: + - package: service + image: post-service + - package: certifier + image: certifier-service + runs-on: ubuntu-latest steps: - name: Git Checkout @@ -27,7 +35,7 @@ jobs: uses: docker/build-push-action@v5 with: context: . - file: ./service/Dockerfile + file: ./${{ matrix.package }}/Dockerfile push: true - tags: spacemeshos/post-service:latest, spacemeshos/post-service:${{ GITHUB.SHA }}, spacemeshos/post-service:${{ github.ref_name }} + tags: spacemeshos/${{ matrix.image }}:latest, spacemeshos/${{ matrix.image }}:${{ GITHUB.SHA }}, spacemeshos/${{ matrix.image }}:${{ github.ref_name }} diff --git a/certifier/proof.json b/certifier/proof.json deleted file mode 100644 index 9a2315f0..00000000 --- a/certifier/proof.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "proof": { - "nonce": 77, - "pow": 1234, - "indices": "hBGTHs44tav7YR87sRVafuzZwObCZnK1Z/exYpxwqSQ=" - }, - "metadata": { - "node_id": "hBGTHs44tav7YR87sRVafuzZwObCZnK1Z/exYpxwqSQ=", - "challenge": "hBGTHs44tav7YR87sRVafuzZwObCZnK1Z/exYpxwqSQ=", - "commitment_atx_id": "ZuxocVjIYWfv7A/K1Lmm8+mNsHzAZaWVpbl5+KINx+I=", - "num_units": 1, - "labels_per_unit": 65536 - } -} \ No newline at end of file From add0b2d3ab87283101298796b93960f5597ba434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Thu, 2 Nov 2023 13:13:34 +0100 Subject: [PATCH 03/12] Fix logging certifier pubkey --- Cargo.lock | 15 ++++++++------- certifier/Cargo.toml | 1 + certifier/src/main.rs | 8 +++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e48b3b63..5db759f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -269,9 +269,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.3" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "base64ct" @@ -442,6 +442,7 @@ name = "certifier" version = "0.1.0" dependencies = [ "axum", + "base64 0.21.5", "clap 4.4.7", "config", "ed25519-dalek", @@ -1450,7 +1451,7 @@ dependencies = [ name = "initializer" version = "0.5.2" dependencies = [ - "base64 0.21.3", + "base64 0.21.5", "clap 4.4.7", "env_logger", "eyre", @@ -1931,7 +1932,7 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3163d2912b7c3b52d651a055f2c7eec9ba5cd22d26ef75b8dd3a59980b185923" dependencies = [ - "base64 0.21.3", + "base64 0.21.5", "serde", ] @@ -2643,7 +2644,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.3", + "base64 0.21.5", ] [[package]] @@ -2826,7 +2827,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" dependencies = [ - "base64 0.21.3", + "base64 0.21.5", "chrono", "hex", "indexmap 1.9.3", @@ -3279,7 +3280,7 @@ dependencies = [ "async-stream", "async-trait", "axum", - "base64 0.21.3", + "base64 0.21.5", "bytes", "h2", "http", diff --git a/certifier/Cargo.toml b/certifier/Cargo.toml index 55bbe582..ceb2a185 100644 --- a/certifier/Cargo.toml +++ b/certifier/Cargo.toml @@ -24,3 +24,4 @@ tracing-log = "0.2.0" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } rand = "0.8.5" serde_json = "1.0.108" +base64 = "0.21.5" diff --git a/certifier/src/main.rs b/certifier/src/main.rs index 2541483a..ee504adf 100644 --- a/certifier/src/main.rs +++ b/certifier/src/main.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; +use base64::{engine::general_purpose, Engine as _}; use clap::{arg, Parser, Subcommand}; use ed25519_dalek::SigningKey; use tracing::info; @@ -66,12 +67,9 @@ async fn main() -> Result<(), Box> { let config = certifier::configuration::get_configuration(&args.config_path)?; let signer = SigningKey::from_bytes(&config.signing_key); + let pubkey_b64 = general_purpose::STANDARD.encode(signer.verifying_key().as_bytes()); - info!( - "listening on: {:?}, pubkey: {:?}", - config.listen, - signer.verifying_key() - ); + info!("listening on: {:?}, pubkey: {}", config.listen, pubkey_b64,); info!("using POST configuration: {:?}", config.post_cfg); let app: axum::Router = certifier::certifier::new(config.post_cfg, signer); From 9f508ca4b9da6799f17a07c76b84578234cb9dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Thu, 2 Nov 2023 16:12:36 +0100 Subject: [PATCH 04/12] Enable axum metrics via prometheus --- Cargo.lock | 164 +++++++++++++++++++++++++++++++++ certifier/Cargo.toml | 1 + certifier/src/configuration.rs | 5 + certifier/src/main.rs | 16 +++- 4 files changed, 185 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 5db759f7..201c1711 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,6 +246,29 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-prometheus" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97def327c5481791abb57ac295bfc70f2e1a0727675b7dbf74bd1b27a72b6fd8" +dependencies = [ + "axum", + "axum-core", + "bytes", + "futures 0.3.28", + "futures-core", + "http", + "http-body", + "matchit", + "metrics", + "metrics-exporter-prometheus", + "once_cell", + "pin-project", + "tokio", + "tower", + "tower-http", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -442,6 +465,7 @@ name = "certifier" version = "0.1.0" dependencies = [ "axum", + "axum-prometheus", "base64 0.21.5", "clap 4.4.7", "config", @@ -1243,6 +1267,15 @@ dependencies = [ "ahash 0.7.7", ] +[[package]] +name = "hashbrown" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" +dependencies = [ + "ahash 0.8.3", +] + [[package]] name = "hashbrown" version = "0.14.0" @@ -1298,6 +1331,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + [[package]] name = "httparse" version = "1.8.0" @@ -1471,6 +1510,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "is-terminal" version = "0.4.9" @@ -1579,6 +1624,15 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "mach2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" +dependencies = [ + "libc", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1618,6 +1672,61 @@ dependencies = [ "autocfg", ] +[[package]] +name = "metrics" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde3af1a009ed76a778cb84fdef9e7dbbdf5775ae3e4cc1f434a6a307f6f76c5" +dependencies = [ + "ahash 0.8.3", + "metrics-macros", + "portable-atomic", +] + +[[package]] +name = "metrics-exporter-prometheus" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a4964177ddfdab1e3a2b37aec7cf320e14169abb0ed73999f558136409178d5" +dependencies = [ + "base64 0.21.5", + "hyper", + "indexmap 1.9.3", + "ipnet", + "metrics", + "metrics-util", + "quanta", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "metrics-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddece26afd34c31585c74a4db0630c376df271c285d682d1e55012197830b6df" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "metrics-util" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4de2ed6e491ed114b40b732e4d1659a9d53992ebd87490c44a6ffe23739d973e" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "hashbrown 0.13.1", + "metrics", + "num_cpus", + "quanta", + "sketches-ddsketch", +] + [[package]] name = "mime" version = "0.3.17" @@ -2073,6 +2182,12 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "portable-atomic" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" + [[package]] name = "post-cbindings" version = "0.5.2" @@ -2304,6 +2419,22 @@ dependencies = [ "prost", ] +[[package]] +name = "quanta" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +dependencies = [ + "crossbeam-utils", + "libc", + "mach2", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -2393,6 +2524,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "raw-cpuid" +version = "10.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "rayon" version = "1.7.0" @@ -2917,6 +3057,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +[[package]] +name = "sketches-ddsketch" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a406c1882ed7f29cd5e248c9848a80e7cb6ae0fea82346d2746f2f941c07e1" + [[package]] name = "slab" version = "0.4.9" @@ -3333,6 +3479,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +dependencies = [ + "bitflags 2.4.0", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.2" diff --git a/certifier/Cargo.toml b/certifier/Cargo.toml index ceb2a185..699420b3 100644 --- a/certifier/Cargo.toml +++ b/certifier/Cargo.toml @@ -25,3 +25,4 @@ tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } rand = "0.8.5" serde_json = "1.0.108" base64 = "0.21.5" +axum-prometheus = "0.4.0" diff --git a/certifier/src/configuration.rs b/certifier/src/configuration.rs index dd3c3ead..6442e559 100644 --- a/certifier/src/configuration.rs +++ b/certifier/src/configuration.rs @@ -9,8 +9,13 @@ use tracing::info; pub struct Config { pub listen: std::net::SocketAddr, #[serde_as(as = "Base64")] + /// The base64-encoded secret key used to sign the proofs. + /// It's 256-bit key as defined in [RFC8032 § 5.1.5]. pub signing_key: SecretKey, pub post_cfg: post::config::Config, + + /// Whether to enable metrics on /metrics. + pub metrics: bool, } pub fn get_configuration(config_path: &Path) -> Result { diff --git a/certifier/src/main.rs b/certifier/src/main.rs index ee504adf..4fa583c5 100644 --- a/certifier/src/main.rs +++ b/certifier/src/main.rs @@ -1,5 +1,7 @@ use std::path::PathBuf; +use axum::routing::get; +use axum_prometheus::PrometheusMetricLayerBuilder; use base64::{engine::general_purpose, Engine as _}; use clap::{arg, Parser, Subcommand}; use ed25519_dalek::SigningKey; @@ -72,7 +74,19 @@ async fn main() -> Result<(), Box> { info!("listening on: {:?}, pubkey: {}", config.listen, pubkey_b64,); info!("using POST configuration: {:?}", config.post_cfg); - let app: axum::Router = certifier::certifier::new(config.post_cfg, signer); + let mut app = certifier::certifier::new(config.post_cfg, signer); + + if config.metrics { + info!("metrics on: {}/metrics", config.listen.to_string()); + let (metric_layer, metric_handle) = PrometheusMetricLayerBuilder::new() + .with_prefix("certifier") + .with_ignore_patterns(&["/metrics"]) + .with_default_metrics() + .build_pair(); + app = app + .route("/metrics", get(|| async move { metric_handle.render() })) + .layer(metric_layer); + } axum::Server::bind(&config.listen) .serve(app.into_make_service()) From 8d493f1020341e2dbc987223244a28634695c34d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Fri, 3 Nov 2023 09:16:25 +0100 Subject: [PATCH 05/12] wip - certifier returns proper status codes --- certifier/src/certifier.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/certifier/src/certifier.rs b/certifier/src/certifier.rs index 5f5a78c0..6fb2ac9a 100644 --- a/certifier/src/certifier.rs +++ b/certifier/src/certifier.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use axum::http::StatusCode; use axum::{extract::State, Json}; use axum::{routing::post, Router}; use ed25519_dalek::{Signer, SigningKey}; @@ -28,22 +29,28 @@ struct CertifyResponse { async fn certify( State(state): State>, Json(request): Json, -) -> Result, String> { +) -> Result, (StatusCode, String)> { tracing::debug!("certifying"); let pub_key = request.metadata.node_id; let s = state.clone(); + + let params = match VerifyingParams::new(&request.metadata, &s.cfg) { + Ok(params) => params, + Err(e) => return Err((StatusCode::BAD_REQUEST, format!("invalid metadata: {e:?}"))), + }; let result = tokio::task::spawn_blocking(move || { - s.verifier.verify( - &request.proof, - &request.metadata, - VerifyingParams::new(&request.metadata, &s.cfg).unwrap(), - ) + s.verifier.verify(&request.proof, &request.metadata, params) }) .await; match result { - Err(e) => return Err(format!("internal error verifying proof: {e:?}")), - Ok(Err(e)) => return Err(format!("invalid proof: {e:?}")), + Err(e) => { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + format!("internal error verifying proof: {e:?}"), + )) + } + Ok(Err(e)) => return Err((StatusCode::FORBIDDEN, format!("invalid proof: {e:?}"))), _ => {} } From 58d4d17566b4353580a6f70f182523f06538ce01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Fri, 3 Nov 2023 15:15:40 +0100 Subject: [PATCH 06/12] Adjust code to new config --- certifier/mainnet.yml | 11 ---------- certifier/src/certifier.rs | 37 +++++++++++++++++----------------- certifier/src/configuration.rs | 3 ++- certifier/src/main.rs | 2 +- 4 files changed, 21 insertions(+), 32 deletions(-) delete mode 100644 certifier/mainnet.yml diff --git a/certifier/mainnet.yml b/certifier/mainnet.yml deleted file mode 100644 index 14a3ee91..00000000 --- a/certifier/mainnet.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Mainnet configuration -listen: "0.0.0.0:80" -post_cfg: - k1: 26 - k2: 37 - k3: 37 - pow_difficulty: "000dfb23b0979b4b000000000000000000000000000000000000000000000000" - scrypt: - n: 8192 - r: 1 - p: 1 diff --git a/certifier/src/certifier.rs b/certifier/src/certifier.rs index 6fb2ac9a..5eff3c34 100644 --- a/certifier/src/certifier.rs +++ b/certifier/src/certifier.rs @@ -4,8 +4,9 @@ use axum::http::StatusCode; use axum::{extract::State, Json}; use axum::{routing::post, Router}; use ed25519_dalek::{Signer, SigningKey}; +use post::config::{InitConfig, ProofConfig}; use post::pow::randomx::{PoW, RandomXFlag}; -use post::verification::{Verifier, VerifyingParams}; +use post::verification::Verifier; use serde::{Deserialize, Serialize}; use serde_with::{base64::Base64, serde_as}; use tracing::instrument; @@ -35,24 +36,20 @@ async fn certify( let pub_key = request.metadata.node_id; let s = state.clone(); - let params = match VerifyingParams::new(&request.metadata, &s.cfg) { - Ok(params) => params, - Err(e) => return Err((StatusCode::BAD_REQUEST, format!("invalid metadata: {e:?}"))), - }; let result = tokio::task::spawn_blocking(move || { - s.verifier.verify(&request.proof, &request.metadata, params) + s.verifier + .verify(&request.proof, &request.metadata, &s.cfg, &s.init_cfg) }) - .await; - match result { - Err(e) => { - return Err(( - StatusCode::INTERNAL_SERVER_ERROR, - format!("internal error verifying proof: {e:?}"), - )) - } - Ok(Err(e)) => return Err((StatusCode::FORBIDDEN, format!("invalid proof: {e:?}"))), - _ => {} - } + .await + .map_err(|e| { + tracing::error!("internal error verifying proof: {e:?}"); + ( + StatusCode::INTERNAL_SERVER_ERROR, + "error verifying proof".into(), + ) + })?; + + result.map_err(|e| (StatusCode::FORBIDDEN, format!("invalid proof: {e:?}")))?; // Sign the nodeID let response = CertifyResponse { @@ -64,16 +61,18 @@ async fn certify( struct AppState { verifier: Verifier, - cfg: post::config::Config, + cfg: ProofConfig, + init_cfg: InitConfig, signer: SigningKey, } -pub fn new(cfg: post::config::Config, signer: SigningKey) -> Router { +pub fn new(cfg: ProofConfig, init_cfg: InitConfig, signer: SigningKey) -> Router { let state = AppState { verifier: Verifier::new(Box::new( PoW::new(RandomXFlag::get_recommended_flags()).expect("creating RandomX PoW verifier"), )), cfg, + init_cfg, signer, }; diff --git a/certifier/src/configuration.rs b/certifier/src/configuration.rs index 6442e559..5f78c12d 100644 --- a/certifier/src/configuration.rs +++ b/certifier/src/configuration.rs @@ -12,7 +12,8 @@ pub struct Config { /// The base64-encoded secret key used to sign the proofs. /// It's 256-bit key as defined in [RFC8032 § 5.1.5]. pub signing_key: SecretKey, - pub post_cfg: post::config::Config, + pub post_cfg: post::config::ProofConfig, + pub init_cfg: post::config::InitConfig, /// Whether to enable metrics on /metrics. pub metrics: bool, diff --git a/certifier/src/main.rs b/certifier/src/main.rs index 4fa583c5..0b597335 100644 --- a/certifier/src/main.rs +++ b/certifier/src/main.rs @@ -74,7 +74,7 @@ async fn main() -> Result<(), Box> { info!("listening on: {:?}, pubkey: {}", config.listen, pubkey_b64,); info!("using POST configuration: {:?}", config.post_cfg); - let mut app = certifier::certifier::new(config.post_cfg, signer); + let mut app = certifier::certifier::new(config.post_cfg, config.init_cfg, signer); if config.metrics { info!("metrics on: {}/metrics", config.listen.to_string()); From 3e69712b2dc5b6aab89d76b8aac51f1841cb48ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Fri, 3 Nov 2023 16:41:13 +0100 Subject: [PATCH 07/12] Integration test for certifying --- Cargo.lock | 322 +++++++++++++++++++++++++++++++- certifier/Cargo.toml | 4 + certifier/src/certifier.rs | 8 +- certifier/tests/test_certify.rs | 80 ++++++++ 4 files changed, 402 insertions(+), 12 deletions(-) create mode 100644 certifier/tests/test_certify.rs diff --git a/Cargo.lock b/Cargo.lock index 201c1711..5f366808 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -473,10 +473,12 @@ dependencies = [ "hex", "post-rs", "rand", + "reqwest", "secrecy", "serde", "serde_json", "serde_with 3.4.0", + "tempfile", "tokio", "tracing", "tracing-log 0.2.0", @@ -669,6 +671,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -962,6 +974,15 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + [[package]] name = "enum_primitive" version = "0.1.1" @@ -1078,6 +1099,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.0" @@ -1391,6 +1427,19 @@ dependencies = [ "tokio-io-timeout", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -1420,6 +1469,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "impl-codec" version = "0.6.0" @@ -1576,9 +1635,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libloading" @@ -1792,6 +1851,24 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nix" version = "0.26.4" @@ -1952,6 +2029,50 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "openssl" +version = "0.10.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" +dependencies = [ + "bitflags 2.4.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "ordered-multimap" version = "0.4.3" @@ -2018,7 +2139,7 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", "windows-targets", ] @@ -2148,6 +2269,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + [[package]] name = "platforms" version = "3.1.2" @@ -2576,6 +2703,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "regex" version = "1.9.4" @@ -2626,6 +2762,44 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c707298afce11da2efef2f600116fa93ffa7a032b5d7b628aa17711ec81383ca" +[[package]] +name = "reqwest" +version = "0.11.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +dependencies = [ + "base64 0.21.5", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "rgb" version = "0.8.36" @@ -2755,9 +2929,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.13" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ "bitflags 2.4.0", "errno", @@ -2830,6 +3004,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2886,6 +3069,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.18" @@ -3210,6 +3416,27 @@ dependencies = [ "winapi", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -3218,13 +3445,13 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.4.1", "rustix", "windows-sys", ] @@ -3318,6 +3545,21 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +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.32.0" @@ -3356,6 +3598,16 @@ dependencies = [ "syn 2.0.29", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -3618,18 +3870,44 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + [[package]] name = "unicode-ident" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + [[package]] name = "untrusted" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "utf8parse" version = "0.2.1" @@ -3648,6 +3926,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -3713,6 +3997,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.87" @@ -3878,6 +4174,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys", +] + [[package]] name = "wyz" version = "0.5.1" diff --git a/certifier/Cargo.toml b/certifier/Cargo.toml index 699420b3..dd29df0b 100644 --- a/certifier/Cargo.toml +++ b/certifier/Cargo.toml @@ -26,3 +26,7 @@ rand = "0.8.5" serde_json = "1.0.108" base64 = "0.21.5" axum-prometheus = "0.4.0" + +[dev-dependencies] +reqwest = { version = "0.11.22", features = ["json"] } +tempfile = "3.8.1" diff --git a/certifier/src/certifier.rs b/certifier/src/certifier.rs index 5eff3c34..cdaa5037 100644 --- a/certifier/src/certifier.rs +++ b/certifier/src/certifier.rs @@ -11,10 +11,10 @@ use serde::{Deserialize, Serialize}; use serde_with::{base64::Base64, serde_as}; use tracing::instrument; -#[derive(Debug, Deserialize)] -struct CertifyRequest { - proof: post::prove::Proof<'static>, - metadata: post::metadata::ProofMetadata, +#[derive(Debug, Deserialize, Serialize)] +pub struct CertifyRequest { + pub proof: post::prove::Proof<'static>, + pub metadata: post::metadata::ProofMetadata, } #[serde_as] diff --git a/certifier/tests/test_certify.rs b/certifier/tests/test_certify.rs new file mode 100644 index 00000000..3cce309c --- /dev/null +++ b/certifier/tests/test_certify.rs @@ -0,0 +1,80 @@ +use std::sync::atomic::AtomicBool; + +use certifier::certifier::CertifyRequest; +use ed25519_dalek::SigningKey; +use post::{ + config::{InitConfig, ProofConfig, ScryptParams}, + initialize::{CpuInitializer, Initialize}, + metadata::ProofMetadata, + pow::randomx::RandomXFlag, + prove::generate_proof, +}; +use reqwest::StatusCode; + +#[tokio::test] +async fn test_certificate_post_proof() { + // Initialize some data + let challenge = b"hello world, challenge me!!!!!!!"; + let datadir = tempfile::tempdir().unwrap(); + + let cfg = ProofConfig { + k1: 20, + k2: 10, + k3: 10, + pow_difficulty: [0xFF; 32], + }; + let init_cfg = InitConfig { + min_num_units: 1, + max_num_units: 1000, + labels_per_unit: 200, + scrypt: ScryptParams::new(2, 1, 1), + }; + + let metadata = CpuInitializer::new(init_cfg.scrypt) + .initialize( + datadir.path(), + &[0u8; 32], + &[0u8; 32], + init_cfg.labels_per_unit, + 2, + init_cfg.labels_per_unit, + None, + ) + .unwrap(); + + // Generate a proof + let pow_flags = RandomXFlag::get_recommended_flags(); + let stop = AtomicBool::new(false); + let proof = generate_proof(datadir.path(), challenge, cfg, 32, 1, pow_flags, stop).unwrap(); + let metadata = ProofMetadata::new(metadata, *challenge); + + // Spawn the certifier service + let signer = SigningKey::generate(&mut rand::rngs::OsRng); + let app = certifier::certifier::new(cfg, init_cfg, signer); + let server = axum::Server::bind(&"127.0.0.1:0".parse().unwrap()).serve(app.into_make_service()); + let addr = server.local_addr(); + tokio::spawn(server); + + let client = reqwest::Client::new(); + + // Certify with a valid proof + let req = CertifyRequest { proof, metadata }; + let response = client + .post(format!("http://{addr}/certify")) + .json(&req) + .send() + .await + .unwrap(); + assert!(response.status().is_success()); + + // Try to certify with an invalid proof + let mut invalid_req = req; + invalid_req.metadata.labels_per_unit = 2; + let response = client + .post(format!("http://{addr}/certify")) + .json(&invalid_req) + .send() + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::FORBIDDEN); +} From 152f4dd910dbb678fb93ea7233b313f8b382fae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Mon, 6 Nov 2023 10:12:49 +0100 Subject: [PATCH 08/12] Serve metrics on different port --- certifier/src/configuration.rs | 5 +++-- certifier/src/main.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/certifier/src/configuration.rs b/certifier/src/configuration.rs index 5f78c12d..f34bafa2 100644 --- a/certifier/src/configuration.rs +++ b/certifier/src/configuration.rs @@ -15,8 +15,9 @@ pub struct Config { pub post_cfg: post::config::ProofConfig, pub init_cfg: post::config::InitConfig, - /// Whether to enable metrics on /metrics. - pub metrics: bool, + /// Address to expose metrics on. + /// Metrics are disabled if not configured. + pub metrics: Option, } pub fn get_configuration(config_path: &Path) -> Result { diff --git a/certifier/src/main.rs b/certifier/src/main.rs index 0b597335..9f228c59 100644 --- a/certifier/src/main.rs +++ b/certifier/src/main.rs @@ -76,16 +76,16 @@ async fn main() -> Result<(), Box> { let mut app = certifier::certifier::new(config.post_cfg, config.init_cfg, signer); - if config.metrics { - info!("metrics on: {}/metrics", config.listen.to_string()); - let (metric_layer, metric_handle) = PrometheusMetricLayerBuilder::new() + if let Some(addr) = config.metrics { + info!("metrics enabled on: http://{addr:?}/metrics"); + let (layer, handle) = PrometheusMetricLayerBuilder::new() .with_prefix("certifier") - .with_ignore_patterns(&["/metrics"]) .with_default_metrics() .build_pair(); - app = app - .route("/metrics", get(|| async move { metric_handle.render() })) - .layer(metric_layer); + + app = app.layer(layer); + let metrics = axum::Router::new().route("/metrics", get(|| async move { handle.render() })); + tokio::spawn(axum::Server::bind(&addr).serve(metrics.into_make_service())); } axum::Server::bind(&config.listen) From 15418783619999cac3fc4f9322073372c297470f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Mon, 6 Nov 2023 10:17:43 +0100 Subject: [PATCH 09/12] Rename --config-path to --config --- certifier/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certifier/src/main.rs b/certifier/src/main.rs index 9f228c59..4ab213de 100644 --- a/certifier/src/main.rs +++ b/certifier/src/main.rs @@ -18,7 +18,7 @@ struct Cli { default_value = "config.yml", env("CERTIFIER_CONFIG_PATH") )] - config_path: PathBuf, + config: PathBuf, #[command(subcommand)] cmd: Option, @@ -67,7 +67,7 @@ async fn main() -> Result<(), Box> { .finish(); tracing::subscriber::set_global_default(subscriber)?; - let config = certifier::configuration::get_configuration(&args.config_path)?; + let config = certifier::configuration::get_configuration(&args.config)?; let signer = SigningKey::from_bytes(&config.signing_key); let pubkey_b64 = general_purpose::STANDARD.encode(signer.verifying_key().as_bytes()); From 4d14816c95920e0d459f2b04400bc949fb78c1de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Mon, 6 Nov 2023 16:01:46 +0100 Subject: [PATCH 10/12] Log k2pow nonce-group and difficulty on debug --- src/verification.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/verification.rs b/src/verification.rs index fbc4bd34..9d317c20 100644 --- a/src/verification.rs +++ b/src/verification.rs @@ -39,6 +39,7 @@ use std::cmp::Ordering; use cipher::BlockEncrypt; use itertools::Itertools; +use log::debug; use crate::{ cipher::AesCipher, @@ -148,6 +149,10 @@ impl Verifier { // Verify K2 PoW let nonce_group = proof.nonce / NONCES_PER_AES; + debug!( + "verifying K2 pow for nonce group: {nonce_group} with difficulty: {:x?}", + pow_difficulty + ); self.pow_verifier.verify( proof.pow, nonce_group From 2f546b7993e1678c08cc790c765fb2a622511199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Thu, 9 Nov 2023 12:33:56 +0700 Subject: [PATCH 11/12] Remove labels_per_unit from ProofMetadata --- certifier/tests/test_certify.rs | 2 +- src/metadata.rs | 2 -- src/verification.rs | 18 ------------------ 3 files changed, 1 insertion(+), 21 deletions(-) diff --git a/certifier/tests/test_certify.rs b/certifier/tests/test_certify.rs index 3cce309c..53023479 100644 --- a/certifier/tests/test_certify.rs +++ b/certifier/tests/test_certify.rs @@ -69,7 +69,7 @@ async fn test_certificate_post_proof() { // Try to certify with an invalid proof let mut invalid_req = req; - invalid_req.metadata.labels_per_unit = 2; + invalid_req.metadata.num_units = 8; let response = client .post(format!("http://{addr}/certify")) .json(&invalid_req) diff --git a/src/metadata.rs b/src/metadata.rs index fb84521d..892bc6f8 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -71,7 +71,6 @@ pub struct ProofMetadata { #[serde_as(as = "Base64")] pub challenge: [u8; 32], pub num_units: u32, - pub labels_per_unit: u64, } impl ProofMetadata { @@ -81,7 +80,6 @@ impl ProofMetadata { node_id: post_metadata.node_id, commitment_atx_id: post_metadata.commitment_atx_id, num_units: post_metadata.num_units, - labels_per_unit: post_metadata.labels_per_unit, } } } diff --git a/src/verification.rs b/src/verification.rs index 9d317c20..7d46dda2 100644 --- a/src/verification.rs +++ b/src/verification.rs @@ -93,8 +93,6 @@ pub enum MetadataValidationError { NumUnitsTooSmall { min: u32, got: u32 }, #[error("numunits too large: {got} < {max}")] NumUnitsTooLarge { max: u32, got: u32 }, - #[error("invalid labels_per_unit: {got} != {expected}")] - LabelsPerUnitInvalid { expected: u64, got: u64 }, } pub fn verify_metadata( @@ -113,12 +111,6 @@ pub fn verify_metadata( got: metadata.num_units, }); } - if metadata.labels_per_unit != init_cfg.labels_per_unit { - return Err(MetadataValidationError::LabelsPerUnitInvalid { - expected: init_cfg.labels_per_unit, - got: metadata.labels_per_unit, - }); - } Ok(()) } @@ -301,7 +293,6 @@ mod tests { commitment_atx_id: [0; 32], challenge: [0; 32], num_units: 10, - labels_per_unit: 2048, }; let mut pow_verifier = Box::new(MockPowVerifier::new()); pow_verifier @@ -341,7 +332,6 @@ mod tests { commitment_atx_id: [0u8; 32], challenge: [0u8; 32], num_units: 10, - labels_per_unit: 2048, }; let mut pow_verifier = Box::new(MockPowVerifier::new()); pow_verifier @@ -397,7 +387,6 @@ mod tests { commitment_atx_id: [0; 32], challenge: [0; 32], num_units: 1, - labels_per_unit: 100, }; let init_cfg = InitConfig { min_num_units: 1, @@ -420,12 +409,5 @@ mod tests { }; assert!(super::verify_metadata(&num_units_large, &init_cfg).is_err()); } - { - let invalid_labels_per_unit = ProofMetadata { - labels_per_unit: 99, - ..valid_meta - }; - assert!(super::verify_metadata(&invalid_labels_per_unit, &init_cfg).is_err()); - } } } From bdbae9e09190a91d130fa6739493e391e0403a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Thu, 9 Nov 2023 14:25:00 +0700 Subject: [PATCH 12/12] Added readme --- certifier/README.md | 65 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 certifier/README.md diff --git a/certifier/README.md b/certifier/README.md new file mode 100644 index 00000000..d37d9094 --- /dev/null +++ b/certifier/README.md @@ -0,0 +1,65 @@ +# POST certifier service +A certifier service that creates certificates for a node confirming it holds a valid POST proof. + +The client (presumably the spacemesh node) submits a POST proof with its metadata to the certifier on /certify HTTP endpoint. The certifier validates the proof and, if valid - signs the nodeID and returns the signature. If the proof is invalid it returns a 403 status code. + +The client can later use this certificate to register in a poet. The poet is supposed to know the certifier's public key and verify the signature over a node ID. + +## Usage +``` +Usage: certifier [OPTIONS] [COMMAND] + +Commands: + generate-keys generate keypair and write it to standard out. the keypair is encoded as json + help Print this message or the help of the given subcommand(s) + +Options: + -c, --config [env: CERTIFIER_CONFIG_PATH=] [default: config.yml] + -h, --help Print help + -V, --version Print version +``` + +### running a service +To run a service, execute the certifier w/o additional command and provide a path to config (either via --config or CERTIFIER_CONFIG_PATH env variable). + +#### Configuration +The config structure is defined [here](src/configuration.rs). An example config: + +```yaml +listen: "127.0.0.1:8080" +signing_key: +post_cfg: + k1: 26 + k2: 37 + k3: 37 + pow_difficulty: "000dfb23b0979b4b000000000000000000000000000000000000000000000000" + +init_cfg: + min_num_units: 4 + max_num_units: 99999 + labels_per_unit: 4294967296 + scrypt: + n: 8192 + r: 1 + p: 1 + +metrics: "127.0.0.1:9090" +``` + +Each field can also be provided as env variable prefixed with CERTIFIER. For example, `CERTIFIER_SIGNING_KEY`. + +#### Docker +There is a docker image created to simplify deployment: `spacemeshos/certifier-service`. + +### Generating keys +Run `certifier generate-keys` to obtain randomly generated new keys. +```sh +❯ certifier generate-keys +{ + "public_key": "N2QnP1E3QmrPIjHt8QPvQXThNjDVKfatr0ncttXn7+Q=", + "secret_key": "DoU0xoVZ1gf/FDvz4K9PldiYCCeiFPhQmWbHd+X6Yjo=" +} +``` + +## Log level +The log level can be controlled via `RUST_LOG` enviroment variable. It can be set to [error, warn, info, debug, trace, off]. \ No newline at end of file