From aa1393002e77f5008432d4dce00d97fd4e951c2b Mon Sep 17 00:00:00 2001 From: Thomas Braun <38082993+tbraun96@users.noreply.github.com> Date: Thu, 24 Oct 2024 03:23:54 -0400 Subject: [PATCH] Event Flows for Tangle (#363) * wip: Working on tangle compat with new event flows * pre-processor w/ macro-injected encoding added * Add integration test, ensure tangle integration test works, pre/post processing works * Remove tangle-events * Cleanup * update CI * Adjust forge usage * chore: remove docs dir out of date --------- Co-authored-by: Drew Stone --- .github/workflows/ci.yml | 12 +- Cargo.lock | 533 ++++++++-------- blueprint-test-utils/src/lib.rs | 2 +- .../contracts/lib/forge-std | 2 +- .../incredible-squaring-eigenlayer/src/lib.rs | 5 +- .../src/tests.rs | 10 +- .../contracts/lib/forge-std | 2 +- .../contracts/lib/tnt-core | 2 +- blueprints/incredible-squaring/src/lib.rs | 14 +- blueprints/incredible-squaring/src/main.rs | 1 + blueprints/periodic-web-poller/src/lib.rs | 1 - .../contracts/lib/forge-std | 2 +- cli/src/deploy.rs | 14 +- docs/event_listeners.md | 256 -------- macros/blueprint-proc-macro-core/src/lib.rs | 24 + .../src/event_listener/evm.rs | 25 +- .../src/event_listener/tangle.rs | 40 +- macros/blueprint-proc-macro/src/job.rs | 578 ++++++++++-------- macros/blueprint-proc-macro/src/report.rs | 232 +++---- macros/blueprint-proc-macro/src/shared.rs | 15 + macros/blueprint-proc-macro/src/tangle/mod.rs | 197 ++++-- macros/playground/Cargo.toml | 7 +- macros/playground/src/lib.rs | 218 ++++++- sdk/Cargo.toml | 1 + sdk/src/error.rs | 2 + sdk/src/event_listener/executor.rs | 13 +- sdk/src/event_listener/mod.rs | 2 +- sdk/src/event_listener/tangle/jobs.rs | 124 ++++ sdk/src/event_listener/tangle/mod.rs | 182 ++++++ sdk/src/event_listener/tangle_events.rs | 204 ------- sdk/src/lib.rs | 1 + 31 files changed, 1436 insertions(+), 1285 deletions(-) delete mode 100644 docs/event_listeners.md create mode 100644 sdk/src/event_listener/tangle/jobs.rs create mode 100644 sdk/src/event_listener/tangle/mod.rs delete mode 100644 sdk/src/event_listener/tangle_events.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c8591ed1..f1e2f47aa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,12 +37,6 @@ jobs: timeout-minutes: 120 name: cargo clippy runs-on: macos-latest - strategy: - matrix: - package: [ - gadget-sdk, - blueprint-manager - ] steps: - name: checkout code uses: actions/checkout@v2 @@ -71,8 +65,11 @@ jobs: - name: install protobuf run: brew install protobuf + - name: Forge build + run: forge update && cd blueprints/incredible-squaring-eigenlayer && forge build --root ./contracts + - name: Run Clippy - run: cargo clippy --package ${{ matrix.package }} --tests -- -D warnings + run: cargo clippy --tests -- -D warnings testing: timeout-minutes: 90 @@ -85,6 +82,7 @@ jobs: blueprint-manager, gadget-context-derive, gadget-blueprint-proc-macro, + gadget-blueprint-proc-macro-playground, ] steps: - name: checkout code diff --git a/Cargo.lock b/Cargo.lock index b12001c9e..41c5dc6b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,11 +128,10 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-chains" -version = "0.1.40" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4932d790c723181807738cf1ac68198ab581cd699545b155601332541ee47bd" +checksum = "94c225801d42099570d0674701dddd4142f0ef715282aeb5985042e2ec962df7" dependencies = [ - "alloy-primitives 0.8.9", "num_enum", "strum", ] @@ -184,7 +183,7 @@ dependencies = [ "itoa", "serde", "serde_json", - "winnow", + "winnow 0.6.20", ] [[package]] @@ -411,7 +410,7 @@ checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -570,7 +569,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -584,7 +583,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -601,7 +600,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", "syn-solidity 0.7.7", "tiny-keccak", ] @@ -619,7 +618,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", "syn-solidity 0.8.9", "tiny-keccak", ] @@ -637,7 +636,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.82", + "syn 2.0.79", "syn-solidity 0.7.7", ] @@ -652,7 +651,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", "syn-solidity 0.8.9", ] @@ -663,7 +662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbcba3ca07cf7975f15d871b721fb18031eec8bce51103907f6dcce00b255d98" dependencies = [ "serde", - "winnow", + "winnow 0.6.20", ] [[package]] @@ -737,7 +736,7 @@ dependencies = [ "alloy-json-rpc 0.1.4", "alloy-transport 0.1.4", "http-body-util", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-util", "reqwest 0.12.8", "serde_json", @@ -771,7 +770,7 @@ dependencies = [ "alloy-transport 0.1.4", "futures", "http 1.1.0", - "rustls 0.23.15", + "rustls 0.23.14", "serde_json", "tokio", "tokio-tungstenite 0.23.1", @@ -854,9 +853,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.91" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "anymap2" @@ -1133,7 +1132,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", "synstructure 0.13.1", ] @@ -1145,7 +1144,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -1293,7 +1292,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -1310,7 +1309,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -1409,7 +1408,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -1479,14 +1478,14 @@ dependencies = [ "percent-encoding", "pin-project-lite", "tracing", - "uuid 1.11.0", + "uuid 1.10.0", ] [[package]] name = "aws-sdk-kms" -version = "1.47.0" +version = "1.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564a597a3c71a957d60a2e4c62c93d78ee5a0d636531e15b760acad983a5c18e" +checksum = "e33590e8d45206fdc4273ded8a1f292bcceaadd513037aa790fc67b237bc30ee" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1569,9 +1568,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.2" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a065c0fe6fdbdf9f11817eb68582b2ab4aff9e9c39e986ae48f7ec576c6322db" +checksum = "d1ce695746394772e7000b39fe073095db6d45a862d0767dd5ad0ac0d7f8eb87" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -1584,7 +1583,7 @@ dependencies = [ "http-body 0.4.6", "http-body 1.0.1", "httparse", - "hyper 0.14.31", + "hyper 0.14.30", "hyper-rustls 0.24.2", "once_cell", "pin-project-lite", @@ -1784,7 +1783,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.82", + "syn 2.0.79", "which", ] @@ -2006,7 +2005,7 @@ dependencies = [ "tokio-util 0.7.12", "tracing", "url", - "uuid 1.11.0", + "uuid 1.10.0", ] [[package]] @@ -2024,7 +2023,7 @@ dependencies = [ "home", "http 1.1.0", "http-body-util", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-named-pipe", "hyper-rustls 0.26.0", "hyper-util", @@ -2112,9 +2111,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" dependencies = [ "serde", ] @@ -2276,9 +2275,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.31" +version = "1.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" dependencies = [ "jobserver", "libc", @@ -2456,7 +2455,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -2817,7 +2816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -2876,7 +2875,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -2933,7 +2932,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -2955,7 +2954,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -3051,7 +3050,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -3062,7 +3061,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -3075,7 +3074,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -3095,7 +3094,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", "unicode-xid", ] @@ -3183,7 +3182,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -3213,7 +3212,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.82", + "syn 2.0.79", "termcolor", "toml", "walkdir", @@ -3471,7 +3470,7 @@ dependencies = [ "serde_json", "sha2 0.10.8", "thiserror", - "uuid 1.11.0", + "uuid 1.10.0", ] [[package]] @@ -3802,7 +3801,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -3815,7 +3814,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -4022,7 +4021,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "syn 2.0.82", + "syn 2.0.79", "toml", "walkdir", ] @@ -4040,7 +4039,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -4066,7 +4065,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.82", + "syn 2.0.79", "tempfile", "thiserror", "tiny-keccak", @@ -4253,7 +4252,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -4383,9 +4382,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.11.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" dependencies = [ "futures-core", "futures-sink", @@ -4597,7 +4596,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -4607,7 +4606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.23.15", + "rustls 0.23.14", "rustls-pki-types", ] @@ -4689,7 +4688,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.82", + "syn 2.0.79", "tracing", "trybuild", ] @@ -4711,6 +4710,9 @@ dependencies = [ "async-trait", "blueprint-metadata", "gadget-sdk", + "reqwest 0.12.8", + "serde_json", + "tokio", "tracing", ] @@ -4724,7 +4726,7 @@ dependencies = [ "gadget-sdk", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", "trybuild", ] @@ -4782,12 +4784,13 @@ dependencies = [ "failure", "futures", "gadget-blueprint-proc-macro", + "gadget-blueprint-proc-macro-core", "gadget-context-derive", "gadget-io", "getrandom", "hex", "http-body-util", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-util", "k256", "libp2p", @@ -4818,7 +4821,7 @@ dependencies = [ "tracing", "tracing-subscriber 0.3.18", "url", - "uuid 1.11.0", + "uuid 1.10.0", "w3f-bls", ] @@ -4909,7 +4912,7 @@ dependencies = [ "gix-utils", "itoa", "thiserror", - "winnow", + "winnow 0.6.20", ] [[package]] @@ -4930,14 +4933,14 @@ dependencies = [ "smallvec", "thiserror", "unicode-bom", - "winnow", + "winnow 0.6.20", ] [[package]] name = "gix-config-value" -version = "0.14.9" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3de3fdca9c75fa4b83a76583d265fa49b1de6b088ebcd210749c24ceeb74660" +checksum = "03f76169faa0dec598eac60f83d7fcdd739ec16596eca8fb144c88973dbe6f8c" dependencies = [ "bitflags 2.6.0", "bstr", @@ -5033,14 +5036,14 @@ dependencies = [ "itoa", "smallvec", "thiserror", - "winnow", + "winnow 0.6.20", ] [[package]] name = "gix-path" -version = "0.10.12" +version = "0.10.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c04e5a94fdb56b1e91eb7df2658ad16832428b8eeda24ff1a0f0288de2bce554" +checksum = "ebfc4febd088abdcbc9f1246896e57e37b7a34f6909840045a1767c6dafac7af" dependencies = [ "bstr", "gix-trace", @@ -5068,14 +5071,14 @@ dependencies = [ "gix-validate", "memmap2", "thiserror", - "winnow", + "winnow 0.6.20", ] [[package]] name = "gix-sec" -version = "0.10.9" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2007538eda296445c07949cf04f4a767307d887184d6b3e83e2d636533ddc6e" +checksum = "0fe4d52f30a737bbece5276fab5d3a8b276dc2650df963e293d0673be34e7a5f" dependencies = [ "bitflags 2.6.0", "gix-path", @@ -5098,15 +5101,15 @@ dependencies = [ [[package]] name = "gix-trace" -version = "0.1.11" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04bdde120c29f1fc23a24d3e115aeeea3d60d8e65bab92cc5f9d90d9302eb952" +checksum = "6cae0e8661c3ff92688ce1c8b8058b3efb312aba9492bbe93661a21705ab431b" [[package]] name = "gix-utils" -version = "0.1.13" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba427e3e9599508ed98a6ddf8ed05493db114564e338e41f6a996d2e4790335f" +checksum = "35192df7fd0fa112263bad8021e2df7167df4cc2a6e6d15892e1e55621d3d4dc" dependencies = [ "fastrand", "unicode-normalization", @@ -5588,9 +5591,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.31" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", @@ -5612,9 +5615,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", @@ -5638,7 +5641,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" dependencies = [ "hex", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-util", "pin-project-lite", "tokio", @@ -5654,7 +5657,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.31", + "hyper 0.14.30", "log", "rustls 0.21.12", "rustls-native-certs 0.6.3", @@ -5670,7 +5673,7 @@ checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-util", "log", "rustls 0.22.4", @@ -5689,10 +5692,10 @@ checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-util", "log", - "rustls 0.23.15", + "rustls 0.23.14", "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", @@ -5708,7 +5711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.31", + "hyper 0.14.30", "native-tls", "tokio", "tokio-native-tls", @@ -5722,7 +5725,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-util", "native-tls", "tokio", @@ -5741,7 +5744,7 @@ dependencies = [ "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.5.0", + "hyper 1.4.1", "pin-project-lite", "socket2", "tokio", @@ -5757,7 +5760,7 @@ checksum = "acf569d43fa9848e510358c07b80f4adf34084ddc28c6a4a651ee8474c070dcc" dependencies = [ "hex", "http-body-util", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-util", "pin-project-lite", "tokio", @@ -5853,7 +5856,7 @@ dependencies = [ "bytes", "futures", "http 0.2.12", - "hyper 0.14.31", + "hyper 0.14.30", "log", "rand", "tokio", @@ -5961,7 +5964,7 @@ dependencies = [ "tokio", "tokio-util 0.7.12", "tracing", - "uuid 1.11.0", + "uuid 1.10.0", ] [[package]] @@ -6038,7 +6041,7 @@ dependencies = [ "tokio", "tokio-util 0.7.12", "tracing", - "uuid 1.11.0", + "uuid 1.10.0", ] [[package]] @@ -6226,9 +6229,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -6255,7 +6258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" dependencies = [ "futures", - "hyper 0.14.31", + "hyper 0.14.30", "jsonrpc-core", "jsonrpc-server-utils", "log", @@ -6342,7 +6345,7 @@ dependencies = [ "http 1.1.0", "jsonrpsee-core 0.23.2", "pin-project", - "rustls 0.23.15", + "rustls 0.23.14", "rustls-pki-types", "rustls-platform-verifier", "soketto 0.8.0", @@ -6365,7 +6368,7 @@ dependencies = [ "beef", "futures-timer", "futures-util", - "hyper 0.14.31", + "hyper 0.14.30", "jsonrpsee-types 0.22.5", "pin-project", "rustc-hash 1.1.0", @@ -6408,7 +6411,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" dependencies = [ "async-trait", - "hyper 0.14.31", + "hyper 0.14.30", "hyper-rustls 0.24.2", "jsonrpsee-core 0.22.5", "jsonrpsee-types 0.22.5", @@ -6590,9 +6593,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.161" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libgit2-sys" @@ -6984,7 +6987,7 @@ dependencies = [ "quinn", "rand", "ring 0.17.8", - "rustls 0.23.15", + "rustls 0.23.14", "socket2", "thiserror", "tokio", @@ -7071,7 +7074,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -7103,7 +7106,7 @@ dependencies = [ "libp2p-identity", "rcgen", "ring 0.17.8", - "rustls 0.23.15", + "rustls 0.23.14", "rustls-webpki 0.101.7", "thiserror", "x509-parser", @@ -7293,7 +7296,7 @@ checksum = "3b51f1d220e3fa869e24cfd75915efe3164bd09bb11b3165db3f37f57bf673e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -7460,7 +7463,7 @@ checksum = "b4f0c8427b39666bf970460908b213ec09b3b350f20c0c2eabcbba51704a08e6" dependencies = [ "base64 0.22.1", "http-body-util", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-rustls 0.27.3", "hyper-util", "indexmap 2.6.0", @@ -7802,9 +7805,9 @@ dependencies = [ [[package]] name = "ntex" -version = "2.7.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223834e688405dcc46b5c28bc9225648c603e64d7b61e8903da33064b6f1464e" +checksum = "93daf570cdedb9a01a3020ccd367b2ff37402b30c979aff2da23e3e84d2b6cfc" dependencies = [ "base64 0.22.1", "bitflags 2.6.0", @@ -7861,9 +7864,9 @@ dependencies = [ [[package]] name = "ntex-h2" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e01b86bf30768ed7dca26bf279d0e0798ba5acf0baef4b0ea8e17a91ba71ad4" +checksum = "98763f0ee78f247c02fe1bcdf6380f306a08d95169f9c2d83619d5e1cb26c738" dependencies = [ "bitflags 2.6.0", "fxhash", @@ -7896,15 +7899,14 @@ dependencies = [ [[package]] name = "ntex-io" -version = "2.7.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c49628e35ff52f36137a8e732261f392de621406a163571888f6163e3f6b10" +checksum = "ae8e90ceb0a9a1bcb57459b8e14c6257519afc8dc3460d68b507fb12e909d02c" dependencies = [ "bitflags 2.6.0", "log", "ntex-bytes", "ntex-codec", - "ntex-rt", "ntex-service", "ntex-util", "pin-project-lite", @@ -7953,9 +7955,9 @@ dependencies = [ [[package]] name = "ntex-rt" -version = "0.4.20" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f86c83f89053c29dcf5f1e9663c53726eea337a3221fa243e61e0410a40ad7" +checksum = "1d24cfad65aab77e56ee1f1a218ca248c141a22f6f65aba8ed56037ec3c6f3a4" dependencies = [ "async-channel", "futures-core", @@ -7987,9 +7989,9 @@ dependencies = [ [[package]] name = "ntex-service" -version = "3.2.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02daa9c4fc8b5382b24dd69d504599a72774d6828e4fc21e9013cb62096db7aa" +checksum = "ab2cc8f131d5fed702d758485fdc45a41dfab69d8ed71b84e2b910b4ea39f795" dependencies = [ "slab", ] @@ -8170,10 +8172,10 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -8266,9 +8268,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ "bitflags 2.6.0", "cfg-if 1.0.0", @@ -8287,7 +8289,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -8298,18 +8300,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.4.0+3.4.0" +version = "300.3.2+3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6" +checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -8326,9 +8328,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-float" -version = "4.4.0" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e7ccb95e240b7c9506a3d544f10d935e142cc90b0a1d56954fb44d89ad6b97" +checksum = "44d501f1a72f71d3c063a6bbc8f7271fa73aa09fe5d6283b6571e2ed176a2537" dependencies = [ "num-traits", ] @@ -8385,7 +8387,7 @@ version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 1.0.109", @@ -8467,7 +8469,7 @@ dependencies = [ "regex", "regex-syntax 0.8.5", "structmeta", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -8615,9 +8617,9 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.14" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" dependencies = [ "memchr", "thiserror", @@ -8626,9 +8628,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.14" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" dependencies = [ "pest", "pest_generator", @@ -8636,22 +8638,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.14" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] name = "pest_meta" -version = "2.7.14" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" dependencies = [ "once_cell", "pest", @@ -8717,7 +8719,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -8755,7 +8757,7 @@ checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -8847,7 +8849,7 @@ dependencies = [ "polkavm-common 0.8.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -8859,7 +8861,7 @@ dependencies = [ "polkavm-common 0.9.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -8869,7 +8871,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" dependencies = [ "polkavm-derive-impl 0.8.0", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -8879,7 +8881,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl 0.9.0", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -8949,12 +8951,12 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "prettyplease" -version = "0.2.24" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "910d41a655dac3b764f1ade94821093d3610248694320cd072303a8eedcf221d" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -8971,13 +8973,23 @@ dependencies = [ "uint", ] +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + [[package]] name = "proc-macro-crate" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit", + "toml_edit 0.22.22", ] [[package]] @@ -9023,14 +9035,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -9075,7 +9087,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -9162,7 +9174,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.15", + "rustls 0.23.14", "socket2", "thiserror", "tokio", @@ -9179,7 +9191,7 @@ dependencies = [ "rand", "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.15", + "rustls 0.23.14", "slab", "thiserror", "tinyvec", @@ -9374,7 +9386,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -9455,7 +9467,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.31", + "hyper 0.14.30", "hyper-rustls 0.24.2", "hyper-tls 0.5.0", "ipnet", @@ -9501,7 +9513,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-rustls 0.27.3", "hyper-tls 0.6.0", "hyper-util", @@ -9514,7 +9526,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.15", + "rustls 0.23.14", "rustls-native-certs 0.8.0", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -9580,7 +9592,7 @@ checksum = "a5a11a05ee1ce44058fa3d5961d05194fdbe3ad6b40f904af764d81b86450e6b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -9877,9 +9889,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.15" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "aws-lc-rs", "log", @@ -9949,9 +9961,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" [[package]] name = "rustls-platform-verifier" @@ -9964,7 +9976,7 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.15", + "rustls 0.23.14", "rustls-native-certs 0.7.3", "rustls-platform-verifier-android", "rustls-webpki 0.102.8", @@ -10004,9 +10016,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-fork" @@ -10132,9 +10144,9 @@ dependencies = [ [[package]] name = "scale-encode" -version = "0.7.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528464e6ae6c8f98e2b79633bf79ef939552e795e316579dab09c61670d56602" +checksum = "4ba0b9c48dc0eb20c60b083c29447c0c4617cb7c4a4c9fef72aa5c5bc539e15e" dependencies = [ "derive_more 0.99.18", "parity-scale-codec", @@ -10147,26 +10159,26 @@ dependencies = [ [[package]] name = "scale-encode-derive" -version = "0.7.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef2618f123c88da9cd8853b69d766068f1eddc7692146d7dfe9b89e25ce2efd" +checksum = "82ab7e60e2d9c8d47105f44527b26f04418e5e624ffc034f6b4a86c0ba19c5bf" dependencies = [ - "darling 0.20.10", - "proc-macro-crate", + "darling 0.14.4", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.82", + "syn 1.0.109", ] [[package]] name = "scale-info" -version = "2.11.4" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22760a375f81a31817aeaf6f5081e9ccb7ffd7f2da1809a6e3fc82b6656f10d5" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" dependencies = [ "bitvec", "cfg-if 1.0.0", - "derive_more 1.0.0", + "derive_more 0.99.18", "parity-scale-codec", "scale-info-derive", "serde", @@ -10174,11 +10186,11 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.4" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abc61ebe25a5c410c0e245028fc9934bf8fa4817199ef5a24a68092edfd34614" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 1.0.109", @@ -10203,7 +10215,7 @@ dependencies = [ "proc-macro2", "quote", "scale-info", - "syn 2.0.82", + "syn 2.0.79", "thiserror", ] @@ -10414,9 +10426,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.213" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -10443,13 +10455,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.213" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -10460,14 +10472,14 @@ checksum = "e578a843d40b4189a4d66bba51d7684f57da5bd7c304c64e14bd63efbef49509" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -10483,7 +10495,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -10534,7 +10546,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -11032,7 +11044,7 @@ checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -11150,10 +11162,10 @@ checksum = "0195f32c628fee3ce1dfbbf2e7e52a30ea85f3589da9fe62a8b816d70fc06294" dependencies = [ "Inflector", "expander", - "proc-macro-crate", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -11578,7 +11590,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -11589,7 +11601,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -11635,7 +11647,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -11711,16 +11723,16 @@ dependencies = [ "scale-info", "scale-typegen", "subxt-metadata", - "syn 2.0.82", + "syn 2.0.79", "thiserror", "tokio", ] [[package]] name = "subxt-core" -version = "0.37.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af3b36405538a36b424d229dc908d1396ceb0994c90825ce928709eac1a159a" +checksum = "59f41eb2e2eea6ed45649508cc735f92c27f1fcfb15229e75f8270ea73177345" dependencies = [ "base58", "blake2", @@ -11784,7 +11796,7 @@ dependencies = [ "quote", "scale-typegen", "subxt-codegen", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -11856,9 +11868,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.82" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -11874,7 +11886,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -11886,7 +11898,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -11924,7 +11936,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -12009,12 +12021,6 @@ version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" -[[package]] -name = "target-triple" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" - [[package]] name = "tempfile" version = "3.10.1" @@ -12113,22 +12119,22 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.65" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.65" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -12209,9 +12215,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -12233,7 +12239,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -12284,7 +12290,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.15", + "rustls 0.23.14", "rustls-pki-types", "tokio", ] @@ -12324,7 +12330,7 @@ checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" dependencies = [ "futures-util", "log", - "rustls 0.23.15", + "rustls 0.23.14", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -12370,7 +12376,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.22.22", ] [[package]] @@ -12382,6 +12388,17 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.6.0", + "toml_datetime", + "winnow 0.5.40", +] + [[package]] name = "toml_edit" version = "0.22.22" @@ -12392,7 +12409,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.20", ] [[package]] @@ -12456,7 +12473,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -12594,15 +12611,14 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.101" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dcd332a5496c026f1e14b7f3d2b7bd98e509660c04239c58b0ba38a12daded4" +checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" dependencies = [ "glob", "serde", "serde_derive", "serde_json", - "target-triple", "termcolor", "toml", ] @@ -12629,7 +12645,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -12665,7 +12681,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls 0.23.15", + "rustls 0.23.14", "rustls-pki-types", "sha1", "thiserror", @@ -12701,7 +12717,7 @@ checksum = "f9534daa9fd3ed0bd911d462a37f172228077e7abf18c18a5f67199d959205f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -12873,9 +12889,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.11.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", ] @@ -12918,9 +12934,9 @@ checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" [[package]] name = "w3f-bls" -version = "0.1.6" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a48c48447120a85b0bdb897ba9426a7aa15b4229498a2e19103e8c9368dd4b2" +checksum = "9c5da5fa2c6afa2c9158eaa7cd9aee249765eb32b5fb0c63ad8b9e79336a47ec" dependencies = [ "ark-bls12-377", "ark-bls12-381", @@ -12982,9 +12998,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if 1.0.0", "once_cell", @@ -12993,24 +13009,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -13020,9 +13036,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -13030,22 +13046,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasmi" @@ -13231,9 +13247,9 @@ dependencies = [ [[package]] name = "wasmtimer" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7ed9d8b15c7fb594d72bfb4b5a276f3d2029333cd93a932f376f5937f6f80ee" +checksum = "5f656cd8858a5164932d8a90f936700860976ec21eb00e0fe2aa8cab13f6b4cf" dependencies = [ "futures", "js-sys", @@ -13245,9 +13261,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -13395,7 +13411,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -13406,7 +13422,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -13662,6 +13678,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "0.6.20" @@ -13823,7 +13848,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] @@ -13843,7 +13868,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.79", ] [[package]] diff --git a/blueprint-test-utils/src/lib.rs b/blueprint-test-utils/src/lib.rs index 3802ff00b..8f8e263bb 100644 --- a/blueprint-test-utils/src/lib.rs +++ b/blueprint-test-utils/src/lib.rs @@ -737,7 +737,7 @@ mod tests_standard { info!("Listening for TaskResponded events..."); while let Some(event) = event_stream.next().await { let TaskResponded { - taskResponse: response, + taskResponse: _response, .. } = event.log_decode::().unwrap().inner.data; let mut counter = successful_responses.lock().await; diff --git a/blueprints/incredible-squaring-eigenlayer/contracts/lib/forge-std b/blueprints/incredible-squaring-eigenlayer/contracts/lib/forge-std index 1de6eecf8..035de35f5 160000 --- a/blueprints/incredible-squaring-eigenlayer/contracts/lib/forge-std +++ b/blueprints/incredible-squaring-eigenlayer/contracts/lib/forge-std @@ -1 +1 @@ -Subproject commit 1de6eecf821de7fe2c908cc48d3ab3dced20717f +Subproject commit 035de35f5e366c8d6ed142aec4ccb57fe2dd87d4 diff --git a/blueprints/incredible-squaring-eigenlayer/src/lib.rs b/blueprints/incredible-squaring-eigenlayer/src/lib.rs index 868b866c5..9fa2b8b50 100644 --- a/blueprints/incredible-squaring-eigenlayer/src/lib.rs +++ b/blueprints/incredible-squaring-eigenlayer/src/lib.rs @@ -72,12 +72,11 @@ pub fn noop(_: u32) { event_listener( listener = EvmContractEventListener( instance = IncredibleSquaringTaskManager, - event = IncredibleSquaringTaskManager::NewTaskCreated, - event_converter = convert_event_to_inputs, - callback = noop, abi = INCREDIBLE_SQUARING_TASK_MANAGER_ABI_STRING, ), event = IncredibleSquaringTaskManager::NewTaskCreated, + pre_processor = convert_event_to_inputs, + post_processor = noop, ), )] pub async fn xsquare_eigen( diff --git a/blueprints/incredible-squaring-eigenlayer/src/tests.rs b/blueprints/incredible-squaring-eigenlayer/src/tests.rs index ad202f729..c481b1f9d 100644 --- a/blueprints/incredible-squaring-eigenlayer/src/tests.rs +++ b/blueprints/incredible-squaring-eigenlayer/src/tests.rs @@ -10,6 +10,7 @@ use blueprint_test_utils::test_ext::NAME_IDS; use blueprint_test_utils::{anvil, get_receipt, inject_test_keys}; use gadget_io::SupportedChains; use gadget_sdk::config::{ContextConfig, GadgetCLICoreSettings, Protocol}; +use gadget_sdk::info; use gadget_sdk::logging::setup_log; use gadget_sdk::run::GadgetRunner; use incredible_squaring_aggregator::aggregator::Aggregator; @@ -45,10 +46,11 @@ alloy_sol_types::sol!( #[allow(clippy::needless_return)] async fn test_eigenlayer_incredible_squaring_blueprint() -> Result<(), Box> { setup_log(); - let (_container, http_endpoint, ws_endpoint) = anvil::start_anvil_container(true).await; - let alice_keystore = setup_eigen_environment(0).await; // We use an ID of 0 for Alice + let (_container, http_endpoint, ws_endpoint) = + anvil::start_anvil_container(&alice_keystore, true).await; + std::env::set_var("EIGENLAYER_HTTP_ENDPOINT", http_endpoint.clone()); std::env::set_var("EIGENLAYER_WS_ENDPOINT", ws_endpoint.clone()); std::env::set_var("REGISTRATION_MODE_ON", "true"); // Set to run registration @@ -244,7 +246,7 @@ async fn test_eigenlayer_incredible_squaring_blueprint() -> Result<(), Box::default(), response_hash); info!("Shutting down aggregator..."); - aggregator_shutdown.send(()).unwrap(); + aggregator_shutdown.send(()).await.unwrap(); // chain_task.abort(); // runner_task.abort(); // aggregator_task.abort(); @@ -291,7 +293,7 @@ async fn mine_blocks(endpoint: &str, blocks: u8) { .output() .await .unwrap(); - info!( + gadget_sdk::info!( "Mined {} block{}", blocks, if blocks == 1 { "" } else { "s" } diff --git a/blueprints/incredible-squaring/contracts/lib/forge-std b/blueprints/incredible-squaring/contracts/lib/forge-std index 1de6eecf8..035de35f5 160000 --- a/blueprints/incredible-squaring/contracts/lib/forge-std +++ b/blueprints/incredible-squaring/contracts/lib/forge-std @@ -1 +1 @@ -Subproject commit 1de6eecf821de7fe2c908cc48d3ab3dced20717f +Subproject commit 035de35f5e366c8d6ed142aec4ccb57fe2dd87d4 diff --git a/blueprints/incredible-squaring/contracts/lib/tnt-core b/blueprints/incredible-squaring/contracts/lib/tnt-core index c1fa9c7c3..fad7030fe 160000 --- a/blueprints/incredible-squaring/contracts/lib/tnt-core +++ b/blueprints/incredible-squaring/contracts/lib/tnt-core @@ -1 +1 @@ -Subproject commit c1fa9c7c3c5891aab9bd25002a434d93c54942cd +Subproject commit fad7030fe53ea5d4a7576316880f5416fe656ee9 diff --git a/blueprints/incredible-squaring/src/lib.rs b/blueprints/incredible-squaring/src/lib.rs index 720c5981e..32f6f5e6c 100644 --- a/blueprints/incredible-squaring/src/lib.rs +++ b/blueprints/incredible-squaring/src/lib.rs @@ -1,5 +1,8 @@ +use gadget_sdk::clients::tangle::runtime::TangleClient; +use gadget_sdk::event_listener::tangle::jobs::{services_post_processor, services_pre_processor}; +use gadget_sdk::event_listener::tangle::TangleEventListener; use gadget_sdk::job; -use std::convert::Infallible; +use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::events::JobCalled; /// Returns x^2 saturating to [`u64::MAX`] if overflow occurs. #[job( @@ -7,10 +10,11 @@ use std::convert::Infallible; params(x), result(_), event_listener( - listener = TangleEventListener, - event = JobCalled, + listener = TangleEventListener, + pre_processor = services_pre_processor, + post_processor = services_post_processor, ), )] -pub fn xsquare(x: u64) -> Result { - Ok(x.saturating_pow(2u32)) +pub fn xsquare(x: u64, context: TangleClient) -> Result { + Ok(x.saturating_pow(2)) } diff --git a/blueprints/incredible-squaring/src/main.rs b/blueprints/incredible-squaring/src/main.rs index 3d2aa096a..d62eb05cb 100644 --- a/blueprints/incredible-squaring/src/main.rs +++ b/blueprints/incredible-squaring/src/main.rs @@ -14,6 +14,7 @@ async fn main() { let x_square = blueprint::XsquareEventHandler { service_id: env.service_id.unwrap(), client: client.clone(), + context: client.clone(), signer, }; diff --git a/blueprints/periodic-web-poller/src/lib.rs b/blueprints/periodic-web-poller/src/lib.rs index 1a25e095b..7e538db48 100644 --- a/blueprints/periodic-web-poller/src/lib.rs +++ b/blueprints/periodic-web-poller/src/lib.rs @@ -10,7 +10,6 @@ use std::convert::Infallible; result(_), event_listener( listener = PeriodicEventListener<2000, WebPoller, serde_json::Value, reqwest::Client>, - event = serde_json::Value, pre_processor = pre_process, post_processor = post_process, ), diff --git a/blueprints/tangle-avs-blueprint/contracts/lib/forge-std b/blueprints/tangle-avs-blueprint/contracts/lib/forge-std index 8f24d6b04..035de35f5 160000 --- a/blueprints/tangle-avs-blueprint/contracts/lib/forge-std +++ b/blueprints/tangle-avs-blueprint/contracts/lib/forge-std @@ -1 +1 @@ -Subproject commit 8f24d6b04c92975e0795b5868aa0d783251cdeaa +Subproject commit 035de35f5e366c8d6ed142aec4ccb57fe2dd87d4 diff --git a/cli/src/deploy.rs b/cli/src/deploy.rs index 08445303c..07ab9f727 100644 --- a/cli/src/deploy.rs +++ b/cli/src/deploy.rs @@ -52,10 +52,12 @@ pub async fn generate_service_blueprint, T: AsRef>( .exec() .context("Getting Metadata about the workspace")?; - let package = find_package(&metadata, pkg_name)?; - let mut blueprint = load_blueprint_metadata(package)?; - build_contracts_if_needed(package, &blueprint).context("Building contracts")?; - deploy_contracts_to_tangle(rpc_url.as_ref(), package, &mut blueprint, signer_evm).await?; + let package = find_package(&metadata, pkg_name)?.clone(); + let package_clone = &package.clone(); + let mut blueprint = + tokio::task::spawn_blocking(move || load_blueprint_metadata(&package)).await??; + build_contracts_if_needed(package_clone, &blueprint).context("Building contracts")?; + deploy_contracts_to_tangle(rpc_url.as_ref(), package_clone, &mut blueprint, signer_evm).await?; bake_blueprint(blueprint) } @@ -110,7 +112,9 @@ pub async fn deploy_to_tangle( Ok(event.blueprint_id) } -pub fn load_blueprint_metadata(package: &cargo_metadata::Package) -> Result { +pub fn load_blueprint_metadata( + package: &cargo_metadata::Package, +) -> Result> { let blueprint_json_path = package .manifest_path .parent() diff --git a/docs/event_listeners.md b/docs/event_listeners.md deleted file mode 100644 index b84af184e..000000000 --- a/docs/event_listeners.md +++ /dev/null @@ -1,256 +0,0 @@ -# Event Listeners - -When building a blueprint, your application may require to listen to events. Events can be of any type, and handling those events is entirely up to your discretion. - -In general, when defining your job, you must register any event listeners and provide a context as such: - -```rust -#[job( - id = 0, - params(x), - result(_), - event_listener(TangleEventListener, MyEventListener1, MyEventListener2, ...), // <-- Register all event listeners here - verifier(evm = "MyVerifier") -)] -pub fn hello_event_listener( - x: u64, - context: MyContext, // <-- The context type must be the first additional parameter - env: GadgetConfiguration, -) -> Result { - Ok(x.saturating_pow(2u32)) -} -``` - -In order to make these registered event listeners to work, we must define structs that implement `EventListener`. -## Creating Event Listeners - -To create an event listener, begin by defining a struct or enum which will listen to events: - -```rust -use gadget_sdk::event_listener::EventListener; -use async_trait::async_trait; - -/// Define a simple event listener that ticks every MS milliseconds. -pub struct Ticker { - additional_delay: u64, -} -``` - -Then, define a context for the event listener: - -```rust -#[derive(Copy, Clone)] -pub struct MyContext { - pub additional_delay: u64, -} -``` - -Next, implement `EventListener` for `Ticker`: - -```rust -/// Implement the [`EventListener`] trait for the Ticker struct. [`EventListener`] has two type parameters: -/// -/// - T: is the type of the event that the listener listens for. This can be anything that is Send + Sync + 'static. -/// In this case, we are using [`Instant`], which is a timestamp. -/// -/// - Ctx: is the context type that the listener receives when constructed. This can be anything that is Send + Sync + 'static, -/// with the special requirement that it is the *first* listed additional parameter in the [`job`] macro (i.e., a parameter not -/// in params(...)). In this case, we are using [`MyContext`]. -#[async_trait] -impl EventListener for Ticker { - /// Use a reference to the context, [`MyContext`], to construct the listener - async fn new(context: &MyContext) -> Result - where - Self: Sized, - { - Ok(Self { additional_delay: context.additional_delay }) - } - - /// Implement the logic that looks for events. In this case, we have a simple stream - /// that returns after MS milliseconds. - async fn next_event(&mut self) -> Option { - tokio::time::sleep(tokio::time::Duration::from_millis(MSEC as u64 + self.additional_delay)).await; - Some(Instant::now()) - } - - /// After next_event is called, the event gets passed here. This is where you would implement - /// listener-specific logic. - async fn handle_event(&mut self, _event: Instant) -> Result<(), Error> { - Ok(()) - } -} -``` - -Finally, register the event listener inside the `job` macro using `event_listener`: - -```rust -#[job( - id = 0, - params(x), - result(_), - event_listener(Ticker::<6000>), // <-- Register the event listener here - verifier(evm = "IncredibleSquaringBlueprint") -)] -pub fn hello_event_listener( - x: u64, - context: MyContext, // <-- The context type must be the first additional parameter - env: GadgetConfiguration, -) -> Result { - Ok(x.saturating_pow(2u32)) -} -``` - -## Primary Event Listeners -Primary event listeners are the most common type of event listener. They are easy to use, and require no context to work since this is done behind the scenes. - -### TangleEventListener -The `TangleEventListener` is a type that listens to the Tangle network for events. This is a required type if you expect your application to use the tangle network to listen to jobs. - -The `TangleEventListener` is already implemented and ready to use. Simply register it in the `job` macro, and your application -will automatically work with the Tangle network. - -```rust -/// Returns x^2 saturating to [`u64::MAX`] if overflow occurs. -#[job( - id = 0, - params(x), - result(_), - event_listener(TangleEventListener), - verifier(evm = "IncredibleSquaringBlueprint") -)] -pub fn xsquare( - x: u64, -) -> Result { - Ok(x.saturating_pow(2u32)) -} -``` - -### EvmContractEventListener -The `EvmContractEventListener` is a type that listens to the Ethereum Virtual Machine (EVM) for events. - -Like the `TangleEventListener`, the `EvmContractEventListener` is already implemented and ready to use. Simply register it in the `job` macro, and your application will automatically work with the EVM. - -```rust -/// Returns x^2 saturating to [`u64::MAX`] if overflow occurs. -#[job( - id = 0, - params(x), - result(_), - event_listener(EvmContractEventListener( - instance = IncredibleSquaringTaskManager, - event = IncredibleSquaringTaskManager::NewTaskCreated, - event_converter = convert_event_to_inputs, - callback = IncredibleSquaringTaskManager::IncredibleSquaringTaskManagerCalls::respondToTask - )), -)] -pub fn xsquare( - x: u64, -) -> Result { - Ok(x.saturating_pow(2u32)) -} -``` - -## Wrapper Event Listeners -Various wrappers exist to simplify how common operations are performed. - -### PeriodicEventListener -Some programs may only be interested in checking for events at regular intervals. In this case, the `PeriodicEventListener` can be used to simplify the process. - -A `PeriodicEventListener` is a wrapper that takes 4 type parameters: - -* `MSEC`: The number of milliseconds between each event check. -* `T`: The inner event listener type -* `Event`: The event type -* `Ctx`: The context type - -We can make a `PeriodicEventListener` that ticks every 5000ms to check the status of a web server using [reqwest](crates.io/crates/reqwest). - -```rust -use gadget_sdk::event_listener::periodic::PeriodicEventListener; - -/// Define an event listener that polls a webserver -pub struct WebPoller { - pub client: reqwest::Client, -} -``` - -Then, implement `EventListener` for `WebPoller`: - -```rust -#[async_trait::async_trait] -impl EventListener for WebPoller { - /// Build the event listener. Note that this time, we don't necessarily need the context - async fn new(_context: &MyContext) -> Result - where - Self: Sized, - { - let client = reqwest::Client::new(); - Ok(Self { client }) - } - - /// Implement the logic that polls the web server - async fn next_event(&mut self) -> Option { - // Send a GET request to the JSONPlaceholder API - let response = self.client - .get("https://jsonplaceholder.typicode.com/todos/1") - .send() - .await?; - - // Check if the request was successful - if response.status().is_success() { - // Parse the JSON response - let resp: serde_json::Value = response.json().await?; - Some(resp) - } else { - None - } - } - - /// Implement any handler logic when an event is received - async fn handle_event(&mut self, _event: serde_json::Value) -> Result<(), Error> { - Ok(()) - } -} -``` - -Finally, register the event listener inside the `job` macro using `event_listener`: - -```rust -#[job( - id = 0, - params(value), - result(_), - event_listener(PeriodicEventListener::<6000, WebPoller, serde_json::Value, MyContext>), // <-- Register the event listener here -)] -pub fn hello_event_listener( - value: serde_json::Value, - context: MyContext, -) -> Result { - let completed = value["completed"].as_bool().unwrap_or(false); - Ok(completed) -} -``` - -## Multiple Event Listeners -Arbitrarily many event listeners can be used in a single job. This is useful when you want to listen to multiple sources to handle job logic - -For example, using the example of the `PeriodicEventListener` above, we can add a `TangleEventListener` to the job: - -```rust -#[job( - id = 0, - params(x), - result(_), - event_listener(TangleEventListener, PeriodicEventListener::<6000, WebPoller, serde_json::Value, MyContext>), // <-- Register the event listeners here - verifier(evm = "IncredibleSquaringBlueprint") -)] -pub fn hello_event_listener( - x: u64, - context: MyContext, - env: GadgetConfiguration, -) -> Result { - Ok(x.saturating_pow(2u32)) -} -``` - -In this case, both the TangleEventListener, which is listening to the Tangle network, and the PeriodicEventListener, which is polling a web server, will be used in *parallel* to listen for events. \ No newline at end of file diff --git a/macros/blueprint-proc-macro-core/src/lib.rs b/macros/blueprint-proc-macro-core/src/lib.rs index 214ae5307..28a5faf9a 100644 --- a/macros/blueprint-proc-macro-core/src/lib.rs +++ b/macros/blueprint-proc-macro-core/src/lib.rs @@ -50,6 +50,30 @@ pub enum FieldType { AccountId, } +impl AsRef for FieldType { + fn as_ref(&self) -> &str { + match self { + FieldType::Uint8 => "u8", + FieldType::Uint16 => "u16", + FieldType::Uint32 => "u32", + FieldType::Uint64 => "u64", + FieldType::Int8 => "i8", + FieldType::Int16 => "i16", + FieldType::Int32 => "i32", + FieldType::Int64 => "i64", + FieldType::Uint128 => "u128", + FieldType::U256 => "U256", + FieldType::Int128 => "i128", + FieldType::Float64 => "f64", + FieldType::Bool => "bool", + FieldType::String => "String", + FieldType::Bytes => "Bytes", + FieldType::AccountId => "AccountId", + ty => unimplemented!("Unsupported FieldType {ty:?}"), + } + } +} + /// The main definition of a service. /// /// This contains the metadata of the service, the job definitions, and other hooks, along with the diff --git a/macros/blueprint-proc-macro/src/event_listener/evm.rs b/macros/blueprint-proc-macro/src/event_listener/evm.rs index 327a57d5c..c1eaa110a 100644 --- a/macros/blueprint-proc-macro/src/event_listener/evm.rs +++ b/macros/blueprint-proc-macro/src/event_listener/evm.rs @@ -28,10 +28,27 @@ pub(crate) fn generate_evm_event_handler( ) -> TokenStream { let (instance_base, instance_name, instance_wrapper_name, _instance) = get_evm_instance_data(event_handler); - let event = event_handler.event().unwrap(); - let event_converter = event_handler.event_converter().unwrap(); - let callback = event_handler.callback().unwrap(); - let abi_string = event_handler.abi().unwrap(); + let event = event_handler + .get_event_listener() + .event + .as_ref() + .expect("Event type must be specified"); + let event_converter = event_handler + .get_event_listener() + .pre_processor + .as_ref() + .unwrap(); + let callback = event_handler + .get_event_listener() + .post_processor + .as_ref() + .unwrap(); + let abi_string = event_handler + .get_event_listener() + .evm_args + .as_ref() + .and_then(|r| r.abi.clone()) + .expect("ABI String must exist"); quote! { #[derive(Debug, Clone)] diff --git a/macros/blueprint-proc-macro/src/event_listener/tangle.rs b/macros/blueprint-proc-macro/src/event_listener/tangle.rs index 5c40b58e9..1862ee2ae 100644 --- a/macros/blueprint-proc-macro/src/event_listener/tangle.rs +++ b/macros/blueprint-proc-macro/src/event_listener/tangle.rs @@ -1,47 +1,11 @@ use proc_macro2::TokenStream; use quote::quote; -use syn::{Ident, LitInt}; +use syn::Ident; #[allow(clippy::too_many_arguments)] -/// This will run all event handlers at once once init is called on the special-case event handler for substrate -pub(crate) fn generate_tangle_event_handler( - struct_name: &Ident, - job_id: &LitInt, - params_tokens: &[TokenStream], - result_tokens: &[TokenStream], - fn_call: &TokenStream, -) -> TokenStream { +pub(crate) fn generate_additional_tangle_logic(struct_name: &Ident) -> TokenStream { quote! { #[automatically_derived] - #[async_trait::async_trait] - impl gadget_sdk::events_watcher::substrate::EventHandler for #struct_name { - async fn handle(&self, event: &gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::events::JobCalled) -> Result>, gadget_sdk::events_watcher::Error> { - use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field; - let mut args_iter = event.args.clone().into_iter(); - #(#params_tokens)* - #fn_call - - let mut result = Vec::new(); - #(#result_tokens)* - - Ok(result) - } - - /// Returns the job ID - fn job_id(&self) -> u8 { - #job_id - } - - /// Returns the service ID - fn service_id(&self) -> u64 { - self.service_id - } - - fn signer(&self) -> &gadget_sdk::keystore::TanglePairSigner { - &self.signer - } - } - impl gadget_sdk::event_listener::markers::IsTangle for #struct_name {} } } diff --git a/macros/blueprint-proc-macro/src/job.rs b/macros/blueprint-proc-macro/src/job.rs index 2d8788644..d876f8ce7 100644 --- a/macros/blueprint-proc-macro/src/job.rs +++ b/macros/blueprint-proc-macro/src/job.rs @@ -1,5 +1,5 @@ use crate::event_listener::evm::{generate_evm_event_handler, get_evm_instance_data}; -use crate::event_listener::tangle::generate_tangle_event_handler; +use crate::event_listener::tangle::generate_additional_tangle_logic; use crate::shared::{pascal_case, type_to_field_type}; use gadget_blueprint_proc_macro_core::{FieldType, JobDefinition, JobMetadata}; use indexmap::{IndexMap, IndexSet}; @@ -37,12 +37,81 @@ pub fn get_job_id_field_name(input: &ItemFn) -> (String, Ident, Ident) { (fn_name_string, job_def_name, job_id_name) } +pub fn get_current_call_id_field_name(input: &ItemFn) -> Ident { + let fn_name = &input.sig.ident; + format_ident!( + "{}_ACTIVE_CALL_ID", + fn_name.to_string().to_ascii_uppercase() + ) +} + /// Job Macro implementation pub(crate) fn job_impl(args: &JobArgs, input: &ItemFn) -> syn::Result { // Extract function name and arguments - let (fn_name_string, job_def_name, job_id_name) = get_job_id_field_name(input); + let (fn_name_string, _job_def_name, _job_id_name) = get_job_id_field_name(input); const SUFFIX: &str = "EventHandler"; + let result = get_result_type(input)?; + let param_map = param_types(input)?; + // Extracts Job ID and param/result types + let job_id = &args.id; + let params_type = declared_params_to_field_types(&args.params, ¶m_map)?; + let result_type = declared_result_type_to_field_types(&args.result, result)?; + + let (event_listener_gen, event_listener_calls) = generate_event_workflow_tokenstream( + input, + SUFFIX, + &fn_name_string, + &args.event_listener, + args.skip_codegen, + ¶m_map, + &args.params, + &result_type, + ); + + // Generate Event Workflow, if not being skipped + let additional_specific_logic = if args.skip_codegen { + proc_macro2::TokenStream::default() + } else { + // Specialized code for the event workflow or otherwise + generate_additional_logic(input, args, ¶m_map, ¶ms_type, SUFFIX) + }; + + let autogen_struct = if args.skip_codegen { + proc_macro2::TokenStream::default() + } else { + generate_autogen_struct( + input, + &args.event_listener, + &args.params, + ¶m_map, + SUFFIX, + &event_listener_calls, + ) + }; + + let job_const_block = generate_job_const_block(input, params_type, result_type, job_id)?; + + // Generates final TokenStream that will be returned + let gen = quote! { + #job_const_block + + #autogen_struct + + #(#event_listener_gen)* + + #[allow(unused_variables)] + #input + + #additional_specific_logic + }; + + // println!("{}", gen.to_string()); + + Ok(gen.into()) +} + +pub fn get_result_type(input: &ItemFn) -> syn::Result<&Type> { let syn::ReturnType::Type(_, result) = &input.sig.output else { return Err(syn::Error::new_spanned( &input.sig.output, @@ -69,43 +138,17 @@ pub(crate) fn job_impl(args: &JobArgs, input: &ItemFn) -> syn::Result, + result: Vec, + job_id: &LitInt, +) -> syn::Result { + let (fn_name_string, job_def_name, job_id_name) = get_job_id_field_name(input); // Creates Job Definition using input parameters let job_def = JobDefinition { metadata: JobMetadata { @@ -113,8 +156,8 @@ pub(crate) fn job_impl(args: &JobArgs, input: &ItemFn) -> syn::Result syn::Result syn::Result> { @@ -180,17 +212,19 @@ pub(crate) fn param_types(input: &ItemFn) -> syn::Result> } #[allow(clippy::too_many_arguments)] -pub(crate) fn generate_event_listener_tokenstream( +pub(crate) fn generate_event_workflow_tokenstream( input: &ItemFn, suffix: &str, - fn_name_string: &str, + _fn_name_string: &str, event_listeners: &EventListenerArgs, skip_codegen: bool, param_types: &IndexMap, params: &[Ident], + result_types: &[FieldType], ) -> (Vec, Vec) { let (event_handler_args, event_handler_arg_types) = get_event_handler_args(param_types, params); let (_, _, struct_name) = generate_fn_name_and_struct(input, suffix); + let (fn_name_string, _job_def_name, job_id_name) = get_job_id_field_name(input); // Generate Event Listener, if not being skipped let mut event_listener_calls = vec![]; let event_listener_gen = if skip_codegen { @@ -204,19 +238,17 @@ pub(crate) fn generate_event_listener_tokenstream( idx, suffix.to_lowercase() ); - let is_tangle = listener_meta.evm_args.is_none(); + let is_not_evm = !matches!(listener_meta.listener_type, ListenerType::Evm); // convert the listener var, which is just a struct name, to an ident let listener = listener_meta.listener.to_token_stream(); - // if Listener == TangleEventListener or EvmContractEventListener, we need to use defaults - let listener_str = listener.to_string(); - let type_args = if is_tangle { + let type_args = if is_not_evm { proc_macro2::TokenStream::default() } else { quote! { } }; - let bounded_type_args = if is_tangle { + let bounded_type_args = if is_not_evm { proc_macro2::TokenStream::default() } else { quote! { } @@ -225,28 +257,14 @@ pub(crate) fn generate_event_listener_tokenstream( let autogen_struct_name = quote! { #struct_name #type_args }; // Check for special cases - let next_listener = if listener_str.contains("TangleEventListener") - || listener_str.contains("EvmContractEventListener") - { + let next_listener = if matches!(listener_meta.listener_type, ListenerType::Evm) { // How to inject not just this event handler, but all event handlers here? - let wrapper = if is_tangle { - quote! { - gadget_sdk::event_listener::tangle_events::TangleEventWrapper<_> - } - } else { - quote! { - gadget_sdk::event_listener::evm_contracts::EthereumHandlerWrapper<#autogen_struct_name, _> - } + let wrapper = quote! { + gadget_sdk::event_listener::evm_contracts::EthereumHandlerWrapper<#autogen_struct_name, _> }; - let ctx_create = if is_tangle { - quote! { - (ctx.client.clone(), std::sync::Arc::new(ctx.clone()) as gadget_sdk::events_watcher::substrate::EventHandlerFor) - } - } else { - quote! { - (ctx.contract.clone(), std::sync::Arc::new(ctx.clone()) as std::sync::Arc<#autogen_struct_name>) - } + let ctx_create = quote! { + (ctx.contract.clone(), std::sync::Arc::new(ctx.clone()) as std::sync::Arc<#autogen_struct_name>) }; if event_listener_calls.is_empty() { @@ -256,11 +274,11 @@ pub(crate) fn generate_event_listener_tokenstream( } event_listener_calls.push(quote! { - listeners.push(#listener_function_name(&self).await.expect("Event listener already initialized")); - }); + listeners.push(#listener_function_name(&self).await.expect("Event listener already initialized")); + }); quote! { - async fn #listener_function_name #bounded_type_args(ctx: &#autogen_struct_name) -> Option>>{ + async fn #listener_function_name #bounded_type_args(ctx: &#autogen_struct_name) -> Option>> { static ONCE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); if !ONCE.load(std::sync::atomic::Ordering::Relaxed) { ONCE.store(true, std::sync::atomic::Ordering::Relaxed); @@ -281,14 +299,17 @@ pub(crate) fn generate_event_listener_tokenstream( } else { // Generate the variable that we are passing as the context into EventListener::create(&mut ctx) // We assume the first supplied event handler arg is the context we are injecting into the event listener + // Then, pass that into the EventFlowWrapper let (context, field_in_self) = event_handler_args .first() .map(|ctx| (quote! {self}, (*ctx).clone())) .expect("No context found"); + let autogen_struct_name = quote! { #struct_name #type_args }; + let context_ty = event_handler_arg_types .first() - .map(|_ty| quote! {#struct_name}) + .map(|ty| quote! {#ty}) .unwrap_or_default(); if event_listener_calls.is_empty() { @@ -301,50 +322,113 @@ pub(crate) fn generate_event_listener_tokenstream( listeners.push(#listener_function_name(&#context).await.expect("Event listener already initialized")); }); - let event_type = &listener_meta.event; - // The event type is what gets sent through the pre_processor_function. - let pre_processor_function = if let Some(preprocessor) = &listener_meta.pre_processor { quote! { #preprocessor } } else { // identity transformation - quote! { |evt| async move { Ok(evt) } } + get_preprocessor_default_identity_function(&listener_meta.listener_type) }; // The job_processor is just the job function. Since it may contain multiple params, we need a new function to call it. let fn_name_ident = &input.sig.ident; + let static_ctx_get_override = quote! { CTX.get().unwrap() }; let ordered_inputs = - get_fn_call_ordered(param_types, params, Some(quote! { CTX.get().unwrap() })); + get_fn_call_ordered(param_types, params, Some(static_ctx_get_override)); + let asyncness = get_asyncness(input); - // The below assumes param0 IS the event streamed from the event listener - let job_processor_wrapper = quote! { - move |param0| async move { - #fn_name_ident (#(#ordered_inputs)*) #asyncness .map_err(|err| gadget_sdk::Error::Other(err.to_string())) + let call_id_static_name = get_current_call_id_field_name(input); + let job_processor_wrapper = if matches!( + listener_meta.listener_type, + ListenerType::Tangle + ) { + let params = declared_params_to_field_types(params, param_types) + .expect("Failed to generate params"); + let params_tokens = event_listeners.get_param_name_tokenstream(¶ms, true); + quote! { + move |event: gadget_sdk::event_listener::tangle::jobs::TangleJobEvent| async move { + if let Some(call_id) = event.call_id { + #call_id_static_name.store(call_id, std::sync::atomic::Ordering::Relaxed); + } + + let mut args_iter = event.args.clone().into_iter(); + #(#params_tokens)* + #fn_name_ident (#(#ordered_inputs)*) #asyncness .map_err(|err| gadget_sdk::Error::Other(err.to_string())) + } + } + } else { + quote! { + move |param0| async move { + #fn_name_ident (#(#ordered_inputs)*) #asyncness .map_err(|err| gadget_sdk::Error::Other(err.to_string())) + } } }; - let post_processor_function = - if let Some(postprocessor) = &listener_meta.post_processor { - quote! { #postprocessor } + + let post_processor_function = if let Some(postprocessor) = + &listener_meta.post_processor + { + if matches!(listener_meta.listener_type, ListenerType::Tangle) { + let result_tokens = + event_listeners.get_param_result_tokenstream(result_types); + quote! { + |job_result| async move { + let ctx = CTX.get().unwrap(); + let mut result = Vec::new(); + // TODO: Will need to decouple this from jobs + #(#result_tokens)* + let tangle_job_result = gadget_sdk::event_listener::tangle::jobs::TangleJobResult { + results: result, + service_id: ctx.service_id, + call_id: #call_id_static_name.load(std::sync::atomic::Ordering::Relaxed), + client: ctx.client.clone(), + signer: ctx.signer.clone(), + }; + + #postprocessor(tangle_job_result).await.map_err(|err| gadget_sdk::Error::Other(err.to_string())) + } + } } else { - // no-op default - quote! { |_evt| async move { Ok(()) } } - }; + quote! { #postprocessor } + } + } else { + // no-op default + quote! { |_evt| async move { Ok(()) } } + }; + + let context_declaration = if matches!( + listener_meta.listener_type, + ListenerType::Tangle + ) { + quote! { + let context = gadget_sdk::event_listener::tangle::TangleListenerInput::<#context_ty> { + client: ctx.client.clone(), + signer: ctx.signer.clone(), + job_id: #job_id_name, + service_id: ctx.service_id, + context: ctx. #field_in_self .clone(), + }; + } + } else { + quote! { let context = ctx. #field_in_self .clone(); } + }; quote! { - async fn #listener_function_name(ctx: &#context_ty) -> Option>> { + async fn #listener_function_name #bounded_type_args(ctx: &#autogen_struct_name) -> Option>> { static ONCE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); if !ONCE.load(std::sync::atomic::Ordering::Relaxed) { ONCE.store(true, std::sync::atomic::Ordering::Relaxed); let (tx, rx) = gadget_sdk::tokio::sync::oneshot::channel(); - static CTX: gadget_sdk::tokio::sync::OnceCell<#context_ty> = gadget_sdk::tokio::sync::OnceCell::const_new(); + + static CTX: gadget_sdk::tokio::sync::OnceCell<#autogen_struct_name> = gadget_sdk::tokio::sync::OnceCell::const_new(); + #context_declaration + if let Err(_err) = CTX.set(ctx.clone()) { gadget_sdk::error!("Failed to set the context"); return None; } let job_processor = #job_processor_wrapper; - let listener = <#listener as gadget_sdk::event_listener::EventListener<#event_type, _>>::new(&ctx. #field_in_self).await.expect("Failed to create event listener"); + let listener = <#listener as gadget_sdk::event_listener::EventListener<_, _>>::new(&context).await.expect("Failed to create event listener"); let mut event_workflow = gadget_sdk::event_listener::executor::EventFlowWrapper::new( listener, #pre_processor_function, @@ -378,6 +462,31 @@ pub(crate) fn generate_event_listener_tokenstream( (event_listener_gen, event_listener_calls) } +fn get_preprocessor_default_identity_function( + listener_type: &ListenerType, +) -> proc_macro2::TokenStream { + match listener_type { + ListenerType::Evm => { + unimplemented!("EVM not implemented yet") + } + ListenerType::Tangle => { + quote! { + |evt| async move { + Ok(evt) + } + } + } + ListenerType::Custom => { + // Identity transform + quote! { + |evt| async move { + Ok(evt) + } + } + } + } +} + /// Get all the params names inside the param_types map /// and not in the params list to be added to the event handler. pub(crate) fn get_event_handler_args<'a>( @@ -404,14 +513,15 @@ fn generate_fn_name_and_struct<'a>(f: &'a ItemFn, suffix: &'a str) -> (&'a Ident #[allow(clippy::too_many_lines)] pub fn generate_autogen_struct( input: &ItemFn, - job_args: &JobArgs, + event_listener_args: &EventListenerArgs, + params: &[Ident], param_types: &IndexMap, suffix: &str, event_listener_calls: &[proc_macro2::TokenStream], ) -> proc_macro2::TokenStream { let (_fn_name, fn_name_string, struct_name) = generate_fn_name_and_struct(input, suffix); - let (event_handler_args, _) = get_event_handler_args(param_types, &job_args.params); + let (event_handler_args, _) = get_event_handler_args(param_types, params); let mut additional_var_indexes = vec![]; let additional_params = event_handler_args @@ -435,7 +545,7 @@ pub fn generate_autogen_struct( let mut type_params = proc_macro2::TokenStream::default(); // Even if multiple tangle listeners, we only need this once - if job_args.event_listener.has_tangle() { + if event_listener_args.has_tangle() { required_fields.push(quote! { pub service_id: u64, pub signer: gadget_sdk::keystore::TanglePairSigner, @@ -444,8 +554,8 @@ pub fn generate_autogen_struct( } // Even if multiple evm listeners, we only need this once - if job_args.event_listener.has_evm() { - let (_, _, instance_wrapper_name, _) = get_evm_instance_data(&job_args.event_listener); + if event_listener_args.has_evm() { + let (_, _, instance_wrapper_name, _) = get_evm_instance_data(event_listener_args); required_fields.push(quote! { pub contract: #instance_wrapper_name, @@ -541,13 +651,13 @@ pub fn generate_additional_logic( job_args: &JobArgs, param_types: &IndexMap, params: &[FieldType], - results: &[FieldType], suffix: &str, ) -> proc_macro2::TokenStream { let (fn_name, _fn_name_string, struct_name) = generate_fn_name_and_struct(input, suffix); - let job_id = &job_args.id; let event_listener_args = &job_args.event_listener; - let params_tokens = job_args.event_listener.get_param_name_tokenstream(params); + let params_tokens = job_args + .event_listener + .get_param_name_tokenstream(params, false); let fn_call_ordered = get_fn_call_ordered(param_types, &job_args.params, None); let asyncness = get_asyncness(input); @@ -565,22 +675,12 @@ pub fn generate_additional_logic( }; }; - let result_tokens = job_args - .event_listener - .get_param_result_tokenstream(results); - match job_args.event_listener.get_event_listener().listener_type { ListenerType::Evm => { generate_evm_event_handler(&struct_name, event_listener_args, ¶ms_tokens, &fn_call) } - ListenerType::Tangle => generate_tangle_event_handler( - &struct_name, - job_id, - ¶ms_tokens, - &result_tokens, - &fn_call, - ), + ListenerType::Tangle => generate_additional_tangle_logic(&struct_name), ListenerType::Custom => proc_macro2::TokenStream::default(), } @@ -692,37 +792,38 @@ impl Parse for Params { } } -impl JobArgs { - fn params_to_field_types( - &self, - param_types: &IndexMap, - ) -> syn::Result> { - let params = self - .params - .iter() - .map(|ident| { - param_types.get(ident).ok_or_else(|| { - syn::Error::new_spanned(ident, "parameter not declared in the function") - }) +pub(crate) fn declared_params_to_field_types( + params: &[Ident], + param_types: &IndexMap, +) -> syn::Result> { + let params = params + .iter() + .map(|ident| { + param_types.get(ident).ok_or_else(|| { + syn::Error::new_spanned(ident, "parameter not declared in the function") }) - .map(|ty| type_to_field_type(ty?)) - .collect::>>()?; - Ok(params) - } + }) + .map(|ty| type_to_field_type(ty?)) + .collect::>>()?; + Ok(params) +} - fn result_to_field_types(&self, result: &Type) -> syn::Result> { - match &self.result { - ResultsKind::Infered => type_to_field_type(result).map(|x| vec![x]), - ResultsKind::Types(types) => { - let xs = types - .iter() - .map(type_to_field_type) - .collect::>>()?; - Ok(xs) - } +pub(crate) fn declared_result_type_to_field_types( + kind: &ResultsKind, + result: &Type, +) -> syn::Result> { + match kind { + ResultsKind::Infered => type_to_field_type(result).map(|x| vec![x]), + ResultsKind::Types(types) => { + let xs = types + .iter() + .map(type_to_field_type) + .collect::>>()?; + Ok(xs) } } } + pub enum ResultsKind { Infered, Types(Vec), @@ -781,9 +882,9 @@ pub(crate) struct SingleListener { pub listener: Type, pub evm_args: Option, pub listener_type: ListenerType, - pub event: Type, - pub post_processor: Option, - pub pre_processor: Option, + pub event: Option, + pub post_processor: Option, + pub pre_processor: Option, } /// Extracts a value from form: "tag = value" @@ -814,6 +915,9 @@ fn extract_x_equals_y( Ok(Some(listener)) } +const EVM_EVENT_LISTENER_TAG: &str = "EvmContractEventListener"; +const TANGLE_EVENT_LISTENER_TAG: &str = "TangleEventListener"; + impl Parse for EventListenerArgs { fn parse(input: ParseStream) -> syn::Result { let _ = input.parse::()?; @@ -823,37 +927,63 @@ impl Parse for EventListenerArgs { let mut listeners = Vec::new(); // Parse a TypePath instead of a LitStr while !content.is_empty() { - let listener = extract_x_equals_y::(&content, true, "listener")? - .expect("No listener defined in listener block"); - - let ty_str = quote! { #listener }.to_string(); + let mut listener = None; + let mut event = None; + let mut pre_processor = None; + let mut post_processor = None; let mut evm_args = None; - if ty_str.contains("EvmContractEventListener") { - evm_args = Some(content.parse::()?); - } + // TODO: Get rid of the needless nesting, this is a mess + while !content.is_empty() { + if content.peek(kw::listener) { + let listener_found = + extract_x_equals_y::(&content, true, "listener")? + .expect("No listener defined in listener block"); - let event = extract_x_equals_y::(&content, true, "event")? - .expect("No event defined in listener block"); - let pre_processor = - extract_x_equals_y::(&content, false, "pre_processor")?; - let post_processor = - extract_x_equals_y::(&content, false, "post_processor")?; + let ty_str = quote! { #listener_found }.to_string(); + if ty_str.contains(EVM_EVENT_LISTENER_TAG) { + evm_args = Some(content.parse::()?); + } + + listener = Some(listener_found) + } else if content.peek(kw::event) { + event = extract_x_equals_y::(&content, false, "event")? + } else if content.peek(kw::pre_processor) { + pre_processor = extract_x_equals_y::( + &content, + false, + "pre_processor", + )?; + } else if content.peek(kw::post_processor) { + post_processor = extract_x_equals_y::( + &content, + false, + "post_processor", + )?; + } else if content.peek(Token![,]) { + let _ = content.parse::()?; + } else { + return Err(content.error( + "Expected one of `listener`, `event`, `pre_processor`, `post_processor`", + )); + } + } + + let listener = listener.expect("No `listener` defined in listener block"); // Create a listener. If this is an EvmContractEventListener, we need to specially parse the arguments // In the case of tangle and everything other listener type, we don't pass evm_args let ty_str = quote! { #listener }.to_string(); - let this_listener = if ty_str.contains("EvmContractEventListener") { - assert!(evm_args.is_some(), "EvmArgs must be passed"); + let this_listener = if let Some(evm_args) = evm_args { SingleListener { listener, - evm_args, + evm_args: Some(evm_args), listener_type: ListenerType::Evm, event, post_processor, pre_processor, } } else { - let listener_type = if ty_str.contains("TangleEventListener") { + let listener_type = if ty_str.contains(TANGLE_EVENT_LISTENER_TAG) { ListenerType::Tangle } else { ListenerType::Custom @@ -889,15 +1019,12 @@ impl Parse for EventListenerArgs { } pub(crate) struct EvmArgs { - instance: Option, - event: Option, - event_converter: Option, - callback: Option, - abi: Option, + pub instance: Option, + pub abi: Option, } impl EventListenerArgs { - fn get_event_listener(&self) -> &SingleListener { + pub fn get_event_listener(&self) -> &SingleListener { &self.listeners[0] } @@ -958,6 +1085,7 @@ impl EventListenerArgs { pub fn get_param_name_tokenstream( &self, params: &[FieldType], + panic_on_decode_fail: bool, ) -> Vec { params .iter() @@ -966,7 +1094,9 @@ impl EventListenerArgs { let ident = format_ident!("param{i}"); let index = Index::from(i); match self.get_event_listener().listener_type { - ListenerType::Tangle => crate::tangle::field_type_to_param_token(&ident, t), + ListenerType::Tangle => { + crate::tangle::field_type_to_param_token(&ident, t, panic_on_decode_fail) + } ListenerType::Evm => { quote! { let #ident = inputs.#index; @@ -983,11 +1113,6 @@ impl EventListenerArgs { .collect::>() } - /// Returns true if on EVM - pub fn get_evm(&self) -> Option<&EvmArgs> { - self.get_event_listener().evm_args.as_ref() - } - pub fn has_tangle(&self) -> bool { self.listeners .iter() @@ -1002,45 +1127,11 @@ impl EventListenerArgs { /// Returns the Event Handler's Contract Instance on the EVM. pub fn instance(&self) -> Option { - match self.get_evm() { + match self.get_event_listener().evm_args.as_ref() { Some(EvmArgs { instance, .. }) => instance.clone(), None => None, } } - - /// Returns the contract instance's event to watch for on the EVM. - pub fn event(&self) -> Option { - match self.get_evm() { - Some(EvmArgs { event, .. }) => event.clone(), - None => None, - } - } - - /// Returns the Event Handler's event converter to convert the event into function arguments - pub fn event_converter(&self) -> Option { - match self.get_evm() { - Some(EvmArgs { - event_converter, .. - }) => event_converter.clone(), - None => None, - } - } - - /// Returns the callback to submit the job function output to. - pub fn callback(&self) -> Option { - match self.get_evm() { - Some(EvmArgs { callback, .. }) => callback.clone(), - None => None, - } - } - - /// Returns the ABI for the contract instance. - pub fn abi(&self) -> Option { - match self.get_evm() { - Some(EvmArgs { abi, .. }) => abi.clone(), - None => None, - } - } } impl Parse for EvmArgs { @@ -1049,9 +1140,6 @@ impl Parse for EvmArgs { syn::parenthesized!(content in input); let mut instance = None; - let mut event = None; - let mut event_converter = None; - let mut callback = None; let mut abi = None; while !content.is_empty() { @@ -1059,36 +1147,18 @@ impl Parse for EvmArgs { let _ = content.parse::()?; let _ = content.parse::()?; instance = Some(content.parse::()?); - } else if content.peek(kw::event) { - let _ = content.parse::()?; - let _ = content.parse::()?; - event = Some(content.parse::()?); - } else if content.peek(kw::event_converter) { - let _ = content.parse::()?; - let _ = content.parse::()?; - event_converter = Some(content.parse::()?); - } else if content.peek(kw::callback) { - let _ = content.parse::()?; - let _ = content.parse::()?; - callback = Some(content.parse::()?); + } else if content.peek(Token![,]) { + let _ = content.parse::()?; } else if content.peek(kw::abi) { let _ = content.parse::()?; let _ = content.parse::()?; abi = Some(content.parse::()?); - } else if content.peek(Token![,]) { - let _ = content.parse::()?; } else { return Err(content.error("Unexpected token")); } } - Ok(EvmArgs { - instance, - event, - event_converter, - callback, - abi, - }) + Ok(EvmArgs { instance, abi }) } } diff --git a/macros/blueprint-proc-macro/src/report.rs b/macros/blueprint-proc-macro/src/report.rs index ff702a524..b587ab1a9 100644 --- a/macros/blueprint-proc-macro/src/report.rs +++ b/macros/blueprint-proc-macro/src/report.rs @@ -1,11 +1,14 @@ -use crate::job::EventListenerArgs; +use crate::job::{ + declared_params_to_field_types, generate_autogen_struct, get_current_call_id_field_name, + get_job_id_field_name, get_result_type, EventListenerArgs, ResultsKind, +}; use crate::shared::{pascal_case, type_to_field_type}; use gadget_blueprint_proc_macro_core::{ FieldType, ReportDefinition, ReportMetadata, ReportResultVerifier, ReportType, }; +use indexmap::IndexMap; use proc_macro::TokenStream; use quote::{format_ident, quote}; -use std::collections::BTreeMap; use syn::{ parenthesized, parse::{Parse, ParseStream}, @@ -39,11 +42,10 @@ mod kw { /// /// Returns a `Result` containing the generated `TokenStream` or a `syn::Error`. pub(crate) fn report_impl(args: &ReportArgs, input: &ItemFn) -> syn::Result { - let fn_name = &input.sig.ident; - let fn_name_string = fn_name.to_string(); + let (fn_name_string, _job_def_name, job_id_name) = get_job_id_field_name(input); let report_def_name = format_ident!("{}_REPORT_DEF", fn_name_string.to_ascii_uppercase()); - - let mut param_types = BTreeMap::new(); + let _ = get_result_type(input); + let mut param_types = IndexMap::new(); for input in &input.sig.inputs { if let syn::FnArg::Typed(arg) = input { if let syn::Pat::Ident(pat_ident) = &*arg.pat { @@ -57,7 +59,7 @@ pub(crate) fn report_impl(args: &ReportArgs, input: &ItemFn) -> syn::Result syn::Result syn::Result syn::Result "JobReportEventHandler", + ReportType::QoS => "QoSReportEventHandler", + }; + + let (event_listener_gen, event_listener_calls) = + crate::job::generate_event_workflow_tokenstream( + input, + suffix, + &fn_name_string, + &args.event_listeners, + args.skip_codegen, + ¶m_types, + &args.params, + &result_type, + ); + + let autogen_struct = generate_autogen_struct( + input, + &args.event_listeners, + &args.params, + ¶m_types, + suffix, + &event_listener_calls, + ); + /*let event_handler_gen = if args.skip_codegen { proc_macro2::TokenStream::new() } else { - match args.report_type { - ReportType::Job => { - generate_job_report_event_handler(args, input, ¶ms_type, &result_type) - } - ReportType::QoS => { - generate_qos_report_event_handler(args, input, ¶ms_type, &result_type) - } + if let ReportType::QoS = args.report_type { + generate_qos_report_event_handler(args, input, ¶ms_type, &result_type) + } else { + proc_macro2::TokenStream::new() } + };*/ + + let call_id_static_name = get_current_call_id_field_name(input); + let job_id = if let Some(job_id) = job_id { + quote! { #job_id } + } else { + quote! { 0 } }; - let gen = quote! { + let job_const_block = quote! { #[doc = "Report definition for the function "] #[doc = #fn_name_string] pub const #report_def_name: &str = #report_def_str; + #[doc = "Job ID for the function "] + #[doc = "[`"] + #[doc = #fn_name_string] + #[doc = "`]"] + #[automatically_derived] + pub const #job_id_name: u8 = #job_id; + + static #call_id_static_name: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); + }; + + let gen = quote! { + #job_const_block + + #autogen_struct + + #[allow(unused_variables)] #input - #event_handler_gen + #(#event_listener_gen)* }; Ok(gen.into()) @@ -286,23 +333,6 @@ impl Parse for ReportArgs { } impl ReportArgs { - fn params_to_field_types( - &self, - param_types: &BTreeMap, - ) -> syn::Result> { - let params = self - .params - .iter() - .map(|ident| { - param_types.get(ident).ok_or_else(|| { - syn::Error::new_spanned(ident, "parameter not declared in the function") - }) - }) - .map(|ty| type_to_field_type(ty?)) - .collect::>>()?; - Ok(params) - } - fn result_to_field_types(&self, result: &Type) -> syn::Result> { match &self.result { ResultsKind::Infered => type_to_field_type(result).map(|x| vec![x]), @@ -317,101 +347,6 @@ impl ReportArgs { } } -/// Generates an event handler for job reports. -/// -/// This function creates a struct that listens for job result submissions -/// and triggers the report function when necessary. -/// -/// # Arguments -/// -/// * `args` - The parsed arguments from the `report` attribute macro. -/// * `input` - The function item that the `report` attribute is attached to. -/// * `param_types` - A map of parameter names to their types. -/// * `params` - The list of parameter field types. -/// * `result` - The list of result field types. -/// -/// # Returns -/// -/// Returns a `TokenStream` containing the generated event handler code. -fn generate_job_report_event_handler( - args: &ReportArgs, - input: &ItemFn, - _params: &[FieldType], - _result: &[FieldType], -) -> proc_macro2::TokenStream { - let fn_name = &input.sig.ident; - let fn_name_string = fn_name.to_string(); - const SUFFIX: &str = "JobReportEventHandler"; - let struct_name = format_ident!("{}{SUFFIX}", pascal_case(&fn_name_string)); - let job_id = args - .job_id - .as_ref() - .expect("Job ID must be present for job reports"); - let param_types = - crate::job::param_types(input).expect("Failed to generate param types for job report"); - let event_type = quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::events::JobResultSubmitted }; - let (event_listener_gen, event_listener_calls) = - crate::job::generate_event_listener_tokenstream( - input, - SUFFIX, - &fn_name_string, - &args.event_listeners, - args.skip_codegen, - ¶m_types, - &args.params, - ); - - let combined_event_listener = - crate::job::generate_combined_event_listener_selector(&struct_name); - quote! { - #[derive(Clone)] - pub struct #struct_name { - pub service_id: u64, - pub signer: gadget_sdk::keystore::TanglePairSigner, - pub client: gadget_sdk::clients::tangle::runtime::TangleClient, - } - - #(#event_listener_gen)* - - #[automatically_derived] - #[async_trait::async_trait] - impl gadget_sdk::events_watcher::substrate::EventHandler for #struct_name { - async fn handle(&self, event: &#event_type) -> Result>, gadget_sdk::events_watcher::Error> { - use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field; - // TODO: Implement parameter extraction and report function call - // This part will depend on the specific structure of your JobResultSubmitted event - // and how you want to handle the report function call - - Ok(vec![]) - } - - /// Returns the job ID - fn job_id(&self) -> u8 { - #job_id - } - - /// Returns the service ID - fn service_id(&self) -> u64 { - self.service_id - } - - fn signer(&self) -> &gadget_sdk::keystore::TanglePairSigner { - &self.signer - } - } - - #[async_trait::async_trait] - impl gadget_sdk::events_watcher::InitializableEventHandler for #struct_name { - async fn init_event_handler(&self) -> Option>> { - #(#event_listener_calls)* - #combined_event_listener - } - } - - impl gadget_sdk::event_listener::markers::IsTangle for #struct_name {} - } -} - /// Generates an event handler for `QoS` reports. /// /// This function creates a struct that periodically collects `QoS` metrics @@ -428,6 +363,7 @@ fn generate_job_report_event_handler( /// # Returns /// /// Returns a `TokenStream` containing the generated event handler code. +#[allow(dead_code)] fn generate_qos_report_event_handler( args: &ReportArgs, input: &ItemFn, @@ -437,15 +373,23 @@ fn generate_qos_report_event_handler( let fn_name = &input.sig.ident; let fn_name_string = fn_name.to_string(); const SUFFIX: &str = "QoSReportEventHandler"; + + let syn::ReturnType::Type(_, result) = &input.sig.output else { + panic!("Report function must have a return type of Result where T is a tuple of the result fields"); + }; + let struct_name = format_ident!("{}{SUFFIX}", pascal_case(&fn_name_string)); let job_id = quote! { 0 }; // We don't care about job ID's for QOS let param_types = crate::job::param_types(input).expect("Failed to generate param types for job report"); // TODO: Allow passing all events, use a dummy value here that satisfies the trait bounds. For now QOS will // trigger only once a singular JobCalled event is received. - let event_type = quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::events::JobCalled }; + let event_type = quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::events::JobResultSubmitted }; + let result_type = crate::job::declared_result_type_to_field_types(&args.result, result) + .expect("Failed to generate result types for job report"); + let (event_listener_gen, event_listener_calls) = - crate::job::generate_event_listener_tokenstream( + crate::job::generate_event_workflow_tokenstream( input, SUFFIX, &fn_name_string, @@ -453,6 +397,7 @@ fn generate_qos_report_event_handler( args.skip_codegen, ¶m_types, &args.params, + &result_type, ); let interval = args @@ -464,13 +409,6 @@ fn generate_qos_report_event_handler( crate::job::generate_combined_event_listener_selector(&struct_name); quote! { - #[derive(Clone)] - pub struct #struct_name { - pub service_id: u64, - pub signer: gadget_sdk::keystore::TanglePairSigner, - pub client: gadget_sdk::clients::tangle::runtime::TangleClient, - } - #(#event_listener_gen)* #[automatically_derived] @@ -526,20 +464,6 @@ fn generate_qos_report_event_handler( } } -pub enum ResultsKind { - Infered, - Types(Vec), -} - -impl std::fmt::Debug for ResultsKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Infered => write!(f, "Infered"), - Self::Types(_) => write!(f, "Types"), - } - } -} - #[derive(Debug)] struct Results(ResultsKind); diff --git a/macros/blueprint-proc-macro/src/shared.rs b/macros/blueprint-proc-macro/src/shared.rs index da1c28461..01955928d 100644 --- a/macros/blueprint-proc-macro/src/shared.rs +++ b/macros/blueprint-proc-macro/src/shared.rs @@ -1,4 +1,5 @@ use gadget_blueprint_proc_macro_core::FieldType; +use quote::ToTokens; use syn::{Ident, Type}; /// Convert a `snake_case` string to `PascalCase` @@ -111,6 +112,20 @@ pub fn path_to_field_type(path: &syn::Path) -> syn::Result { args, "unsupported parenthesized arguments", )), + // Support for SomeConcreteType where T, V, K is a simple type + syn::PathArguments::AngleBracketed(inner) if !inner.args.is_empty() => { + let mut ret = vec![]; + for inner_arg in &inner.args { + if let syn::GenericArgument::Type(inner_ty) = inner_arg { + let inner_type = type_to_field_type(inner_ty)?; + ret.push((inner_ty.to_token_stream().to_string(), Box::new(inner_type))) + } else { + return Err(syn::Error::new_spanned(inner_arg, "unsupported type param")); + } + } + Ok(FieldType::Struct(ident.to_string(), ret)) + } + syn::PathArguments::AngleBracketed(_) => { Err(syn::Error::new_spanned(args, "unsupported complex type")) } diff --git a/macros/blueprint-proc-macro/src/tangle/mod.rs b/macros/blueprint-proc-macro/src/tangle/mod.rs index 8308480dd..73ba526b8 100644 --- a/macros/blueprint-proc-macro/src/tangle/mod.rs +++ b/macros/blueprint-proc-macro/src/tangle/mod.rs @@ -3,72 +3,84 @@ use quote::{format_ident, quote}; use syn::Ident; #[allow(clippy::too_many_lines)] -pub fn field_type_to_param_token(ident: &Ident, t: &FieldType) -> proc_macro2::TokenStream { +pub fn field_type_to_param_token( + ident: &Ident, + t: &FieldType, + panic_on_decode_fail: bool, +) -> proc_macro2::TokenStream { + let else_block = if panic_on_decode_fail { + quote! { + panic!("Failed to decode the field"); + } + } else { + quote! { + return Ok(vec![]); + } + }; match t { FieldType::Void => unreachable!("void type should not be in params"), FieldType::Bool => { - quote! { let Some(Field::Bool(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Bool(#ident)) = args_iter.next() else { #else_block }; } } FieldType::Uint8 => { - quote! { let Some(Field::Uint8(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint8(#ident)) = args_iter.next() else { #else_block }; } } FieldType::Int8 => { - quote! { let Some(Field::Int8(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int8(#ident)) = args_iter.next() else { #else_block }; } } FieldType::Uint16 => { - quote! { let Some(Field::Uint16(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint16(#ident)) = args_iter.next() else { #else_block }; } } FieldType::Int16 => { - quote! { let Some(Field::Int16(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int16(#ident)) = args_iter.next() else { #else_block }; } } FieldType::Uint32 => { - quote! { let Some(Field::Uint32(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint32(#ident)) = args_iter.next() else { #else_block }; } } FieldType::Int32 => { - quote! { let Some(Field::Int32(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int32(#ident)) = args_iter.next() else { #else_block }; } } FieldType::Uint64 => { - quote! { let Some(Field::Uint64(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint64(#ident)) = args_iter.next() else { #else_block }; } } FieldType::Int64 => { - quote! { let Some(Field::Int64(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int64(#ident)) = args_iter.next() else { #else_block }; } } FieldType::Uint128 => { - quote! { let Some(Field::Uint128(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint128(#ident)) = args_iter.next() else { #else_block }; } } FieldType::U256 => { - quote! { let Some(Field::U256(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::U256(#ident)) = args_iter.next() else { #else_block }; } } FieldType::Int128 => { - quote! { let Some(Field::Int128(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int128(#ident)) = args_iter.next() else { #else_block }; } } FieldType::Float64 => { - quote! { let Some(Field::Float64(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Float64(#ident)) = args_iter.next() else { #else_block }; } } FieldType::String => { let inner_ident = format_ident!("{}_inner", ident); quote! { - let Some(Field::String(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::BoundedString(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#inner_ident)))) = args_iter.next() else { return Ok(vec![]); }; + let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::String(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::BoundedString(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#inner_ident)))) = args_iter.next() else { #else_block }; // Convert the BoundedVec to a String let #ident = match String::from_utf8(#inner_ident) { Ok(s) => s, Err(e) => { ::gadget_sdk::warn!("failed to convert bytes to a valid utf8 string: {e}"); - use gadget_sdk::events_watcher::Error; - return Err(Error::Handler(Box::new(e))); + return Err(gadget_sdk::Error::Other(e.to_string())); } }; } } FieldType::Bytes => { - quote! { let Some(Field::Bytes(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#ident))) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Bytes(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#ident))) = args_iter.next() else { #else_block }; } } FieldType::Optional(t_x) => { let inner_ident = format_ident!("{}_inner", ident); let x_ident = format_ident!("{}_option", ident); - let x_inner = field_type_to_param_token(&x_ident, t_x); + let x_inner = field_type_to_param_token(&x_ident, t_x, panic_on_decode_fail); let inner = quote! { - let Some(#inner_ident) = args_iter.next() else { return Ok(vec![]); }; + let Some(#inner_ident) = args_iter.next() else { #else_block; }; }; quote! { #inner @@ -77,22 +89,28 @@ pub fn field_type_to_param_token(ident: &Ident, t: &FieldType) -> proc_macro2::T #x_inner Some(#x_ident) }, - Field::None => None, + gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::None => None, }; } } FieldType::Array(_, _) => todo!("Handle array"), - FieldType::List(_) => { + FieldType::List(ty) => { let inner_ident = format_ident!("{}_inner", ident); let inner = quote! { - let Some(Field::List(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#inner_ident))) = args_iter.next() else { return Ok(vec![]); }; + let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::List(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#inner_ident))) = args_iter.next() else { #else_block; }; }; + let ty_variant_ident = format_ident!("{ty:?}"); + quote! { #inner let #ident = #inner_ident .into_iter() - .map(|item| item.0) + .map(|item| if let gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::<>:: #ty_variant_ident(val) = item { + val.0 + } else { + panic!("Failed to decode the list"); + }) .collect::>(); } } @@ -103,7 +121,8 @@ pub fn field_type_to_param_token(ident: &Ident, t: &FieldType) -> proc_macro2::T .map(|(field_name, field_type)| { let field_ident = format_ident!("{}", field_name); let inner_ident = format_ident!("{}_{}", ident, field_name); - let inner_token = field_type_to_param_token(&inner_ident, field_type); + let inner_token = + field_type_to_param_token(&inner_ident, field_type, panic_on_decode_fail); quote! { #inner_token #field_ident: #inner_ident, @@ -112,7 +131,7 @@ pub fn field_type_to_param_token(ident: &Ident, t: &FieldType) -> proc_macro2::T .collect(); quote! { - let Some(Field::Struct(#ident)) = args_iter.next() else { return Ok(vec![]); }; + let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Struct(#ident)) = args_iter.next() else { #else_block }; let mut #ident = #ident.into_iter(); #(#field_tokens)* let #ident = #struct_ident { @@ -122,7 +141,7 @@ pub fn field_type_to_param_token(ident: &Ident, t: &FieldType) -> proc_macro2::T } FieldType::AccountId => { - quote! { let Some(Field::AccountId(#ident)) = args_iter.next() else { return Ok(vec![]); }; } + quote! { let Some(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::AccountId(#ident)) = args_iter.next() else { #else_block }; } } } } @@ -130,24 +149,50 @@ pub fn field_type_to_param_token(ident: &Ident, t: &FieldType) -> proc_macro2::T pub fn field_type_to_result_token(ident: &Ident, t: &FieldType) -> proc_macro2::TokenStream { match t { FieldType::Void => quote! {}, - FieldType::Bool => quote! { result.push(Field::Bool(#ident)); }, - FieldType::Uint8 => quote! { result.push(Field::Uint8(#ident)); }, - FieldType::Int8 => quote! { result.push(Field::Int8(#ident)); }, - FieldType::Uint16 => quote! { result.push(Field::Uint16(#ident)); }, - FieldType::Int16 => quote! { result.push(Field::Int16(#ident)); }, - FieldType::Uint32 => quote! { result.push(Field::Uint32(#ident)); }, - FieldType::Int32 => quote! { result.push(Field::Int32(#ident)); }, - FieldType::Uint64 => quote! { result.push(Field::Uint64(#ident)); }, - FieldType::Int64 => quote! { result.push(Field::Int64(#ident)); }, - FieldType::Uint128 => quote! { result.push(Field::Uint128(#ident)); }, - FieldType::U256 => quote! { result.push(Field::U256(#ident)); }, - FieldType::Int128 => quote! { result.push(Field::Int128(#ident)); }, - FieldType::Float64 => quote! { result.push(Field::Float64(#ident)); }, + FieldType::Bool => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Bool(#ident)); } + } + FieldType::Uint8 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint8(#ident)); } + } + FieldType::Int8 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int8(#ident)); } + } + FieldType::Uint16 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint16(#ident)); } + } + FieldType::Int16 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int16(#ident)); } + } + FieldType::Uint32 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint32(#ident)); } + } + FieldType::Int32 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int32(#ident)); } + } + FieldType::Uint64 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint64(#ident)); } + } + FieldType::Int64 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int64(#ident)); } + } + FieldType::Uint128 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint128(#ident)); } + } + FieldType::U256 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::U256(#ident)); } + } + FieldType::Int128 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int128(#ident)); } + } + FieldType::Float64 => { + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Float64(#ident)); } + } FieldType::String => { - quote! { result.push(Field::String(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::BoundedString(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#ident.into_bytes())))); } + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::String(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::BoundedString(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#ident.into_bytes())))); } } FieldType::Bytes => { - quote! { result.push(Field::Bytes(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#ident))); } + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Bytes(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#ident))); } } FieldType::Optional(t_x) => { let v_ident = format_ident!("v"); @@ -155,7 +200,7 @@ pub fn field_type_to_result_token(ident: &Ident, t: &FieldType) -> proc_macro2:: quote! { match #ident { Some(v) => #tokens, - None => result.push(Field::None), + None => result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::None), } } } @@ -164,30 +209,58 @@ pub fn field_type_to_result_token(ident: &Ident, t: &FieldType) -> proc_macro2:: let inner_ident = format_ident!("{}_inner", ident); let field = match **t_x { FieldType::Void => unreachable!(), - FieldType::Bool => quote! { Field::Bool(item) }, - FieldType::Uint8 => quote! { Field::Uint8(item) }, - FieldType::Int8 => quote! { Field::Int8(item) }, - FieldType::Uint16 => quote! { Field::Uint16(item) }, - FieldType::Int16 => quote! { Field::Int16(item) }, - FieldType::Uint32 => quote! { Field::Uint32(item) }, - FieldType::Int32 => quote! { Field::Int32(item) }, - FieldType::Uint64 => quote! { Field::Uint64(item) }, - FieldType::Int64 => quote! { Field::Int64(item) }, - FieldType::Uint128 => quote! { Field::Uint128(item) }, - FieldType::Int128 => quote! { Field::Int128(item) }, - FieldType::U256 => quote! { Field::U256(item) }, - FieldType::Float64 => quote! { Field::Float64(item) }, + FieldType::Bool => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Bool(item) } + } + FieldType::Uint8 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint8(item) } + } + FieldType::Int8 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int8(item) } + } + FieldType::Uint16 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint16(item) } + } + FieldType::Int16 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int16(item) } + } + FieldType::Uint32 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint32(item) } + } + FieldType::Int32 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int32(item) } + } + FieldType::Uint64 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint64(item) } + } + FieldType::Int64 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int64(item) } + } + FieldType::Uint128 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Uint128(item) } + } + FieldType::Int128 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Int128(item) } + } + FieldType::U256 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::U256(item) } + } + FieldType::Float64 => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Float64(item) } + } FieldType::String => { - quote! { Field::String(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::BoundedString(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(item.into_bytes()))) } + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::String(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::BoundedString(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(item.into_bytes()))) } } FieldType::Bytes => { - quote! { Field::Bytes(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(item)) } + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Bytes(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(item)) } } FieldType::Optional(_) => todo!("handle optionals into lists"), FieldType::Array(_, _) => todo!("handle arrays into lists"), FieldType::List(_) => todo!("handle nested lists"), FieldType::Struct(_, _) => todo!("handle nested structs"), - FieldType::AccountId => quote! { Field::AccountId(item) }, + FieldType::AccountId => { + quote! { gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::AccountId(item) } + } }; let inner = quote! { let #inner_ident = #ident.into_iter().map(|item| #field).collect::>(); @@ -195,7 +268,7 @@ pub fn field_type_to_result_token(ident: &Ident, t: &FieldType) -> proc_macro2:: quote! { #inner - result.push(Field::List(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#inner_ident))); + result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::List(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(#inner_ident))); } } FieldType::Struct(name, fields) => { @@ -219,11 +292,11 @@ pub fn field_type_to_result_token(ident: &Ident, t: &FieldType) -> proc_macro2:: #(#field_tokens)* let struct_name = gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::BoundedString::::from(#name); let fields_vec = vec![#(#field_tokens),*]; - result.push(Field::Struct(struct_name, gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(fields_vec))); + result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::Struct(struct_name, gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec(fields_vec))); } } FieldType::AccountId => { - quote! { result.push(Field::AccountId(#ident)); } + quote! { result.push(gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field::AccountId(#ident)); } } } } diff --git a/macros/playground/Cargo.toml b/macros/playground/Cargo.toml index e9e44a666..a9037a5d8 100644 --- a/macros/playground/Cargo.toml +++ b/macros/playground/Cargo.toml @@ -25,5 +25,10 @@ async-trait = { workspace = true } tracing = { workspace = true } gadget-sdk = { workspace = true, features = ["default"] } +[dev-dependencies] +reqwest = { workspace = true } +serde_json = { workspace = true } +tokio = { workspace = true } + [build-dependencies] -blueprint-metadata = { workspace = true } +blueprint-metadata = { workspace = true } \ No newline at end of file diff --git a/macros/playground/src/lib.rs b/macros/playground/src/lib.rs index e8133c5ff..543eb8a17 100644 --- a/macros/playground/src/lib.rs +++ b/macros/playground/src/lib.rs @@ -1,4 +1,10 @@ #![allow(dead_code)] +use gadget_sdk::clients::tangle::runtime::TangleClient; +use gadget_sdk::event_listener::tangle::jobs::{services_post_processor, services_pre_processor}; +use gadget_sdk::event_listener::tangle::TangleEventListener; +use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::events::{ + JobCalled, JobResultSubmitted, +}; use gadget_sdk::{benchmark, job, registration_hook, report, request_hook}; #[derive(Debug, Clone, Copy)] @@ -28,9 +34,9 @@ pub struct MyContext; // ================== /// Simple Threshold (t) Keygen Job for n parties. -#[job(id = 0, params(n, t), event_listener(listener = TangleEventListener, event = JobCalled), result(_))] -pub fn keygen(ctx: &MyContext, n: u16, t: u16) -> Result, Error> { - let _ = (n, t, ctx); +#[job(id = 0, params(n, t), event_listener(listener = TangleEventListener, pre_processor = services_pre_processor), result(_))] +pub fn keygen(context: TangleClient, n: u16, t: u16) -> Result, Error> { + let _ = (n, t, context); Ok(vec![0; 33]) } @@ -38,10 +44,10 @@ pub fn keygen(ctx: &MyContext, n: u16, t: u16) -> Result, Error> { #[job( id = 1, params(keygen_id, data), - event_listener(listener = TangleEventListener, event = JobCalled), + event_listener(listener = TangleEventListener, pre_processor = services_pre_processor), result(_) )] -pub async fn sign(keygen_id: u64, data: Vec) -> Result, Error> { +pub async fn sign(context: TangleClient, keygen_id: u64, data: Vec) -> Result, Error> { let _ = (keygen_id, data); Ok(vec![0; 65]) } @@ -49,17 +55,31 @@ pub async fn sign(keygen_id: u64, data: Vec) -> Result, Error> { #[job( id = 2, params(keygen_id, new_t), - event_listener(listener = TangleEventListener, event = JobCalled), + event_listener( + listener = TangleEventListener, + pre_processor = services_pre_processor, + post_processor = services_post_processor, + ), result(_) )] -pub fn refresh(keygen_id: u64, new_t: Option) -> Result, Error> { +pub fn refresh( + context: TangleClient, + keygen_id: u64, + new_t: Option, +) -> Result, Error> { let _ = (keygen_id, new_t); Ok(vec![0; 33]) } /// Say hello to someone or the world. -#[job(id = 3, params(who), event_listener(listener = TangleEventListener, event = JobCalled), result(_))] -pub fn say_hello(who: Option) -> Result { +#[job(id = 3, params(who), + event_listener( + listener = TangleEventListener, + pre_processor = services_pre_processor, + post_processor = services_post_processor, + ), + result(_))] +pub fn say_hello(context: TangleClient, who: Option) -> Result { match who { Some(who) => Ok(format!("Hello, {}!", who)), None => Ok("Hello, World!".to_string()), @@ -84,36 +104,50 @@ pub fn on_request(nft_id: u64); #[report( job_id = 0, params(n, t, msgs), - event_listener(listener = TangleEventListener, event = JobCalled), + event_listener( + listener = TangleEventListener, + pre_processor = services_pre_processor, + post_processor = services_post_processor, + ), result(_), report_type = "job", verifier(evm = "KeygenContract") )] -fn report_keygen(n: u16, t: u16, msgs: Vec>) -> u32 { +fn report_keygen( + context: TangleClient, + n: u16, + t: u16, + msgs: Vec>, +) -> Result { let _ = (n, t, msgs); - 0 + Ok(0) } #[report( params(uptime, response_time, error_rate), - event_listener(listener = TangleEventListener, event = JobCalled), - result(Vec), + event_listener(listener = TangleEventListener, pre_processor = services_pre_processor,), + result(_), report_type = "qos", interval = 3600, metric_thresholds(uptime = 99, response_time = 1000, error_rate = 5) )] -fn report_service_health(uptime: f64, response_time: u64, error_rate: f64) -> Vec { +fn report_service_health( + context: TangleClient, + uptime: u64, + response_time: u64, + error_rate: u64, +) -> Result, gadget_sdk::Error> { let mut issues = Vec::new(); - if uptime < 99.0 { + if uptime < 99 { issues.push(b"Low uptime".to_vec()); } if response_time > 1000 { issues.push(b"High response time".to_vec()); } - if error_rate > 5.0 { + if error_rate > 5 { issues.push(b"High error rate".to_vec()); } - issues.concat() + Ok(issues.concat()) } // ================== @@ -123,13 +157,23 @@ fn report_service_health(uptime: f64, response_time: u64, error_rate: f64) -> Ve fn keygen_2_of_3() { let n = 3; let t = 2; - let result = keygen(&MyContext, n, t); + let result = keygen(&TangleClient, n, t); assert!(result.is_ok()); } #[cfg(test)] mod tests { + use async_trait::async_trait; use gadget_sdk as sdk; + use gadget_sdk::job_runner::MultiJobRunner; + use sdk::event_listener::periodic::PeriodicEventListener; + use sdk::event_listener::EventListener; + use sdk::job; + use std::convert::Infallible; + use std::sync::atomic::AtomicUsize; + use std::sync::Arc; + use std::time::Duration; + #[test] fn generated_blueprint() { eprintln!("{}", super::KEYGEN_JOB_DEF); @@ -187,11 +231,137 @@ mod tests { } } + #[job( + id = 0, + params(value), + result(_), + event_listener( + listener = PeriodicEventListener<1500, WebPoller, serde_json::Value, Arc>, + pre_processor = pre_process, + post_processor = post_process, + ), + )] + // Maps a boolean value obtained from pre-processing to a u8 value + pub async fn web_poller(value: bool, count: Arc) -> Result { + gadget_sdk::info!("Running web_poller on value: {value}"); + Ok(value as u8) + } + + async fn pre_process(event: serde_json::Value) -> Result { + gadget_sdk::info!("Running web_poller pre-processor on value: {event}"); + let completed = event["completed"].as_bool().unwrap_or(false); + Ok(completed) + } + + async fn post_process(job_output: u8) -> Result<(), gadget_sdk::Error> { + gadget_sdk::info!("Running web_poller post-processor on value: {job_output}"); + if job_output == 1 { + Ok(()) + } else { + Err(gadget_sdk::Error::Other( + "Job failed since query returned with a false status".to_string(), + )) + } + } + + /// Define an event listener that polls a webserver + pub struct WebPoller { + pub client: reqwest::Client, + pub count: Arc, + } + + #[async_trait] + impl EventListener> for WebPoller { + async fn new(context: &Arc) -> Result + where + Self: Sized, + { + let client = reqwest::Client::new(); + Ok(Self { + client, + count: context.clone(), + }) + } + + /// Implement the logic that polls the web server + async fn next_event(&mut self) -> Option { + // Send a GET request to the JSONPlaceholder API + let response = self + .client + .get("https://jsonplaceholder.typicode.com/todos/10") + .send() + .await + .ok()?; + + // Check if the request was successful + if response.status().is_success() { + // Parse the JSON response + let resp: serde_json::Value = response.json().await.ok()?; + self.count.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + Some(resp) + } else { + None + } + } + + /// Implement any handler logic when an event is received + async fn handle_event( + &mut self, + _event: serde_json::Value, + ) -> Result<(), gadget_sdk::Error> { + unreachable!("Not called here") + } + } + + #[tokio::test] + async fn test_web_poller_event_workflow_works() { + gadget_sdk::logging::setup_log(); + let count = &Arc::new(AtomicUsize::new(0)); + let job = WebPollerEventHandler { + count: count.clone(), + }; + + let task0 = async move { + MultiJobRunner::new(None) + .with_job() + .finish(job) + .run() + .await + .expect("Job failed"); + }; + + let periodic_poller = async move { + loop { + if count.load(std::sync::atomic::Ordering::SeqCst) > 3 { + break; + } + + tokio::time::sleep(Duration::from_millis(500)).await + } + }; + + tokio::select! { + _ = task0 => { + panic!("Should not occur") + }, + _ = periodic_poller => { + assert!(count.load(std::sync::atomic::Ordering::SeqCst) > 3); + }, + } + } + fn setup_env() { - // TODO: Add all GadgetContext vars into the env + // Add required env vars for all child processes/gadgets + let env_vars = [ + ("RPC_URL".to_string(), "ws://127.0.0.1".to_string()), + ("KEYSTORE_URI".to_string(), "/".to_string()), + ("BLUEPRINT_ID".to_string(), 0.to_string()), + ("SERVICE_ID".to_string(), 0.to_string()), + ("DATA_DIR".to_string(), "/".to_string()), + ]; + + for (key, value) in env_vars { + std::env::set_var(key, value); + } } - // #[test] - // fn example_benchmark() { - // super::keygen_2_of_3_benchmark(); - // } } diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 30c4c86fa..cd716fa41 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -85,6 +85,7 @@ tokio-retry = { workspace = true } # Macros gadget-blueprint-proc-macro = { workspace = true, default-features = false } gadget-context-derive = { workspace = true, default-features = false } +gadget-blueprint-proc-macro-core = { workspace = true, default-features = false } # Benchmarking deps sysinfo = { workspace = true } diff --git a/sdk/src/error.rs b/sdk/src/error.rs index d613e73c3..cb5b92c46 100644 --- a/sdk/src/error.rs +++ b/sdk/src/error.rs @@ -54,6 +54,8 @@ pub enum Error { Metrics(#[from] crate::metrics::Error), #[error("Io error: {0}")] IoError(#[from] std::io::Error), + #[error("The type has been skipped in the preprocessor")] + SkipPreProcessedType, #[error("Other error: {0}")] Other(String), } diff --git a/sdk/src/event_listener/executor.rs b/sdk/src/event_listener/executor.rs index 0ab1ad772..fc8625019 100644 --- a/sdk/src/event_listener/executor.rs +++ b/sdk/src/event_listener/executor.rs @@ -58,9 +58,16 @@ where async fn event_loop(&mut self) -> Result<(), crate::Error> { // TODO: add exponential backoff logic here while let Some(event) = self.next_event().await { - let preprocessed_event = self.pre_process(event).await?; - let job_output = self.process(preprocessed_event).await?; - self.post_process(job_output).await?; + match self.pre_process(event).await { + Ok(preprocessed_event) => { + let job_output = self.process(preprocessed_event).await?; + self.post_process(job_output).await?; + } + Err(crate::Error::SkipPreProcessedType) => {} + Err(e) => { + return Err(e); + } + } } Err(crate::Error::Other( diff --git a/sdk/src/event_listener/mod.rs b/sdk/src/event_listener/mod.rs index 4e6e6fe3d..f8ab56b49 100644 --- a/sdk/src/event_listener/mod.rs +++ b/sdk/src/event_listener/mod.rs @@ -7,7 +7,7 @@ pub mod evm_contracts; pub mod executor; pub mod markers; pub mod periodic; -pub mod tangle_events; +pub mod tangle; /// The [`EventListener`] trait defines the interface for event listeners. #[async_trait] diff --git a/sdk/src/event_listener/tangle/jobs.rs b/sdk/src/event_listener/tangle/jobs.rs new file mode 100644 index 000000000..148681335 --- /dev/null +++ b/sdk/src/event_listener/tangle/jobs.rs @@ -0,0 +1,124 @@ +use crate::clients::tangle::runtime::TangleClient; +use crate::event_listener::tangle::{BlockNumber, TangleEvent}; +use crate::Error; +use subxt_core::events::StaticEvent; +use subxt_core::utils::AccountId32; +use tangle_subxt::tangle_testnet_runtime::api; +use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::field::Field; +use tangle_subxt::tangle_testnet_runtime::api::services::calls::types; +use tangle_subxt::tangle_testnet_runtime::api::services::calls::types::call::{Job, ServiceId}; +use tangle_subxt::tangle_testnet_runtime::api::services::events::{ + job_called, JobCalled, JobResultSubmitted, +}; + +pub trait ServicesJobPalletItem: StaticEvent { + fn call_id(&self) -> job_called::CallId; + fn job_id(&self) -> Job; + fn service_id(&self) -> ServiceId; + fn args(self) -> Option>> { + None + } +} + +impl ServicesJobPalletItem for JobCalled { + fn call_id(&self) -> job_called::CallId { + self.call_id + } + + fn job_id(&self) -> Job { + self.job + } + + fn service_id(&self) -> ServiceId { + self.service_id + } + + fn args(self) -> Option>> { + Some(self.args) + } +} + +impl ServicesJobPalletItem for JobResultSubmitted { + fn call_id(&self) -> job_called::CallId { + self.call_id + } + + fn job_id(&self) -> Job { + self.job + } + + fn service_id(&self) -> ServiceId { + self.service_id + } +} + +pub async fn services_pre_processor( + event: TangleEvent, +) -> Result, Error> { + let this_service_id = event.service_id; + let this_job_id = event.job_id; + crate::info!("Pre-processing event for sid/bid = {this_service_id}/{this_job_id} ..."); + if let Ok(Some(evt)) = event.evt.as_event::() { + let service_id = evt.service_id(); + let job = evt.job_id(); + let call_id = evt.call_id(); + let args = evt.args().unwrap_or_default(); + + if job == this_job_id && service_id == this_service_id { + crate::info!("Found actionable event for sid/bid = {service_id}/{job} ..."); + return Ok(TangleJobEvent { + args, + context: event.context, + block_number: event.block_number, + signer: event.signer, + client: event.client, + call_id: Some(call_id), + job_id: this_job_id, + service_id: this_service_id, + }); + } + } + + Err(Error::SkipPreProcessedType) +} + +/// By default, the tangle post-processor takes in a job result and submits the result on-chain +pub async fn services_post_processor( + TangleJobResult { + results, + service_id, + call_id, + client, + signer, + }: TangleJobResult, +) -> Result<(), Error> { + crate::info!("Submitting result on-chain for service {service_id} call_id {call_id} ..."); + let response = api::tx() + .services() + .submit_result(service_id, call_id, results); + let _ = crate::tx::tangle::send(&client, &signer, &response) + .await + .map_err(|err| Error::Client(err.to_string()))?; + crate::info!("Submitted result on-chain"); + Ok(()) +} + +pub struct TangleJobResult { + pub results: types::submit_result::Result, + pub service_id: ServiceId, + pub call_id: job_called::CallId, + pub client: TangleClient, + pub signer: crate::keystore::TanglePairSigner, +} + +// TODO: Move up this a module to make call_id generic +pub struct TangleJobEvent { + pub args: Vec>, + pub context: Ctx, + pub client: TangleClient, + pub signer: crate::keystore::TanglePairSigner, + pub block_number: BlockNumber, + pub call_id: Option, + pub job_id: Job, + pub service_id: ServiceId, +} diff --git a/sdk/src/event_listener/tangle/mod.rs b/sdk/src/event_listener/tangle/mod.rs new file mode 100644 index 000000000..4995ab285 --- /dev/null +++ b/sdk/src/event_listener/tangle/mod.rs @@ -0,0 +1,182 @@ +use crate::clients::tangle::runtime::{TangleClient, TangleConfig}; +use crate::event_listener::markers::IsTangle; +use crate::event_listener::EventListener; +use crate::Error; +use async_trait::async_trait; +use gadget_blueprint_proc_macro_core::FieldType; +use sp_core::crypto::AccountId32; +use std::collections::VecDeque; +use std::marker::PhantomData; +use subxt::backend::StreamOfResults; +use subxt_core::events::EventDetails; +use tangle_subxt::tangle_testnet_runtime::api::services::calls::types::call::{Job, ServiceId}; +use tokio::sync::Mutex; + +pub mod jobs; + +pub struct TangleEventListener { + current_block: Option, + job_id: Job, + service_id: ServiceId, + listener: Mutex>>, + context: Ctx, + signer: crate::keystore::TanglePairSigner, + client: TangleClient, + enqueued_events: VecDeque>, + _pd: PhantomData, +} + +pub type BlockNumber = u32; + +#[derive(Clone)] +pub struct TangleListenerInput { + pub client: TangleClient, + pub job_id: Job, + pub service_id: ServiceId, + pub signer: crate::keystore::TanglePairSigner, + pub context: Ctx, +} + +/// Emitted by the [`TangleEventListener`] when a new event is received. +/// +/// Root events are preferred to be used as the Evt, as then the application can +/// sort through a series of events to find the ones it is interested in for +/// pre-processing. +pub struct TangleEvent { + pub evt: EventDetails, + pub context: Ctx, + pub block_number: BlockNumber, + pub signer: crate::keystore::TanglePairSigner, + pub client: TangleClient, + pub job_id: Job, + pub service_id: ServiceId, + _pd: PhantomData, +} + +impl IsTangle for TangleEventListener {} + +#[async_trait] +impl + EventListener, TangleListenerInput> + for TangleEventListener +{ + async fn new(context: &TangleListenerInput) -> Result + where + Self: Sized, + { + let TangleListenerInput { + client, + job_id, + service_id, + context, + signer, + } = context; + + let listener = Mutex::new(client.blocks().subscribe_finalized().await?); + Ok(Self { + listener, + current_block: None, + job_id: *job_id, + service_id: *service_id, + context: context.clone(), + client: client.clone(), + signer: signer.clone(), + enqueued_events: VecDeque::new(), + _pd: PhantomData, + }) + } + + async fn next_event(&mut self) -> Option> { + loop { + if let Some(evt) = self.enqueued_events.pop_front() { + return Some(TangleEvent { + evt, + context: self.context.clone(), + signer: self.signer.clone(), + block_number: self.current_block?, + client: self.client.clone(), + job_id: self.job_id, + service_id: self.service_id, + _pd: PhantomData, + }); + } + + let next_events = self.listener.get_mut().next().await?.ok()?; + let block_number = next_events.number(); + self.current_block = Some(block_number); + + let next_events = next_events.events().await.ok()?; + let mut root_events = next_events.iter().flatten().collect::>(); + + crate::info!("Found {} possible events ...", root_events.len()); + + if let Some(evt) = root_events.pop_front() { + if !root_events.is_empty() { + // Store for the next iteration; we can override this since we know + // by this point in the code there are no more events to process in + // the queue + self.enqueued_events = root_events; + } + + return Some(TangleEvent { + evt, + context: self.context.clone(), + signer: self.signer.clone(), + block_number, + client: self.client.clone(), + job_id: self.job_id, + service_id: self.service_id, + _pd: PhantomData, + }); + } + } + } + + async fn handle_event(&mut self, _event: TangleEvent) -> Result<(), Error> { + unimplemented!("placeholder; will be removed") + } +} + +pub trait FieldTypeToValue: Sized { + fn to_value(&self, field_type: FieldType) -> Self; +} + +macro_rules! impl_field_type_to_value { + ($($t:ty => $f:pat),*) => { + $( + impl FieldTypeToValue for $t { + fn to_value(&self, field_type: FieldType) -> Self { + match field_type { + $f => self.clone(), + _ => panic!("Invalid field type!"), + } + } + } + )* + }; +} + +impl_field_type_to_value!( + u8 => FieldType::Uint8, + u16 => FieldType::Uint16, + u32 => FieldType::Uint32, + u64 => FieldType::Uint64, + i8 => FieldType::Int8, + i16 => FieldType::Int16, + i32 => FieldType::Int32, + i64 => FieldType::Int64, + u128 => FieldType::Uint128, + i128 => FieldType::Int128, + f64 => FieldType::Float64, + bool => FieldType::Bool, + AccountId32 => FieldType::AccountId +); + +impl FieldTypeToValue for String { + fn to_value(&self, field_type: FieldType) -> Self { + match field_type { + FieldType::String => self.clone(), + _ => panic!("Invalid field type!"), + } + } +} diff --git a/sdk/src/event_listener/tangle_events.rs b/sdk/src/event_listener/tangle_events.rs deleted file mode 100644 index 18604f8a9..000000000 --- a/sdk/src/event_listener/tangle_events.rs +++ /dev/null @@ -1,204 +0,0 @@ -use crate::clients::tangle::runtime::{TangleClient, TangleConfig}; -use crate::events_watcher::substrate::EventHandlerFor; -use crate::Error; -use async_trait::async_trait; -use subxt::backend::StreamOfResults; -use subxt::OnlineClient; -use subxt_core::events::StaticEvent; -use tangle_subxt::tangle_testnet_runtime::api::services::events::{ - job_called, JobCalled, JobResultSubmitted, -}; -use tokio::sync::Mutex; -use tokio_retry::Retry; - -use crate::event_listener::get_exponential_backoff; -use crate::event_listener::EventListener; - -pub trait HasServiceAndJobId: StaticEvent + Send + Sync + 'static { - fn service_id(&self) -> u64; - fn job_id(&self) -> u8; - fn id_of_call(&self) -> job_called::CallId; -} - -impl HasServiceAndJobId for JobCalled { - fn service_id(&self) -> u64 { - self.service_id - } - - fn job_id(&self) -> u8 { - self.job - } - - fn id_of_call(&self) -> job_called::CallId { - self.call_id - } -} - -impl HasServiceAndJobId for JobResultSubmitted { - fn service_id(&self) -> u64 { - self.service_id - } - - fn job_id(&self) -> u8 { - self.job - } - - fn id_of_call(&self) -> job_called::CallId { - self.call_id - } -} - -pub struct TangleEventWrapper { - handler: EventHandlerFor, - client: OnlineClient, - current_block: Option, - listener: - Mutex>>>, -} - -pub type TangleEventListener = TangleEventWrapper; -pub type TangleJobEventListener = TangleEventWrapper; - -pub type TangleEventWrapperContext = (TangleClient, EventHandlerFor); -#[async_trait] -impl - EventListener, TangleEventWrapperContext> for TangleEventWrapper -{ - async fn new(ctx: &TangleEventWrapperContext) -> Result - where - Self: Sized, - { - let (client, handler) = ctx; - let listener = Mutex::new(client.blocks().subscribe_finalized().await?); - Ok(Self { - listener, - client: client.clone(), - current_block: None, - handler: handler.clone(), - }) - } - - async fn next_event(&mut self) -> Option> { - loop { - let next_block = self.listener.get_mut().next().await?.ok()?; - let block_id = next_block.number(); - self.current_block = Some(block_id); - let events = next_block.events().await.ok()?; - for _evt in events.iter().flatten() { - crate::info!( - "Event found || required: sid={}, jid={}", - self.handler.service_id(), - self.handler.job_id() - ); - } - - let events = events - .find::() - .flatten() - .filter(|event| { - event.service_id() == self.handler.service_id() - && event.job_id() == self.handler.job_id() - }) - .collect::>(); - - if !events.is_empty() { - return Some(events); - } - } - } - - async fn handle_event(&mut self, job_events: Vec) -> Result<(), Error> { - use crate::tangle_subxt::tangle_testnet_runtime::api as TangleApi; - const MAX_RETRY_COUNT: usize = 5; - crate::info!("Handling actionable events ..."); - crate::info!( - "Handling {} JobCalled Events @ block {}", - job_events.len(), - self.current_block.unwrap_or_default() - ); - - let mut tasks = Vec::new(); - for call in job_events.iter() { - let handler = &self.handler; - let client = &self.client; - let service_id = call.service_id(); - let call_id = call.id_of_call(); - let signer = handler.signer().clone(); - - let task = async move { - let backoff = get_exponential_backoff::(); - - Retry::spawn(backoff, || async { - let result = handler.handle(call).await?; - let response = TangleApi::tx() - .services() - .submit_result(service_id, call_id, result); - let _ = crate::tx::tangle::send(client, &signer, &response) - .await - .map_err(|err| Error::Client(err.to_string()))?; - Ok::<_, Error>(()) - }) - .await - }; - - tasks.push(task); - } - - let results = futures::future::join_all(tasks).await; - // this event will be marked as handled if at least one handler succeeded. - // this because, for the failed events, we already tried to handle them - // many times (at this point), and there is no point in trying again. - let mark_as_handled = results.iter().any(Result::is_ok); - // also, for all the failed event handlers, we should print what went - // wrong. - for r in &results { - if let Err(e) = r { - crate::error!("Error from result: {e:?}"); - } - } - - if mark_as_handled { - crate::info!( - "event handled successfully at block {}", - self.current_block.unwrap_or_default() - ); - } else { - crate::error!("Error while handling event, all handlers failed."); - crate::warn!("Restarting event watcher ..."); - // this a transient error, so we will retry again. - return Ok(()); - } - - Ok(()) - } - - async fn execute(&mut self) -> Result<(), Error> { - const MAX_RETRY_COUNT: usize = 10; - let mut backoff = get_exponential_backoff::(); - - let mut retry_count = 0; - loop { - match self.run_event_loop().await { - Ok(_) => break Ok(()), - Err(e) => { - if retry_count >= MAX_RETRY_COUNT { - break Err(e); - } - retry_count += 1; - tokio::time::sleep(backoff.nth(retry_count).unwrap()).await; - } - } - } - } -} - -impl TangleEventWrapper { - async fn run_event_loop(&mut self) -> Result<(), Error> { - while let Some(events) = self.next_event().await { - self.handle_event(events).await?; - } - - crate::warn!("Event listener has stopped"); - Err(Error::Other("Event listener has stopped".to_string())) - } -} diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 0fd27cb4e..0964ed97a 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -78,6 +78,7 @@ pub use structopt; pub use subxt_core; pub use tangle_subxt; pub use tokio; +pub use uuid; // External modules usually used in proc-macro codegen. #[doc(hidden)]