From 18c3cc4dd91cef196e678d0ade88f3f5e500a4e8 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Wed, 25 Dec 2024 13:24:21 -0500 Subject: [PATCH 1/4] feat: migrate blueprint-manager --- Cargo.lock | 959 ++---------------- Cargo.toml | 1 + crates/blueprint/Cargo.toml | 1 + crates/blueprint/manager/CHANGELOG.md | 87 ++ crates/blueprint/manager/Cargo.toml | 46 + crates/blueprint/manager/src/config.rs | 31 + crates/blueprint/manager/src/error.rs | 30 + .../manager/src/executor/event_handler.rs | 379 +++++++ crates/blueprint/manager/src/executor/mod.rs | 332 ++++++ crates/blueprint/manager/src/gadget/mod.rs | 7 + crates/blueprint/manager/src/gadget/native.rs | 37 + crates/blueprint/manager/src/lib.rs | 16 + crates/blueprint/manager/src/main.rs | 38 + .../blueprint/manager/src/protocols/config.rs | 14 + crates/blueprint/manager/src/protocols/mod.rs | 2 + .../manager/src/protocols/resolver.rs | 14 + crates/blueprint/manager/src/sdk/config.rs | 16 + crates/blueprint/manager/src/sdk/entry.rs | 39 + crates/blueprint/manager/src/sdk/mod.rs | 3 + crates/blueprint/manager/src/sdk/utils.rs | 151 +++ .../blueprint/manager/src/sources/github.rs | 79 ++ crates/blueprint/manager/src/sources/mod.rs | 175 ++++ .../blueprint/manager/src/sources/testing.rs | 92 ++ crates/crypto/src/lib.rs | 3 + crates/crypto/tangle-pair-signer/src/lib.rs | 123 ++- .../src/tangle_pair_signer.rs | 121 --- crates/event-listeners/tangle/src/events.rs | 2 +- crates/keystore/Cargo.toml | 1 + .../keystore/src/keystore/backends/tangle.rs | 23 +- crates/keystore/src/keystore/config.rs | 2 +- 30 files changed, 1790 insertions(+), 1034 deletions(-) create mode 100644 crates/blueprint/manager/CHANGELOG.md create mode 100644 crates/blueprint/manager/Cargo.toml create mode 100644 crates/blueprint/manager/src/config.rs create mode 100644 crates/blueprint/manager/src/error.rs create mode 100644 crates/blueprint/manager/src/executor/event_handler.rs create mode 100644 crates/blueprint/manager/src/executor/mod.rs create mode 100644 crates/blueprint/manager/src/gadget/mod.rs create mode 100644 crates/blueprint/manager/src/gadget/native.rs create mode 100644 crates/blueprint/manager/src/lib.rs create mode 100644 crates/blueprint/manager/src/main.rs create mode 100644 crates/blueprint/manager/src/protocols/config.rs create mode 100644 crates/blueprint/manager/src/protocols/mod.rs create mode 100644 crates/blueprint/manager/src/protocols/resolver.rs create mode 100644 crates/blueprint/manager/src/sdk/config.rs create mode 100644 crates/blueprint/manager/src/sdk/entry.rs create mode 100644 crates/blueprint/manager/src/sdk/mod.rs create mode 100644 crates/blueprint/manager/src/sdk/utils.rs create mode 100644 crates/blueprint/manager/src/sources/github.rs create mode 100644 crates/blueprint/manager/src/sources/mod.rs create mode 100644 crates/blueprint/manager/src/sources/testing.rs delete mode 100644 crates/crypto/tangle-pair-signer/src/tangle_pair_signer.rs diff --git a/Cargo.lock b/Cargo.lock index b22430c..0ae3822 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,7 +95,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "const-random", "getrandom", "once_cell", "version_check", @@ -111,15 +110,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aligned" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "377e4c0ba83e4431b10df45c1d4666f178ea9c552cac93e60c3a88bf32785923" -dependencies = [ - "as-slice", -] - [[package]] name = "allocator-api2" version = "0.2.21" @@ -1086,12 +1076,6 @@ version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" -[[package]] -name = "anymap2" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" - [[package]] name = "ark-bls12-377" version = "0.4.0" @@ -1488,15 +1472,6 @@ dependencies = [ "serde", ] -[[package]] -name = "as-slice" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" -dependencies = [ - "stable_deref_trait", -] - [[package]] name = "ascii-canvas" version = "3.0.0" @@ -1758,17 +1733,6 @@ dependencies = [ "url", ] -[[package]] -name = "auth-git2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3810b5af212b013fe7302b12d86616c6c39a48e18f2e4b812a5a9e5710213791" -dependencies = [ - "dirs", - "git2", - "terminal-prompt", -] - [[package]] name = "auto_impl" version = "1.2.0" @@ -2371,6 +2335,36 @@ dependencies = [ "gadget-std", ] +[[package]] +name = "blueprint-manager" +version = "0.2.2" +dependencies = [ + "async-trait", + "auto_impl", + "clap", + "color-eyre", + "futures", + "gadget-clients", + "gadget-config", + "gadget-crypto", + "gadget-keystore", + "gadget-logging", + "gadget-networking", + "gadget-std", + "hex", + "itertools 0.13.0", + "libp2p", + "parking_lot", + "reqwest 0.12.9", + "serde", + "sha2 0.10.8", + "tangle-subxt", + "tokio", + "toml", + "tracing", + "tracing-subscriber 0.3.19", +] + [[package]] name = "blueprint-metadata" version = "0.2.1" @@ -2390,6 +2384,7 @@ name = "blueprint-util-meta" version = "0.1.0" dependencies = [ "blueprint-build-utils", + "blueprint-manager", "blueprint-metadata", ] @@ -2465,17 +2460,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "bstr" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" -dependencies = [ - "memchr", - "regex-automata 0.4.9", - "serde", -] - [[package]] name = "bumpalo" version = "3.16.0" @@ -2558,49 +2542,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo-generate" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b611d852b731eaaf84d3dfed2cefc1468f772b403ae0499fd3436a6a2b42b273" -dependencies = [ - "anstyle", - "anyhow", - "auth-git2", - "clap", - "console", - "dialoguer", - "env_logger", - "fs-err", - "git2", - "gix-config", - "heck", - "home", - "ignore", - "indexmap 2.7.0", - "indicatif", - "liquid", - "liquid-core", - "liquid-derive", - "liquid-lib", - "log", - "names", - "openssl", - "paste", - "path-absolutize", - "regex", - "remove_dir_all", - "rhai", - "sanitize-filename", - "semver 1.0.24", - "serde", - "tempfile", - "thiserror 1.0.69", - "time", - "toml", - "walkdir", -] - [[package]] name = "cargo-platform" version = "0.1.9" @@ -2610,41 +2551,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo-tangle" -version = "0.4.0" -dependencies = [ - "alloy-json-abi", - "alloy-network 0.5.4", - "alloy-provider", - "alloy-rpc-types-eth 0.5.4", - "alloy-signer-local", - "anyhow", - "cargo-generate", - "cargo_metadata", - "clap", - "clap-cargo", - "color-eyre", - "escargot", - "gadget-blueprint-proc-macro-core", - "gadget-clients", - "gadget-crypto", - "gadget-crypto-core", - "gadget-keystore", - "gadget-logging", - "gadget-std", - "gadget-utils-tangle", - "hex", - "serde_json", - "subxt", - "tangle-subxt", - "tempfile", - "thiserror 2.0.7", - "tokio", - "tracing-subscriber 0.3.19", - "w3f-bls 0.1.8 (git+https://github.com/drewstone/bls.git?branch=drew%2Fbump-ark-versions)", -] - [[package]] name = "cargo_metadata" version = "0.18.1" @@ -2769,16 +2675,6 @@ dependencies = [ "clap_derive", ] -[[package]] -name = "clap-cargo" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b2ea69cefa96b848b73ad516ad1d59a195cdf9263087d977f648a818c8b43e" -dependencies = [ - "anstyle", - "clap", -] - [[package]] name = "clap_builder" version = "4.5.23" @@ -2927,7 +2823,7 @@ dependencies = [ "hidapi-rusb", "js-sys", "log", - "nix 0.26.4", + "nix", "once_cell", "thiserror 1.0.69", "tokio", @@ -2943,10 +2839,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" dependencies = [ "backtrace", + "color-spantrace", "eyre", "indenter", "once_cell", "owo-colors", + "tracing-error", + "url", +] + +[[package]] +name = "color-spantrace" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", ] [[package]] @@ -2980,19 +2891,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "console" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" -dependencies = [ - "encode_unicode", - "libc", - "once_cell", - "unicode-width", - "windows-sys 0.59.0", -] - [[package]] name = "const-hex" version = "1.14.0" @@ -3012,26 +2910,6 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "const-random" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" -dependencies = [ - "const-random-macro", -] - -[[package]] -name = "const-random-macro" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" -dependencies = [ - "getrandom", - "once_cell", - "tiny-keccak", -] - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -3259,15 +3137,6 @@ dependencies = [ "syn 2.0.90", ] -[[package]] -name = "cvt" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ae9bf77fbf2d39ef573205d554d87e86c12f1994e9ea335b0651b9b278bcf1" -dependencies = [ - "cfg-if", -] - [[package]] name = "darling" version = "0.14.4" @@ -3480,19 +3349,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "dialoguer" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" -dependencies = [ - "console", - "shell-words", - "tempfile", - "thiserror 1.0.69", - "zeroize", -] - [[package]] name = "digest" version = "0.9.0" @@ -3567,12 +3423,6 @@ dependencies = [ "syn 2.0.90", ] -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - [[package]] name = "docify" version = "0.2.9" @@ -3996,12 +3846,6 @@ dependencies = [ "log", ] -[[package]] -name = "encode_unicode" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" - [[package]] name = "encoding_rs" version = "0.8.35" @@ -4074,29 +3918,6 @@ dependencies = [ "syn 2.0.90", ] -[[package]] -name = "env_filter" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] - [[package]] name = "environmental" version = "1.1.4" @@ -4119,18 +3940,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "escargot" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a3ac187a16b5382fef8c69fd1bad123c67b7cf3932240a2d43dcdd32cded88" -dependencies = [ - "log", - "once_cell", - "serde", - "serde_json", -] - [[package]] name = "etcetera" version = "0.8.0" @@ -4522,12 +4331,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" -[[package]] -name = "faster-hex" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" - [[package]] name = "fastrand" version = "2.3.0" @@ -4699,20 +4502,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "fs_at" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14af6c9694ea25db25baa2a1788703b9e7c6648dcaeeebeb98f7561b5384c036" -dependencies = [ - "aligned", - "cfg-if", - "cvt", - "libc", - "nix 0.29.0", - "windows-sys 0.52.0", -] - [[package]] name = "funty" version = "2.0.0" @@ -5178,7 +4967,6 @@ dependencies = [ name = "gadget-crypto-core" version = "0.1.0" dependencies = [ - "clap", "gadget-std", "serde", "thiserror 2.0.7", @@ -5748,264 +5536,12 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "git2" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" -dependencies = [ - "bitflags 2.6.0", - "libc", - "libgit2-sys", - "log", - "openssl-probe", - "openssl-sys", - "url", -] - -[[package]] -name = "gix-actor" -version = "0.31.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e454357e34b833cc3a00b6efbbd3dd4d18b24b9fb0c023876ec2645e8aa3f2" -dependencies = [ - "bstr", - "gix-date", - "gix-utils", - "itoa", - "thiserror 1.0.69", - "winnow", -] - -[[package]] -name = "gix-config" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fafe42957e11d98e354a66b6bd70aeea00faf2f62dd11164188224a507c840" -dependencies = [ - "bstr", - "gix-config-value", - "gix-features", - "gix-glob", - "gix-path", - "gix-ref", - "gix-sec", - "memchr", - "once_cell", - "smallvec", - "thiserror 1.0.69", - "unicode-bom", - "winnow", -] - -[[package]] -name = "gix-config-value" -version = "0.14.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49aaeef5d98390a3bcf9dbc6440b520b793d1bf3ed99317dc407b02be995b28e" -dependencies = [ - "bitflags 2.6.0", - "bstr", - "gix-path", - "libc", - "thiserror 2.0.7", -] - -[[package]] -name = "gix-date" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eed6931f21491ee0aeb922751bd7ec97b4b2fe8fbfedcb678e2a2dce5f3b8c0" -dependencies = [ - "bstr", - "itoa", - "thiserror 1.0.69", - "time", -] - -[[package]] -name = "gix-features" -version = "0.38.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac7045ac9fe5f9c727f38799d002a7ed3583cd777e3322a7c4b43e3cf437dc69" -dependencies = [ - "gix-hash", - "gix-trace", - "gix-utils", - "libc", - "prodash", - "sha1_smol", - "walkdir", -] - -[[package]] -name = "gix-fs" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2bfe6249cfea6d0c0e0990d5226a4cb36f030444ba9e35e0639275db8f98575" -dependencies = [ - "fastrand", - "gix-features", - "gix-utils", -] - -[[package]] -name = "gix-glob" -version = "0.16.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74908b4bbc0a0a40852737e5d7889f676f081e340d5451a16e5b4c50d592f111" -dependencies = [ - "bitflags 2.6.0", - "bstr", - "gix-features", - "gix-path", -] - -[[package]] -name = "gix-hash" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d7df7366121b5018f947a04d37f034717e113dcf9ccd85c34b58e57a74d5e" -dependencies = [ - "faster-hex", - "thiserror 1.0.69", -] - -[[package]] -name = "gix-lock" -version = "14.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bc7fe297f1f4614774989c00ec8b1add59571dc9b024b4c00acb7dedd4e19d" -dependencies = [ - "gix-tempfile", - "gix-utils", - "thiserror 1.0.69", -] - -[[package]] -name = "gix-object" -version = "0.42.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25da2f46b4e7c2fa7b413ce4dffb87f69eaf89c2057e386491f4c55cadbfe386" -dependencies = [ - "bstr", - "gix-actor", - "gix-date", - "gix-features", - "gix-hash", - "gix-utils", - "gix-validate", - "itoa", - "smallvec", - "thiserror 1.0.69", - "winnow", -] - -[[package]] -name = "gix-path" -version = "0.10.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc292ef1a51e340aeb0e720800338c805975724c1dfbd243185452efd8645b7" -dependencies = [ - "bstr", - "gix-trace", - "home", - "once_cell", - "thiserror 2.0.7", -] - -[[package]] -name = "gix-ref" -version = "0.44.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3394a2997e5bc6b22ebc1e1a87b41eeefbcfcff3dbfa7c4bd73cb0ac8f1f3e2e" -dependencies = [ - "gix-actor", - "gix-date", - "gix-features", - "gix-fs", - "gix-hash", - "gix-lock", - "gix-object", - "gix-path", - "gix-tempfile", - "gix-utils", - "gix-validate", - "memmap2", - "thiserror 1.0.69", - "winnow", -] - -[[package]] -name = "gix-sec" -version = "0.10.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8b876ef997a955397809a2ec398d6a45b7a55b4918f2446344330f778d14fd6" -dependencies = [ - "bitflags 2.6.0", - "gix-path", - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "gix-tempfile" -version = "14.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046b4927969fa816a150a0cda2e62c80016fe11fb3c3184e4dddf4e542f108aa" -dependencies = [ - "gix-fs", - "libc", - "once_cell", - "parking_lot", - "tempfile", -] - -[[package]] -name = "gix-trace" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04bdde120c29f1fc23a24d3e115aeeea3d60d8e65bab92cc5f9d90d9302eb952" - -[[package]] -name = "gix-utils" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba427e3e9599508ed98a6ddf8ed05493db114564e338e41f6a996d2e4790335f" -dependencies = [ - "fastrand", - "unicode-normalization", -] - -[[package]] -name = "gix-validate" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c27dd34a49b1addf193c92070bcbf3beaf6e10f16a78544de6372e146a0acf" -dependencies = [ - "bstr", - "thiserror 1.0.69", -] - [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" -[[package]] -name = "globset" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - [[package]] name = "gloo-net" version = "0.5.0" @@ -6396,12 +5932,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "hyper" version = "0.14.31" @@ -6779,22 +6309,6 @@ dependencies = [ "xmltree", ] -[[package]] -name = "ignore" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata 0.4.9", - "same-file", - "walkdir", - "winapi-util", -] - [[package]] name = "impl-codec" version = "0.6.0" @@ -6865,20 +6379,7 @@ dependencies = [ name = "indexmap-nostd" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" - -[[package]] -name = "indicatif" -version = "0.17.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" -dependencies = [ - "console", - "number_prefix", - "portable-atomic", - "unicode-width", - "web-time", -] +checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "inout" @@ -7293,16 +6794,6 @@ dependencies = [ "sha3-asm", ] -[[package]] -name = "kstring" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1" -dependencies = [ - "serde", - "static_assertions", -] - [[package]] name = "lalrpop" version = "0.20.2" @@ -7345,20 +6836,6 @@ version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" -[[package]] -name = "libgit2-sys" -version = "0.17.0+1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" -dependencies = [ - "cc", - "libc", - "libssh2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", -] - [[package]] name = "libm" version = "0.2.11" @@ -7941,20 +7418,6 @@ dependencies = [ "libsecp256k1-core", ] -[[package]] -name = "libssh2-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", -] - [[package]] name = "libusb1-sys" version = "0.7.0" @@ -7967,18 +7430,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "libz-sys" -version = "1.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "linked-hash-map" version = "0.5.6" @@ -7997,63 +7448,6 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" -[[package]] -name = "liquid" -version = "0.26.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cdcc72b82748f47c2933c172313f5a9aea5b2c4eb3fa4c66b4ea55bb60bb4b1" -dependencies = [ - "doc-comment", - "liquid-core", - "liquid-derive", - "liquid-lib", - "serde", -] - -[[package]] -name = "liquid-core" -version = "0.26.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2752e978ffc53670f3f2e8b3ef09f348d6f7b5474a3be3f8a5befe5382e4effb" -dependencies = [ - "anymap2", - "itertools 0.13.0", - "kstring", - "liquid-derive", - "num-traits", - "pest", - "pest_derive", - "regex", - "serde", - "time", -] - -[[package]] -name = "liquid-derive" -version = "0.26.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b51f1d220e3fa869e24cfd75915efe3164bd09bb11b3165db3f37f57bf673e3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "liquid-lib" -version = "0.26.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b1a298d3d2287ee5b1e43840d885b8fdfc37d3f4e90d82aacfd04d021618da" -dependencies = [ - "itertools 0.13.0", - "liquid-core", - "once_cell", - "percent-encoding", - "regex", - "time", - "unicode-segmentation", -] - [[package]] name = "litemap" version = "0.7.4" @@ -8167,15 +7561,6 @@ dependencies = [ "rustix 0.38.42", ] -[[package]] -name = "memmap2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" -dependencies = [ - "libc", -] - [[package]] name = "memoffset" version = "0.7.1" @@ -8331,15 +7716,6 @@ dependencies = [ "unsigned-varint 0.7.2", ] -[[package]] -name = "names" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc" -dependencies = [ - "rand", -] - [[package]] name = "native-tls" version = "0.2.12" @@ -8441,18 +7817,6 @@ dependencies = [ "pin-utils", ] -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "cfg_aliases", - "libc", -] - [[package]] name = "no-std-net" version = "0.6.0" @@ -8481,15 +7845,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "normpath" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "ntapi" version = "0.4.1" @@ -8597,21 +7952,6 @@ dependencies = [ "syn 2.0.90", ] -[[package]] -name = "num_threads" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" -dependencies = [ - "libc", -] - -[[package]] -name = "number_prefix" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" - [[package]] name = "nybbles" version = "0.2.1" @@ -8722,15 +8062,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "openssl-src" -version = "300.4.1+3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" -dependencies = [ - "cc", -] - [[package]] name = "openssl-sys" version = "0.9.104" @@ -8739,7 +8070,6 @@ checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", - "openssl-src", "pkg-config", "vcpkg", ] @@ -8890,24 +8220,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "path-absolutize" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4af381fe79fa195b4909485d99f73a80792331df0625188e707854f0b3383f5" -dependencies = [ - "path-dedot", -] - -[[package]] -name = "path-dedot" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ba0ad7e047712414213ff67533e6dd477af0a4e1d14fb52343e53d30ea9397" -dependencies = [ - "once_cell", -] - [[package]] name = "path-slash" version = "0.2.1" @@ -8982,40 +8294,6 @@ dependencies = [ "ucd-trie", ] -[[package]] -name = "pest_derive" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "pest_meta" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" -dependencies = [ - "once_cell", - "pest", - "sha2 0.10.8", -] - [[package]] name = "petgraph" version = "0.6.5" @@ -9402,12 +8680,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prodash" -version = "28.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79" - [[package]] name = "prometheus-client" version = "0.22.3" @@ -9740,9 +9012,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -9788,20 +9060,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "remove_dir_all" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a694f9e0eb3104451127f6cc1e5de55f59d3b1fc8c5ddfaeb6f1e716479ceb4a" -dependencies = [ - "cfg-if", - "cvt", - "fs_at", - "libc", - "normpath", - "windows-sys 0.59.0", -] - [[package]] name = "reqwest" version = "0.11.27" @@ -9915,34 +9173,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "rhai" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61797318be89b1a268a018a92a7657096d83f3ecb31418b9e9c16dcbb043b702" -dependencies = [ - "ahash 0.8.11", - "bitflags 2.6.0", - "instant", - "num-traits", - "once_cell", - "rhai_codegen", - "smallvec", - "smartstring", - "thin-vec", -] - -[[package]] -name = "rhai_codegen" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5a11a05ee1ce44058fa3d5961d05194fdbe3ad6b40f904af764d81b86450e6b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "ring" version = "0.16.20" @@ -10042,7 +9272,7 @@ dependencies = [ "netlink-packet-utils", "netlink-proto", "netlink-sys", - "nix 0.26.4", + "nix", "thiserror 1.0.69", "tokio", ] @@ -10419,16 +9649,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "sanitize-filename" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "scale-bits" version = "0.6.0" @@ -10922,12 +10142,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha1_smol" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" - [[package]] name = "sha2" version = "0.9.9" @@ -10981,12 +10195,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shell-words" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" - [[package]] name = "shlex" version = "1.3.0" @@ -11060,17 +10268,6 @@ dependencies = [ "serde", ] -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - [[package]] name = "smol" version = "2.0.2" @@ -12278,14 +11475,15 @@ checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix 0.38.42", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -12308,16 +11506,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "terminal-prompt" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572818b3472910acbd5dff46a3413715c18e934b071ab2ba464a7b2c2af16376" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "terminal_size" version = "0.4.1" @@ -12357,12 +11545,6 @@ dependencies = [ "url", ] -[[package]] -name = "thin-vec" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" - [[package]] name = "thiserror" version = "1.0.69" @@ -12430,9 +11612,7 @@ checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", - "libc", "num-conv", - "num_threads", "powerfmt", "serde", "time-core", @@ -12637,7 +11817,6 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ - "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -12790,6 +11969,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" +dependencies = [ + "tracing", + "tracing-subscriber 0.3.19", +] + [[package]] name = "tracing-futures" version = "0.2.5" @@ -13049,12 +12238,6 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" -[[package]] -name = "unicode-bom" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" - [[package]] name = "unicode-ident" version = "1.0.14" @@ -13070,18 +12253,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" - [[package]] name = "unicode-xid" version = "0.2.6" diff --git a/Cargo.toml b/Cargo.toml index 40477ee..b1c1e57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ broken_intra_doc_links = "deny" [workspace.dependencies] # Blueprint utils blueprint-util-meta = { version = "0.1.0", path = "./crates/blueprint", default-features = false } +blueprint-manager = { version = "0.2.2", path = "./crates/blueprint/manager", default-features = false } blueprint-metadata = { version = "0.2.1", path = "./crates/blueprint/metadata", default-features = false } blueprint-build-utils = { version = "0.1.0", path = "./crates/blueprint/build-utils", default-features = false } gadget-blueprint-serde = { version = "0.3.1", path = "./crates/blueprint/serde", default-features = false } diff --git a/crates/blueprint/Cargo.toml b/crates/blueprint/Cargo.toml index ef09d1c..c5c9aca 100644 --- a/crates/blueprint/Cargo.toml +++ b/crates/blueprint/Cargo.toml @@ -9,5 +9,6 @@ repository.workspace = true publish = false [dependencies] +blueprint-manager.workspace = true blueprint-metadata.workspace = true blueprint-build-utils.workspace = true \ No newline at end of file diff --git a/crates/blueprint/manager/CHANGELOG.md b/crates/blueprint/manager/CHANGELOG.md new file mode 100644 index 0000000..7145f63 --- /dev/null +++ b/crates/blueprint/manager/CHANGELOG.md @@ -0,0 +1,87 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.2.2](https://github.com/tangle-network/gadget/compare/blueprint-manager-v0.2.1...blueprint-manager-v0.2.2) - 2024-12-11 + +### Other + +- Call ID Insertion and Resolution + For [#520](https://github.com/tangle-network/gadget/pull/520) ([#533](https://github.com/tangle-network/gadget/pull/533)) + +## [0.2.1](https://github.com/tangle-network/gadget/compare/blueprint-manager-v0.2.0...blueprint-manager-v0.2.1) - 2024-12-04 + +### Other + +- updated the following local packages: gadget-sdk + +## [0.2.0](https://github.com/tangle-network/gadget/compare/blueprint-manager-v0.1.3...blueprint-manager-v0.2.0) - 2024-11-29 + +### Other + +- *(gadget-sdk)* [**breaking**] update to latest tangle ([#503](https://github.com/tangle-network/gadget/pull/503)) + +## [0.1.3](https://github.com/tangle-network/gadget/compare/blueprint-manager-v0.1.2...blueprint-manager-v0.1.3) - 2024-11-20 + +### Other + +- updated the following local packages: gadget-sdk + +## [0.1.2](https://github.com/tangle-network/gadget/compare/blueprint-manager-v0.1.1...blueprint-manager-v0.1.2) - 2024-11-16 + +### Other + +- updated the following local packages: gadget-sdk + +## [0.1.1](https://github.com/tangle-network/gadget/releases/tag/blueprint-manager-v0.1.1) - 2024-11-08 + +### Added + +- [**breaking**] Refactor EventFlows for EVM and Remove + EventWatchers ([#423](https://github.com/tangle-network/gadget/pull/423)) +- symbiotic initial integration ([#411](https://github.com/tangle-network/gadget/pull/411)) +- add optional data dir to blueprint manager ([#342](https://github.com/tangle-network/gadget/pull/342)) +- eigenlayer incredible squaring blueprint and test ([#312](https://github.com/tangle-network/gadget/pull/312)) +- add EVM Provider and Tangle Client Context Extensions ([#319](https://github.com/tangle-network/gadget/pull/319)) +- Keystore Context Extensions ([#316](https://github.com/tangle-network/gadget/pull/316)) +- add benchmarking mode ([#248](https://github.com/tangle-network/gadget/pull/248)) + +### Fixed + +- *(gadget-sdk)* [**breaking**] prevent duplicate and self-referential + messages ([#458](https://github.com/tangle-network/gadget/pull/458)) +- *(sdk)* [**breaking**] allow for zero-based `blueprint_id` ([#426](https://github.com/tangle-network/gadget/pull/426)) +- *(cargo-tangle)* CLI bugs ([#409](https://github.com/tangle-network/gadget/pull/409)) +- *(sdk)* [**breaking**] downgrade substrate dependencies for now +- add `data_dir` back to `GadgetConfiguration` ([#350](https://github.com/tangle-network/gadget/pull/350)) + +### Other + +- set blueprint-manager publishable ([#462](https://github.com/tangle-network/gadget/pull/462)) +- add a p2p test for testing the networking layer ([#450](https://github.com/tangle-network/gadget/pull/450)) +- Continue Improving Event Flows ([#399](https://github.com/tangle-network/gadget/pull/399)) +- improve blueprint-manager and blueprint-test-utils ([#421](https://github.com/tangle-network/gadget/pull/421)) +- Leverage blueprint in incredible squaring aggregator ([#365](https://github.com/tangle-network/gadget/pull/365)) +- Event Listener Upgrade + Wrapper Types + sdk::main macro ([#333](https://github.com/tangle-network/gadget/pull/333)) +- docs fix spelling issues ([#336](https://github.com/tangle-network/gadget/pull/336)) +- Event listener ([#317](https://github.com/tangle-network/gadget/pull/317)) +- Remove Logger ([#311](https://github.com/tangle-network/gadget/pull/311)) +- Streamline keystore, cleanup testing, refactor blueprint manager, add tests, remove unnecessary + code ([#285](https://github.com/tangle-network/gadget/pull/285)) +- CI Improvements ([#301](https://github.com/tangle-network/gadget/pull/301)) +- [feat] Gadget Metadata ([#274](https://github.com/tangle-network/gadget/pull/274)) +- [MEGA PR] Overhaul repo, add Eigenlayer AVS example, remove many crates, add testing, remove unused + code ([#246](https://github.com/tangle-network/gadget/pull/246)) +- Add mpc blueprint starting point, cleanup abstractions ([#252](https://github.com/tangle-network/gadget/pull/252)) +- Add more checks to CI ([#244](https://github.com/tangle-network/gadget/pull/244)) +- [feat] benchmark proc-macro ([#238](https://github.com/tangle-network/gadget/pull/238)) +- Spelling fix +- Promote all dependencies to workspace ([#233](https://github.com/tangle-network/gadget/pull/233)) +- Make `{core, io, common}` no_std and WASM compatible ([#231](https://github.com/tangle-network/gadget/pull/231)) +- Remove shell sdk and put inside blueprint manager ([#229](https://github.com/tangle-network/gadget/pull/229)) +- Blueprint testing ([#206](https://github.com/tangle-network/gadget/pull/206)) diff --git a/crates/blueprint/manager/Cargo.toml b/crates/blueprint/manager/Cargo.toml new file mode 100644 index 0000000..20a7a70 --- /dev/null +++ b/crates/blueprint/manager/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "blueprint-manager" +version = "0.2.2" +description = "Tangle Blueprint manager and Runner" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true + +[[bin]] +name = "blueprint-manager" +path = "src/main.rs" + +[dependencies] +gadget-clients = { workspace = true, features = ["std", "tangle"] } +gadget-config = { workspace = true, features = ["std", "networking"] } +gadget-crypto = { workspace = true, features = ["std", "tangle-pair-signer"] } +gadget-keystore = { workspace = true, features = ["std", "tangle"] } +gadget-logging = { workspace = true, features = ["std"] } +gadget-networking = { workspace = true, features = ["std"] } +gadget-std = { workspace = true, features = ["std"] } + +clap = { workspace = true, features = ["derive", "wrap_help"] } +color-eyre = { workspace = true, features = ["tracing-error", "color-spantrace", "issue-url"] } +serde = { workspace = true } +tangle-subxt = { workspace = true } +toml = { workspace = true } +hex = { workspace = true } +tokio = { workspace = true, features = ["process", "io-util", "signal", "macros"] } +reqwest = { workspace = true } +sha2 = { workspace = true } +futures = { workspace = true } +itertools = { workspace = true } +tracing = { workspace = true, features = ["log"] } +tracing-subscriber = { workspace = true, features = ["env-filter", "ansi", "tracing-log"] } +libp2p = { workspace = true } +auto_impl = { workspace = true } +parking_lot = { workspace = true } +async-trait = { workspace = true } + +[lints] +workspace = true + +[package.metadata.dist] +dist = false diff --git a/crates/blueprint/manager/src/config.rs b/crates/blueprint/manager/src/config.rs new file mode 100644 index 0000000..207427f --- /dev/null +++ b/crates/blueprint/manager/src/config.rs @@ -0,0 +1,31 @@ +use clap::Parser; +use std::path::PathBuf; + +#[derive(Debug, Parser)] +#[command( + name = "Blueprint Manager", + about = "An program executor that connects to the Tangle network and runs protocols dynamically on the fly" +)] +pub struct BlueprintManagerConfig { + /// The path to the gadget configuration file + #[arg(short = 's', long)] + pub gadget_config: Option, + /// The path to the keystore + #[arg(short = 'k', long)] + pub keystore_uri: String, + /// The directory in which all gadgets will store their data + #[arg(long, short = 'd', default_value = "./data")] + pub data_dir: PathBuf, + /// The verbosity level, can be used multiple times to increase verbosity + #[arg(long, short = 'v', action = clap::ArgAction::Count)] + pub verbose: u8, + /// Whether to use pretty logging + #[arg(long)] + pub pretty: bool, + /// An optional unique string identifier for the blueprint manager to differentiate between multiple + /// running instances of a BlueprintManager (mostly for debugging purposes) + #[arg(long, alias = "id")] + pub instance_id: Option, + #[arg(long, short = 't')] + pub test_mode: bool, +} diff --git a/crates/blueprint/manager/src/error.rs b/crates/blueprint/manager/src/error.rs new file mode 100644 index 0000000..74d0130 --- /dev/null +++ b/crates/blueprint/manager/src/error.rs @@ -0,0 +1,30 @@ +use std::fmt::{Display, Formatter}; + +#[derive(Debug, Clone)] +pub struct Error { + pub message: String, +} + +impl Error { + pub fn msg>(msg: T) -> Self { + Self { + message: msg.into(), + } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(self, f) + } +} + +impl std::error::Error for Error {} + +impl From for Error { + fn from(error: std::io::Error) -> Self { + Error { + message: error.to_string(), + } + } +} diff --git a/crates/blueprint/manager/src/executor/event_handler.rs b/crates/blueprint/manager/src/executor/event_handler.rs new file mode 100644 index 0000000..5931c9d --- /dev/null +++ b/crates/blueprint/manager/src/executor/event_handler.rs @@ -0,0 +1,379 @@ +use crate::config::BlueprintManagerConfig; +use crate::gadget::native::FilteredBlueprint; +use crate::gadget::ActiveGadgets; +use crate::sdk::utils::bounded_string_to_string; +use crate::sources::github::GithubBinaryFetcher; +use crate::sources::BinarySourceFetcher; +use color_eyre::eyre::OptionExt; +use gadget_clients::tangle::client::{TangleConfig, TangleEvent}; +use gadget_clients::tangle::services::{RpcServicesWithBlueprint, TangleServicesClient}; +use gadget_config::{GadgetConfiguration, Protocol}; +use gadget_logging::{error, info, trace, warn}; +use std::fmt::Debug; +use std::sync::atomic::Ordering; +use tangle_subxt::subxt::utils::AccountId32; +use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::{ + Gadget, GadgetSourceFetcher, +}; +use tangle_subxt::tangle_testnet_runtime::api::services::events::{ + JobCalled, JobResultSubmitted, PreRegistration, Registered, ServiceInitiated, Unregistered, +}; + +pub struct VerifiedBlueprint<'a> { + pub(crate) fetcher: Box, + pub(crate) blueprint: FilteredBlueprint, +} + +impl Debug for VerifiedBlueprint<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + format!( + "{}/bid={}/sid(s)={:?}", + self.blueprint.name, self.blueprint.blueprint_id, self.blueprint.services + ) + .fmt(f) + } +} + +pub async fn handle_services( + blueprints: &[VerifiedBlueprint<'_>], + gadget_config: &GadgetConfiguration, + blueprint_manager_opts: &BlueprintManagerConfig, + active_gadgets: &mut ActiveGadgets, +) -> color_eyre::Result<()> { + for blueprint in blueprints { + if let Err(err) = crate::sources::handle( + blueprint, + gadget_config, + blueprint_manager_opts, + active_gadgets, + ) + .await + { + error!("{err}"); + } + } + + Ok(()) +} + +#[derive(Default, Debug)] +pub struct EventPollResult { + pub needs_update: bool, + // A vec of blueprints we have not yet become registered to + pub blueprint_registrations: Vec, +} + +pub(crate) async fn check_blueprint_events( + event: &TangleEvent, + active_gadgets: &mut ActiveGadgets, + account_id: &AccountId32, +) -> EventPollResult { + let pre_registation_events = event.events.find::(); + let registered_events = event.events.find::(); + let unregistered_events = event.events.find::(); + let service_initiated_events = event.events.find::(); + let job_called_events = event.events.find::(); + let job_result_submitted_events = event.events.find::(); + + let mut result = EventPollResult::default(); + + for evt in pre_registation_events { + match evt { + Ok(evt) => { + if &evt.operator == account_id { + result.blueprint_registrations.push(evt.blueprint_id); + info!("Pre-registered event: {evt:?}"); + } + } + Err(err) => { + warn!("Error handling pre-registered event: {err:?}"); + } + } + } + + // Handle registered events + for evt in registered_events { + match evt { + Ok(evt) => { + info!("Registered event: {evt:?}"); + result.needs_update = true; + } + Err(err) => { + warn!("Error handling registered event: {err:?}"); + } + } + } + + // Handle unregistered events + for evt in unregistered_events { + match evt { + Ok(evt) => { + info!("Unregistered event: {evt:?}"); + if &evt.operator == account_id && active_gadgets.remove(&evt.blueprint_id).is_some() + { + info!("Removed services for blueprint_id: {}", evt.blueprint_id,); + + result.needs_update = true; + } + } + Err(err) => { + warn!("Error handling unregistered event: {err:?}"); + } + } + } + + // Handle service initiated events + for evt in service_initiated_events { + match evt { + Ok(evt) => { + info!("Service initiated event: {evt:?}"); + } + Err(err) => { + warn!("Error handling service initiated event: {err:?}"); + } + } + } + + // Handle job called events + for evt in job_called_events { + match evt { + Ok(evt) => { + info!("Job called event: {evt:?}"); + } + Err(err) => { + warn!("Error handling job called event: {err:?}"); + } + } + } + + // Handle job result submitted events + for evt in job_result_submitted_events { + match evt { + Ok(evt) => { + info!("Job result submitted event: {evt:?}"); + } + Err(err) => { + warn!("Error handling job result submitted event: {err:?}"); + } + } + } + + result +} + +#[allow(clippy::too_many_arguments)] +pub(crate) async fn handle_tangle_event( + event: &TangleEvent, + blueprints: &[RpcServicesWithBlueprint], + gadget_config: &GadgetConfiguration, + gadget_manager_opts: &BlueprintManagerConfig, + active_gadgets: &mut ActiveGadgets, + poll_result: EventPollResult, + client: &TangleServicesClient, +) -> color_eyre::Result<()> { + info!("Received notification {}", event.number); + const DEFAULT_PROTOCOL: Protocol = Protocol::Tangle; + warn!("Using Tangle protocol as default over Eigen. This is a temporary development workaround. You can alter this behavior here"); + + // const DEFAULT_PROTOCOL: Protocol = Protocol::Eigenlayer; + // warn!("Using Eigen protocol as default over Tangle. This is a temporary development workaround. You can alter this behavior here"); + + let mut registration_blueprints = vec![]; + // First, check to see if we need to register any new services invoked by the PreRegistration event + if !poll_result.blueprint_registrations.is_empty() { + for blueprint_id in &poll_result.blueprint_registrations { + let blueprint = client + .get_blueprint_by_id(event.hash, *blueprint_id) + .await? + .ok_or_eyre("Unable to retrieve blueprint for registration mode")?; + + let general_blueprint = FilteredBlueprint { + blueprint_id: *blueprint_id, + services: vec![0], // Add a dummy service id for now, since it does not matter for registration mode + gadget: blueprint.gadget, + name: bounded_string_to_string(blueprint.metadata.name)?, + registration_mode: true, + protocol: DEFAULT_PROTOCOL, + }; + + registration_blueprints.push(general_blueprint); + } + } + + let mut verified_blueprints = vec![]; + + for blueprint in blueprints + .iter() + .map(|r| FilteredBlueprint { + blueprint_id: r.blueprint_id, + services: r.services.iter().map(|r| r.id).collect(), + gadget: r.blueprint.gadget.clone(), + name: bounded_string_to_string(r.clone().blueprint.metadata.name) + .unwrap_or("unknown_blueprint_name".to_string()), + registration_mode: false, + protocol: DEFAULT_PROTOCOL, + }) + .chain(registration_blueprints) + { + let mut test_fetcher_idx = None; + let mut fetcher_candidates: Vec> = vec![]; + + if let Gadget::Native(gadget) = &blueprint.gadget { + for (source_idx, gadget_source) in gadget.sources.0.iter().enumerate() { + match &gadget_source.fetcher { + GadgetSourceFetcher::Github(gh) => { + let fetcher = GithubBinaryFetcher { + fetcher: gh.clone(), + blueprint_id: blueprint.blueprint_id, + gadget_name: blueprint.name.clone(), + }; + + fetcher_candidates.push(Box::new(fetcher)); + } + + GadgetSourceFetcher::Testing(test) => { + // TODO: demote to TRACE once proven to work + if !gadget_manager_opts.test_mode { + warn!("Ignoring testing fetcher as we are not in test mode"); + continue; + } + + let fetcher = crate::sources::testing::TestSourceFetcher { + fetcher: test.clone(), + blueprint_id: blueprint.blueprint_id, + gadget_name: blueprint.name.clone(), + }; + + test_fetcher_idx = Some(source_idx); + fetcher_candidates.push(Box::new(fetcher)); + } + + _ => { + warn!("Blueprint does not contain a supported fetcher"); + continue; + } + } + } + + // A bunch of sanity checks to enforce structure + + // Ensure that we have at least one fetcher + if fetcher_candidates.is_empty() { + warn!("No fetchers found for blueprint: {}", blueprint.name,); + continue; + } + + // Ensure that we have a test fetcher if we are in test mode + if gadget_manager_opts.test_mode && test_fetcher_idx.is_none() { + return Err(color_eyre::Report::msg(format!( + "No testing fetcher found for blueprint `{}` despite operating in TEST MODE", + blueprint.name, + ))); + } + + // Ensure that we have only one fetcher if we are in test mode + if gadget_manager_opts.test_mode { + fetcher_candidates = + vec![fetcher_candidates.remove(test_fetcher_idx.expect("Should exist"))]; + } + + // Ensure there is only a single candidate fetcher + if fetcher_candidates.len() != 1 { + warn!( + "Multiple fetchers found for blueprint: {}. Invalidating blueprint", + blueprint.name, + ); + continue; + } + + let verified_blueprint = VerifiedBlueprint { + fetcher: fetcher_candidates.pop().expect("Should exist"), + blueprint, + }; + + verified_blueprints.push(verified_blueprint); + } else { + warn!("Blueprint does not contain a native gadget and thus currently unsupported"); + } + } + + trace!( + "OnChain Verified Blueprints: {:?}", + verified_blueprints + .iter() + .map(|r| format!("{r:?}")) + .collect::>() + ); + + // Step 3: Check to see if we need to start any new services + handle_services( + &verified_blueprints, + gadget_config, + gadget_manager_opts, + active_gadgets, + ) + .await?; + + // Check to see if local is running services that are not on-chain + let mut to_remove: Vec<(u64, u64)> = vec![]; + + // Loop through every (blueprint_id, service_id) running. See if the service is still on-chain. If not, kill it and add it to to_remove + for (blueprint_id, process_handles) in &mut *active_gadgets { + for service_id in process_handles.keys() { + info!( + "Checking service for on-chain termination: bid={blueprint_id}//sid={service_id}" + ); + + // Since the below "verified blueprints" were freshly obtained from an on-chain source, + // we compare all these fresh values to see if we're running a service locally that is no longer on-chain + for verified_blueprints in &verified_blueprints { + let services = &verified_blueprints.blueprint.services; + // Safe assertion since we know there is at least one fetcher. All fetchers should have the same blueprint id + let fetcher = &verified_blueprints.fetcher; + if fetcher.blueprint_id() == *blueprint_id && !services.contains(service_id) { + warn!("Killing service that is no longer on-chain: bid={blueprint_id}//sid={service_id}"); + to_remove.push((*blueprint_id, *service_id)); + } + } + } + } + + // Check to see if any process handles have died + for (blueprint_id, process_handles) in &mut *active_gadgets { + for (service_id, process_handle) in process_handles { + if !to_remove.contains(&(*blueprint_id, *service_id)) + && !process_handle.0.load(Ordering::Relaxed) + { + // By removing any killed processes, we will auto-restart them on the next finality notification if required + warn!("Killing service that has died to allow for auto-restart"); + to_remove.push((*blueprint_id, *service_id)); + } + } + } + + for (blueprint_id, service_id) in to_remove { + warn!("Removing service that is no longer active on-chain or killed: bid={blueprint_id}//sid={service_id}"); + let mut should_delete_blueprint = false; + if let Some(gadgets) = active_gadgets.get_mut(&blueprint_id) { + if let Some((_, mut process_handle)) = gadgets.remove(&service_id) { + if let Some(abort_handle) = process_handle.take() { + if abort_handle.send(()).is_err() { + error!("Failed to send abort signal to service: bid={blueprint_id}//sid={service_id}"); + } else { + warn!("Sent abort signal to service: bid={blueprint_id}//sid={service_id}"); + } + } + } + + if gadgets.is_empty() { + should_delete_blueprint = true; + } + } + + if should_delete_blueprint { + active_gadgets.remove(&blueprint_id); + } + } + + Ok(()) +} diff --git a/crates/blueprint/manager/src/executor/mod.rs b/crates/blueprint/manager/src/executor/mod.rs new file mode 100644 index 0000000..526afcb --- /dev/null +++ b/crates/blueprint/manager/src/executor/mod.rs @@ -0,0 +1,332 @@ +use crate::config::BlueprintManagerConfig; +use crate::gadget::ActiveGadgets; +use crate::sdk::entry::SendFuture; +use crate::sdk::utils; +use crate::sdk::utils::msg_to_error; +use color_eyre::eyre::OptionExt; +use color_eyre::Report; +use gadget_clients::tangle::client::{TangleClient, TangleConfig}; +use gadget_clients::tangle::services::{RpcServicesWithBlueprint, TangleServicesClient}; +use gadget_clients::tangle::EventsClient; +use gadget_config::GadgetConfiguration; +use gadget_crypto::tangle_pair_signer::TanglePairSigner; +use gadget_keystore::backends::tangle::TangleBackend; +use gadget_keystore::{Keystore, KeystoreConfig}; +use gadget_logging::info; +use std::collections::HashMap; +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; +use tangle_subxt::subxt::blocks::BlockRef; +use tangle_subxt::subxt::ext::sp_core::{ecdsa, sr25519, H256}; +use tangle_subxt::subxt::tx::Signer; +use tangle_subxt::subxt::utils::AccountId32; +use tangle_subxt::subxt::Config; +use tokio::task::JoinHandle; + +pub(crate) mod event_handler; + +pub async fn get_blueprints( + runtime: &TangleServicesClient, + block_hash: [u8; 32], + account_id: AccountId32, +) -> color_eyre::Result> +where + BlockRef<::Hash>: From>, +{ + runtime + .query_operator_blueprints(block_hash, account_id) + .await + .map_err(|err| msg_to_error(err.to_string())) +} + +pub struct BlueprintManagerHandle { + shutdown_call: Option>, + start_tx: Option>, + running_task: JoinHandle>, + span: tracing::Span, + sr25519_id: TanglePairSigner, + ecdsa_id: TanglePairSigner, + keystore_uri: String, +} + +impl BlueprintManagerHandle { + /// Send a start signal to the blueprint manager + pub fn start(&mut self) -> color_eyre::Result<()> { + let _span = self.span.enter(); + match self.start_tx.take() { + Some(tx) => match tx.send(()) { + Ok(_) => { + info!("Start signal sent to Blueprint Manager"); + Ok(()) + } + Err(_) => Err(Report::msg( + "Failed to send start signal to Blueprint Manager", + )), + }, + None => Err(Report::msg("Blueprint Manager Already Started")), + } + } + + /// Returns the SR25519 keypair for this blueprint manager + pub fn sr25519_id(&self) -> &TanglePairSigner { + &self.sr25519_id + } + + /// Returns the ECDSA keypair for this blueprint manager + pub fn ecdsa_id(&self) -> &TanglePairSigner { + &self.ecdsa_id + } + + /// Shutdown the blueprint manager + pub async fn shutdown(&mut self) -> color_eyre::Result<()> { + self.shutdown_call + .take() + .map(|tx| tx.send(())) + .ok_or_eyre("Shutdown already called")? + .map_err(|_| Report::msg("Failed to send shutdown signal to Blueprint Manager")) + } + + /// Returns the keystore URI for this blueprint manager + pub fn keystore_uri(&self) -> &str { + &self.keystore_uri + } + + pub fn span(&self) -> &tracing::Span { + &self.span + } +} + +/// Add default behavior for unintentional dropping of the BlueprintManagerHandle +/// This will ensure that the BlueprintManagerHandle is executed even if the handle +/// is dropped, which is similar behavior to the tokio SpawnHandle +impl Drop for BlueprintManagerHandle { + fn drop(&mut self) { + let _ = self.start(); + } +} + +/// Implement the Future trait for the BlueprintManagerHandle to allow +/// for the handle to be awaited on +impl Future for BlueprintManagerHandle { + type Output = color_eyre::Result<()>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // Start the blueprint manager if it has not been started + let this = self.get_mut(); + if this.start_tx.is_some() { + if let Err(err) = this.start() { + return Poll::Ready(Err(err)); + } + } + + let result = futures::ready!(Pin::new(&mut this.running_task).poll(cx)); + + match result { + Ok(res) => Poll::Ready(res), + Err(err) => Poll::Ready(Err(Report::msg(format!( + "Blueprint Manager Closed Unexpectedly (JoinError): {err:?}" + )))), + } + } +} + +#[allow(clippy::too_many_lines)] +pub async fn run_blueprint_manager>( + blueprint_manager_config: BlueprintManagerConfig, + gadget_config: GadgetConfiguration, + shutdown_cmd: F, +) -> color_eyre::Result { + let logger_id = if let Some(custom_id) = &blueprint_manager_config.instance_id { + custom_id.as_str() + } else { + "Local" + }; + + let span = tracing::info_span!("Blueprint-Manager", id = logger_id); + + let _span = span.enter(); + info!("Starting blueprint manager ... waiting for start signal ..."); + + let data_dir = &blueprint_manager_config.data_dir; + if !data_dir.exists() { + info!( + "Data directory does not exist, creating it at `{}`", + data_dir.display() + ); + std::fs::create_dir_all(data_dir)?; + } + + // TODO: Actual error handling + let (tangle_key, ecdsa_key) = { + let keystore = Keystore::new(KeystoreConfig::new().fs_root(&gadget_config.keystore_uri))?; + let sr_key_pub = keystore + .iter_sr25519() + .next() + .expect("No SR25519 keys found"); + let sr_pair = keystore + .expose_sr25519_secret(&sr_key_pub)? + .expect("No matching SR25519 key"); + let sr_key = TanglePairSigner::new(sr_pair); + + let ecdsa_key_pub = keystore.iter_ecdsa().next().expect("No ECDSA keys found"); + let ecdsa_pair = keystore + .expose_ecdsa_secret(&ecdsa_key_pub)? + .expect("No matching ECDSA key"); + let ecdsa_key = TanglePairSigner::new(ecdsa_pair); + + (sr_key, ecdsa_key) + }; + + let sub_account_id = tangle_key.account_id().clone(); + + let mut active_gadgets = HashMap::new(); + + let keystore_uri = gadget_config.keystore_uri.clone(); + + let manager_task = async move { + let tangle_client = TangleClient::new(gadget_config.clone()).await?; + let services_client = tangle_client.services_client(); + + // With the basics setup, we must now implement the main logic of the Blueprint Manager + // Handle initialization logic + // NOTE: The node running this code should be registered as an operator for the blueprints, otherwise, this + // code will fail + let mut operator_subscribed_blueprints = handle_init( + &tangle_client, + services_client, + &sub_account_id, + &mut active_gadgets, + &gadget_config, + &blueprint_manager_config, + ) + .await?; + + // Now, run the main event loop + // Listen to FinalityNotifications and poll for new/deleted services that correspond to the blueprints above + while let Some(event) = tangle_client.next_event().await { + let result = event_handler::check_blueprint_events( + &event, + &mut active_gadgets, + &sub_account_id.clone(), + ) + .await; + + if result.needs_update { + operator_subscribed_blueprints = services_client + .query_operator_blueprints(event.hash, sub_account_id.clone()) + .await + .map_err(|err| msg_to_error(err.to_string()))?; + } + + event_handler::handle_tangle_event( + &event, + &operator_subscribed_blueprints, + &gadget_config, + &blueprint_manager_config, + &mut active_gadgets, + result, + &services_client, + ) + .await?; + } + + Err::<(), _>(utils::msg_to_error("Finality Notification stream died")) + }; + + let (tx_stop, rx_stop) = tokio::sync::oneshot::channel::<()>(); + + let shutdown_task = async move { + tokio::select! { + _res0 = shutdown_cmd => { + info!("Shutdown-1 command received, closing application"); + }, + + _res1 = rx_stop => { + info!("Manual shutdown signal received, closing application"); + } + } + }; + + let (start_tx, start_rx) = tokio::sync::oneshot::channel::<()>(); + + let combined_task = async move { + start_rx + .await + .map_err(|_err| Report::msg("Failed to receive start signal"))?; + + tokio::select! { + res0 = manager_task => { + Err(Report::msg(format!("Blueprint Manager Closed Unexpectedly: {res0:?}"))) + }, + + _ = shutdown_task => { + Ok(()) + } + } + }; + + drop(_span); + let handle = tokio::spawn(combined_task); + + let handle = BlueprintManagerHandle { + start_tx: Some(start_tx), + shutdown_call: Some(tx_stop), + running_task: handle, + span, + sr25519_id: tangle_key, + ecdsa_id: ecdsa_key, + keystore_uri, + }; + + Ok(handle) +} + +/// * Query to get Vec +/// * For each RpcServicesWithBlueprint, fetch the associated gadget binary (fetch/download) +/// -> If the services field is empty, just emit and log inside the executed binary "that states a new service instance got created by one of these blueprints" +/// -> If the services field is not empty, for each service in RpcServicesWithBlueprint.services, spawn the gadget binary, using params to set the job type to listen to (in terms of our old language, each spawned service represents a single "RoleType") +async fn handle_init( + tangle_runtime: &TangleClient, + services_client: &TangleServicesClient, + sub_account_id: &AccountId32, + active_gadgets: &mut ActiveGadgets, + gadget_config: &GadgetConfiguration, + blueprint_manager_config: &BlueprintManagerConfig, +) -> color_eyre::Result> { + info!("Beginning initialization of Blueprint Manager"); + + let (operator_subscribed_blueprints, init_event) = + if let Some(event) = tangle_runtime.next_event().await { + ( + get_blueprints(services_client, event.hash, sub_account_id.clone()) + .await + .map_err(|err| Report::msg(format!("Failed to obtain blueprints: {err}")))?, + event, + ) + } else { + return Err(Report::msg("Failed to get initial block hash")); + }; + + info!( + "Received {} initial blueprints this operator is registered to", + operator_subscribed_blueprints.len() + ); + + // Immediately poll, handling the initial state + let poll_result = + event_handler::check_blueprint_events(&init_event, active_gadgets, sub_account_id).await; + + event_handler::handle_tangle_event( + &init_event, + &operator_subscribed_blueprints, + gadget_config, + blueprint_manager_config, + active_gadgets, + poll_result, + services_client, + ) + .await?; + + Ok(operator_subscribed_blueprints) +} diff --git a/crates/blueprint/manager/src/gadget/mod.rs b/crates/blueprint/manager/src/gadget/mod.rs new file mode 100644 index 0000000..e6cc053 --- /dev/null +++ b/crates/blueprint/manager/src/gadget/mod.rs @@ -0,0 +1,7 @@ +use gadget_std::collections::HashMap; +use gadget_std::sync::atomic::AtomicBool; +use gadget_std::sync::Arc; + +pub type ActiveGadgets = + HashMap, Option>)>>; +pub mod native; diff --git a/crates/blueprint/manager/src/gadget/native.rs b/crates/blueprint/manager/src/gadget/native.rs new file mode 100644 index 0000000..ffff209 --- /dev/null +++ b/crates/blueprint/manager/src/gadget/native.rs @@ -0,0 +1,37 @@ +use crate::sdk::utils::get_formatted_os_string; +use gadget_config::Protocol; +use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::{ + Gadget, GadgetBinary, +}; + +pub struct FilteredBlueprint { + pub blueprint_id: u64, + pub services: Vec, + pub gadget: Gadget, + pub name: String, + pub registration_mode: bool, + pub protocol: Protocol, +} + +pub fn get_gadget_binary(gadget_binaries: &[GadgetBinary]) -> Option<&GadgetBinary> { + let os = get_formatted_os_string().to_lowercase(); + let arch = std::env::consts::ARCH.to_lowercase(); + for binary in gadget_binaries { + let binary_str = format!("{:?}", binary.os).to_lowercase(); + if binary_str.contains(&os) || os.contains(&binary_str) || binary_str == os { + let mut arch_str = format!("{:?}", binary.arch).to_lowercase(); + + if arch_str == "amd" { + arch_str = "x86".to_string() + } else if arch_str == "amd64" { + arch_str = "x86_64".to_string() + } + + if arch_str == arch { + return Some(binary); + } + } + } + + None +} diff --git a/crates/blueprint/manager/src/lib.rs b/crates/blueprint/manager/src/lib.rs new file mode 100644 index 0000000..7168062 --- /dev/null +++ b/crates/blueprint/manager/src/lib.rs @@ -0,0 +1,16 @@ +pub mod config; +pub mod error; +pub mod executor; +pub mod gadget; +pub mod protocols; +pub mod sdk; +pub mod sources; +pub use executor::run_blueprint_manager; + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/crates/blueprint/manager/src/main.rs b/crates/blueprint/manager/src/main.rs new file mode 100644 index 0000000..c405488 --- /dev/null +++ b/crates/blueprint/manager/src/main.rs @@ -0,0 +1,38 @@ +use blueprint_manager::config::BlueprintManagerConfig; +use blueprint_manager::sdk; +use blueprint_manager::sdk::utils::msg_to_error; +use clap::Parser; +use sdk::entry; + +#[tokio::main] +#[allow(clippy::needless_return)] +async fn main() -> color_eyre::Result<()> { + color_eyre::install()?; + let mut blueprint_manager_config = BlueprintManagerConfig::parse(); + + blueprint_manager_config.data_dir = std::path::absolute(&blueprint_manager_config.data_dir)?; + + entry::setup_blueprint_manager_logger( + blueprint_manager_config.verbose, + blueprint_manager_config.pretty, + "gadget", + )?; + + // TODO: blueprint-manager CLI mode + return Err(msg_to_error("TODO: blueprint-manager CLI mode".to_string())); + + // let gadget_config_settings = std::fs::read_to_string(gadget_config)?; + // let gadget_config: GadgetConfig = + // toml::from_str(&gadget_config_settings).map_err(|err| msg_to_error(err.to_string()))?; + // + // // Allow CTRL-C to shutdown this CLI application instance + // let shutdown_signal = async move { + // let _ = tokio::signal::ctrl_c().await; + // }; + // + // let handle = + // run_blueprint_manager(blueprint_manager_config, gadget_config, shutdown_signal).await?; + // handle.await?; + // + // Ok(()) +} diff --git a/crates/blueprint/manager/src/protocols/config.rs b/crates/blueprint/manager/src/protocols/config.rs new file mode 100644 index 0000000..efb0f47 --- /dev/null +++ b/crates/blueprint/manager/src/protocols/config.rs @@ -0,0 +1,14 @@ +use gadget_std::collections::HashMap; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct ProtocolConfig { + pub(crate) protocols: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ProtocolToml { + pub package: String, + pub repository: Option>, + pub bin_hashes: Option>, +} diff --git a/crates/blueprint/manager/src/protocols/mod.rs b/crates/blueprint/manager/src/protocols/mod.rs new file mode 100644 index 0000000..2f1bf1d --- /dev/null +++ b/crates/blueprint/manager/src/protocols/mod.rs @@ -0,0 +1,2 @@ +pub mod config; +pub mod resolver; diff --git a/crates/blueprint/manager/src/protocols/resolver.rs b/crates/blueprint/manager/src/protocols/resolver.rs new file mode 100644 index 0000000..95c5158 --- /dev/null +++ b/crates/blueprint/manager/src/protocols/resolver.rs @@ -0,0 +1,14 @@ +use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::{ + GadgetBinary, GithubFetcher, +}; + +#[derive(Debug)] +pub struct NativeGithubMetadata { + pub git: String, + pub tag: String, + pub owner: String, + pub repo: String, + pub gadget_binaries: Vec, + pub blueprint_id: u64, + pub fetcher: GithubFetcher, +} diff --git a/crates/blueprint/manager/src/sdk/config.rs b/crates/blueprint/manager/src/sdk/config.rs new file mode 100644 index 0000000..47b7f66 --- /dev/null +++ b/crates/blueprint/manager/src/sdk/config.rs @@ -0,0 +1,16 @@ +use gadget_keystore::KeystoreConfig; +use libp2p::Multiaddr; +use std::net::IpAddr; +use std::path::PathBuf; +use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::ServiceBlueprint; + +#[derive(Debug)] +pub struct SingleGadgetConfig { + pub base_path: PathBuf, + pub keystore: KeystoreConfig, + pub bind_ip: IpAddr, + pub bind_port: u16, + pub bootnodes: Vec, + pub services: Vec, + pub n_protocols: usize, +} diff --git a/crates/blueprint/manager/src/sdk/entry.rs b/crates/blueprint/manager/src/sdk/entry.rs new file mode 100644 index 0000000..44523ba --- /dev/null +++ b/crates/blueprint/manager/src/sdk/entry.rs @@ -0,0 +1,39 @@ +use futures::Future; +use tracing_subscriber::EnvFilter; + +pub trait SendFuture<'a, T>: Send + Future + 'a {} +impl<'a, F: Send + Future + 'a, T> SendFuture<'a, T> for F {} + +/// Sets up the logger for the blueprint manager, based on the verbosity level passed in. +pub fn setup_blueprint_manager_logger( + verbose: u8, + pretty: bool, + filter: &str, +) -> color_eyre::Result<()> { + use tracing::Level; + let log_level = match verbose { + 0 => Level::ERROR, + 1 => Level::WARN, + 2 => Level::INFO, + 3 => Level::DEBUG, + _ => Level::TRACE, + }; + let env_filter = + EnvFilter::from_default_env().add_directive(format!("{filter}={log_level}").parse()?); + let logger = tracing_subscriber::fmt() + .with_target(false) + .with_level(true) + .with_line_number(false) + .without_time() + .with_max_level(log_level) + .with_env_filter(env_filter); + if pretty { + let _ = logger.pretty().try_init(); + } else { + let _ = logger.compact().try_init(); + } + + //let _ = env_logger::try_init(); + + Ok(()) +} diff --git a/crates/blueprint/manager/src/sdk/mod.rs b/crates/blueprint/manager/src/sdk/mod.rs new file mode 100644 index 0000000..6d16dec --- /dev/null +++ b/crates/blueprint/manager/src/sdk/mod.rs @@ -0,0 +1,3 @@ +pub mod config; +pub mod entry; +pub mod utils; diff --git a/crates/blueprint/manager/src/sdk/utils.rs b/crates/blueprint/manager/src/sdk/utils.rs new file mode 100644 index 0000000..e11c0df --- /dev/null +++ b/crates/blueprint/manager/src/sdk/utils.rs @@ -0,0 +1,151 @@ +use crate::protocols::resolver::NativeGithubMetadata; +use gadget_logging::{info, warn}; +use sha2::Digest; +use std::path::Path; +use std::string::FromUtf8Error; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::BoundedString; +use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::{ + GadgetBinary, GithubFetcher, +}; + +pub fn github_fetcher_to_native_github_metadata( + gh: &GithubFetcher, + blueprint_id: u64, +) -> NativeGithubMetadata { + let owner = bytes_to_utf8_string(gh.owner.0 .0.clone()).expect("Should be valid"); + let repo = bytes_to_utf8_string(gh.repo.0 .0.clone()).expect("Should be valid"); + let tag = bytes_to_utf8_string(gh.tag.0 .0.clone()).expect("Should be valid"); + let git = format!("https://github.com/{owner}/{repo}"); + + NativeGithubMetadata { + fetcher: gh.clone(), + git, + tag, + repo, + owner, + gadget_binaries: gh.binaries.0.clone(), + blueprint_id, + } +} + +pub fn bounded_string_to_string(string: BoundedString) -> Result { + let bytes: &Vec = &string.0 .0; + String::from_utf8(bytes.clone()) +} + +pub fn hash_bytes_to_hex>(input: T) -> String { + let mut hasher = sha2::Sha256::default(); + hasher.update(input); + hex::encode(hasher.finalize()) +} + +pub async fn valid_file_exists(path: &str, expected_hash: &str) -> bool { + // The hash is sha3_256 of the binary + if let Ok(file) = tokio::fs::read(path).await { + // Compute the SHA3-256 + let retrieved_bytes = hash_bytes_to_hex(file); + expected_hash == retrieved_bytes.as_str() + } else { + false + } +} + +pub fn get_formatted_os_string() -> String { + let os = std::env::consts::OS; + + match os { + "macos" => "apple-darwin".to_string(), + "windows" => "pc-windows-msvc".to_string(), + "linux" => "unknown-linux-gnu".to_string(), + _ => os.to_string(), + } +} + +pub fn get_download_url(binary: &GadgetBinary, fetcher: &GithubFetcher) -> String { + let os = get_formatted_os_string(); + let ext = if os == "windows" { ".exe" } else { "" }; + let owner = String::from_utf8(fetcher.owner.0 .0.clone()).expect("Should be a valid owner"); + let repo = String::from_utf8(fetcher.repo.0 .0.clone()).expect("Should be a valid repo"); + let tag = String::from_utf8(fetcher.tag.0 .0.clone()).expect("Should be a valid tag"); + let binary_name = + String::from_utf8(binary.name.0 .0.clone()).expect("Should be a valid binary name"); + let os_name = format!("{:?}", binary.os).to_lowercase(); + let arch_name = format!("{:?}", binary.arch).to_lowercase(); + // https://github.com///releases/download/v/ + format!("https://github.com/{owner}/{repo}/releases/download/v{tag}/{binary_name}-{os_name}-{arch_name}{ext}") +} + +pub fn msg_to_error>(msg: T) -> color_eyre::Report { + color_eyre::Report::msg(msg.into()) +} + +pub fn get_service_str(svc: &NativeGithubMetadata) -> String { + let repo = svc.git.clone(); + let vals: Vec<&str> = repo.split(".com/").collect(); + vals[1].to_string() +} + +pub async fn chmod_x_file>(path: P) -> color_eyre::Result<()> { + let success = tokio::process::Command::new("chmod") + .arg("+x") + .arg(format!("{}", path.as_ref().display())) + .spawn()? + .wait_with_output() + .await? + .status + .success(); + + if success { + Ok(()) + } else { + Err(color_eyre::eyre::eyre!( + "Failed to chmod +x {}", + path.as_ref().display() + )) + } +} + +pub fn is_windows() -> bool { + std::env::consts::OS == "windows" +} + +pub fn generate_running_process_status_handle( + process: tokio::process::Child, + service_name: &str, +) -> (Arc, tokio::sync::oneshot::Sender<()>) { + let (stop_tx, stop_rx) = tokio::sync::oneshot::channel::<()>(); + let status = Arc::new(AtomicBool::new(true)); + let status_clone = status.clone(); + let service_name = service_name.to_string(); + + let task = async move { + info!("Starting process execution for {service_name}"); + let output = process.wait_with_output().await; + warn!("Process for {service_name} exited: {output:?}"); + status_clone.store(false, Ordering::Relaxed); + }; + + let task = async move { + tokio::select! { + _ = stop_rx => {}, + _ = task => {}, + } + }; + + tokio::spawn(task); + (status, stop_tx) +} + +pub fn bytes_to_utf8_string>>(input: T) -> color_eyre::Result { + String::from_utf8(input.into()).map_err(|err| msg_to_error(err.to_string())) +} + +pub fn slice_32_to_sha_hex_string(hash: [u8; 32]) -> String { + use std::fmt::Write; + hash.iter().fold(String::new(), |mut acc, byte| { + write!(&mut acc, "{:02x}", byte).expect("Should be able to write"); + acc + }) +} diff --git a/crates/blueprint/manager/src/sources/github.rs b/crates/blueprint/manager/src/sources/github.rs new file mode 100644 index 0000000..dfba067 --- /dev/null +++ b/crates/blueprint/manager/src/sources/github.rs @@ -0,0 +1,79 @@ +use crate::gadget::native::get_gadget_binary; +use crate::sdk; +use crate::sdk::utils::{ + get_download_url, hash_bytes_to_hex, is_windows, msg_to_error, valid_file_exists, +}; +use crate::sources::BinarySourceFetcher; +use async_trait::async_trait; +use color_eyre::eyre::OptionExt; +use gadget_logging::{error, info}; +use std::path::PathBuf; +use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::GithubFetcher; +use tokio::io::AsyncWriteExt; + +pub struct GithubBinaryFetcher { + pub fetcher: GithubFetcher, + pub blueprint_id: u64, + pub gadget_name: String, +} + +#[async_trait] +impl BinarySourceFetcher for GithubBinaryFetcher { + async fn get_binary(&self) -> color_eyre::Result { + let relevant_binary = get_gadget_binary(&self.fetcher.binaries.0) + .ok_or_eyre("Unable to find matching binary")?; + let expected_hash = sdk::utils::slice_32_to_sha_hex_string(relevant_binary.sha256); + let current_dir = std::env::current_dir()?; + let mut binary_download_path = + format!("{}/protocol-{:?}", current_dir.display(), self.fetcher.tag); + + if is_windows() { + binary_download_path += ".exe" + } + + info!("Downloading to {binary_download_path}"); + + // Check if the binary exists, if not download it + let retrieved_hash = if !valid_file_exists(&binary_download_path, &expected_hash).await { + let url = get_download_url(relevant_binary, &self.fetcher); + + let download = reqwest::get(&url) + .await + .map_err(|err| msg_to_error(err.to_string()))? + .bytes() + .await + .map_err(|err| msg_to_error(err.to_string()))?; + let retrieved_hash = hash_bytes_to_hex(&download); + + // Write the binary to disk + let mut file = tokio::fs::File::create(&binary_download_path).await?; + file.write_all(&download).await?; + file.flush().await?; + Some(retrieved_hash) + } else { + None + }; + + if let Some(retrieved_hash) = retrieved_hash { + if retrieved_hash.trim() != expected_hash.trim() { + error!( + "Binary hash {} mismatched expected hash of {} for protocol: {}", + retrieved_hash, expected_hash, self.gadget_name + ); + return Ok(PathBuf::from(binary_download_path)); + } + } + + Err(color_eyre::Report::msg( + "The hash of the downloaded binary did not match", + )) + } + + fn blueprint_id(&self) -> u64 { + self.blueprint_id + } + + fn name(&self) -> String { + self.gadget_name.clone() + } +} diff --git a/crates/blueprint/manager/src/sources/mod.rs b/crates/blueprint/manager/src/sources/mod.rs new file mode 100644 index 0000000..07c8d02 --- /dev/null +++ b/crates/blueprint/manager/src/sources/mod.rs @@ -0,0 +1,175 @@ +use crate::config::BlueprintManagerConfig; +use crate::executor::event_handler::VerifiedBlueprint; +use crate::gadget::ActiveGadgets; +use crate::sdk::utils::{chmod_x_file, generate_running_process_status_handle, is_windows}; +use async_trait::async_trait; +use gadget_config::{GadgetConfiguration, Protocol}; +use gadget_logging::{error, info, warn}; +use std::path::PathBuf; + +pub mod github; +pub mod testing; + +#[async_trait] +#[auto_impl::auto_impl(Box)] +pub trait BinarySourceFetcher: Send + Sync { + async fn get_binary(&self) -> color_eyre::Result; + fn blueprint_id(&self) -> u64; + fn name(&self) -> String; +} + +pub async fn handle( + blueprint: &VerifiedBlueprint<'_>, + gadget_config: &GadgetConfiguration, + blueprint_manager_opts: &BlueprintManagerConfig, + active_gadgets: &mut ActiveGadgets, +) -> color_eyre::Result<()> { + let blueprint_source = &blueprint.fetcher; + let blueprint = &blueprint.blueprint; + + let blueprint_id = blueprint_source.blueprint_id(); + let service_str = blueprint_source.name(); + + if active_gadgets.contains_key(&blueprint_id) { + return Ok(()); + } + + let mut binary_download_path = blueprint_source.get_binary().await?; + + // Ensure the binary is executable + if is_windows() { + if binary_download_path.extension().is_none() { + binary_download_path.set_extension("exe"); + } + } else if let Err(err) = chmod_x_file(&binary_download_path).await { + warn!("Failed to chmod +x the binary: {err}"); + } + + for service_id in &blueprint.services { + let sub_service_str = format!("{service_str}-{service_id}"); + let arguments = generate_process_arguments( + gadget_config, + blueprint_manager_opts, + blueprint_id, + *service_id, + blueprint.protocol, + )?; + + // Add required env vars for all child processes/gadgets + let mut env_vars = vec![ + ( + "HTTP_RPC_URL".to_string(), + gadget_config.http_rpc_endpoint.to_string(), + ), + ( + "WS_RPC_URL".to_string(), + gadget_config.ws_rpc_endpoint.to_string(), + ), + ( + "KEYSTORE_URI".to_string(), + blueprint_manager_opts.keystore_uri.clone(), + ), + ("BLUEPRINT_ID".to_string(), format!("{}", blueprint_id)), + ("SERVICE_ID".to_string(), format!("{}", service_id)), + ]; + + let base_data_dir = &blueprint_manager_opts.data_dir; + let data_dir = base_data_dir.join(format!("blueprint-{blueprint_id}-{sub_service_str}")); + env_vars.push(( + "DATA_DIR".to_string(), + data_dir.to_string_lossy().into_owned(), + )); + + // Ensure our child process inherits the current processes' environment vars + env_vars.extend(std::env::vars()); + + if blueprint.registration_mode { + env_vars.push(("REGISTRATION_MODE_ON".to_string(), "true".to_string())); + } + + info!("Starting protocol: {sub_service_str} with args: {arguments:?}"); + + // Now that the file is loaded, spawn the process + let process_handle = tokio::process::Command::new(&binary_download_path) + .kill_on_drop(true) + .stdout(std::process::Stdio::inherit()) // Inherit the stdout of this process + .stderr(std::process::Stdio::inherit()) // Inherit the stderr of this process + .stdin(std::process::Stdio::null()) + .current_dir(&std::env::current_dir()?) + .envs(env_vars) + .args(arguments) + .spawn()?; + + if blueprint.registration_mode { + // We must wait for the process to exit successfully + let status = process_handle.wait_with_output().await?; + if !status.status.success() { + error!( + "Protocol (registration mode) {sub_service_str} failed to execute: {status:?}" + ); + } else { + info!("***Protocol (registration mode) {sub_service_str} executed successfully***"); + } + } else { + // A normal running gadget binary. Store the process handle and let the event loop handle the rest + + let (status_handle, abort) = + generate_running_process_status_handle(process_handle, &sub_service_str); + + active_gadgets + .entry(blueprint_id) + .or_default() + .insert(*service_id, (status_handle, Some(abort))); + } + } + + Ok(()) +} + +pub fn generate_process_arguments( + gadget_config: &GadgetConfiguration, + opt: &BlueprintManagerConfig, + blueprint_id: u64, + service_id: u64, + protocol: Protocol, +) -> color_eyre::Result> { + let mut arguments = vec![]; + arguments.push("run".to_string()); + + if opt.test_mode { + arguments.push("--test-mode".to_string()); + } + + if opt.pretty { + arguments.push("--pretty".to_string()); + } + + for bootnode in &gadget_config.bootnodes { + arguments.push(format!("--bootnodes={}", bootnode)); + } + + arguments.extend([ + format!("--http-rpc-url={}", gadget_config.http_rpc_endpoint), + format!("--ws-rpc-url={}", gadget_config.ws_rpc_endpoint), + format!("--keystore-uri={}", gadget_config.keystore_uri), + format!("--protocol={}", protocol), + format!( + "--log-id=Blueprint-{blueprint_id}-Service-{service_id}{}", + opt.instance_id + .clone() + .map_or(String::new(), |id| format!("-{}", id)) + ), + ]); + + // TODO: Add support for keystore password + // if let Some(keystore_password) = &gadget_config.keystore_password { + // arguments.push(format!("--keystore-password={}", keystore_password)); + // } + + // Uses occurrences of clap short -v + if opt.verbose > 0 { + arguments.push(format!("-{}", "v".repeat(opt.verbose as usize))); + } + + Ok(arguments) +} diff --git a/crates/blueprint/manager/src/sources/testing.rs b/crates/blueprint/manager/src/sources/testing.rs new file mode 100644 index 0000000..df26298 --- /dev/null +++ b/crates/blueprint/manager/src/sources/testing.rs @@ -0,0 +1,92 @@ +use crate::sources::BinarySourceFetcher; +use async_trait::async_trait; +use color_eyre::Report; +use gadget_logging::trace; +use std::path::PathBuf; +use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::TestFetcher; + +pub struct TestSourceFetcher { + pub fetcher: TestFetcher, + pub blueprint_id: u64, + pub gadget_name: String, +} + +#[async_trait] +impl BinarySourceFetcher for TestSourceFetcher { + async fn get_binary(&self) -> color_eyre::Result { + // Step 1: Build the binary. It will be stored in the root directory/bin/ + let TestFetcher { + cargo_package, + base_path, + .. + } = &self.fetcher; + let cargo_bin = String::from_utf8(cargo_package.0 .0.clone()) + .map_err(|err| Report::msg(format!("Failed to parse `cargo_bin`: {:?}", err)))?; + let base_path_str = String::from_utf8(base_path.0 .0.clone()) + .map_err(|err| Report::msg(format!("Failed to parse `base_path`: {:?}", err)))?; + let git_repo_root = get_git_repo_root_path().await?; + + let profile = if cfg!(debug_assertions) { + "debug" + } else { + "release" + }; + let base_path = std::path::absolute(git_repo_root.join(&base_path_str))?; + + let target_dir = match std::env::var("CARGO_TARGET_DIR") { + Ok(target) => PathBuf::from(target), + Err(_) => git_repo_root.join(&base_path).join("target"), + }; + + let binary_path = target_dir.join(profile).join(&cargo_bin); + let binary_path = std::path::absolute(&binary_path)?; + + trace!("Base Path: {}", base_path.display()); + trace!("Binary Path: {}", binary_path.display()); + + // Run cargo build on the cargo_bin and ensure it build to the binary_path + let mut command = tokio::process::Command::new("cargo"); + command + .arg("build") + .arg(format!("--target-dir={}", target_dir.display())) + .arg("--bin") + .arg(&cargo_bin); + + if !cfg!(debug_assertions) { + command.arg("--release"); + } + + let output = command.current_dir(&base_path).output().await?; + + if !output.status.success() { + return Err(Report::msg(format!("Failed to build binary: {:?}", output))); + } + + Ok(binary_path) + } + + fn blueprint_id(&self) -> u64 { + self.blueprint_id + } + + fn name(&self) -> String { + self.gadget_name.clone() + } +} +async fn get_git_repo_root_path() -> color_eyre::Result { + // Run a process to determine the root directory for this repo + let output = tokio::process::Command::new("git") + .arg("rev-parse") + .arg("--show-toplevel") + .output() + .await?; + + if !output.status.success() { + return Err(Report::msg(format!( + "Failed to get git root path: {:?}", + output + ))); + } + + Ok(PathBuf::from(String::from_utf8(output.stdout)?.trim())) +} diff --git a/crates/crypto/src/lib.rs b/crates/crypto/src/lib.rs index 884e09a..d0189df 100644 --- a/crates/crypto/src/lib.rs +++ b/crates/crypto/src/lib.rs @@ -28,6 +28,9 @@ pub use gadget_crypto_tangle_pair_signer as tangle_pair_signer; #[cfg(feature = "hashing")] pub use gadget_crypto_hashing as hashing; +#[cfg(feature = "tangle-pair-signer")] +pub use gadget_crypto_tangle_pair_signer as tangle_pair_signer; + #[derive(Debug, Error)] pub enum CryptoCoreError { #[cfg(feature = "k256")] diff --git a/crates/crypto/tangle-pair-signer/src/lib.rs b/crates/crypto/tangle-pair-signer/src/lib.rs index 84c198e..e62d4af 100644 --- a/crates/crypto/tangle-pair-signer/src/lib.rs +++ b/crates/crypto/tangle-pair-signer/src/lib.rs @@ -1,6 +1,125 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod error; -pub mod tangle_pair_signer; -pub use tangle_pair_signer::*; +use gadget_std::vec::Vec; +pub use sp_core; +use sp_core::crypto::DeriveError; +use sp_core::crypto::SecretStringError; +use sp_core::DeriveJunction; +use subxt::PolkadotConfig; +use subxt_core::{ + tx::signer::{PairSigner, Signer}, + utils::{AccountId32, MultiAddress, MultiSignature}, +}; + +#[derive(Clone, Debug)] +pub struct TanglePairSigner { + pub(crate) pair: subxt::tx::PairSigner, +} + +impl sp_core::crypto::CryptoType for TanglePairSigner { + type Pair = Pair; +} + +impl TanglePairSigner +where + ::Signature: Into, + subxt::ext::sp_runtime::MultiSigner: From<::Public>, +{ + pub fn new(pair: Pair) -> Self { + TanglePairSigner { + pair: PairSigner::new(pair), + } + } + + pub fn into_inner(self) -> PairSigner { + self.pair + } + + pub fn signer(&self) -> &Pair { + self.pair.signer() + } +} + +impl Signer for TanglePairSigner +where + Pair: sp_core::Pair, + Pair::Signature: Into, +{ + fn account_id(&self) -> AccountId32 { + self.pair.account_id() + } + + fn address(&self) -> MultiAddress { + self.pair.address() + } + + fn sign(&self, signer_payload: &[u8]) -> MultiSignature { + self.pair.sign(signer_payload) + } +} + +impl sp_core::Pair for TanglePairSigner +where + ::Signature: Into, + subxt::ext::sp_runtime::MultiSigner: From<::Public>, +{ + type Public = Pair::Public; + type Seed = Pair::Seed; + type Signature = Pair::Signature; + + fn derive>( + &self, + path: Iter, + seed: Option, + ) -> Result<(Self, Option), DeriveError> { + Pair::derive(self.pair.signer(), path, seed).map(|(pair, seed)| { + ( + TanglePairSigner { + pair: PairSigner::new(pair), + }, + seed, + ) + }) + } + + fn from_seed_slice(seed: &[u8]) -> Result { + Pair::from_seed_slice(seed).map(|pair| TanglePairSigner { + pair: PairSigner::new(pair), + }) + } + + fn sign(&self, message: &[u8]) -> Self::Signature { + Pair::sign(self.pair.signer(), message) + } + + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + Pair::verify(sig, message, pubkey) + } + + fn public(&self) -> Self::Public { + Pair::public(self.pair.signer()) + } + + fn to_raw_vec(&self) -> Vec { + Pair::to_raw_vec(self.pair.signer()) + } +} + +#[cfg(feature = "evm")] +impl TanglePairSigner { + /// Returns the alloy-compatible key for the ECDSA key pair. + pub fn alloy_key( + &self, + ) -> crate::error::Result> { + let k256_ecdsa_secret_key = self.pair.signer().seed(); + let res = alloy_signer_local::LocalSigner::from_slice(&k256_ecdsa_secret_key)?; + Ok(res) + } + + /// Returns the Alloy Address for the ECDSA key pair. + pub fn alloy_address(&self) -> crate::error::Result { + Ok(self.alloy_key()?.address()) + } +} diff --git a/crates/crypto/tangle-pair-signer/src/tangle_pair_signer.rs b/crates/crypto/tangle-pair-signer/src/tangle_pair_signer.rs deleted file mode 100644 index 07947ee..0000000 --- a/crates/crypto/tangle-pair-signer/src/tangle_pair_signer.rs +++ /dev/null @@ -1,121 +0,0 @@ -use gadget_std::vec::Vec; -pub use sp_core; -use sp_core::crypto::DeriveError; -use sp_core::crypto::SecretStringError; -use sp_core::DeriveJunction; -use subxt::PolkadotConfig; -use subxt_core::{ - tx::signer::{PairSigner, Signer}, - utils::{AccountId32, MultiAddress, MultiSignature}, -}; - -#[derive(Clone, Debug)] -pub struct TanglePairSigner { - pub pair: subxt::tx::PairSigner, -} - -impl sp_core::crypto::CryptoType for TanglePairSigner { - type Pair = Pair; -} - -impl TanglePairSigner -where - ::Signature: Into, - subxt::ext::sp_runtime::MultiSigner: From<::Public>, -{ - pub fn new(pair: Pair) -> Self { - TanglePairSigner { - pair: PairSigner::new(pair), - } - } - - pub fn into_inner(self) -> PairSigner { - self.pair - } - - pub fn signer(&self) -> &Pair { - self.pair.signer() - } -} - -impl Signer for TanglePairSigner -where - Pair: sp_core::Pair, - Pair::Signature: Into, -{ - fn account_id(&self) -> AccountId32 { - self.pair.account_id() - } - - fn address(&self) -> MultiAddress { - self.pair.address() - } - - fn sign(&self, signer_payload: &[u8]) -> MultiSignature { - self.pair.sign(signer_payload) - } -} - -impl sp_core::Pair for TanglePairSigner -where - ::Signature: Into, - subxt::ext::sp_runtime::MultiSigner: From<::Public>, -{ - type Public = Pair::Public; - type Seed = Pair::Seed; - type Signature = Pair::Signature; - - fn derive>( - &self, - path: Iter, - seed: Option, - ) -> Result<(Self, Option), DeriveError> { - Pair::derive(self.pair.signer(), path, seed).map(|(pair, seed)| { - ( - TanglePairSigner { - pair: PairSigner::new(pair), - }, - seed, - ) - }) - } - - fn from_seed_slice(seed: &[u8]) -> Result { - Pair::from_seed_slice(seed).map(|pair| TanglePairSigner { - pair: PairSigner::new(pair), - }) - } - - fn sign(&self, message: &[u8]) -> Self::Signature { - Pair::sign(self.pair.signer(), message) - } - - fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { - Pair::verify(sig, message, pubkey) - } - - fn public(&self) -> Self::Public { - Pair::public(self.pair.signer()) - } - - fn to_raw_vec(&self) -> Vec { - Pair::to_raw_vec(self.pair.signer()) - } -} - -#[cfg(feature = "evm")] -impl TanglePairSigner { - /// Returns the alloy-compatible key for the ECDSA key pair. - pub fn alloy_key( - &self, - ) -> crate::error::Result> { - let k256_ecdsa_secret_key = self.pair.signer().seed(); - let res = alloy_signer_local::LocalSigner::from_slice(&k256_ecdsa_secret_key)?; - Ok(res) - } - - /// Returns the Alloy Address for the ECDSA key pair. - pub fn alloy_address(&self) -> crate::error::Result { - Ok(self.alloy_key()?.address()) - } -} diff --git a/crates/event-listeners/tangle/src/events.rs b/crates/event-listeners/tangle/src/events.rs index 22a9170..abf0d9f 100644 --- a/crates/event-listeners/tangle/src/events.rs +++ b/crates/event-listeners/tangle/src/events.rs @@ -1,7 +1,7 @@ use crate::error::{Result, TangleEventListenerError}; use async_trait::async_trait; use gadget_clients::tangle::client::{OnlineClient, TangleConfig}; -use gadget_crypto_tangle_pair_signer::tangle_pair_signer::TanglePairSigner; +use gadget_crypto_tangle_pair_signer::TanglePairSigner; use gadget_event_listeners_core::marker::IsTangle; use gadget_event_listeners_core::EventListener; use gadget_std::collections::VecDeque; diff --git a/crates/keystore/Cargo.toml b/crates/keystore/Cargo.toml index 737d734..f2166aa 100644 --- a/crates/keystore/Cargo.toml +++ b/crates/keystore/Cargo.toml @@ -121,6 +121,7 @@ tangle = [ "ecdsa", "sr25519-schnorrkel", "zebra", + "gadget-crypto/tangle-pair-signer", ] tangle-bls = [ diff --git a/crates/keystore/src/keystore/backends/tangle.rs b/crates/keystore/src/keystore/backends/tangle.rs index 1cf017e..e74ba4c 100644 --- a/crates/keystore/src/keystore/backends/tangle.rs +++ b/crates/keystore/src/keystore/backends/tangle.rs @@ -3,15 +3,10 @@ use crate::keystore::Keystore; use gadget_crypto::sp_core_crypto::{ SpEcdsaPair, SpEcdsaPublic, SpEd25519Pair, SpEd25519Public, SpSr25519Pair, SpSr25519Public, }; +use gadget_crypto::tangle_pair_signer::TanglePairSigner; use gadget_crypto::KeyTypeId; use sp_core::Pair; use sp_core::{ecdsa, ed25519, sr25519}; -use subxt::tx::PairSigner; -use subxt::PolkadotConfig; - -pub struct TanglePairSigner { - pub pair: subxt::tx::PairSigner, -} #[async_trait::async_trait] pub trait TangleBackend: Send + Sync { @@ -56,9 +51,9 @@ pub trait TangleBackend: Send + Sync { let pair = pair.into(); let seed = pair.as_ref().secret.to_bytes(); let _ = self.sr25519_generate_new(Some(&seed))?; - Ok(TanglePairSigner { - pair: PairSigner::new(sr25519::Pair::from_seed_slice(&seed)?), - }) + Ok(TanglePairSigner::new(sr25519::Pair::from_seed_slice( + &seed, + )?)) } fn create_ed25519_from_pair>( @@ -68,9 +63,9 @@ pub trait TangleBackend: Send + Sync { let pair = pair.into(); let seed = pair.seed(); let _ = self.ed25519_generate_new(Some(&seed))?; - Ok(TanglePairSigner { - pair: PairSigner::new(ed25519::Pair::from_seed_slice(&seed)?), - }) + Ok(TanglePairSigner::new(ed25519::Pair::from_seed_slice( + &seed, + )?)) } fn create_ecdsa_from_pair>( @@ -80,9 +75,7 @@ pub trait TangleBackend: Send + Sync { let pair = pair.into(); let seed = pair.seed(); let _ = self.ecdsa_generate_new(Some(&seed))?; - Ok(TanglePairSigner { - pair: PairSigner::new(ecdsa::Pair::from_seed_slice(&seed)?), - }) + Ok(TanglePairSigner::new(ecdsa::Pair::from_seed_slice(&seed)?)) } } diff --git a/crates/keystore/src/keystore/config.rs b/crates/keystore/src/keystore/config.rs index 2b79cc5..660ea56 100644 --- a/crates/keystore/src/keystore/config.rs +++ b/crates/keystore/src/keystore/config.rs @@ -30,7 +30,7 @@ /// [`InMemoryStorage`]: crate::storage::InMemoryStorage /// [`Keystore`]: crate::Keystore /// [`Keystore::new()`]: crate::Keystore::new -#[derive(Default)] +#[derive(Default, Debug)] pub struct KeystoreConfig { pub(crate) in_memory: bool, #[cfg(feature = "std")] From 43481066d44af14d0b764b4e60bc6956171249b3 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Thu, 26 Dec 2024 13:17:34 -0500 Subject: [PATCH 2/4] chore(blueprint-manager): remove dead code --- .../blueprint/manager/src/protocols/config.rs | 14 --------- crates/blueprint/manager/src/protocols/mod.rs | 1 - crates/blueprint/manager/src/sdk/config.rs | 16 ---------- crates/blueprint/manager/src/sdk/mod.rs | 1 - crates/blueprint/manager/src/sdk/utils.rs | 30 ------------------- 5 files changed, 62 deletions(-) delete mode 100644 crates/blueprint/manager/src/protocols/config.rs delete mode 100644 crates/blueprint/manager/src/sdk/config.rs diff --git a/crates/blueprint/manager/src/protocols/config.rs b/crates/blueprint/manager/src/protocols/config.rs deleted file mode 100644 index efb0f47..0000000 --- a/crates/blueprint/manager/src/protocols/config.rs +++ /dev/null @@ -1,14 +0,0 @@ -use gadget_std::collections::HashMap; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -pub struct ProtocolConfig { - pub(crate) protocols: Vec, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct ProtocolToml { - pub package: String, - pub repository: Option>, - pub bin_hashes: Option>, -} diff --git a/crates/blueprint/manager/src/protocols/mod.rs b/crates/blueprint/manager/src/protocols/mod.rs index 2f1bf1d..e755804 100644 --- a/crates/blueprint/manager/src/protocols/mod.rs +++ b/crates/blueprint/manager/src/protocols/mod.rs @@ -1,2 +1 @@ -pub mod config; pub mod resolver; diff --git a/crates/blueprint/manager/src/sdk/config.rs b/crates/blueprint/manager/src/sdk/config.rs deleted file mode 100644 index 47b7f66..0000000 --- a/crates/blueprint/manager/src/sdk/config.rs +++ /dev/null @@ -1,16 +0,0 @@ -use gadget_keystore::KeystoreConfig; -use libp2p::Multiaddr; -use std::net::IpAddr; -use std::path::PathBuf; -use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::ServiceBlueprint; - -#[derive(Debug)] -pub struct SingleGadgetConfig { - pub base_path: PathBuf, - pub keystore: KeystoreConfig, - pub bind_ip: IpAddr, - pub bind_port: u16, - pub bootnodes: Vec, - pub services: Vec, - pub n_protocols: usize, -} diff --git a/crates/blueprint/manager/src/sdk/mod.rs b/crates/blueprint/manager/src/sdk/mod.rs index 6d16dec..555eb18 100644 --- a/crates/blueprint/manager/src/sdk/mod.rs +++ b/crates/blueprint/manager/src/sdk/mod.rs @@ -1,3 +1,2 @@ -pub mod config; pub mod entry; pub mod utils; diff --git a/crates/blueprint/manager/src/sdk/utils.rs b/crates/blueprint/manager/src/sdk/utils.rs index e11c0df..dd4ca8d 100644 --- a/crates/blueprint/manager/src/sdk/utils.rs +++ b/crates/blueprint/manager/src/sdk/utils.rs @@ -10,26 +10,6 @@ use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives: GadgetBinary, GithubFetcher, }; -pub fn github_fetcher_to_native_github_metadata( - gh: &GithubFetcher, - blueprint_id: u64, -) -> NativeGithubMetadata { - let owner = bytes_to_utf8_string(gh.owner.0 .0.clone()).expect("Should be valid"); - let repo = bytes_to_utf8_string(gh.repo.0 .0.clone()).expect("Should be valid"); - let tag = bytes_to_utf8_string(gh.tag.0 .0.clone()).expect("Should be valid"); - let git = format!("https://github.com/{owner}/{repo}"); - - NativeGithubMetadata { - fetcher: gh.clone(), - git, - tag, - repo, - owner, - gadget_binaries: gh.binaries.0.clone(), - blueprint_id, - } -} - pub fn bounded_string_to_string(string: BoundedString) -> Result { let bytes: &Vec = &string.0 .0; String::from_utf8(bytes.clone()) @@ -81,12 +61,6 @@ pub fn msg_to_error>(msg: T) -> color_eyre::Report { color_eyre::Report::msg(msg.into()) } -pub fn get_service_str(svc: &NativeGithubMetadata) -> String { - let repo = svc.git.clone(); - let vals: Vec<&str> = repo.split(".com/").collect(); - vals[1].to_string() -} - pub async fn chmod_x_file>(path: P) -> color_eyre::Result<()> { let success = tokio::process::Command::new("chmod") .arg("+x") @@ -138,10 +112,6 @@ pub fn generate_running_process_status_handle( (status, stop_tx) } -pub fn bytes_to_utf8_string>>(input: T) -> color_eyre::Result { - String::from_utf8(input.into()).map_err(|err| msg_to_error(err.to_string())) -} - pub fn slice_32_to_sha_hex_string(hash: [u8; 32]) -> String { use std::fmt::Write; hash.iter().fold(String::new(), |mut acc, byte| { From d26dfa450c7873ca705b1b42cdfa3d15067faa56 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Fri, 27 Dec 2024 11:36:21 -0500 Subject: [PATCH 3/4] refactor(blueprint-manager): lots of cleanup --- Cargo.lock | 2 + crates/blueprint/manager/Cargo.toml | 1 + crates/blueprint/manager/src/error.rs | 57 ++-- .../manager/src/executor/event_handler.rs | 309 +++++++++++------- crates/blueprint/manager/src/executor/mod.rs | 49 +-- crates/blueprint/manager/src/lib.rs | 1 - crates/blueprint/manager/src/main.rs | 4 +- crates/blueprint/manager/src/protocols/mod.rs | 1 - .../manager/src/protocols/resolver.rs | 14 - crates/blueprint/manager/src/sdk/utils.rs | 40 +-- .../blueprint/manager/src/sources/github.rs | 61 ++-- crates/blueprint/manager/src/sources/mod.rs | 174 +++------- .../blueprint/manager/src/sources/testing.rs | 18 +- crates/clients/Cargo.toml | 3 + crates/clients/core/src/lib.rs | 22 +- crates/clients/eigenlayer/src/error.rs | 8 +- crates/clients/evm/src/error.rs | 4 +- crates/clients/networking/src/error.rs | 4 +- crates/clients/networking/src/p2p.rs | 8 +- crates/clients/src/error.rs | 17 + crates/clients/src/lib.rs | 2 + crates/clients/tangle/src/client.rs | 73 ++--- crates/clients/tangle/src/error.rs | 30 +- crates/clients/tangle/src/services.rs | 6 +- 24 files changed, 432 insertions(+), 476 deletions(-) delete mode 100644 crates/blueprint/manager/src/protocols/mod.rs delete mode 100644 crates/blueprint/manager/src/protocols/resolver.rs create mode 100644 crates/clients/src/error.rs diff --git a/Cargo.lock b/Cargo.lock index 0ae3822..a81b9ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2359,6 +2359,7 @@ dependencies = [ "serde", "sha2 0.10.8", "tangle-subxt", + "thiserror 2.0.7", "tokio", "toml", "tracing", @@ -4853,6 +4854,7 @@ dependencies = [ "gadget-client-evm", "gadget-client-networking", "gadget-client-tangle", + "thiserror 2.0.7", ] [[package]] diff --git a/crates/blueprint/manager/Cargo.toml b/crates/blueprint/manager/Cargo.toml index 20a7a70..8fe8e0e 100644 --- a/crates/blueprint/manager/Cargo.toml +++ b/crates/blueprint/manager/Cargo.toml @@ -32,6 +32,7 @@ reqwest = { workspace = true } sha2 = { workspace = true } futures = { workspace = true } itertools = { workspace = true } +thiserror.workspace = true tracing = { workspace = true, features = ["log"] } tracing-subscriber = { workspace = true, features = ["env-filter", "ansi", "tracing-log"] } libp2p = { workspace = true } diff --git a/crates/blueprint/manager/src/error.rs b/crates/blueprint/manager/src/error.rs index 74d0130..01ac696 100644 --- a/crates/blueprint/manager/src/error.rs +++ b/crates/blueprint/manager/src/error.rs @@ -1,30 +1,39 @@ -use std::fmt::{Display, Formatter}; +pub type Result = std::result::Result; -#[derive(Debug, Clone)] -pub struct Error { - pub message: String, -} +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("No fetchers found for blueprint")] + NoFetchers, + #[error("Multiple fetchers found for blueprint")] + MultipleFetchers, + #[error("No testing fetcher found for blueprint, despite operating in test mode")] + NoTestFetcher, + #[error("Blueprint does not contain a supported fetcher")] + UnsupportedGadget, -impl Error { - pub fn msg>(msg: T) -> Self { - Self { - message: msg.into(), - } - } -} + #[error("Unable to find matching binary")] + NoMatchingBinary, + #[error("Binary hash {expected} mismatched expected hash of {actual}")] + HashMismatch { expected: String, actual: String }, + #[error("Failed to build binary: {0:?}")] + BuildBinary(std::process::Output), + #[error("Failed to fetch git root: {0:?}")] + FetchGitRoot(std::process::Output), -impl Display for Error { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - std::fmt::Debug::fmt(self, f) - } -} + #[error("Failed to get initial block hash")] + InitialBlock, + #[error("Finality Notification stream died")] + ClientDied, + #[error("{0}")] + Other(String), -impl std::error::Error for Error {} + #[error(transparent)] + Io(#[from] std::io::Error), + #[error(transparent)] + Utf8(#[from] std::string::FromUtf8Error), -impl From for Error { - fn from(error: std::io::Error) -> Self { - Error { - message: error.to_string(), - } - } + #[error(transparent)] + Request(#[from] reqwest::Error), + #[error(transparent)] + TangleClient(#[from] gadget_clients::tangle::error::Error), } diff --git a/crates/blueprint/manager/src/executor/event_handler.rs b/crates/blueprint/manager/src/executor/event_handler.rs index 5931c9d..5e01e22 100644 --- a/crates/blueprint/manager/src/executor/event_handler.rs +++ b/crates/blueprint/manager/src/executor/event_handler.rs @@ -1,10 +1,12 @@ use crate::config::BlueprintManagerConfig; +use crate::error::{Error, Result}; use crate::gadget::native::FilteredBlueprint; use crate::gadget::ActiveGadgets; -use crate::sdk::utils::bounded_string_to_string; +use crate::sdk::utils::{ + bounded_string_to_string, generate_running_process_status_handle, make_executable, +}; use crate::sources::github::GithubBinaryFetcher; -use crate::sources::BinarySourceFetcher; -use color_eyre::eyre::OptionExt; +use crate::sources::{process_arguments_and_env, BinarySourceFetcher}; use gadget_clients::tangle::client::{TangleConfig, TangleEvent}; use gadget_clients::tangle::services::{RpcServicesWithBlueprint, TangleServicesClient}; use gadget_config::{GadgetConfiguration, Protocol}; @@ -24,6 +26,85 @@ pub struct VerifiedBlueprint<'a> { pub(crate) blueprint: FilteredBlueprint, } +impl VerifiedBlueprint<'_> { + pub async fn start_services_if_needed( + &self, + gadget_config: &GadgetConfiguration, + blueprint_manager_opts: &BlueprintManagerConfig, + active_gadgets: &mut ActiveGadgets, + ) -> Result<()> { + let blueprint_source = &self.fetcher; + let blueprint = &self.blueprint; + + let blueprint_id = blueprint_source.blueprint_id(); + if active_gadgets.contains_key(&blueprint_id) { + return Ok(()); + } + + let mut binary_download_path = blueprint_source.get_binary().await?; + + // Ensure the binary is executable + if cfg!(target_family = "windows") { + if binary_download_path.extension().is_none() { + binary_download_path.set_extension("exe"); + } + } else if let Err(err) = make_executable(&binary_download_path) { + let msg = format!("Failed to make the binary executable: {err}"); + warn!("{}", msg); + return Err(Error::Other(msg)); + } + + let service_str = blueprint_source.name(); + for service_id in &blueprint.services { + let sub_service_str = format!("{service_str}-{service_id}"); + let (arguments, env_vars) = process_arguments_and_env( + gadget_config, + blueprint_manager_opts, + blueprint_id, + *service_id, + blueprint, + &sub_service_str, + ); + + info!("Starting protocol: {sub_service_str} with args: {arguments:?}"); + + // Now that the file is loaded, spawn the process + let process_handle = tokio::process::Command::new(&binary_download_path) + .kill_on_drop(true) + .stdin(std::process::Stdio::null()) + .current_dir(&std::env::current_dir()?) + .envs(env_vars) + .args(arguments) + .spawn()?; + + if blueprint.registration_mode { + // We must wait for the process to exit successfully + let status = process_handle.wait_with_output().await?; + if status.status.success() { + info!("***Protocol (registration mode) {sub_service_str} executed successfully***"); + } else { + error!( + "Protocol (registration mode) {sub_service_str} failed to execute: {status:?}" + ); + } + continue; + } + + // A normal running gadget binary. Store the process handle and let the event loop handle the rest + + let (status_handle, abort) = + generate_running_process_status_handle(process_handle, &sub_service_str); + + active_gadgets + .entry(blueprint_id) + .or_default() + .insert(*service_id, (status_handle, Some(abort))); + } + + Ok(()) + } +} + impl Debug for VerifiedBlueprint<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { format!( @@ -34,28 +115,6 @@ impl Debug for VerifiedBlueprint<'_> { } } -pub async fn handle_services( - blueprints: &[VerifiedBlueprint<'_>], - gadget_config: &GadgetConfiguration, - blueprint_manager_opts: &BlueprintManagerConfig, - active_gadgets: &mut ActiveGadgets, -) -> color_eyre::Result<()> { - for blueprint in blueprints { - if let Err(err) = crate::sources::handle( - blueprint, - gadget_config, - blueprint_manager_opts, - active_gadgets, - ) - .await - { - error!("{err}"); - } - } - - Ok(()) -} - #[derive(Default, Debug)] pub struct EventPollResult { pub needs_update: bool, @@ -63,7 +122,7 @@ pub struct EventPollResult { pub blueprint_registrations: Vec, } -pub(crate) async fn check_blueprint_events( +pub(crate) fn check_blueprint_events( event: &TangleEvent, active_gadgets: &mut ActiveGadgets, account_id: &AccountId32, @@ -166,11 +225,11 @@ pub(crate) async fn handle_tangle_event( event: &TangleEvent, blueprints: &[RpcServicesWithBlueprint], gadget_config: &GadgetConfiguration, - gadget_manager_opts: &BlueprintManagerConfig, + manager_opts: &BlueprintManagerConfig, active_gadgets: &mut ActiveGadgets, poll_result: EventPollResult, client: &TangleServicesClient, -) -> color_eyre::Result<()> { +) -> Result<()> { info!("Received notification {}", event.number); const DEFAULT_PROTOCOL: Protocol = Protocol::Tangle; warn!("Using Tangle protocol as default over Eigen. This is a temporary development workaround. You can alter this behavior here"); @@ -185,7 +244,11 @@ pub(crate) async fn handle_tangle_event( let blueprint = client .get_blueprint_by_id(event.hash, *blueprint_id) .await? - .ok_or_eyre("Unable to retrieve blueprint for registration mode")?; + .ok_or_else(|| { + Error::Other(String::from( + "Unable to retrieve blueprint for registration mode", + )) + })?; let general_blueprint = FilteredBlueprint { blueprint_id: *blueprint_id, @@ -215,86 +278,14 @@ pub(crate) async fn handle_tangle_event( }) .chain(registration_blueprints) { - let mut test_fetcher_idx = None; - let mut fetcher_candidates: Vec> = vec![]; - - if let Gadget::Native(gadget) = &blueprint.gadget { - for (source_idx, gadget_source) in gadget.sources.0.iter().enumerate() { - match &gadget_source.fetcher { - GadgetSourceFetcher::Github(gh) => { - let fetcher = GithubBinaryFetcher { - fetcher: gh.clone(), - blueprint_id: blueprint.blueprint_id, - gadget_name: blueprint.name.clone(), - }; - - fetcher_candidates.push(Box::new(fetcher)); - } - - GadgetSourceFetcher::Testing(test) => { - // TODO: demote to TRACE once proven to work - if !gadget_manager_opts.test_mode { - warn!("Ignoring testing fetcher as we are not in test mode"); - continue; - } - - let fetcher = crate::sources::testing::TestSourceFetcher { - fetcher: test.clone(), - blueprint_id: blueprint.blueprint_id, - gadget_name: blueprint.name.clone(), - }; - - test_fetcher_idx = Some(source_idx); - fetcher_candidates.push(Box::new(fetcher)); - } - - _ => { - warn!("Blueprint does not contain a supported fetcher"); - continue; - } - } - } - - // A bunch of sanity checks to enforce structure - - // Ensure that we have at least one fetcher - if fetcher_candidates.is_empty() { - warn!("No fetchers found for blueprint: {}", blueprint.name,); - continue; - } - - // Ensure that we have a test fetcher if we are in test mode - if gadget_manager_opts.test_mode && test_fetcher_idx.is_none() { - return Err(color_eyre::Report::msg(format!( - "No testing fetcher found for blueprint `{}` despite operating in TEST MODE", - blueprint.name, - ))); - } + let mut fetcher_candidates = get_fetcher_candidates(&blueprint, manager_opts)?; - // Ensure that we have only one fetcher if we are in test mode - if gadget_manager_opts.test_mode { - fetcher_candidates = - vec![fetcher_candidates.remove(test_fetcher_idx.expect("Should exist"))]; - } - - // Ensure there is only a single candidate fetcher - if fetcher_candidates.len() != 1 { - warn!( - "Multiple fetchers found for blueprint: {}. Invalidating blueprint", - blueprint.name, - ); - continue; - } - - let verified_blueprint = VerifiedBlueprint { - fetcher: fetcher_candidates.pop().expect("Should exist"), - blueprint, - }; + let verified_blueprint = VerifiedBlueprint { + fetcher: fetcher_candidates.pop().expect("Should exist"), + blueprint, + }; - verified_blueprints.push(verified_blueprint); - } else { - warn!("Blueprint does not contain a native gadget and thus currently unsupported"); - } + verified_blueprints.push(verified_blueprint); } trace!( @@ -306,20 +297,18 @@ pub(crate) async fn handle_tangle_event( ); // Step 3: Check to see if we need to start any new services - handle_services( - &verified_blueprints, - gadget_config, - gadget_manager_opts, - active_gadgets, - ) - .await?; + for blueprint in &verified_blueprints { + blueprint + .start_services_if_needed(gadget_config, manager_opts, active_gadgets) + .await?; + } // Check to see if local is running services that are not on-chain let mut to_remove: Vec<(u64, u64)> = vec![]; // Loop through every (blueprint_id, service_id) running. See if the service is still on-chain. If not, kill it and add it to to_remove for (blueprint_id, process_handles) in &mut *active_gadgets { - for service_id in process_handles.keys() { + for (service_id, process_handle) in process_handles { info!( "Checking service for on-chain termination: bid={blueprint_id}//sid={service_id}" ); @@ -335,12 +324,8 @@ pub(crate) async fn handle_tangle_event( to_remove.push((*blueprint_id, *service_id)); } } - } - } - // Check to see if any process handles have died - for (blueprint_id, process_handles) in &mut *active_gadgets { - for (service_id, process_handle) in process_handles { + // Check to see if any process handles have died if !to_remove.contains(&(*blueprint_id, *service_id)) && !process_handle.0.load(Ordering::Relaxed) { @@ -377,3 +362,87 @@ pub(crate) async fn handle_tangle_event( Ok(()) } + +fn get_fetcher_candidates( + blueprint: &FilteredBlueprint, + manager_opts: &BlueprintManagerConfig, +) -> Result>> { + let mut test_fetcher_idx = None; + let mut fetcher_candidates: Vec> = vec![]; + + let sources; + match &blueprint.gadget { + Gadget::Native(gadget) => { + sources = &gadget.sources.0; + } + Gadget::Wasm(_) => { + warn!("WASM gadgets are not supported yet"); + return Err(Error::UnsupportedGadget); + } + Gadget::Container(_) => { + warn!("Container gadgets are not supported yet"); + return Err(Error::UnsupportedGadget); + } + } + + for (source_idx, gadget_source) in sources.iter().enumerate() { + match &gadget_source.fetcher { + GadgetSourceFetcher::Github(gh) => { + let fetcher = GithubBinaryFetcher { + fetcher: gh.clone(), + blueprint_id: blueprint.blueprint_id, + gadget_name: blueprint.name.clone(), + }; + + fetcher_candidates.push(Box::new(fetcher)); + } + + GadgetSourceFetcher::Testing(test) => { + // TODO: demote to TRACE once proven to work + if !manager_opts.test_mode { + warn!("Ignoring testing fetcher as we are not in test mode"); + continue; + } + + let fetcher = crate::sources::testing::TestSourceFetcher { + fetcher: test.clone(), + blueprint_id: blueprint.blueprint_id, + gadget_name: blueprint.name.clone(), + }; + + test_fetcher_idx = Some(source_idx); + fetcher_candidates.push(Box::new(fetcher)); + } + + _ => { + warn!("Blueprint does not contain a supported fetcher"); + continue; + } + } + } + + // A bunch of sanity checks to enforce structure + + // Ensure that we have at least one fetcher + if fetcher_candidates.is_empty() { + return Err(Error::NoFetchers); + } + + // Ensure there is only a single candidate fetcher + if fetcher_candidates.len() != 1 { + return Err(Error::MultipleFetchers); + } + + // Ensure that we have a test fetcher if we are in test mode + if manager_opts.test_mode && test_fetcher_idx.is_none() { + return Err(Error::NoTestFetcher); + } + + // Ensure that we have only one fetcher if we are in test mode + if manager_opts.test_mode { + fetcher_candidates = + vec![fetcher_candidates.remove(test_fetcher_idx.expect("Should exist"))]; + } + + Ok(fetcher_candidates) +} diff --git a/crates/blueprint/manager/src/executor/mod.rs b/crates/blueprint/manager/src/executor/mod.rs index 526afcb..b51434b 100644 --- a/crates/blueprint/manager/src/executor/mod.rs +++ b/crates/blueprint/manager/src/executor/mod.rs @@ -1,8 +1,8 @@ use crate::config::BlueprintManagerConfig; +use crate::error::Error; +use crate::error::Result; use crate::gadget::ActiveGadgets; use crate::sdk::entry::SendFuture; -use crate::sdk::utils; -use crate::sdk::utils::msg_to_error; use color_eyre::eyre::OptionExt; use color_eyre::Report; use gadget_clients::tangle::client::{TangleClient, TangleConfig}; @@ -17,29 +17,13 @@ use std::collections::HashMap; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; -use tangle_subxt::subxt::blocks::BlockRef; -use tangle_subxt::subxt::ext::sp_core::{ecdsa, sr25519, H256}; +use tangle_subxt::subxt::ext::sp_core::{ecdsa, sr25519}; use tangle_subxt::subxt::tx::Signer; use tangle_subxt::subxt::utils::AccountId32; -use tangle_subxt::subxt::Config; use tokio::task::JoinHandle; pub(crate) mod event_handler; -pub async fn get_blueprints( - runtime: &TangleServicesClient, - block_hash: [u8; 32], - account_id: AccountId32, -) -> color_eyre::Result> -where - BlockRef<::Hash>: From>, -{ - runtime - .query_operator_blueprints(block_hash, account_id) - .await - .map_err(|err| msg_to_error(err.to_string())) -} - pub struct BlueprintManagerHandle { shutdown_call: Option>, start_tx: Option>, @@ -215,8 +199,7 @@ pub async fn run_blueprint_manager>( if result.needs_update { operator_subscribed_blueprints = services_client .query_operator_blueprints(event.hash, sub_account_id.clone()) - .await - .map_err(|err| msg_to_error(err.to_string()))?; + .await?; } event_handler::handle_tangle_event( @@ -226,12 +209,12 @@ pub async fn run_blueprint_manager>( &blueprint_manager_config, &mut active_gadgets, result, - &services_client, + services_client, ) .await?; } - Err::<(), _>(utils::msg_to_error("Finality Notification stream died")) + Err::<(), _>(Error::ClientDied) }; let (tx_stop, rx_stop) = tokio::sync::oneshot::channel::<()>(); @@ -293,20 +276,16 @@ async fn handle_init( active_gadgets: &mut ActiveGadgets, gadget_config: &GadgetConfiguration, blueprint_manager_config: &BlueprintManagerConfig, -) -> color_eyre::Result> { +) -> Result> { info!("Beginning initialization of Blueprint Manager"); - let (operator_subscribed_blueprints, init_event) = - if let Some(event) = tangle_runtime.next_event().await { - ( - get_blueprints(services_client, event.hash, sub_account_id.clone()) - .await - .map_err(|err| Report::msg(format!("Failed to obtain blueprints: {err}")))?, - event, - ) - } else { - return Err(Report::msg("Failed to get initial block hash")); - }; + let Some(init_event) = tangle_runtime.next_event().await else { + return Err(Error::InitialBlock); + }; + + let operator_subscribed_blueprints = services_client + .query_operator_blueprints(init_event.hash, sub_account_id.clone()) + .await?; info!( "Received {} initial blueprints this operator is registered to", diff --git a/crates/blueprint/manager/src/lib.rs b/crates/blueprint/manager/src/lib.rs index 7168062..70e8063 100644 --- a/crates/blueprint/manager/src/lib.rs +++ b/crates/blueprint/manager/src/lib.rs @@ -2,7 +2,6 @@ pub mod config; pub mod error; pub mod executor; pub mod gadget; -pub mod protocols; pub mod sdk; pub mod sources; pub use executor::run_blueprint_manager; diff --git a/crates/blueprint/manager/src/main.rs b/crates/blueprint/manager/src/main.rs index c405488..0e06d14 100644 --- a/crates/blueprint/manager/src/main.rs +++ b/crates/blueprint/manager/src/main.rs @@ -1,6 +1,5 @@ use blueprint_manager::config::BlueprintManagerConfig; use blueprint_manager::sdk; -use blueprint_manager::sdk::utils::msg_to_error; use clap::Parser; use sdk::entry; @@ -19,7 +18,8 @@ async fn main() -> color_eyre::Result<()> { )?; // TODO: blueprint-manager CLI mode - return Err(msg_to_error("TODO: blueprint-manager CLI mode".to_string())); + eprintln!("TODO: blueprint-manager CLI mode"); + return Ok(()); // let gadget_config_settings = std::fs::read_to_string(gadget_config)?; // let gadget_config: GadgetConfig = diff --git a/crates/blueprint/manager/src/protocols/mod.rs b/crates/blueprint/manager/src/protocols/mod.rs deleted file mode 100644 index e755804..0000000 --- a/crates/blueprint/manager/src/protocols/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod resolver; diff --git a/crates/blueprint/manager/src/protocols/resolver.rs b/crates/blueprint/manager/src/protocols/resolver.rs deleted file mode 100644 index 95c5158..0000000 --- a/crates/blueprint/manager/src/protocols/resolver.rs +++ /dev/null @@ -1,14 +0,0 @@ -use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::{ - GadgetBinary, GithubFetcher, -}; - -#[derive(Debug)] -pub struct NativeGithubMetadata { - pub git: String, - pub tag: String, - pub owner: String, - pub repo: String, - pub gadget_binaries: Vec, - pub blueprint_id: u64, - pub fetcher: GithubFetcher, -} diff --git a/crates/blueprint/manager/src/sdk/utils.rs b/crates/blueprint/manager/src/sdk/utils.rs index dd4ca8d..278b3d0 100644 --- a/crates/blueprint/manager/src/sdk/utils.rs +++ b/crates/blueprint/manager/src/sdk/utils.rs @@ -1,8 +1,7 @@ -use crate::protocols::resolver::NativeGithubMetadata; +use crate::error::Result; use gadget_logging::{info, warn}; use sha2::Digest; use std::path::Path; -use std::string::FromUtf8Error; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::BoundedString; @@ -10,9 +9,10 @@ use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives: GadgetBinary, GithubFetcher, }; -pub fn bounded_string_to_string(string: BoundedString) -> Result { +pub fn bounded_string_to_string(string: BoundedString) -> Result { let bytes: &Vec = &string.0 .0; - String::from_utf8(bytes.clone()) + let ret = String::from_utf8(bytes.clone())?; + Ok(ret) } pub fn hash_bytes_to_hex>(input: T) -> String { @@ -57,32 +57,18 @@ pub fn get_download_url(binary: &GadgetBinary, fetcher: &GithubFetcher) -> Strin format!("https://github.com/{owner}/{repo}/releases/download/v{tag}/{binary_name}-{os_name}-{arch_name}{ext}") } -pub fn msg_to_error>(msg: T) -> color_eyre::Report { - color_eyre::Report::msg(msg.into()) -} - -pub async fn chmod_x_file>(path: P) -> color_eyre::Result<()> { - let success = tokio::process::Command::new("chmod") - .arg("+x") - .arg(format!("{}", path.as_ref().display())) - .spawn()? - .wait_with_output() - .await? - .status - .success(); +pub fn make_executable>(path: P) -> Result<()> { + #[cfg(target_family = "unix")] + { + use std::os::unix::fs::PermissionsExt; - if success { - Ok(()) - } else { - Err(color_eyre::eyre::eyre!( - "Failed to chmod +x {}", - path.as_ref().display() - )) + let f = std::fs::File::open(path)?; + let mut perms = f.metadata()?.permissions(); + perms.set_mode(perms.mode() | 0o111); + f.set_permissions(perms)?; } -} -pub fn is_windows() -> bool { - std::env::consts::OS == "windows" + Ok(()) } pub fn generate_running_process_status_handle( diff --git a/crates/blueprint/manager/src/sources/github.rs b/crates/blueprint/manager/src/sources/github.rs index dfba067..a317a60 100644 --- a/crates/blueprint/manager/src/sources/github.rs +++ b/crates/blueprint/manager/src/sources/github.rs @@ -1,12 +1,10 @@ +use crate::error::{Error, Result}; use crate::gadget::native::get_gadget_binary; use crate::sdk; -use crate::sdk::utils::{ - get_download_url, hash_bytes_to_hex, is_windows, msg_to_error, valid_file_exists, -}; +use crate::sdk::utils::{get_download_url, hash_bytes_to_hex, valid_file_exists}; use crate::sources::BinarySourceFetcher; use async_trait::async_trait; -use color_eyre::eyre::OptionExt; -use gadget_logging::{error, info}; +use gadget_logging::info; use std::path::PathBuf; use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::GithubFetcher; use tokio::io::AsyncWriteExt; @@ -19,54 +17,43 @@ pub struct GithubBinaryFetcher { #[async_trait] impl BinarySourceFetcher for GithubBinaryFetcher { - async fn get_binary(&self) -> color_eyre::Result { - let relevant_binary = get_gadget_binary(&self.fetcher.binaries.0) - .ok_or_eyre("Unable to find matching binary")?; + async fn get_binary(&self) -> Result { + let relevant_binary = + get_gadget_binary(&self.fetcher.binaries.0).ok_or(Error::NoMatchingBinary)?; let expected_hash = sdk::utils::slice_32_to_sha_hex_string(relevant_binary.sha256); let current_dir = std::env::current_dir()?; let mut binary_download_path = format!("{}/protocol-{:?}", current_dir.display(), self.fetcher.tag); - if is_windows() { + if cfg!(target_family = "windows") { binary_download_path += ".exe" } info!("Downloading to {binary_download_path}"); // Check if the binary exists, if not download it - let retrieved_hash = if !valid_file_exists(&binary_download_path, &expected_hash).await { - let url = get_download_url(relevant_binary, &self.fetcher); + if !valid_file_exists(&binary_download_path, &expected_hash).await { + return Ok(PathBuf::from(binary_download_path)); + } + + let url = get_download_url(relevant_binary, &self.fetcher); - let download = reqwest::get(&url) - .await - .map_err(|err| msg_to_error(err.to_string()))? - .bytes() - .await - .map_err(|err| msg_to_error(err.to_string()))?; - let retrieved_hash = hash_bytes_to_hex(&download); + let download = reqwest::get(&url).await?.bytes().await?; + let retrieved_hash = hash_bytes_to_hex(&download); - // Write the binary to disk - let mut file = tokio::fs::File::create(&binary_download_path).await?; - file.write_all(&download).await?; - file.flush().await?; - Some(retrieved_hash) - } else { - None - }; + // Write the binary to disk + let mut file = tokio::fs::File::create(&binary_download_path).await?; + file.write_all(&download).await?; + file.flush().await?; - if let Some(retrieved_hash) = retrieved_hash { - if retrieved_hash.trim() != expected_hash.trim() { - error!( - "Binary hash {} mismatched expected hash of {} for protocol: {}", - retrieved_hash, expected_hash, self.gadget_name - ); - return Ok(PathBuf::from(binary_download_path)); - } + if retrieved_hash.trim() != expected_hash.trim() { + return Err(Error::HashMismatch { + expected: expected_hash, + actual: retrieved_hash, + }); } - Err(color_eyre::Report::msg( - "The hash of the downloaded binary did not match", - )) + Ok(PathBuf::from(binary_download_path)) } fn blueprint_id(&self) -> u64 { diff --git a/crates/blueprint/manager/src/sources/mod.rs b/crates/blueprint/manager/src/sources/mod.rs index 07c8d02..c223c7c 100644 --- a/crates/blueprint/manager/src/sources/mod.rs +++ b/crates/blueprint/manager/src/sources/mod.rs @@ -1,10 +1,8 @@ use crate::config::BlueprintManagerConfig; -use crate::executor::event_handler::VerifiedBlueprint; -use crate::gadget::ActiveGadgets; -use crate::sdk::utils::{chmod_x_file, generate_running_process_status_handle, is_windows}; +use crate::error::Result; +use crate::gadget::native::FilteredBlueprint; use async_trait::async_trait; -use gadget_config::{GadgetConfiguration, Protocol}; -use gadget_logging::{error, info, warn}; +use gadget_config::GadgetConfiguration; use std::path::PathBuf; pub mod github; @@ -13,134 +11,27 @@ pub mod testing; #[async_trait] #[auto_impl::auto_impl(Box)] pub trait BinarySourceFetcher: Send + Sync { - async fn get_binary(&self) -> color_eyre::Result; + async fn get_binary(&self) -> Result; fn blueprint_id(&self) -> u64; fn name(&self) -> String; } -pub async fn handle( - blueprint: &VerifiedBlueprint<'_>, +pub fn process_arguments_and_env( gadget_config: &GadgetConfiguration, - blueprint_manager_opts: &BlueprintManagerConfig, - active_gadgets: &mut ActiveGadgets, -) -> color_eyre::Result<()> { - let blueprint_source = &blueprint.fetcher; - let blueprint = &blueprint.blueprint; - - let blueprint_id = blueprint_source.blueprint_id(); - let service_str = blueprint_source.name(); - - if active_gadgets.contains_key(&blueprint_id) { - return Ok(()); - } - - let mut binary_download_path = blueprint_source.get_binary().await?; - - // Ensure the binary is executable - if is_windows() { - if binary_download_path.extension().is_none() { - binary_download_path.set_extension("exe"); - } - } else if let Err(err) = chmod_x_file(&binary_download_path).await { - warn!("Failed to chmod +x the binary: {err}"); - } - - for service_id in &blueprint.services { - let sub_service_str = format!("{service_str}-{service_id}"); - let arguments = generate_process_arguments( - gadget_config, - blueprint_manager_opts, - blueprint_id, - *service_id, - blueprint.protocol, - )?; - - // Add required env vars for all child processes/gadgets - let mut env_vars = vec![ - ( - "HTTP_RPC_URL".to_string(), - gadget_config.http_rpc_endpoint.to_string(), - ), - ( - "WS_RPC_URL".to_string(), - gadget_config.ws_rpc_endpoint.to_string(), - ), - ( - "KEYSTORE_URI".to_string(), - blueprint_manager_opts.keystore_uri.clone(), - ), - ("BLUEPRINT_ID".to_string(), format!("{}", blueprint_id)), - ("SERVICE_ID".to_string(), format!("{}", service_id)), - ]; - - let base_data_dir = &blueprint_manager_opts.data_dir; - let data_dir = base_data_dir.join(format!("blueprint-{blueprint_id}-{sub_service_str}")); - env_vars.push(( - "DATA_DIR".to_string(), - data_dir.to_string_lossy().into_owned(), - )); - - // Ensure our child process inherits the current processes' environment vars - env_vars.extend(std::env::vars()); - - if blueprint.registration_mode { - env_vars.push(("REGISTRATION_MODE_ON".to_string(), "true".to_string())); - } - - info!("Starting protocol: {sub_service_str} with args: {arguments:?}"); - - // Now that the file is loaded, spawn the process - let process_handle = tokio::process::Command::new(&binary_download_path) - .kill_on_drop(true) - .stdout(std::process::Stdio::inherit()) // Inherit the stdout of this process - .stderr(std::process::Stdio::inherit()) // Inherit the stderr of this process - .stdin(std::process::Stdio::null()) - .current_dir(&std::env::current_dir()?) - .envs(env_vars) - .args(arguments) - .spawn()?; - - if blueprint.registration_mode { - // We must wait for the process to exit successfully - let status = process_handle.wait_with_output().await?; - if !status.status.success() { - error!( - "Protocol (registration mode) {sub_service_str} failed to execute: {status:?}" - ); - } else { - info!("***Protocol (registration mode) {sub_service_str} executed successfully***"); - } - } else { - // A normal running gadget binary. Store the process handle and let the event loop handle the rest - - let (status_handle, abort) = - generate_running_process_status_handle(process_handle, &sub_service_str); - - active_gadgets - .entry(blueprint_id) - .or_default() - .insert(*service_id, (status_handle, Some(abort))); - } - } - - Ok(()) -} - -pub fn generate_process_arguments( - gadget_config: &GadgetConfiguration, - opt: &BlueprintManagerConfig, + manager_opts: &BlueprintManagerConfig, blueprint_id: u64, service_id: u64, - protocol: Protocol, -) -> color_eyre::Result> { + blueprint: &FilteredBlueprint, + sub_service_str: &str, +) -> (Vec, Vec<(String, String)>) { let mut arguments = vec![]; arguments.push("run".to_string()); - if opt.test_mode { + if manager_opts.test_mode { arguments.push("--test-mode".to_string()); } - if opt.pretty { + if manager_opts.pretty { arguments.push("--pretty".to_string()); } @@ -152,10 +43,11 @@ pub fn generate_process_arguments( format!("--http-rpc-url={}", gadget_config.http_rpc_endpoint), format!("--ws-rpc-url={}", gadget_config.ws_rpc_endpoint), format!("--keystore-uri={}", gadget_config.keystore_uri), - format!("--protocol={}", protocol), + format!("--protocol={}", blueprint.protocol), format!( "--log-id=Blueprint-{blueprint_id}-Service-{service_id}{}", - opt.instance_id + manager_opts + .instance_id .clone() .map_or(String::new(), |id| format!("-{}", id)) ), @@ -167,9 +59,41 @@ pub fn generate_process_arguments( // } // Uses occurrences of clap short -v - if opt.verbose > 0 { - arguments.push(format!("-{}", "v".repeat(opt.verbose as usize))); + if manager_opts.verbose > 0 { + arguments.push(format!("-{}", "v".repeat(manager_opts.verbose as usize))); + } + + // Add required env vars for all child processes/gadgets + let mut env_vars = vec![ + ( + "HTTP_RPC_URL".to_string(), + gadget_config.http_rpc_endpoint.to_string(), + ), + ( + "WS_RPC_URL".to_string(), + gadget_config.ws_rpc_endpoint.to_string(), + ), + ( + "KEYSTORE_URI".to_string(), + manager_opts.keystore_uri.clone(), + ), + ("BLUEPRINT_ID".to_string(), format!("{}", blueprint_id)), + ("SERVICE_ID".to_string(), format!("{}", service_id)), + ]; + + let base_data_dir = &manager_opts.data_dir; + let data_dir = base_data_dir.join(format!("blueprint-{blueprint_id}-{sub_service_str}")); + env_vars.push(( + "DATA_DIR".to_string(), + data_dir.to_string_lossy().into_owned(), + )); + + // Ensure our child process inherits the current processes' environment vars + env_vars.extend(std::env::vars()); + + if blueprint.registration_mode { + env_vars.push(("REGISTRATION_MODE_ON".to_string(), "true".to_string())); } - Ok(arguments) + (arguments, env_vars) } diff --git a/crates/blueprint/manager/src/sources/testing.rs b/crates/blueprint/manager/src/sources/testing.rs index df26298..80bb3b8 100644 --- a/crates/blueprint/manager/src/sources/testing.rs +++ b/crates/blueprint/manager/src/sources/testing.rs @@ -1,6 +1,6 @@ +use crate::error::{Error, Result}; use crate::sources::BinarySourceFetcher; use async_trait::async_trait; -use color_eyre::Report; use gadget_logging::trace; use std::path::PathBuf; use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::TestFetcher; @@ -13,7 +13,7 @@ pub struct TestSourceFetcher { #[async_trait] impl BinarySourceFetcher for TestSourceFetcher { - async fn get_binary(&self) -> color_eyre::Result { + async fn get_binary(&self) -> Result { // Step 1: Build the binary. It will be stored in the root directory/bin/ let TestFetcher { cargo_package, @@ -21,9 +21,9 @@ impl BinarySourceFetcher for TestSourceFetcher { .. } = &self.fetcher; let cargo_bin = String::from_utf8(cargo_package.0 .0.clone()) - .map_err(|err| Report::msg(format!("Failed to parse `cargo_bin`: {:?}", err)))?; + .map_err(|err| Error::Other(format!("Failed to parse `cargo_bin`: {:?}", err)))?; let base_path_str = String::from_utf8(base_path.0 .0.clone()) - .map_err(|err| Report::msg(format!("Failed to parse `base_path`: {:?}", err)))?; + .map_err(|err| Error::Other(format!("Failed to parse `base_path`: {:?}", err)))?; let git_repo_root = get_git_repo_root_path().await?; let profile = if cfg!(debug_assertions) { @@ -57,9 +57,8 @@ impl BinarySourceFetcher for TestSourceFetcher { } let output = command.current_dir(&base_path).output().await?; - if !output.status.success() { - return Err(Report::msg(format!("Failed to build binary: {:?}", output))); + return Err(Error::BuildBinary(output)); } Ok(binary_path) @@ -73,7 +72,7 @@ impl BinarySourceFetcher for TestSourceFetcher { self.gadget_name.clone() } } -async fn get_git_repo_root_path() -> color_eyre::Result { +async fn get_git_repo_root_path() -> Result { // Run a process to determine the root directory for this repo let output = tokio::process::Command::new("git") .arg("rev-parse") @@ -82,10 +81,7 @@ async fn get_git_repo_root_path() -> color_eyre::Result { .await?; if !output.status.success() { - return Err(Report::msg(format!( - "Failed to get git root path: {:?}", - output - ))); + return Err(Error::FetchGitRoot(output)); } Ok(PathBuf::from(String::from_utf8(output.stdout)?.trim())) diff --git a/crates/clients/Cargo.toml b/crates/clients/Cargo.toml index bee79db..21127e5 100644 --- a/crates/clients/Cargo.toml +++ b/crates/clients/Cargo.toml @@ -10,6 +10,8 @@ gadget-client-tangle = { workspace = true, optional = true } gadget-client-networking = { workspace = true, optional = true } gadget-client-core = { workspace = true } +thiserror.workspace = true + [features] default = ["std"] std = [ @@ -17,6 +19,7 @@ std = [ "gadget-client-evm?/std", "gadget-client-networking?/std", "gadget-client-tangle?/std", + "thiserror/std" ] web = ["gadget-client-tangle?/web"] diff --git a/crates/clients/core/src/lib.rs b/crates/clients/core/src/lib.rs index eb9e23c..ba6470c 100644 --- a/crates/clients/core/src/lib.rs +++ b/crates/clients/core/src/lib.rs @@ -13,19 +13,24 @@ pub trait GadgetServicesClient: Send + Sync + 'static { type PublicAccountIdentity: Send + Sync + 'static; /// A generalized ID that distinguishes the current blueprint from others type Id: Send + Sync + 'static; + type Error: core::error::Error + From + Send + Sync + 'static; + /// Returns the set of operators for the current job async fn get_operators( &self, - ) -> Result, Error>; + ) -> Result< + OperatorSet, + Self::Error, + >; /// Returns the ID of the operator - async fn operator_id(&self) -> Result; + async fn operator_id(&self) -> Result; /// Returns the unique ID for this blueprint - async fn blueprint_id(&self) -> Result; + async fn blueprint_id(&self) -> Result; /// Returns an operator set with the index of the current operator within that set async fn get_operators_and_operator_id( &self, - ) -> Result<(OperatorSet, usize), Error> { + ) -> Result<(OperatorSet, usize), Self::Error> { let operators = self .get_operators() .await @@ -51,11 +56,12 @@ pub trait GadgetServicesClient: Send + Sync + 'static { } /// Returns the index of the current operator in the operator set - async fn get_operator_index(&self) -> Result { - self.get_operators_and_operator_id() + async fn get_operator_index(&self) -> Result { + let (_, index) = self + .get_operators_and_operator_id() .await - .map_err(|err| Error::GetOperatorIndex(err.to_string())) - .map(|(_, index)| index) + .map_err(|err| Error::GetOperatorIndex(err.to_string()))?; + Ok(index) } } diff --git a/crates/clients/eigenlayer/src/error.rs b/crates/clients/eigenlayer/src/error.rs index 6d64c15..04f8fe6 100644 --- a/crates/clients/eigenlayer/src/error.rs +++ b/crates/clients/eigenlayer/src/error.rs @@ -2,7 +2,7 @@ use gadget_std::string::ParseError; use thiserror::Error; #[derive(Debug, Error)] -pub enum EigenlayerClientError { +pub enum Error { #[error("IO error: {0}")] Io(#[from] gadget_std::io::Error), #[error("Parse error {0}")] @@ -25,10 +25,10 @@ pub enum EigenlayerClientError { OtherStatic(&'static str), } -impl From<&'static str> for EigenlayerClientError { +impl From<&'static str> for Error { fn from(e: &'static str) -> Self { - EigenlayerClientError::OtherStatic(e) + Error::OtherStatic(e) } } -pub type Result = gadget_std::result::Result; +pub type Result = gadget_std::result::Result; diff --git a/crates/clients/evm/src/error.rs b/crates/clients/evm/src/error.rs index 688dca5..df41f37 100644 --- a/crates/clients/evm/src/error.rs +++ b/crates/clients/evm/src/error.rs @@ -2,7 +2,7 @@ use gadget_std::string::String; use thiserror::Error; #[derive(Debug, Error)] -pub enum EvmError { +pub enum Error { #[error("Provider error: {0}")] Provider(String), #[error("Invalid address: {0}")] @@ -15,4 +15,4 @@ pub enum EvmError { Abi(String), } -pub type Result = gadget_std::result::Result; +pub type Result = gadget_std::result::Result; diff --git a/crates/clients/networking/src/error.rs b/crates/clients/networking/src/error.rs index 5f4c51d..710fb67 100644 --- a/crates/clients/networking/src/error.rs +++ b/crates/clients/networking/src/error.rs @@ -2,7 +2,7 @@ use gadget_std::string::String; use thiserror::Error; #[derive(Debug, Error)] -pub enum NetworkError { +pub enum Error { #[error("P2P error: {0}")] P2p(String), #[error("Transport error: {0}")] @@ -13,4 +13,4 @@ pub enum NetworkError { Configuration(String), } -pub type Result = gadget_std::result::Result; +pub type Result = gadget_std::result::Result; diff --git a/crates/clients/networking/src/p2p.rs b/crates/clients/networking/src/p2p.rs index 9ab9330..fc5c9bd 100644 --- a/crates/clients/networking/src/p2p.rs +++ b/crates/clients/networking/src/p2p.rs @@ -1,4 +1,4 @@ -use crate::error::{NetworkError, Result}; +use crate::error::{Error, Result}; use gadget_config::GadgetConfiguration; use gadget_crypto::k256_crypto::{K256SigningKey, K256VerifyingKey}; use gadget_networking::gossip::GossipHandle; @@ -35,7 +35,7 @@ impl P2PClient { pub fn libp2p_identity(&self, ed25519_seed: Vec) -> Result { let mut seed_bytes = ed25519_seed; let keypair = libp2p::identity::Keypair::ed25519_from_bytes(&mut seed_bytes) - .map_err(|err| NetworkError::Configuration(err.to_string()))?; + .map_err(|err| Error::Configuration(err.to_string()))?; Ok(keypair) } @@ -68,9 +68,7 @@ impl P2PClient { Ok(handle) => Ok(handle), Err(err) => { gadget_logging::error!("Failed to start network: {}", err.to_string()); - Err(NetworkError::Protocol(format!( - "Failed to start network: {err}" - ))) + Err(Error::Protocol(format!("Failed to start network: {err}"))) } } } diff --git a/crates/clients/src/error.rs b/crates/clients/src/error.rs new file mode 100644 index 0000000..bbe7735 --- /dev/null +++ b/crates/clients/src/error.rs @@ -0,0 +1,17 @@ +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Core(#[from] gadget_client_core::Error), + #[error(transparent)] + #[cfg(feature = "eigenlayer")] + Eigenlayer(#[from] gadget_client_eigenlayer::error::Error), + #[error(transparent)] + #[cfg(feature = "evm")] + Evm(#[from] gadget_client_evm::error::Error), + #[error(transparent)] + #[cfg(feature = "networking")] + Networking(#[from] gadget_client_networking::error::Error), + #[error(transparent)] + #[cfg(feature = "tangle")] + Tangle(#[from] gadget_client_tangle::error::Error), +} diff --git a/crates/clients/src/lib.rs b/crates/clients/src/lib.rs index d6e6c30..e82d0b2 100644 --- a/crates/clients/src/lib.rs +++ b/crates/clients/src/lib.rs @@ -1,5 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +pub mod error; + #[cfg(feature = "eigenlayer")] pub use gadget_client_eigenlayer as eigenlayer; diff --git a/crates/clients/tangle/src/client.rs b/crates/clients/tangle/src/client.rs index f7c8ac7..2c7a76c 100644 --- a/crates/clients/tangle/src/client.rs +++ b/crates/clients/tangle/src/client.rs @@ -1,5 +1,5 @@ use sp_core::ecdsa; -use crate::error::Result; +use crate::error::{Result, Error}; use crate::EventsClient; use gadget_std::sync::Arc; use gadget_std::time::Duration; @@ -10,7 +10,7 @@ use subxt::utils::AccountId32; use subxt::{self, PolkadotConfig}; use tangle_subxt::tangle_testnet_runtime::api; use tangle_subxt::tangle_testnet_runtime::api::runtime_types::pallet_multi_asset_delegation::types::operator::OperatorMetadata; -use gadget_client_core::{Error, GadgetServicesClient, OperatorSet}; +use gadget_client_core::{GadgetServicesClient, OperatorSet}; use gadget_config::GadgetConfiguration; use gadget_crypto_sp_core::{SpEcdsa, SpSr25519}; use gadget_keystore::{Keystore, KeystoreConfig}; @@ -56,18 +56,13 @@ impl TangleClient { keystore_config.fs_root(config.keystore_uri.replace("file://", "")) }; - let keystore = Arc::new(Keystore::new(keystore_config).map_err(|err| Error::msg(err))?); + let keystore = Arc::new(Keystore::new(keystore_config)?); let rpc_url = config.ws_rpc_endpoint.as_str(); - let client = TangleServicesClient::new( - subxt::OnlineClient::from_url(rpc_url) - .await - .map_err(|err| Error::msg(err))?, - ); + let client = TangleServicesClient::new(subxt::OnlineClient::from_url(rpc_url).await?); let account_id = keystore - .get_public_key_local::(KEY_ID) - .map_err(|err| Error::msg(err))? + .get_public_key_local::(KEY_ID)? .0 .0 .into(); @@ -137,13 +132,11 @@ impl TangleClient { .rpc_client .storage() .at_latest() - .await - .map_err(|err| Error::msg(err))?; + .await?; let metadata_storage_key = api::storage().multi_asset_delegation().operators(operator); - storage - .fetch(&metadata_storage_key) - .await - .map_err(|err| Error::msg(err)) + + let ret = storage.fetch(&metadata_storage_key).await?; + Ok(ret) } /// Retrieves the current party index and operator mapping @@ -162,10 +155,7 @@ impl TangleClient { Error, > { let parties = self.get_operators().await?; - let my_id = self - .keystore - .get_public_key_local::(KEY_ID) - .map_err(|err| Error::msg(err))?; + let my_id = self.keystore.get_public_key_local::(KEY_ID)?; gadget_logging::trace!( "Looking for {my_id:?} in parties: {:?}", @@ -175,7 +165,7 @@ impl TangleClient { let index_of_my_id = parties .iter() .position(|(_id, key)| key == &my_id.0) - .ok_or_else(|| Error::msg("Party not found in operator list"))?; + .ok_or(Error::PartyNotFound)?; Ok((index_of_my_id, parties)) } @@ -241,6 +231,7 @@ impl GadgetServicesClient for TangleClient { type PublicApplicationIdentity = ecdsa::Public; type PublicAccountIdentity = AccountId32; type Id = BlueprintId; + type Error = Error; /// Retrieves the ECDSA keys for all current service operators /// @@ -253,7 +244,7 @@ impl GadgetServicesClient for TangleClient { &self, ) -> std::result::Result< OperatorSet, - Error, + Self::Error, > { let client = &self.services_client; let current_blueprint = self.blueprint_id().await?; @@ -261,7 +252,7 @@ impl GadgetServicesClient for TangleClient { .config .protocol_settings .tangle() - .map_err(|err| Error::msg(err))? + .map_err(|_| Error::NotTangle)? .service_id .ok_or_else(|| Error::Other("No service ID injected into config".into()))?; let now = self @@ -271,14 +262,8 @@ impl GadgetServicesClient for TangleClient { let current_service_op = self .services_client .current_service_operators(now, service_id) - .await - .map_err(|err| Error::msg(err))?; - let storage = client - .rpc_client - .storage() - .at_latest() - .await - .map_err(|err| Error::msg(err))?; + .await?; + let storage = client.rpc_client.storage().at_latest().await?; let mut map = std::collections::BTreeMap::new(); for (operator, _) in current_service_op { @@ -287,7 +272,7 @@ impl GadgetServicesClient for TangleClient { .operators(current_blueprint, &operator); let maybe_pref = storage.fetch(&addr).await.map_err(|err| { - Error::msg(format!( + Error::Other(format!( "Failed to fetch operator storage for {operator}: {err}" )) })?; @@ -295,35 +280,29 @@ impl GadgetServicesClient for TangleClient { if let Some(pref) = maybe_pref { map.insert(operator, ecdsa::Public(pref.key)); } else { - return Err(Error::msg(format!( - "Missing ECDSA key for operator {operator}" - ))); + return Err(Error::MissingEcdsa(operator)); } } Ok(map) } - async fn operator_id(&self) -> std::result::Result { - Ok(self - .keystore - .get_public_key_local::(KEY_ID) - .map_err(|err| Error::msg(err))? - .0) + async fn operator_id( + &self, + ) -> std::result::Result { + Ok(self.keystore.get_public_key_local::(KEY_ID)?.0) } /// Retrieves the current blueprint ID from the configuration /// /// # Errors /// Returns an error if the blueprint ID is not found in the configuration - async fn blueprint_id(&self) -> std::result::Result { - let id = self + async fn blueprint_id(&self) -> std::result::Result { + let c = self .config .protocol_settings .tangle() - .map(|c| c.blueprint_id) - .map_err(|err| format!("Blueprint ID not found in configuration: {err}")) - .map_err(|err| Error::msg(err))?; - Ok(id) + .map_err(|_| Error::NotTangle)?; + Ok(c.blueprint_id) } } diff --git a/crates/clients/tangle/src/error.rs b/crates/clients/tangle/src/error.rs index 18fbe17..ba23f19 100644 --- a/crates/clients/tangle/src/error.rs +++ b/crates/clients/tangle/src/error.rs @@ -1,20 +1,34 @@ use gadget_std::io; use gadget_std::string::String; +use subxt_core::utils::AccountId32; use thiserror::Error; #[derive(Debug, Error)] -pub enum TangleClientError { - #[error("IO error: {0}")] - Io(#[from] io::Error), - #[error("Subxt error: {0}")] - Subxt(#[from] subxt::Error), +pub enum Error { #[error("Tangle error: {0}")] Tangle(TangleDispatchError), + #[error("Not a Tangle instance")] + NotTangle, + + #[error("Missing ECDSA key for operator: {0}")] + MissingEcdsa(AccountId32), + #[error("Party not found in operator list")] + PartyNotFound, + #[error("{0}")] Other(String), + + #[error(transparent)] + Keystore(#[from] gadget_keystore::Error), + #[error(transparent)] + Core(#[from] gadget_client_core::Error), + #[error("IO error: {0}")] + Io(#[from] io::Error), + #[error("Subxt error: {0}")] + Subxt(#[from] subxt::Error), } -pub type Result = gadget_std::result::Result; +pub type Result = gadget_std::result::Result; #[derive(Debug)] pub struct TangleDispatchError( @@ -31,9 +45,9 @@ impl From for TangleClientError { +impl From for Error { fn from(error: TangleDispatchError) -> Self { - TangleClientError::Tangle(error) + Error::Tangle(error) } } diff --git a/crates/clients/tangle/src/services.rs b/crates/clients/tangle/src/services.rs index 1878ab9..725acc2 100644 --- a/crates/clients/tangle/src/services.rs +++ b/crates/clients/tangle/src/services.rs @@ -1,4 +1,4 @@ -use crate::error::TangleClientError; +use crate::error::Error; use crate::error::{Result, TangleDispatchError}; use gadget_std::string::ToString; use gadget_std::vec::Vec; @@ -88,7 +88,7 @@ where let ret = self.rpc_client.storage().at(at).fetch(&call).await?; match ret { Some(blueprints) => Ok(blueprints.1), - None => Err(TangleClientError::Other("Blueprint not found".to_string())), + None => Err(Error::Other("Blueprint not found".to_string())), } } @@ -103,7 +103,7 @@ where let ret = self.rpc_client.storage().at(at).fetch(&call).await?; match ret { Some(blueprints) => Ok(blueprints.0), - None => Err(TangleClientError::Other("Blueprint not found".to_string())), + None => Err(Error::Other("Blueprint not found".to_string())), } } From f37ba82bd6418b1d275579ef2e5a9f4ac282794e Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Fri, 27 Dec 2024 12:49:32 -0500 Subject: [PATCH 4/4] fix: get crates building again --- Cargo.lock | 901 +++++++++++++++++- cli/src/deploy/tangle.rs | 10 +- crates/blueprint/manager/src/executor/mod.rs | 5 +- crates/crypto/src/lib.rs | 3 - crates/event-listeners/tangle/Cargo.toml | 2 +- .../macros/blueprint-proc-macro/src/report.rs | 2 +- crates/macros/core/src/lib.rs | 1 - rust-toolchain.toml | 2 +- 8 files changed, 902 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a81b9ef..25c8d18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,6 +95,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "const-random", "getrandom", "once_cell", "version_check", @@ -110,6 +111,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "377e4c0ba83e4431b10df45c1d4666f178ea9c552cac93e60c3a88bf32785923" +dependencies = [ + "as-slice", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -1076,6 +1086,12 @@ version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +[[package]] +name = "anymap2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" + [[package]] name = "ark-bls12-377" version = "0.4.0" @@ -1472,6 +1488,15 @@ dependencies = [ "serde", ] +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "ascii-canvas" version = "3.0.0" @@ -1733,6 +1758,17 @@ dependencies = [ "url", ] +[[package]] +name = "auth-git2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3810b5af212b013fe7302b12d86616c6c39a48e18f2e4b812a5a9e5710213791" +dependencies = [ + "dirs", + "git2", + "terminal-prompt", +] + [[package]] name = "auto_impl" version = "1.2.0" @@ -2461,6 +2497,17 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "bstr" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" +dependencies = [ + "memchr", + "regex-automata 0.4.9", + "serde", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -2543,6 +2590,49 @@ dependencies = [ "serde", ] +[[package]] +name = "cargo-generate" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b611d852b731eaaf84d3dfed2cefc1468f772b403ae0499fd3436a6a2b42b273" +dependencies = [ + "anstyle", + "anyhow", + "auth-git2", + "clap", + "console", + "dialoguer", + "env_logger", + "fs-err", + "git2", + "gix-config", + "heck", + "home", + "ignore", + "indexmap 2.7.0", + "indicatif", + "liquid", + "liquid-core", + "liquid-derive", + "liquid-lib", + "log", + "names", + "openssl", + "paste", + "path-absolutize", + "regex", + "remove_dir_all", + "rhai", + "sanitize-filename", + "semver 1.0.24", + "serde", + "tempfile", + "thiserror 1.0.69", + "time", + "toml", + "walkdir", +] + [[package]] name = "cargo-platform" version = "0.1.9" @@ -2552,6 +2642,41 @@ dependencies = [ "serde", ] +[[package]] +name = "cargo-tangle" +version = "0.4.0" +dependencies = [ + "alloy-json-abi", + "alloy-network 0.5.4", + "alloy-provider", + "alloy-rpc-types-eth 0.5.4", + "alloy-signer-local", + "anyhow", + "cargo-generate", + "cargo_metadata", + "clap", + "clap-cargo", + "color-eyre", + "escargot", + "gadget-blueprint-proc-macro-core", + "gadget-clients", + "gadget-crypto", + "gadget-crypto-core", + "gadget-keystore", + "gadget-logging", + "gadget-std", + "gadget-utils-tangle", + "hex", + "serde_json", + "subxt", + "tangle-subxt", + "tempfile", + "thiserror 2.0.7", + "tokio", + "tracing-subscriber 0.3.19", + "w3f-bls 0.1.8 (git+https://github.com/drewstone/bls.git?branch=drew%2Fbump-ark-versions)", +] + [[package]] name = "cargo_metadata" version = "0.18.1" @@ -2676,6 +2801,16 @@ dependencies = [ "clap_derive", ] +[[package]] +name = "clap-cargo" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2ea69cefa96b848b73ad516ad1d59a195cdf9263087d977f648a818c8b43e" +dependencies = [ + "anstyle", + "clap", +] + [[package]] name = "clap_builder" version = "4.5.23" @@ -2824,7 +2959,7 @@ dependencies = [ "hidapi-rusb", "js-sys", "log", - "nix", + "nix 0.26.4", "once_cell", "thiserror 1.0.69", "tokio", @@ -2892,6 +3027,19 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "console" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", +] + [[package]] name = "const-hex" version = "1.14.0" @@ -2911,6 +3059,26 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -3138,6 +3306,15 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "cvt" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ae9bf77fbf2d39ef573205d554d87e86c12f1994e9ea335b0651b9b278bcf1" +dependencies = [ + "cfg-if", +] + [[package]] name = "darling" version = "0.14.4" @@ -3350,6 +3527,19 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "dialoguer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" +dependencies = [ + "console", + "shell-words", + "tempfile", + "thiserror 1.0.69", + "zeroize", +] + [[package]] name = "digest" version = "0.9.0" @@ -3424,6 +3614,12 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + [[package]] name = "docify" version = "0.2.9" @@ -3847,6 +4043,12 @@ dependencies = [ "log", ] +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -3919,6 +4121,29 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "environmental" version = "1.1.4" @@ -3941,6 +4166,18 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "escargot" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05a3ac187a16b5382fef8c69fd1bad123c67b7cf3932240a2d43dcdd32cded88" +dependencies = [ + "log", + "once_cell", + "serde", + "serde_json", +] + [[package]] name = "etcetera" version = "0.8.0" @@ -4332,6 +4569,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "faster-hex" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" + [[package]] name = "fastrand" version = "2.3.0" @@ -4503,6 +4746,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs_at" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14af6c9694ea25db25baa2a1788703b9e7c6648dcaeeebeb98f7561b5384c036" +dependencies = [ + "aligned", + "cfg-if", + "cvt", + "libc", + "nix 0.29.0", + "windows-sys 0.52.0", +] + [[package]] name = "funty" version = "2.0.0" @@ -4969,6 +5226,7 @@ dependencies = [ name = "gadget-crypto-core" version = "0.1.0" dependencies = [ + "clap", "gadget-std", "serde", "thiserror 2.0.7", @@ -5538,12 +5796,264 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "git2" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" +dependencies = [ + "bitflags 2.6.0", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "gix-actor" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0e454357e34b833cc3a00b6efbbd3dd4d18b24b9fb0c023876ec2645e8aa3f2" +dependencies = [ + "bstr", + "gix-date", + "gix-utils", + "itoa", + "thiserror 1.0.69", + "winnow", +] + +[[package]] +name = "gix-config" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fafe42957e11d98e354a66b6bd70aeea00faf2f62dd11164188224a507c840" +dependencies = [ + "bstr", + "gix-config-value", + "gix-features", + "gix-glob", + "gix-path", + "gix-ref", + "gix-sec", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", + "unicode-bom", + "winnow", +] + +[[package]] +name = "gix-config-value" +version = "0.14.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49aaeef5d98390a3bcf9dbc6440b520b793d1bf3ed99317dc407b02be995b28e" +dependencies = [ + "bitflags 2.6.0", + "bstr", + "gix-path", + "libc", + "thiserror 2.0.7", +] + +[[package]] +name = "gix-date" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eed6931f21491ee0aeb922751bd7ec97b4b2fe8fbfedcb678e2a2dce5f3b8c0" +dependencies = [ + "bstr", + "itoa", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "gix-features" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac7045ac9fe5f9c727f38799d002a7ed3583cd777e3322a7c4b43e3cf437dc69" +dependencies = [ + "gix-hash", + "gix-trace", + "gix-utils", + "libc", + "prodash", + "sha1_smol", + "walkdir", +] + +[[package]] +name = "gix-fs" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2bfe6249cfea6d0c0e0990d5226a4cb36f030444ba9e35e0639275db8f98575" +dependencies = [ + "fastrand", + "gix-features", + "gix-utils", +] + +[[package]] +name = "gix-glob" +version = "0.16.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74908b4bbc0a0a40852737e5d7889f676f081e340d5451a16e5b4c50d592f111" +dependencies = [ + "bitflags 2.6.0", + "bstr", + "gix-features", + "gix-path", +] + +[[package]] +name = "gix-hash" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93d7df7366121b5018f947a04d37f034717e113dcf9ccd85c34b58e57a74d5e" +dependencies = [ + "faster-hex", + "thiserror 1.0.69", +] + +[[package]] +name = "gix-lock" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bc7fe297f1f4614774989c00ec8b1add59571dc9b024b4c00acb7dedd4e19d" +dependencies = [ + "gix-tempfile", + "gix-utils", + "thiserror 1.0.69", +] + +[[package]] +name = "gix-object" +version = "0.42.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25da2f46b4e7c2fa7b413ce4dffb87f69eaf89c2057e386491f4c55cadbfe386" +dependencies = [ + "bstr", + "gix-actor", + "gix-date", + "gix-features", + "gix-hash", + "gix-utils", + "gix-validate", + "itoa", + "smallvec", + "thiserror 1.0.69", + "winnow", +] + +[[package]] +name = "gix-path" +version = "0.10.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc292ef1a51e340aeb0e720800338c805975724c1dfbd243185452efd8645b7" +dependencies = [ + "bstr", + "gix-trace", + "home", + "once_cell", + "thiserror 2.0.7", +] + +[[package]] +name = "gix-ref" +version = "0.44.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3394a2997e5bc6b22ebc1e1a87b41eeefbcfcff3dbfa7c4bd73cb0ac8f1f3e2e" +dependencies = [ + "gix-actor", + "gix-date", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-utils", + "gix-validate", + "memmap2", + "thiserror 1.0.69", + "winnow", +] + +[[package]] +name = "gix-sec" +version = "0.10.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8b876ef997a955397809a2ec398d6a45b7a55b4918f2446344330f778d14fd6" +dependencies = [ + "bitflags 2.6.0", + "gix-path", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "gix-tempfile" +version = "14.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046b4927969fa816a150a0cda2e62c80016fe11fb3c3184e4dddf4e542f108aa" +dependencies = [ + "gix-fs", + "libc", + "once_cell", + "parking_lot", + "tempfile", +] + +[[package]] +name = "gix-trace" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04bdde120c29f1fc23a24d3e115aeeea3d60d8e65bab92cc5f9d90d9302eb952" + +[[package]] +name = "gix-utils" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba427e3e9599508ed98a6ddf8ed05493db114564e338e41f6a996d2e4790335f" +dependencies = [ + "fastrand", + "unicode-normalization", +] + +[[package]] +name = "gix-validate" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c27dd34a49b1addf193c92070bcbf3beaf6e10f16a78544de6372e146a0acf" +dependencies = [ + "bstr", + "thiserror 1.0.69", +] + [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "globset" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + [[package]] name = "gloo-net" version = "0.5.0" @@ -5934,6 +6444,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.31" @@ -6311,6 +6827,22 @@ dependencies = [ "xmltree", ] +[[package]] +name = "ignore" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata 0.4.9", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "impl-codec" version = "0.6.0" @@ -6383,6 +6915,19 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" +[[package]] +name = "indicatif" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", + "web-time", +] + [[package]] name = "inout" version = "0.1.3" @@ -6796,6 +7341,16 @@ dependencies = [ "sha3-asm", ] +[[package]] +name = "kstring" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1" +dependencies = [ + "serde", + "static_assertions", +] + [[package]] name = "lalrpop" version = "0.20.2" @@ -6838,6 +7393,20 @@ version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +[[package]] +name = "libgit2-sys" +version = "0.17.0+1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + [[package]] name = "libm" version = "0.2.11" @@ -7420,6 +7989,20 @@ dependencies = [ "libsecp256k1-core", ] +[[package]] +name = "libssh2-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + [[package]] name = "libusb1-sys" version = "0.7.0" @@ -7432,6 +8015,18 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libz-sys" +version = "1.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -7450,6 +8045,63 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "liquid" +version = "0.26.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cdcc72b82748f47c2933c172313f5a9aea5b2c4eb3fa4c66b4ea55bb60bb4b1" +dependencies = [ + "doc-comment", + "liquid-core", + "liquid-derive", + "liquid-lib", + "serde", +] + +[[package]] +name = "liquid-core" +version = "0.26.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2752e978ffc53670f3f2e8b3ef09f348d6f7b5474a3be3f8a5befe5382e4effb" +dependencies = [ + "anymap2", + "itertools 0.13.0", + "kstring", + "liquid-derive", + "num-traits", + "pest", + "pest_derive", + "regex", + "serde", + "time", +] + +[[package]] +name = "liquid-derive" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b51f1d220e3fa869e24cfd75915efe3164bd09bb11b3165db3f37f57bf673e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "liquid-lib" +version = "0.26.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b1a298d3d2287ee5b1e43840d885b8fdfc37d3f4e90d82aacfd04d021618da" +dependencies = [ + "itertools 0.13.0", + "liquid-core", + "once_cell", + "percent-encoding", + "regex", + "time", + "unicode-segmentation", +] + [[package]] name = "litemap" version = "0.7.4" @@ -7563,6 +8215,15 @@ dependencies = [ "rustix 0.38.42", ] +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.7.1" @@ -7718,6 +8379,15 @@ dependencies = [ "unsigned-varint 0.7.2", ] +[[package]] +name = "names" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc" +dependencies = [ + "rand", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -7819,6 +8489,18 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "no-std-net" version = "0.6.0" @@ -7847,6 +8529,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "normpath" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "ntapi" version = "0.4.1" @@ -7954,6 +8645,21 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "nybbles" version = "0.2.1" @@ -8064,6 +8770,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.4.1+3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.104" @@ -8072,6 +8787,7 @@ checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -8222,6 +8938,24 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "path-absolutize" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4af381fe79fa195b4909485d99f73a80792331df0625188e707854f0b3383f5" +dependencies = [ + "path-dedot", +] + +[[package]] +name = "path-dedot" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ba0ad7e047712414213ff67533e6dd477af0a4e1d14fb52343e53d30ea9397" +dependencies = [ + "once_cell", +] + [[package]] name = "path-slash" version = "0.2.1" @@ -8296,6 +9030,40 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pest_derive" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "pest_meta" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" +dependencies = [ + "once_cell", + "pest", + "sha2 0.10.8", +] + [[package]] name = "petgraph" version = "0.6.5" @@ -8682,6 +9450,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prodash" +version = "28.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79" + [[package]] name = "prometheus-client" version = "0.22.3" @@ -9014,9 +9788,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -9062,6 +9836,20 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "remove_dir_all" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a694f9e0eb3104451127f6cc1e5de55f59d3b1fc8c5ddfaeb6f1e716479ceb4a" +dependencies = [ + "cfg-if", + "cvt", + "fs_at", + "libc", + "normpath", + "windows-sys 0.59.0", +] + [[package]] name = "reqwest" version = "0.11.27" @@ -9175,6 +9963,34 @@ dependencies = [ "subtle", ] +[[package]] +name = "rhai" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61797318be89b1a268a018a92a7657096d83f3ecb31418b9e9c16dcbb043b702" +dependencies = [ + "ahash 0.8.11", + "bitflags 2.6.0", + "instant", + "num-traits", + "once_cell", + "rhai_codegen", + "smallvec", + "smartstring", + "thin-vec", +] + +[[package]] +name = "rhai_codegen" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5a11a05ee1ce44058fa3d5961d05194fdbe3ad6b40f904af764d81b86450e6b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "ring" version = "0.16.20" @@ -9274,7 +10090,7 @@ dependencies = [ "netlink-packet-utils", "netlink-proto", "netlink-sys", - "nix", + "nix 0.26.4", "thiserror 1.0.69", "tokio", ] @@ -9651,6 +10467,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "sanitize-filename" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "scale-bits" version = "0.6.0" @@ -10144,6 +10970,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + [[package]] name = "sha2" version = "0.9.9" @@ -10197,6 +11029,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + [[package]] name = "shlex" version = "1.3.0" @@ -10270,6 +11108,17 @@ dependencies = [ "serde", ] +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "static_assertions", + "version_check", +] + [[package]] name = "smol" version = "2.0.2" @@ -11477,15 +12326,14 @@ checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" [[package]] name = "tempfile" -version = "3.14.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "once_cell", "rustix 0.38.42", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -11508,6 +12356,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal-prompt" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572818b3472910acbd5dff46a3413715c18e934b071ab2ba464a7b2c2af16376" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "terminal_size" version = "0.4.1" @@ -11547,6 +12405,12 @@ dependencies = [ "url", ] +[[package]] +name = "thin-vec" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" + [[package]] name = "thiserror" version = "1.0.69" @@ -11614,7 +12478,9 @@ checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", @@ -11819,6 +12685,7 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -12240,6 +13107,12 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" +[[package]] +name = "unicode-bom" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" + [[package]] name = "unicode-ident" version = "1.0.14" @@ -12255,6 +13128,18 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + [[package]] name = "unicode-xid" version = "0.2.6" diff --git a/cli/src/deploy/tangle.rs b/cli/src/deploy/tangle.rs index 7f38ada..280c946 100644 --- a/cli/src/deploy/tangle.rs +++ b/cli/src/deploy/tangle.rs @@ -4,17 +4,15 @@ use alloy_rpc_types_eth::TransactionRequest; use alloy_signer_local::PrivateKeySigner; use color_eyre::eyre::{self, Context, ContextCompat, Result}; use gadget_blueprint_proc_macro_core::{BlueprintManager, ServiceBlueprint}; -use gadget_clients::tangle::runtime::TangleConfig; +use gadget_crypto::tangle_pair_signer::TanglePairSigner; use gadget_std::fmt::Debug; use gadget_std::path::PathBuf; +use subxt::tx::Signer; use tangle_subxt::subxt; use tangle_subxt::subxt::ext::sp_core; -use tangle_subxt::subxt::tx::PairSigner; use tangle_subxt::tangle_testnet_runtime::api as TangleApi; use tangle_subxt::tangle_testnet_runtime::api::services::calls::types; -pub type TanglePairSigner = PairSigner; - #[derive(Clone)] pub struct Opts { /// The name of the package to deploy (if the workspace has multiple packages) @@ -26,7 +24,7 @@ pub struct Opts { /// The path to the manifest file pub manifest_path: gadget_std::path::PathBuf, /// The signer for deploying the blueprint - pub signer: Option, + pub signer: Option>, /// The signer for deploying the smart contract pub signer_evm: Option, } @@ -106,7 +104,7 @@ pub async fn deploy_to_tangle( let signer = if let Some(signer) = signer { signer } else { - crate::signer::load_signer_from_env()?.pair + crate::signer::load_signer_from_env()? }; let my_account_id = signer.account_id(); diff --git a/crates/blueprint/manager/src/executor/mod.rs b/crates/blueprint/manager/src/executor/mod.rs index b51434b..118ac5a 100644 --- a/crates/blueprint/manager/src/executor/mod.rs +++ b/crates/blueprint/manager/src/executor/mod.rs @@ -193,8 +193,7 @@ pub async fn run_blueprint_manager>( &event, &mut active_gadgets, &sub_account_id.clone(), - ) - .await; + ); if result.needs_update { operator_subscribed_blueprints = services_client @@ -294,7 +293,7 @@ async fn handle_init( // Immediately poll, handling the initial state let poll_result = - event_handler::check_blueprint_events(&init_event, active_gadgets, sub_account_id).await; + event_handler::check_blueprint_events(&init_event, active_gadgets, sub_account_id); event_handler::handle_tangle_event( &init_event, diff --git a/crates/crypto/src/lib.rs b/crates/crypto/src/lib.rs index d0189df..884e09a 100644 --- a/crates/crypto/src/lib.rs +++ b/crates/crypto/src/lib.rs @@ -28,9 +28,6 @@ pub use gadget_crypto_tangle_pair_signer as tangle_pair_signer; #[cfg(feature = "hashing")] pub use gadget_crypto_hashing as hashing; -#[cfg(feature = "tangle-pair-signer")] -pub use gadget_crypto_tangle_pair_signer as tangle_pair_signer; - #[derive(Debug, Error)] pub enum CryptoCoreError { #[cfg(feature = "k256")] diff --git a/crates/event-listeners/tangle/Cargo.toml b/crates/event-listeners/tangle/Cargo.toml index e1594cb..239bec9 100644 --- a/crates/event-listeners/tangle/Cargo.toml +++ b/crates/event-listeners/tangle/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] gadget-blueprint-serde = { workspace = true } gadget-clients = { workspace = true, features = ["tangle"] } -gadget-contexts = { workspace = true, features = ["keystore"] } +gadget-contexts = { workspace = true, features = ["keystore", "tangle"] } gadget-crypto-tangle-pair-signer = { workspace = true } gadget-event-listeners-core = { workspace = true } gadget-keystore = { workspace = true } diff --git a/crates/macros/blueprint-proc-macro/src/report.rs b/crates/macros/blueprint-proc-macro/src/report.rs index 9d4b1e6..1a32a94 100644 --- a/crates/macros/blueprint-proc-macro/src/report.rs +++ b/crates/macros/blueprint-proc-macro/src/report.rs @@ -403,7 +403,7 @@ fn generate_qos_report_event_handler( #[automatically_derived] #[gadget_sdk::async_trait::async_trait] - impl gadget_sdk::event_utils::substrate::EventHandler for #struct_name { + impl gadget_sdk::event_utils::substrate::EventHandler for #struct_name { async fn handle(&self, event: &#event_type) -> Result>, gadget_sdk::event_utils::Error> { use std::time::Duration; use gadget_sdk::slashing::reports::{QoSReporter, DefaultQoSReporter}; diff --git a/crates/macros/core/src/lib.rs b/crates/macros/core/src/lib.rs index 703287b..c72c579 100644 --- a/crates/macros/core/src/lib.rs +++ b/crates/macros/core/src/lib.rs @@ -55,7 +55,6 @@ pub enum FieldType { } impl FieldType { - #[must_use] /// Returns the Rust type representation of this field type as a string. /// /// This method converts the `FieldType` enum variant into its corresponding Rust type string. diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 0ae1bd9..16c9114 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.83.0" +channel = "nightly-2024-10-13" components = ["rustfmt", "clippy", "rust-src"] targets = ["wasm32-unknown-unknown"] profile = "minimal"