From e320c8058e46765ed541da0dd6e65a154bca0887 Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:17:31 +0530 Subject: [PATCH 1/9] init --- .DS_Store | Bin 0 -> 6148 bytes .env.example | 16 + .gitignore | 2 + .idea/.gitignore | 8 + .idea/GitLink.xml | 6 + .idea/dataSources.xml | 19 + .idea/madara-orchestrator.iml | 11 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + Cargo.lock | 5665 +++++++++++++++++ Cargo.toml | 35 + README.md | 11 + diesel.toml | 9 + docs/orchestrator_da_sequencer_diagram.png | Bin 0 -> 272128 bytes docs/orchestrator_da_sequencer_diagram.txt | 53 + migrations/.DS_Store | Bin 0 -> 6148 bytes migrations/.keep | 0 .../down.sql | 6 + .../up.sql | 36 + migrations/1709667414_jobs_table/down.sql | 1 + migrations/1709667414_jobs_table/up.sql | 11 + rustfmt.toml | 20 + src/.DS_Store | Bin 0 -> 6148 bytes src/config.rs | 72 + src/controllers/errors.rs | 21 + src/controllers/jobs_controller.rs | 20 + src/controllers/mod.rs | 2 + src/da_clients/ethereum/config.rs | 22 + src/da_clients/ethereum/mod.rs | 36 + src/da_clients/mod.rs | 21 + src/database/mod.rs | 41 + src/database/mongodb/config.rs | 12 + src/database/mongodb/mod.rs | 122 + src/jobs/constants.rs | 2 + src/jobs/da_job/mod.rs | 182 + src/jobs/mod.rs | 158 + src/jobs/types.rs | 61 + src/main.rs | 38 + src/queue/job_queue.rs | 97 + src/queue/mod.rs | 18 + src/queue/sqs/mod.rs | 39 + src/routes.rs | 30 + src/utils/env_utils.rs | 13 + src/utils/job_utils.rs | 18 + src/utils/mod.rs | 2 + 45 files changed, 6950 insertions(+) create mode 100644 .DS_Store create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/GitLink.xml create mode 100644 .idea/dataSources.xml create mode 100644 .idea/madara-orchestrator.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 diesel.toml create mode 100644 docs/orchestrator_da_sequencer_diagram.png create mode 100644 docs/orchestrator_da_sequencer_diagram.txt create mode 100644 migrations/.DS_Store create mode 100644 migrations/.keep create mode 100644 migrations/00000000000000_diesel_initial_setup/down.sql create mode 100644 migrations/00000000000000_diesel_initial_setup/up.sql create mode 100644 migrations/1709667414_jobs_table/down.sql create mode 100644 migrations/1709667414_jobs_table/up.sql create mode 100644 rustfmt.toml create mode 100644 src/.DS_Store create mode 100644 src/config.rs create mode 100644 src/controllers/errors.rs create mode 100644 src/controllers/jobs_controller.rs create mode 100644 src/controllers/mod.rs create mode 100644 src/da_clients/ethereum/config.rs create mode 100644 src/da_clients/ethereum/mod.rs create mode 100644 src/da_clients/mod.rs create mode 100644 src/database/mod.rs create mode 100644 src/database/mongodb/config.rs create mode 100644 src/database/mongodb/mod.rs create mode 100644 src/jobs/constants.rs create mode 100644 src/jobs/da_job/mod.rs create mode 100644 src/jobs/mod.rs create mode 100644 src/jobs/types.rs create mode 100644 src/main.rs create mode 100644 src/queue/job_queue.rs create mode 100644 src/queue/mod.rs create mode 100644 src/queue/sqs/mod.rs create mode 100644 src/routes.rs create mode 100644 src/utils/env_utils.rs create mode 100644 src/utils/job_utils.rs create mode 100644 src/utils/mod.rs diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..da9842491bd242e2715c5a6ac7f01fb2a746897c GIT binary patch literal 6148 zcmeHLKQ9D96o2EET!>@~g+#E0kSHX+0E_bpBnpK%cXEWY!l^XdsVOuHja(E8;R|R` zh=k6EkVt$2zc=&bX6zlE2=kJi-|W2i_V?zuf9B?hNKNmS$B9BB%Hv=RI?*&S_Vbak zHW}#!D!#@>WqhubRJSsbe!wf>75I$`@Vgt(7*%MEYR>!HKJ#q*s!5@+ypb$pEPoUp zj1E8COu7E@m;S9)>)X(UOrm!1u2Gp*sOT`ay)3w1oBRH}d;ivOTlv+b!T!{BdVHCQ zaQJf<%pZU|p%U#l?7`Tf?X$UG!;!n%z06y3ZRTcvhc}3sx09-vcZIg8NHz2l+Wb@l z4feH)v+J1{=zEiyHoc}@+jp@}owUSt=4b~smK=5HWWC|BYq=ii|ENXsZ1$|z;Zyp4 zbU=+F7%O-poM*8?ETY|yt}0k43oK+c?oy#CL&-v7Hv{>&@j75GyMsGu-c zn8uW3ZOu%M*V+ij5)L+wOAYE2G_oA)4ll+0zk)XSBJKcV!PFo|VE%`Imcch(fge@i E9Wu+tsQ>@~ literal 0 HcmV?d00001 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..cb7f9cd --- /dev/null +++ b/.env.example @@ -0,0 +1,16 @@ +HOST= +PORT= +DATABASE_URL= +MADARA_RPC_URL= +DA_LAYER= + +# Ethereum +ETHEREUM_RPC_URL= +MEMORY_PAGES_CONTRACT_ADDRESS= + +# MongoDB connection string +MONGODB_CONNECTION_STRING + +# SQS +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fedaa2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +.env diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/GitLink.xml b/.idea/GitLink.xml new file mode 100644 index 0000000..009597c --- /dev/null +++ b/.idea/GitLink.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..089ad98 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,19 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://localhost:5432/postgres + $ProjectFileDir$ + + + mongo + true + com.dbschema.MongoJdbcDriver + mongodb+srv://cluster0.dztzhor.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0 + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/madara-orchestrator.iml b/.idea/madara-orchestrator.iml new file mode 100644 index 0000000..cf84ae4 --- /dev/null +++ b/.idea/madara-orchestrator.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..fbaa916 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4b46409 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,5665 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "alloy" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy?rev=86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6#86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6" +dependencies = [ + "alloy-core", + "alloy-providers", + "alloy-rpc-client", + "alloy-transport", + "alloy-transport-http", + "reqwest", +] + +[[package]] +name = "alloy-core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd180ed0c69492633d6d7d9e22dab64951fb56906f4294a8e0739c8036df315" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-types", +] + +[[package]] +name = "alloy-dyn-abi" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2919acdad13336bc5dc26b636cdd6892c2f27fb0d4a58320a00c2713cf6a4e9a" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-type-parser", + "alloy-sol-types", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow 0.6.5", +] + +[[package]] +name = "alloy-eips" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy?rev=86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6#86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-json-abi" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ed0f2a6c3a1c947b4508522a53a190dba8f94dcd4e3e1a5af945a498e78f2f" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy?rev=86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6#86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-network" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy?rev=86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6#86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6" +dependencies = [ + "alloy-eips", + "alloy-json-rpc", + "alloy-primitives", + "alloy-rlp", + "serde", +] + +[[package]] +name = "alloy-primitives" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "600d34d8de81e23b6d909c094e23b3d357e01ca36b78a8c5424c501eedbe86f0" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "k256", + "keccak-asm", + "proptest", + "rand", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-providers" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy?rev=86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6#86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6" +dependencies = [ + "alloy-network", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-trace-types", + "alloy-rpc-types", + "alloy-transport", + "alloy-transport-http", + "async-stream", + "async-trait", + "auto_impl", + "futures", + "lru", + "reqwest", + "serde", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a047897373be4bbb0224c1afdabca92648dc57a9c9ef6e7b0be3aff7a859c83" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy?rev=86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6#86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "alloy-transport-http", + "futures", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-rpc-trace-types" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy?rev=86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6#86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-rpc-types" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy?rev=86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6#86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "itertools 0.12.1", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86ec0a47740b20bc5613b8712d0d321d031c4efc58e9645af96085d5cccfc27" +dependencies = [ + "const-hex", + "dunce", + "heck", + "indexmap 2.2.5", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.52", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0045cc89524e1451ccf33e8581355b6027ac7c6e494bb02959d4213ad0d8e91d" +dependencies = [ + "winnow 0.6.5", +] + +[[package]] +name = "alloy-sol-types" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad09ec5853fa700d12d778ad224dcdec636af424d29fad84fb9a2f16a5b0ef09" +dependencies = [ + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy?rev=86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6#86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6" +dependencies = [ + "alloy-json-rpc", + "base64 0.21.7", + "futures-util", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "url", + "wasm-bindgen-futures", +] + +[[package]] +name = "alloy-transport-http" +version = "0.1.0" +source = "git+https://github.com/alloy-rs/alloy?rev=86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6#86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "reqwest", + "serde_json", + "tower", + "url", +] + +[[package]] +name = "amq-protocol" +version = "7.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d40d8b2465c7959dd40cee32ba6ac334b5de57e9fca0cc756759894a4152a5d" +dependencies = [ + "amq-protocol-tcp", + "amq-protocol-types", + "amq-protocol-uri", + "cookie-factory", + "nom", + "serde", +] + +[[package]] +name = "amq-protocol-tcp" +version = "7.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cb2100adae7da61953a2c3a01935d86caae13329fadce3333f524d6d6ce12e2" +dependencies = [ + "amq-protocol-uri", + "tcp-stream", + "tracing", +] + +[[package]] +name = "amq-protocol-types" +version = "7.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "156ff13c8a3ced600b4e54ed826a2ae6242b6069d00dd98466827cef07d3daff" +dependencies = [ + "cookie-factory", + "nom", + "serde", + "serde_json", +] + +[[package]] +name = "amq-protocol-uri" +version = "7.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "751bbd7d440576066233e740576f1b31fdc6ab86cfabfbd48c548de77eca73e4" +dependencies = [ + "amq-protocol-types", + "percent-encoding", + "url", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" +dependencies = [ + "concurrent-queue", + "event-listener 5.2.0", + "event-listener-strategy 0.5.0", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" +dependencies = [ + "async-lock 3.3.0", + "async-task", + "concurrent-queue", + "fastrand 2.0.1", + "futures-lite 2.2.0", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.2.0", + "async-executor", + "async-io 2.3.1", + "async-lock 3.3.0", + "blocking", + "futures-lite 2.2.0", + "once_cell", +] + +[[package]] +name = "async-global-executor-trait" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33dd14c5a15affd2abcff50d84efd4009ada28a860f01c14f9d654f3e81b3f75" +dependencies = [ + "async-global-executor", + "async-trait", + "executor-trait", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2 0.4.10", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" +dependencies = [ + "async-lock 3.3.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.2.0", + "parking", + "polling 3.5.0", + "rustix 0.38.31", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +dependencies = [ + "event-listener 4.0.3", + "event-listener-strategy 0.4.0", + "pin-project-lite", +] + +[[package]] +name = "async-reactor-trait" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6012d170ad00de56c9ee354aef2e358359deb1ec504254e0e5a3774771de0e" +dependencies = [ + "async-io 1.13.0", + "async-trait", + "futures-core", + "reactor-trait", +] + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "async-task" +version = "4.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "aws-config" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b96342ea8948ab9bef3e6234ea97fc32e2d8a88d8fb6a084e52267317f94b6b" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-sdk-sso", + "aws-sdk-ssooidc", + "aws-sdk-sts", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand 2.0.1", + "hex", + "http 0.2.12", + "hyper 0.14.28", + "ring", + "time", + "tokio", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-credential-types" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "273fa47dafc9ef14c2c074ddddbea4561ff01b7f68d5091c0e9737ced605c01d" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "zeroize", +] + +[[package]] +name = "aws-runtime" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e38bab716c8bf07da24be07ecc02e0f5656ce8f30a891322ecdcb202f943b85" +dependencies = [ + "aws-credential-types", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand 2.0.1", + "http 0.2.12", + "http-body 0.4.6", + "percent-encoding", + "pin-project-lite", + "tracing", + "uuid 1.7.0", +] + +[[package]] +name = "aws-sdk-sqs" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5aef8bff2d0020c6423eeb529ca0af9463ea21f09a031929b3b2a6ad0058678" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "http 0.2.12", + "once_cell", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-sso" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d84bd3925a17c9adbf6ec65d52104a44a09629d8f70290542beeee69a95aee7f" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "http 0.2.12", + "once_cell", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-ssooidc" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c2dae39e997f58bc4d6292e6244b26ba630c01ab671b6f9f44309de3eb80ab8" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "http 0.2.12", + "once_cell", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-sts" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17fd9a53869fee17cea77e352084e1aa71e2c5e323d974c13a9c2bcfd9544c7f" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-query", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "http 0.2.12", + "once_cell", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sigv4" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ada00a4645d7d89f296fe0ddbc3fe3554f03035937c849a05d37ddffc1f29a1" +dependencies = [ + "aws-credential-types", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "form_urlencoded", + "hex", + "hmac", + "http 0.2.12", + "http 1.1.0", + "once_cell", + "percent-encoding", + "sha2", + "time", + "tracing", +] + +[[package]] +name = "aws-smithy-async" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf7f09a27286d84315dfb9346208abb3b0973a692454ae6d0bc8d803fcce3b4" +dependencies = [ + "futures-util", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "aws-smithy-http" +version = "0.60.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6ca214a6a26f1b7ebd63aa8d4f5e2194095643023f9608edf99a58247b9d80d" +dependencies = [ + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http-body 0.4.6", + "once_cell", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", +] + +[[package]] +name = "aws-smithy-json" +version = "0.60.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1af80ecf3057fb25fe38d1687e94c4601a7817c6a1e87c1b0635f7ecb644ace5" +dependencies = [ + "aws-smithy-types", +] + +[[package]] +name = "aws-smithy-query" +version = "0.60.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb27084f72ea5fc20033efe180618677ff4a2f474b53d84695cfe310a6526cbc" +dependencies = [ + "aws-smithy-types", + "urlencoding", +] + +[[package]] +name = "aws-smithy-runtime" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb5fca54a532a36ff927fbd7407a7c8eb9c3b4faf72792ba2965ea2cad8ed55" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "fastrand 2.0.1", + "h2 0.3.24", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", + "hyper-rustls", + "once_cell", + "pin-project-lite", + "pin-utils", + "rustls", + "tokio", + "tracing", +] + +[[package]] +name = "aws-smithy-runtime-api" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22389cb6f7cac64f266fb9f137745a9349ced7b47e0d2ba503e9e40ede4f7060" +dependencies = [ + "aws-smithy-async", + "aws-smithy-types", + "bytes", + "http 0.2.12", + "http 1.1.0", + "pin-project-lite", + "tokio", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-types" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f081da5481210523d44ffd83d9f0740320050054006c719eae0232d411f024d3" +dependencies = [ + "base64-simd", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http-body 0.4.6", + "itoa", + "num-integer", + "pin-project-lite", + "pin-utils", + "ryu", + "serde", + "time", + "tokio", + "tokio-util", +] + +[[package]] +name = "aws-smithy-xml" +version = "0.60.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fccd8f595d0ca839f9f2548e66b99514a85f92feb4c01cf2868d93eb4888a42" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "aws-types" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07c63521aa1ea9a9f92a701f1a08ce3fd20b46c6efc0d5c8947c1fd879e3df1" +dependencies = [ + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "http 0.2.12", + "rustc_version 0.4.0", + "tracing", +] + +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core 0.3.4", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" +dependencies = [ + "async-trait", + "axum-core 0.4.3", + "axum-macros", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.2.0", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base-encode" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17bd29f7c70f32e9387f4d4acfa5ea7b7749ef784fb78cf382df97069337b8c" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bb8" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df7c2093d15d6a1d33b1f972e1c5ea3177748742b97a5f392aa83a65262c6780" +dependencies = [ + "async-trait", + "futures-channel", + "futures-util", + "parking_lot", + "tokio", +] + +[[package]] +name = "bb8-redis" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4094bc17b933090cfded54315a86db01d67ec999583d4bab894c520f8c097d1f" +dependencies = [ + "async-trait", + "bb8", + "redis", +] + +[[package]] +name = "bigdecimal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blocking" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +dependencies = [ + "async-channel 2.2.0", + "async-lock 3.3.0", + "async-task", + "fastrand 2.0.1", + "futures-io", + "futures-lite 2.2.0", + "piper", + "tracing", +] + +[[package]] +name = "bson" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce21468c1c9c154a85696bb25c20582511438edb6ad67f846ba1378ffdd80222" +dependencies = [ + "ahash", + "base64 0.13.1", + "bitvec", + "hex", + "indexmap 2.2.5", + "js-sys", + "once_cell", + "rand", + "serde", + "serde_bytes", + "serde_json", + "time", + "uuid 1.7.0", +] + +[[package]] +name = "bumpalo" +version = "3.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +dependencies = [ + "serde", +] + +[[package]] +name = "bytes-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" +dependencies = [ + "bytes", + "either", +] + +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + +[[package]] +name = "cc" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.4", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "color-eyre" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-hex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbd12d49ab0eaf8193ba9175e45f56bbc2e4b27d57b8cfe62aa47942a46b9a9" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie-factory" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc16" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "338089f42c427b86394a5ee60ff321da23a5c89c9d89514c829687b26359fcff" + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +dependencies = [ + "darling_core 0.20.8", + "darling_macro 0.20.8", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.52", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +dependencies = [ + "darling_core 0.20.8", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.109", +] + +[[package]] +name = "des" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-as-inner" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac", + "pbkdf2", + "rand", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3", + "thiserror", + "uuid 0.8.2", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" +dependencies = [ + "event-listener 5.2.0", + "pin-project-lite", +] + +[[package]] +name = "executor-trait" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a1052dd43212a7777ec6a69b117da52f5e52f07aec47d00c1a2b33b85d06b08" +dependencies = [ + "async-trait", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "futures-core", + "futures-sink", + "pin-project", + "spin", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" +dependencies = [ + "fastrand 2.0.1", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "google-cloud-auth" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3798ce9d99d548f28a7f942dcd546befae21c9a1310a7b54e920a7ee241aca3" +dependencies = [ + "async-trait", + "base64 0.21.7", + "google-cloud-metadata", + "google-cloud-token", + "home", + "jsonwebtoken", + "reqwest", + "serde", + "serde_json", + "thiserror", + "time", + "tokio", + "tracing", + "urlencoding", +] + +[[package]] +name = "google-cloud-gax" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb60314136e37de9e2a05ddb427b9c5a39c3d188de2e2f026c6af74425eef44" +dependencies = [ + "google-cloud-token", + "http 0.2.12", + "thiserror", + "tokio", + "tokio-retry", + "tonic", + "tower", + "tracing", +] + +[[package]] +name = "google-cloud-googleapis" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8a478015d079296167e3f08e096dc99cffc2cb50fa203dd38aaa9dd37f8354" +dependencies = [ + "prost", + "prost-types", + "tonic", +] + +[[package]] +name = "google-cloud-metadata" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc279bfb50487d7bcd900e8688406475fc750fe474a835b2ab9ade9eb1fc90e2" +dependencies = [ + "reqwest", + "thiserror", + "tokio", +] + +[[package]] +name = "google-cloud-pubsub" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1da196da473976944d408a91213bafe078e7223e10694d3f8ed36b6e210fa130" +dependencies = [ + "async-channel 1.9.0", + "async-stream", + "google-cloud-auth", + "google-cloud-gax", + "google-cloud-googleapis", + "google-cloud-token", + "prost-types", + "thiserror", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "google-cloud-token" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c12ba8b21d128a2ce8585955246977fbce4415f680ebf9199b6f9d6d725f" +dependencies = [ + "async-trait", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.2.5", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31d030e59af851932b72ceebadf4a2b5986dba4c3b99dd2493f8273a0f151943" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 1.1.0", + "indexmap 2.2.5", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.24", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.6", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.2", + "http 1.1.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.28", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper 0.14.28", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.28", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.2.0", + "pin-project-lite", + "socket2 0.5.6", + "tokio", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2 0.5.6", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb8515fff80ed850aea4a1595f2e519c003e2a00a82fe168ebf5269196caf444" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "lapin" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f3067a1fcfbc3fc46455809c023e69b8f6602463201010f4ae5a3b572adb9dc" +dependencies = [ + "amq-protocol", + "async-global-executor-trait", + "async-reactor-trait", + "async-trait", + "executor-trait", + "flume 0.10.14", + "futures-core", + "futures-io", + "parking_lot", + "pinky-swear", + "reactor-trait", + "serde", + "tracing", + "waker-fn", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "lru" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +dependencies = [ + "hashbrown 0.14.3", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "madara-orchestrator" +version = "0.1.0" +dependencies = [ + "alloy", + "async-trait", + "axum 0.7.4", + "axum-macros", + "color-eyre", + "dotenvy", + "futures", + "mongodb", + "omniqueue", + "reqwest", + "rstest", + "serde", + "serde_json", + "starknet", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber", + "url", + "uuid 1.7.0", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest 0.10.7", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "mongodb" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de59562e5c71656c098d8e966641b31da87b89dc3dcb6e761d3b37dcdfa0cb72" +dependencies = [ + "async-trait", + "base64 0.13.1", + "bitflags 1.3.2", + "bson", + "chrono", + "derivative", + "derive_more", + "futures-core", + "futures-executor", + "futures-io", + "futures-util", + "hex", + "hmac", + "lazy_static", + "md-5", + "pbkdf2", + "percent-encoding", + "rand", + "rustc_version_runtime", + "rustls", + "rustls-pemfile", + "serde", + "serde_bytes", + "serde_with 1.14.0", + "sha-1", + "sha2", + "socket2 0.4.10", + "stringprep", + "strsim", + "take_mut", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "trust-dns-proto", + "trust-dns-resolver", + "typed-builder", + "uuid 1.7.0", + "webpki-roots", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "omniqueue" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cba3b7f69e420be6e32a580307e38aef7f53ac01cc09c3bb6851aec37d710894" +dependencies = [ + "async-trait", + "aws-config", + "aws-sdk-sqs", + "bb8", + "bb8-redis", + "futures-util", + "google-cloud-googleapis", + "google-cloud-pubsub", + "lapin", + "redis", + "serde", + "serde_json", + "svix-ksuid", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags 2.4.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "outref" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "p12" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4873306de53fe82e7e484df31e1e947d61514b6ea2ed6cd7b45d63006fd9224" +dependencies = [ + "cbc", + "cipher", + "des", + "getrandom", + "hmac", + "lazy_static", + "rc2", + "sha1", + "yasna", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pem" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" +dependencies = [ + "base64 0.21.7", + "serde", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pinky-swear" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cfae3ead413ca051a681152bd266438d3bfa301c9bdf836939a14c721bb2a21" +dependencies = [ + "doc-comment", + "flume 0.11.0", + "parking_lot", + "tracing", +] + +[[package]] +name = "piper" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.0.1", + "futures-io", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.31", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.4.2", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.2", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "prost" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "prost-types" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +dependencies = [ + "prost", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rc2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62c64daa8e9438b84aaae55010a93f396f8e60e3911590fcba770d04643fc1dd" +dependencies = [ + "cipher", +] + +[[package]] +name = "reactor-trait" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "438a4293e4d097556730f4711998189416232f009c137389e0f961d2bc0ddc58" +dependencies = [ + "async-trait", + "futures-core", + "futures-io", +] + +[[package]] +name = "redis" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c580d9cbbe1d1b479e8d67cf9daf6a62c957e6846048408b80b43ac3f6af84cd" +dependencies = [ + "async-trait", + "bytes", + "combine", + "crc16", + "futures", + "futures-util", + "itoa", + "log", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rand", + "ryu", + "sha1_smol", + "socket2 0.4.10", + "tokio", + "tokio-native-tls", + "tokio-util", + "url", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.6", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-lite" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "relative-path" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" + +[[package]] +name = "reqwest" +version = "0.11.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.24", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", + "hyper-rustls", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rstest" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97eeab2f3c0a199bc4be135c36c924b6590b88c377d416494288c14f2db30199" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version 0.4.0", +] + +[[package]] +name = "rstest_macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" +dependencies = [ + "cfg-if", + "glob", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version 0.4.0", + "syn 2.0.52", + "unicode-ident", +] + +[[package]] +name = "ruint" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b1d9521f889713d1221270fdd63370feca7e5c71a18745343402fa86e4f04f" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86854cf50259291520509879a5c294c3c9a4c334e9ff65071c51e42ef1e2343" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.22", +] + +[[package]] +name = "rustc_version_runtime" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d31b7153270ebf48bf91c65ae5b0c00e749c4cfad505f66530ac74950249582f" +dependencies = [ + "rustc_version 0.2.3", + "semver 0.9.0", +] + +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-connector" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25da151615461c7347114b1ad1a7458b4cdebc69cb220cd140cd5cb324b1dd37" +dependencies = [ + "log", + "rustls", + "rustls-native-certs", + "rustls-webpki", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2", + "salsa20", + "sha2", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", +] + +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "serde_json" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +dependencies = [ + "indexmap 2.2.5", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_json_pythonic" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62212da9872ca2a0cad0093191ee33753eddff9266cbbc1b4a602d13a3a768db" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros 1.5.2", +] + +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "base64 0.13.1", + "chrono", + "hex", + "indexmap 1.9.3", + "serde", + "serde_json", + "serde_with_macros 2.3.3", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling 0.13.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling 0.20.8", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sha3-asm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac61da6b35ad76b195eb4771210f947734321a8d81d7738e1580d953bc7a15e" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "starknet" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f8002bf3d750dd2c0434aca8b5e88e2438cd6c452f4c18f34d0a8a9f42cb1a" +dependencies = [ + "starknet-accounts", + "starknet-contract", + "starknet-core", + "starknet-crypto", + "starknet-ff", + "starknet-macros", + "starknet-providers", + "starknet-signers", +] + +[[package]] +name = "starknet-accounts" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8e39a5807a735343493781dd5e640c4af838de470b0a73f420bed642fdc2ff1" +dependencies = [ + "async-trait", + "auto_impl", + "starknet-core", + "starknet-providers", + "starknet-signers", + "thiserror", +] + +[[package]] +name = "starknet-contract" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4996991356cd0e9499c663680eba7e77de4109e4995f652c1608899a65c09ee" +dependencies = [ + "serde", + "serde_json", + "serde_with 2.3.3", + "starknet-accounts", + "starknet-core", + "starknet-providers", + "thiserror", +] + +[[package]] +name = "starknet-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b15034c07557615f6bea248cb2ac91a103f56792c515319025a5edc4de2a60e" +dependencies = [ + "base64 0.21.7", + "flate2", + "hex", + "serde", + "serde_json", + "serde_json_pythonic", + "serde_with 2.3.3", + "sha3", + "starknet-crypto", + "starknet-ff", +] + +[[package]] +name = "starknet-crypto" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c03f5ac70f9b067f48db7d2d70bdf18ee0f731e8192b6cfa679136becfcdb0" +dependencies = [ + "crypto-bigint", + "hex", + "hmac", + "num-bigint", + "num-integer", + "num-traits", + "rfc6979", + "sha2", + "starknet-crypto-codegen", + "starknet-curve", + "starknet-ff", + "zeroize", +] + +[[package]] +name = "starknet-crypto-codegen" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af6527b845423542c8a16e060ea1bc43f67229848e7cd4c4d80be994a84220ce" +dependencies = [ + "starknet-curve", + "starknet-ff", + "syn 2.0.52", +] + +[[package]] +name = "starknet-curve" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63c454fecadfb3fe56ee82c405439d663c8a037667cc9d8e4acb1fb17e15b1af" +dependencies = [ + "starknet-ff", +] + +[[package]] +name = "starknet-ff" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "067419451efdea1ee968df8438369960c167e0e905c05b84afd074f50e1d6f3d" +dependencies = [ + "ark-ff 0.4.2", + "bigdecimal", + "crypto-bigint", + "getrandom", + "hex", + "num-bigint", + "serde", +] + +[[package]] +name = "starknet-macros" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5d2964612f0ccd0a700279e33cfc98d6db04f64645ff834f3b7ec422142d7a" +dependencies = [ + "starknet-core", + "syn 2.0.52", +] + +[[package]] +name = "starknet-providers" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a4bd1c262936543d6d14d299f476585e8c9625a4e284d9255b54f1c2e68e64a" +dependencies = [ + "async-trait", + "auto_impl", + "ethereum-types", + "flate2", + "log", + "reqwest", + "serde", + "serde_json", + "serde_with 2.3.3", + "starknet-core", + "thiserror", + "url", +] + +[[package]] +name = "starknet-signers" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c5eb659e66b56ceafb9025cd601226d8f34d273f1b826cd4053ab6333ff0898" +dependencies = [ + "async-trait", + "auto_impl", + "crypto-bigint", + "eth-keystore", + "rand", + "starknet-core", + "starknet-crypto", + "thiserror", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stringprep" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +dependencies = [ + "finl_unicode", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "svix-ksuid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66f014385b7fc154f59e9480770c2187b6e61037c2439895788a9a4d421d7859" +dependencies = [ + "base-encode", + "byteorder", + "getrandom", + "time", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3d0961cd53c23ea94eeec56ba940f636f6394788976e9f16ca5ee0aca7464a" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tcp-stream" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4da30af7998f51ee1aa48ab24276fe303a697b004e31ff542b192c088d5630a5" +dependencies = [ + "cfg-if", + "p12", + "rustls-connector", + "rustls-pemfile", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand 2.0.1", + "rustix 0.38.31", + "windows-sys 0.52.0", +] + +[[package]] +name = "thiserror" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.6", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-retry" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" +dependencies = [ + "pin-project", + "rand", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.2.5", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "tonic" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" +dependencies = [ + "async-stream", + "async-trait", + "axum 0.6.20", + "base64 0.21.7", + "bytes", + "flate2", + "h2 0.3.24", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "rustls", + "rustls-pemfile", + "tokio", + "tokio-rustls", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", + "webpki-roots", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "trust-dns-proto" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.2.3", + "ipnet", + "lazy_static", + "log", + "rand", + "smallvec", + "thiserror", + "tinyvec", + "tokio", + "url", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" +dependencies = [ + "cfg-if", + "futures-util", + "ipconfig", + "lazy_static", + "log", + "lru-cache", + "parking_lot", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "trust-dns-proto", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typed-builder" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna 0.5.0", + "percent-encoding", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "waker-fn" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.52", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..83ac7ef --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "madara-orchestrator" +version = "0.1.0" +edition = "2021" +authors = ["Apoorv Sadana <@apoorvsadana>"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +axum = { version = "0.7.4", features = ["macros"] } +axum-macros = "0.4.1" +tokio = { version = "1.36.0", features = ["sync", "macros", "rt-multi-thread"] } +tracing = "0.1.40" +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } +dotenvy = "0.15.7" +starknet = "0.9.0" +color-eyre = "0.6.2" +rstest = "0.18.2" +async-trait = "0.1.77" +alloy = { git = "https://github.com/alloy-rs/alloy", rev = "86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6", features = ["providers", "rpc-client", "transport-http"], optional = true } +reqwest = { version = "0.11.24", optional = true } +url = "2.5.0" +uuid = { version = "1.7.0", features = ["v4", "serde"] } +serde = { version = "1.0.197" } +futures = "0.3.30" +mongodb = { version = "2.8.1", features = ["bson-uuid-1"], optional = true } +omniqueue = { version = "0.2.0", optional = true } +thiserror = "1.0.57" +serde_json = "1.0.114" + +[features] +default = ["ethereum", "with_mongdb", "with_sqs"] +ethereum = ["alloy", "reqwest"] +with_mongdb = ["mongodb"] +with_sqs = ["omniqueue"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..33eb453 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Madara Orchestrator + +The Madara orchestrator is designed to be an additional service which runs in parallel to Madara and handles + +1. publishing data to the respective DA layer +2. running SNOS and submitting jobs to the prover +3. updating the state on Cairo core contracts + +As a v1, the orchestrator handles the DA publishing. The architecture for the same is as follows + +![orchestrator_da_sequencer_diagram](./docs/orchestrator_da_sequencer_diagram.png) \ No newline at end of file diff --git a/diesel.toml b/diesel.toml new file mode 100644 index 0000000..c028f4a --- /dev/null +++ b/diesel.toml @@ -0,0 +1,9 @@ +# For documentation on how to configure this file, +# see https://diesel.rs/guides/configuring-diesel-cli + +[print_schema] +file = "src/schema.rs" +custom_type_derives = ["diesel::query_builder::QueryId"] + +[migrations_directory] +dir = "migrations" diff --git a/docs/orchestrator_da_sequencer_diagram.png b/docs/orchestrator_da_sequencer_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..0575db64bb30effcb0b088749d0340bbac42b2c2 GIT binary patch literal 272128 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 z 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 Ma&SFRZBI@4H<0Y=6#xJL literal 0 HcmV?d00001 diff --git a/docs/orchestrator_da_sequencer_diagram.txt b/docs/orchestrator_da_sequencer_diagram.txt new file mode 100644 index 0000000..eca14f7 --- /dev/null +++ b/docs/orchestrator_da_sequencer_diagram.txt @@ -0,0 +1,53 @@ +title DA Service + +participant DA service +database DB +participant Madara + + +DA service->DB: get last updated block +DB-->DA service: last_updated_block +DA service->Madara: get latest block +Madara -->DA service: latest block +loop for each block +DA service->DB: insert new row with block_no\nas primary key, status as CREATED in da_tracker table +DB-->DA service:ok +DA service->Queue: process block_no, attempt 1 +end +group for each block +Queue-->DA service:receive message to process block_no, attemp_no (n) +alt case nDB: get block_no row from da_tracker +DB-->DA service: row +note over DA service: ensure row is in CREATED state\nand take a lock over it to avoid\nduplicate submissions +DA service->Madara: starknet_getStateUpdate +Madara-->DA service: state diffs +note over DA service: convert state diffs to calldata +DA service->DA layer: submit data blob +DA layer-->DA service: txn_hash +DA service->DB: update block_no with txn_hash and change status\nto SUBMITTED and release lock +DB-->DA service:ok +DA service->Queue: verify txn_hash with d delay, attempt 1 +Queue-->DA service: receive message to verify txn hash +DA service->DA layer: check txn inclusion +alt case transaction is finalized +DA layer-->DA service: txn has been finalized +DA service->DB: update block_no row to SUCCESS +DB-->DA service:ok +else case transaction is still pending +DA layer-->DA service: txn hasn't been finalized yet +alt case n < MAX_ATTEMPTS_VERIFICATION +DA service->Queue: verify txn_hash with d delay, attempt n+1 +else case n >= MAX_ATTEMPTS_VERIFICATION +DA service->DB: update block_no to TIMED_OUT_VERIFICATION and raise alert +DB-->DA service: ok +end +else case txn has been rejected/orphaned +DA layer-->DA service: txn failed/not found +DA service->Queue: process block_no, attempt n+1 +end +else case n>=MAX_ATTEMPTS_SUBMISSION +DA service->DB:update block_no to TIMED_OUT_SUBMISSION and raise alert +DB-->DA service:ok +end +end \ No newline at end of file diff --git a/migrations/.DS_Store b/migrations/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..60e51e56ddd77652cc36abb4b383072dd075bf78 GIT binary patch literal 6148 zcmeH~y-EW?5XWcrgrH3t!OjI=z=L40JHz<|0UL`mF~JWmUcjWXx!$L;u(Ghy$~W*O z{LjwlB_tM+_<_tEv;X~?x$F=2HcLdVHSWbkbt0<4S)+9nbBxE?XKY1#c+iC$yHq_h z)2+h@7=b@VfcNgs#ICLO?|Uty9$iqMuHiXls9(WH@J?uR|A@vk%+KQXX)zee3fJzI zmw8a6X*Vyr$XI(kzIl0ixIb8C_TD#UAD&NA@%Y)aNij9Se4qC4G^v4h17t6$pe{IP z;MqYfr~WikceGgaB)8k`?Dbi=E%5$9QL*`2hB@nJ24=rc0B1H^Z9~*bBVYuKzy|^T zK6p55qFRcEPX~%{1%O8A4u(44B{;^bCaR?uelhezG z(>FW4p}6pNXxF~I>Ei6gT)|tie tS?l2^a5kP-iiQvrdK`xeAH`enU>NgUfhMY@D0*P_M<8IZ!U+5*fj8WRff4`! literal 0 HcmV?d00001 diff --git a/migrations/.keep b/migrations/.keep new file mode 100644 index 0000000..e69de29 diff --git a/migrations/00000000000000_diesel_initial_setup/down.sql b/migrations/00000000000000_diesel_initial_setup/down.sql new file mode 100644 index 0000000..a9f5260 --- /dev/null +++ b/migrations/00000000000000_diesel_initial_setup/down.sql @@ -0,0 +1,6 @@ +-- This file was automatically created by Diesel to setup helper functions +-- and other internal bookkeeping. This file is safe to edit, any future +-- changes will be added to existing projects as new migrations. + +DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass); +DROP FUNCTION IF EXISTS diesel_set_updated_at(); diff --git a/migrations/00000000000000_diesel_initial_setup/up.sql b/migrations/00000000000000_diesel_initial_setup/up.sql new file mode 100644 index 0000000..d68895b --- /dev/null +++ b/migrations/00000000000000_diesel_initial_setup/up.sql @@ -0,0 +1,36 @@ +-- This file was automatically created by Diesel to setup helper functions +-- and other internal bookkeeping. This file is safe to edit, any future +-- changes will be added to existing projects as new migrations. + + + + +-- Sets up a trigger for the given table to automatically set a column called +-- `updated_at` whenever the row is modified (unless `updated_at` was included +-- in the modified columns) +-- +-- # Example +-- +-- ```sql +-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW()); +-- +-- SELECT diesel_manage_updated_at('users'); +-- ``` +CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$ +BEGIN + EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s + FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$ +BEGIN + IF ( + NEW IS DISTINCT FROM OLD AND + NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at + ) THEN + NEW.updated_at := current_timestamp; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; diff --git a/migrations/1709667414_jobs_table/down.sql b/migrations/1709667414_jobs_table/down.sql new file mode 100644 index 0000000..b23f8f7 --- /dev/null +++ b/migrations/1709667414_jobs_table/down.sql @@ -0,0 +1 @@ +DROP TABLE jobs; \ No newline at end of file diff --git a/migrations/1709667414_jobs_table/up.sql b/migrations/1709667414_jobs_table/up.sql new file mode 100644 index 0000000..be4f0ca --- /dev/null +++ b/migrations/1709667414_jobs_table/up.sql @@ -0,0 +1,11 @@ +CREATE TABLE jobs +( + id VARCHAR(255) PRIMARY KEY, + status VARCHAR(255) NOT NULL, + external_id VARCHAR(255), + metadata JSON, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +SELECT diesel_manage_updated_at('jobs'); \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..af44f68 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,20 @@ +edition = "2021" +newline_style = "Unix" +use_field_init_shorthand = true +use_small_heuristics = "Max" +use_try_shorthand = true +max_width = 120 + +# Unstable features below +unstable_features = true +version = "Two" +comment_width = 100 +format_code_in_doc_comments = true +format_macro_bodies = true +format_macro_matchers = true +format_strings = true +imports_granularity = "Module" +group_imports = "StdExternalCrate" +normalize_comments = true +normalize_doc_attributes = true +wrap_comments = true diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..69a7bb33078a152e2fc509172b26d1b5b0bb1e45 GIT binary patch literal 6148 zcmeHLzb^zq6n?`>7L9^XZXpyJSL&9WMxv1W18`3K$e#7%B+C5{s70dFDpZO~Bur=Z1Mls1o5duCr9P_AGA)92L>qY5F!MIHezlXI&Gr0Y zt@r*`bIl#I8n>8!=bOXR*F0Ns>*uBinQM4rqV_BAzR~%cy>|Zj#^vL@JR?@Toj>0rCqHZO zmket*o8K?!YNvoxz$wsFfZq=R3S($65!9~^RC)^l^w6vg$Gn%|n809YFcCx#Oi3tE zLY3KKC<#Y_yk-=+v@-T literal 0 HcmV?d00001 diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..ccdbe5d --- /dev/null +++ b/src/config.rs @@ -0,0 +1,72 @@ +use crate::da_clients::ethereum::config::EthereumDaConfig; +use crate::da_clients::ethereum::EthereumDaClient; +use crate::da_clients::{DaClient, DaConfig}; +use crate::database::mongodb::config::MongoDbConfig; +use crate::database::mongodb::MongoDb; +use crate::database::{Database, DatabaseConfig}; +use crate::queue::sqs::SqsQueue; +use crate::queue::{init_consumers, QueueProvider}; +use crate::utils::env_utils::get_env_var_or_panic; +use dotenvy::dotenv; +use starknet::providers::jsonrpc::HttpTransport; +use starknet::providers::{JsonRpcClient, Url}; +use std::sync::Arc; +use tokio::sync::OnceCell; + +pub struct Config { + starknet_client: Arc>, + da_client: Box, + database: Box, + queue: Box, +} + +impl Config { + pub fn starknet_client(&self) -> &Arc> { + &self.starknet_client + } + + pub fn da_client(&self) -> &Box { + &self.da_client + } + + pub fn database(&self) -> &Box { + &self.database + } + + pub fn queue(&self) -> &Box { + &self.queue + } +} + +pub static CONFIG: OnceCell = OnceCell::const_new(); + +async fn init_config() -> Config { + dotenv().ok(); + + // init starknet client + let provider = JsonRpcClient::new(HttpTransport::new( + Url::parse(get_env_var_or_panic("MADARA_RPC_URL").as_str()).expect("Failed to parse URL"), + )); + + // init database + let database = Box::new(MongoDb::new(MongoDbConfig::new_from_env()).await); + + // init the queue + let queue = Box::new(SqsQueue {}); + + Config { starknet_client: Arc::new(provider), da_client: build_da_client(), database, queue } +} + +pub async fn config() -> &'static Config { + CONFIG.get_or_init(init_config).await +} + +fn build_da_client() -> Box { + match get_env_var_or_panic("DA_LAYER").as_str() { + "ethereum" => { + let config = EthereumDaConfig::new_from_env(); + return Box::new(EthereumDaClient::from(config)); + } + _ => panic!("Unsupported DA layer"), + } +} diff --git a/src/controllers/errors.rs b/src/controllers/errors.rs new file mode 100644 index 0000000..6bd3d4c --- /dev/null +++ b/src/controllers/errors.rs @@ -0,0 +1,21 @@ +use axum::response::IntoResponse; +use axum::Json; +use color_eyre::eyre::ErrReport; +use serde_json::json; +use tracing::log; + +#[derive(thiserror::Error, Debug)] +pub enum AppError { + #[error("Internal Server Error {0}")] + InternalServerError(#[from] ErrReport), +} + +impl IntoResponse for AppError { + fn into_response(self) -> axum::http::Response { + log::error!("Error: {:?}", self); + let (status, err_msg) = match self { + Self::InternalServerError(msg) => (axum::http::StatusCode::INTERNAL_SERVER_ERROR, msg.to_string()), + }; + (status, Json(json!({"message": err_msg }))).into_response() + } +} diff --git a/src/controllers/jobs_controller.rs b/src/controllers/jobs_controller.rs new file mode 100644 index 0000000..9d0d117 --- /dev/null +++ b/src/controllers/jobs_controller.rs @@ -0,0 +1,20 @@ +use crate::controllers::errors::AppError; +use crate::jobs::types::JobType; +use crate::AppState; +use axum::extract::Json; +use axum::extract::State; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct CreateJobRequest { + job_type: JobType, + internal_id: String, +} + +pub async fn create_job( + State(state): State, + Json(payload): Json, +) -> Result, AppError> { + crate::jobs::create_job(payload.job_type, payload.internal_id).await?; + Ok(Json::from(())) +} diff --git a/src/controllers/mod.rs b/src/controllers/mod.rs new file mode 100644 index 0000000..2246a30 --- /dev/null +++ b/src/controllers/mod.rs @@ -0,0 +1,2 @@ +mod errors; +pub mod jobs_controller; diff --git a/src/da_clients/ethereum/config.rs b/src/da_clients/ethereum/config.rs new file mode 100644 index 0000000..9a7278b --- /dev/null +++ b/src/da_clients/ethereum/config.rs @@ -0,0 +1,22 @@ +use crate::da_clients::DaConfig; +use crate::utils::env_utils::get_env_var_or_panic; +use alloy::rpc::client::RpcClient; +use alloy::transports::http::Http; +use reqwest::Client; +use std::str::FromStr; +use url::Url; + +#[derive(Clone, Debug)] +pub struct EthereumDaConfig { + pub rpc_url: String, + pub memory_pages_contract: String, +} + +impl DaConfig for EthereumDaConfig { + fn new_from_env() -> Self { + Self { + rpc_url: get_env_var_or_panic("ETHEREUM_RPC_URL"), + memory_pages_contract: get_env_var_or_panic("MEMORY_PAGES_CONTRACT_ADDRESS"), + } + } +} diff --git a/src/da_clients/ethereum/mod.rs b/src/da_clients/ethereum/mod.rs new file mode 100644 index 0000000..8b3064d --- /dev/null +++ b/src/da_clients/ethereum/mod.rs @@ -0,0 +1,36 @@ +use alloy::rpc::client::RpcClient; +use alloy::transports::http::Http; +use async_trait::async_trait; +use color_eyre::Result; +use reqwest::Client; +use starknet::core::types::FieldElement; +use std::str::FromStr; +use url::Url; + +use crate::da_clients::ethereum::config::EthereumDaConfig; +use crate::da_clients::DaClient; +use crate::jobs::types::JobVerificationStatus; + +pub mod config; +pub struct EthereumDaClient { + provider: RpcClient>, +} + +#[async_trait] +impl DaClient for EthereumDaClient { + async fn publish_state_diff(&self, state_diff: Vec) -> Result { + unimplemented!() + } + + async fn verify_inclusion(&self, external_id: &String) -> Result { + todo!() + } +} + +impl From for EthereumDaClient { + fn from(config: EthereumDaConfig) -> Self { + let provider = RpcClient::builder() + .reqwest_http(Url::from_str(config.rpc_url.as_str()).expect("Failed to parse ETHEREUM_RPC_URL")); + EthereumDaClient { provider } + } +} diff --git a/src/da_clients/mod.rs b/src/da_clients/mod.rs new file mode 100644 index 0000000..464b4c6 --- /dev/null +++ b/src/da_clients/mod.rs @@ -0,0 +1,21 @@ +use crate::jobs::types::JobVerificationStatus; +use axum::async_trait; +use color_eyre::Result; +use starknet::core::types::FieldElement; + +pub mod ethereum; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum DaLayer { + Ethereum, +} + +#[async_trait] +pub trait DaClient: Send + Sync { + async fn publish_state_diff(&self, state_diff: Vec) -> Result; + async fn verify_inclusion(&self, external_id: &String) -> Result; +} + +pub trait DaConfig { + fn new_from_env() -> Self; +} diff --git a/src/database/mod.rs b/src/database/mod.rs new file mode 100644 index 0000000..a55874a --- /dev/null +++ b/src/database/mod.rs @@ -0,0 +1,41 @@ +use crate::jobs::types::{JobItem, JobStatus, JobType}; +use async_trait::async_trait; +use color_eyre::Result; +use std::collections::HashMap; +use uuid::Uuid; + +pub mod mongodb; + +/// The Database trait is used to define the methods that a database +/// should implement to be used as a storage for the orchestrator. The +/// purpose of this trait is to allow developers to use any DB of their choice +/// as long as they implement the trait +/// +/// The Database should support optimistic locking. For example, assume we've two threads +/// A and B and both read the same Job entry J at nearly the same time. If A updates J at +/// time T1 and then B updates J at time T2 (T2>T1), then B's update should fail because +/// it's version of J is outdated. +#[async_trait] +pub trait Database: Send + Sync { + async fn create_job(&self, job: JobItem) -> Result; + async fn get_job_by_id(&self, id: Uuid) -> Result>; + async fn get_job_by_internal_id_and_type( + &self, + internal_id: &String, + job_type: &JobType, + ) -> Result>; + async fn update_job_status(&self, job: &JobItem, new_status: JobStatus) -> Result<()>; + async fn update_external_id_and_status_and_metadata( + &self, + job: &JobItem, + external_id: String, + new_status: JobStatus, + metadata: HashMap, + ) -> Result<()>; + + async fn update_metadata(&self, job: &JobItem, metadata: HashMap) -> Result<()>; +} + +pub trait DatabaseConfig { + fn new_from_env() -> Self; +} diff --git a/src/database/mongodb/config.rs b/src/database/mongodb/config.rs new file mode 100644 index 0000000..aea02a4 --- /dev/null +++ b/src/database/mongodb/config.rs @@ -0,0 +1,12 @@ +use crate::database::DatabaseConfig; +use crate::utils::env_utils::get_env_var_or_panic; + +pub struct MongoDbConfig { + pub url: String, +} + +impl DatabaseConfig for MongoDbConfig { + fn new_from_env() -> Self { + Self { url: get_env_var_or_panic("MONGODB_CONNECTION_STRING") } + } +} diff --git a/src/database/mongodb/mod.rs b/src/database/mongodb/mod.rs new file mode 100644 index 0000000..1e77866 --- /dev/null +++ b/src/database/mongodb/mod.rs @@ -0,0 +1,122 @@ +use crate::database::mongodb::config::MongoDbConfig; +use crate::database::Database; +use crate::jobs::types::{JobItem, JobStatus, JobType}; +use async_trait::async_trait; +use color_eyre::eyre::eyre; +use color_eyre::Result; +use mongodb::bson::{Bson, Document}; +use mongodb::options::UpdateOptions; +use mongodb::{ + bson::doc, + options::{ClientOptions, ServerApi, ServerApiVersion}, + Client, Collection, +}; +use std::collections::HashMap; +use uuid::Uuid; + +pub mod config; + +pub struct MongoDb { + client: Client, +} + +impl MongoDb { + pub async fn new(config: MongoDbConfig) -> Self { + let mut client_options = ClientOptions::parse(config.url).await.expect("Failed to parse MongoDB Url"); + // Set the server_api field of the client_options object to set the version of the Stable API on the client + let server_api = ServerApi::builder().version(ServerApiVersion::V1).build(); + client_options.server_api = Some(server_api); + // Get a handle to the cluster + let client = Client::with_options(client_options).expect("Failed to create MongoDB client"); + // Ping the server to see if you can connect to the cluster + client.database("admin").run_command(doc! {"ping": 1}, None).await.expect("Failed to ping MongoDB deployment"); + println!("Pinged your deployment. You successfully connected to MongoDB!"); + + MongoDb { client } + } + + fn get_job_collection(&self) -> Collection { + self.client.database("orchestrator").collection("jobs") + } + + /// Updates the job in the database optimistically. This means that the job is updated only if the + /// version of the job in the database is the same as the version of the job passed in. If the version + /// is different, the update fails. + async fn update_job_optimistically(&self, current_job: &JobItem, update: Document) -> Result<()> { + let filter = doc! { + "id": current_job.id, + "version": current_job.version, + }; + let options = UpdateOptions::builder().upsert(false).build(); + let result = self.get_job_collection().update_one(filter, update, options).await?; + if result.modified_count == 0 { + return Err(eyre!("Failed to update job. Job version is likely outdated")); + } + Ok(()) + } +} + +#[async_trait] +impl Database for MongoDb { + async fn create_job(&self, job: JobItem) -> Result { + self.get_job_collection().insert_one(&job, None).await?; + Ok(job) + } + + async fn get_job_by_id(&self, id: Uuid) -> Result> { + let filter = doc! { + "id": id + }; + Ok(self.get_job_collection().find_one(filter, None).await?) + } + + async fn get_job_by_internal_id_and_type( + &self, + internal_id: &String, + job_type: &JobType, + ) -> Result> { + let filter = doc! { + "internal_id": internal_id, + "job_type": mongodb::bson::to_bson(&job_type)?, + }; + Ok(self.get_job_collection().find_one(filter, None).await?) + } + + async fn update_job_status(&self, job: &JobItem, new_status: JobStatus) -> Result<()> { + let update = doc! { + "$set": { + "status": mongodb::bson::to_bson(&new_status)?, + } + }; + self.update_job_optimistically(job, update).await?; + Ok(()) + } + + async fn update_external_id_and_status_and_metadata( + &self, + job: &JobItem, + external_id: String, + new_status: JobStatus, + metadata: HashMap, + ) -> Result<()> { + let update = doc! { + "$set": { + "status": mongodb::bson::to_bson(&new_status)?, + "external_id": external_id, + "metadata": mongodb::bson::to_document(&metadata)? + } + }; + self.update_job_optimistically(job, update).await?; + Ok(()) + } + + async fn update_metadata(&self, job: &JobItem, metadata: HashMap) -> Result<()> { + let update = doc! { + "$set": { + "metadata": mongodb::bson::to_document(&metadata)? + } + }; + self.update_job_optimistically(job, update).await?; + Ok(()) + } +} diff --git a/src/jobs/constants.rs b/src/jobs/constants.rs new file mode 100644 index 0000000..47a2cae --- /dev/null +++ b/src/jobs/constants.rs @@ -0,0 +1,2 @@ +pub const JOB_PROCESS_ATTEMPT_METADATA_KEY: &str = "process_attempt_no"; +pub const JOB_VERIFICATION_ATTEMPT_METADATA_KEY: &str = "verification_attempt_no"; diff --git a/src/jobs/da_job/mod.rs b/src/jobs/da_job/mod.rs new file mode 100644 index 0000000..a879dac --- /dev/null +++ b/src/jobs/da_job/mod.rs @@ -0,0 +1,182 @@ +use crate::config::Config; +use crate::jobs::types::{JobItem, JobStatus, JobType, JobVerificationStatus}; +use crate::jobs::{increment_key_in_metadata, Job}; +use async_trait::async_trait; +use color_eyre::eyre::eyre; +use color_eyre::Result; +use starknet::core::types::{BlockId, FieldElement, MaybePendingStateUpdate, StateUpdate, StorageEntry}; +use starknet::providers::Provider; +use std::collections::HashMap; +use tracing::log; +use uuid::Uuid; + +pub struct DaJob; + +#[async_trait] +impl Job for DaJob { + async fn create_job(&self, config: &Config, internal_id: String) -> Result { + Ok(JobItem { + id: Uuid::new_v4(), + internal_id, + job_type: JobType::DataSubmission, + status: JobStatus::Created, + external_id: String::new(), + metadata: HashMap::new(), + version: 0, + }) + } + + async fn process_job(&self, config: &Config, job: &JobItem) -> Result { + let block_no = job.internal_id.parse::()?; + let state_update = config.starknet_client().get_state_update(BlockId::Number(block_no)).await?; + + let state_update = match state_update { + MaybePendingStateUpdate::PendingUpdate(_) => { + log::error!("Cannot process block {} for job id {} as it's still in pending state", block_no, job.id); + return Err(eyre!( + "Cannot process block {} for job id {} as it's still in pending state", + block_no, + job.id + )); + } + MaybePendingStateUpdate::Update(state_update) => state_update, + }; + + let blob_data = state_update_to_blob_data(block_no, state_update); + let external_id = config.da_client().publish_state_diff(blob_data).await?; + + Ok(external_id) + } + + async fn verify_job(&self, config: &Config, job: &JobItem) -> Result { + Ok(config.da_client().verify_inclusion(&job.external_id).await?) + } + + fn max_process_attempts(&self) -> u64 { + 1 + } + + fn max_verification_attempts(&self) -> u64 { + 3 + } + + fn verification_polling_delay_seconds(&self) -> u64 { + 60 + } +} + +fn state_update_to_blob_data(block_no: u64, state_update: StateUpdate) -> Vec { + let state_diff = state_update.state_diff; + let mut blob_data: Vec = vec![ + // TODO: confirm first three fields + FieldElement::from(state_diff.storage_diffs.len()), + FieldElement::ONE, + FieldElement::ONE, + FieldElement::from(block_no), + state_update.block_hash, + ]; + + let storage_diffs: HashMap> = + state_diff.storage_diffs.iter().map(|item| (item.address, &item.storage_entries)).collect(); + let declared_classes: HashMap = + state_diff.declared_classes.iter().map(|item| (item.class_hash, item.compiled_class_hash)).collect(); + let deployed_contracts: HashMap = + state_diff.deployed_contracts.iter().map(|item| (item.address, item.class_hash)).collect(); + let replaced_classes: HashMap = + state_diff.replaced_classes.iter().map(|item| (item.contract_address, item.class_hash)).collect(); + let mut nonces: HashMap = + state_diff.nonces.iter().map(|item| (item.contract_address, item.nonce)).collect(); + + // Loop over storage diffs + for (addr, writes) in storage_diffs { + blob_data.push(addr.clone()); + + let class_flag = deployed_contracts.get(&addr).or_else(|| replaced_classes.get(&addr)); + + let nonce = nonces.remove(&addr); + blob_data.push(da_word(class_flag.is_some(), nonce, writes.len() as u64)); + + if let Some(class_hash) = class_flag { + blob_data.push(class_hash.clone()); + } + + for entry in writes { + blob_data.push(entry.key); + blob_data.push(entry.value); + } + } + + // Handle nonces + for (addr, nonce) in nonces { + blob_data.push(addr); + + let class_flag = deployed_contracts.get(&addr).or_else(|| replaced_classes.get(&addr)); + + blob_data.push(da_word(class_flag.is_some(), Some(nonce), 0_u64)); + if let Some(class_hash) = class_flag { + blob_data.push(class_hash.clone()); + } + } + + // Handle deployed contracts + for (addr, class_hash) in deployed_contracts { + blob_data.push(addr); + + blob_data.push(da_word(true, None, 0_u64)); + blob_data.push(class_hash); + } + + // Handle declared classes + blob_data.push(FieldElement::from(declared_classes.len())); + + for (class_hash, compiled_class_hash) in &declared_classes { + blob_data.push(class_hash.clone()); + blob_data.push(compiled_class_hash.clone()); + } + + blob_data +} + +/// DA word encoding: +/// |---padding---|---class flag---|---new nonce---|---num changes---| +/// 127 bits 1 bit 64 bits 64 bits +fn da_word(class_flag: bool, nonce_change: Option, num_changes: u64) -> FieldElement { + const CLASS_FLAG_TRUE: &str = "0x100000000000000000000000000000001"; // 2 ^ 128 + 1 + const NONCE_BASE: &str = "0xFFFFFFFFFFFFFFFF"; // 2 ^ 64 - 1 + + let mut word = FieldElement::ZERO; + + if class_flag { + word += FieldElement::from_hex_be(CLASS_FLAG_TRUE).unwrap(); + } + if let Some(new_nonce) = nonce_change { + word += new_nonce + FieldElement::from_hex_be(NONCE_BASE).unwrap(); + } + + word += FieldElement::from(num_changes); + + word +} + +#[cfg(test)] +mod tests { + use super::*; + use rstest::rstest; + + #[rstest] + #[case(false, 1, 1, "18446744073709551617")] + #[case(false, 1, 0, "18446744073709551616")] + #[case(false, 0, 6, "6")] + #[case(true, 1, 0, "340282366920938463481821351505477763073")] + fn da_word_works( + #[case] class_flag: bool, + #[case] new_nonce: u64, + #[case] num_changes: u64, + #[case] expected: String, + ) { + let new_nonce = if new_nonce > 0 { Some(FieldElement::from(new_nonce)) } else { None }; + let da_word = da_word(class_flag, new_nonce, num_changes); + let expected = FieldElement::from_dec_str(expected.as_str()).unwrap(); + assert_eq!(da_word, expected); + } +} diff --git a/src/jobs/mod.rs b/src/jobs/mod.rs new file mode 100644 index 0000000..d823852 --- /dev/null +++ b/src/jobs/mod.rs @@ -0,0 +1,158 @@ +use crate::config::{config, Config}; +use crate::jobs::constants::JOB_PROCESS_ATTEMPT_METADATA_KEY; +use crate::jobs::types::{JobItem, JobStatus, JobType, JobVerificationStatus}; +use crate::queue::job_queue::{add_job_to_process_queue, add_job_to_verification_queue}; +use async_trait::async_trait; +use color_eyre::eyre::eyre; +use color_eyre::Result; +use std::collections::HashMap; +use std::time::Duration; +use tracing::log; +use uuid::Uuid; + +mod constants; +pub mod da_job; +pub mod types; + +#[async_trait] +pub trait Job: Send + Sync { + async fn create_job(&self, config: &Config, internal_id: String) -> Result; + async fn process_job(&self, config: &Config, job: &JobItem) -> Result; + async fn verify_job(&self, config: &Config, job: &JobItem) -> Result; + fn max_process_attempts(&self) -> u64; + fn max_verification_attempts(&self) -> u64; + fn verification_polling_delay_seconds(&self) -> u64; +} + +pub async fn create_job(job_type: JobType, internal_id: String) -> Result<()> { + let config = config().await; + let existing_job = config.database().get_job_by_internal_id_and_type(&internal_id, &job_type).await?; + if existing_job.is_some() { + log::debug!("Job already exists for internal_id {:?} and job_type {:?}. Skipping.", internal_id, job_type); + return Err(eyre!( + "Job already exists for internal_id {:?} and job_type {:?}. Skipping.", + internal_id, + job_type + )); + } + + let job_handler = get_job_handler(&job_type); + let job_item = job_handler.create_job(config, internal_id).await?; + config.database().create_job(job_item.clone()).await?; + + add_job_to_process_queue(job_item.id).await?; + Ok(()) +} + +pub async fn process_job(id: Uuid) -> Result<()> { + let config = config().await; + let job = get_job(id).await?; + + match job.status { + // we only want to process jobs that are in the created or verification failed state. + // verification failed state means that the previous processing failed and we want to retry + JobStatus::Created | JobStatus::VerificationFailed => { + log::info!("Processing job with id {:?}", id); + } + _ => { + log::error!("Invalid status {:?} for job with id {:?}. Cannot process.", id, job.status); + return Err(eyre!("Invalid status {:?} for job with id {:?}. Cannot process.", id, job.status)); + } + } + // this updates the version of the job. this ensures that if another thread was about to process + // the same job, it would fail to update the job in the database because the version would be outdated + config.database().update_job_status(&job, JobStatus::LockedForProcessing).await?; + + let job_handler = get_job_handler(&job.job_type); + let external_id = job_handler.process_job(config, &job).await?; + + let metadata = increment_key_in_metadata(&job.metadata, JOB_PROCESS_ATTEMPT_METADATA_KEY)?; + config + .database() + .update_external_id_and_status_and_metadata(&job, external_id, JobStatus::PendingVerification, metadata) + .await?; + + add_job_to_verification_queue(job.id, Duration::from_secs(job_handler.verification_polling_delay_seconds())) + .await?; + + Ok(()) +} + +pub async fn verify_job(id: Uuid) -> Result<()> { + let config = config().await; + let job = get_job(id).await?; + + match job.status { + JobStatus::PendingVerification => { + log::info!("Verifying job with id {:?}", id); + } + _ => { + log::error!("Invalid status {:?} for job with id {:?}. Cannot verify.", id, job.status); + return Err(eyre!("Invalid status {:?} for job with id {:?}. Cannot verify.", id, job.status)); + } + } + + let job_handler = get_job_handler(&job.job_type); + let verification_status = job_handler.verify_job(config, &job).await?; + + match verification_status { + JobVerificationStatus::VERIFIED => { + config.database().update_job_status(&job, JobStatus::Completed).await?; + } + JobVerificationStatus::REJECTED => { + config.database().update_job_status(&job, JobStatus::VerificationFailed).await?; + + // retry job processing if we haven't exceeded the max limit + let process_attempts = get_u64_from_metadata(&job.metadata, JOB_PROCESS_ATTEMPT_METADATA_KEY)?; + if process_attempts < job_handler.max_process_attempts() { + log::info!( + "Verification failed for job {}. Retrying processing attempt {}.", + job.id, + process_attempts + 1 + ); + add_job_to_process_queue(job.id).await?; + return Ok(()); + } + } + JobVerificationStatus::PENDING => { + log::info!("Inclusion is still pending for job {}. Pushing back to queue.", job.id); + add_job_to_verification_queue( + job.id, + Duration::from_secs(job_handler.verification_polling_delay_seconds()), + ) + .await?; + } + }; + + Ok(()) +} + +fn get_job_handler(job_type: &JobType) -> Box { + match job_type { + JobType::DataSubmission => Box::new(da_job::DaJob), + _ => unimplemented!("Job type not implemented yet."), + } +} + +async fn get_job(id: Uuid) -> Result { + let config = config().await; + let job = config.database().get_job_by_id(id).await?; + match job { + Some(job) => Ok(job), + None => { + log::error!("Failed to find job with id {:?}", id); + return Err(eyre!("Failed to process job with id {:?}", id)); + } + } +} + +fn increment_key_in_metadata(metadata: &HashMap, key: &str) -> Result> { + let mut new_metadata = metadata.clone(); + let attempt = metadata.get(key).unwrap_or(&"0".to_string()).parse::()?; + new_metadata.insert(key.to_string(), (attempt + 1).to_string()); + Ok(new_metadata) +} + +fn get_u64_from_metadata(metadata: &HashMap, key: &str) -> Result { + Ok(metadata.get(key).unwrap_or(&"0".to_string()).parse::()?) +} diff --git a/src/jobs/types.rs b/src/jobs/types.rs new file mode 100644 index 0000000..a6ee471 --- /dev/null +++ b/src/jobs/types.rs @@ -0,0 +1,61 @@ +use mongodb::bson::serde_helpers::uuid_1_as_binary; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use uuid::Uuid; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum JobType { + /// Submitting DA data to the DA layer + DataSubmission, + /// Getting a proof from the proving service + ProofCreation, + /// Verifying the proof on the base layer + ProofVerification, + /// Updaing the state root on the base layer + StateUpdation, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum JobStatus { + /// An acknowledgement that the job has been received by the + /// orchestrator and is waiting to be processed + Created, + /// Some system has taken a lock over the job for processing and no + /// other system to process the job + LockedForProcessing, + /// The job has been processed and is pending verification + PendingVerification, + /// The job has been processed and verified. No other actions needs to be taken + Completed, + /// The job was processed but the was unable to be verified under the given time + VerificationTimeout, + /// The job failed processing + VerificationFailed, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct JobItem { + /// an uuid to identify a job + #[serde(with = "uuid_1_as_binary")] + pub id: Uuid, + /// a meaningful id used to track a job internally, ex: block_no, txn_hash + pub internal_id: String, + /// the type of job + pub job_type: JobType, + /// the status of the job + pub status: JobStatus, + /// external id to track the status of the job. for ex, txn hash for blob inclusion + /// or job_id from SHARP + pub external_id: String, + /// additional field to store values related to the job + pub metadata: HashMap, + /// helps to keep track of the version of the item for optimistic locking + pub version: i32, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum JobVerificationStatus { + PENDING, + VERIFIED, + REJECTED, +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..bd15f98 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,38 @@ +mod config; +mod da_clients; +mod database; +mod jobs; +mod queue; +mod routes; +mod utils; +mod controllers; + +use crate::config::config; +use crate::queue::init_consumers; +use crate::routes::app_router; +use crate::utils::env_utils::get_env_var_or_default; +use dotenvy::dotenv; + +#[derive(Clone)] +pub struct AppState {} + +#[tokio::main] +async fn main() { + dotenv().ok(); + tracing_subscriber::fmt().with_max_level(tracing::Level::INFO).with_target(false).init(); + + // initial config setup + config().await; + let host = get_env_var_or_default("HOST", "127.0.0.1"); + let port = get_env_var_or_default("PORT", "3000").parse::().expect("PORT must be a u16"); + let address = format!("{}:{}", host, port); + let listener = tokio::net::TcpListener::bind(address.clone()).await.expect("Failed to get listener"); + let state = AppState {}; + let app = app_router(state.clone()).with_state(state); + + // init consumer + init_consumers().await.expect("Failed to init consumers"); + + tracing::info!("Listening on http://{}", address); + axum::serve(listener, app).await.expect("Failed to start axum server"); +} diff --git a/src/queue/job_queue.rs b/src/queue/job_queue.rs new file mode 100644 index 0000000..78fbd28 --- /dev/null +++ b/src/queue/job_queue.rs @@ -0,0 +1,97 @@ +use crate::config::config; +use crate::jobs::{process_job, verify_job}; +use color_eyre::eyre::eyre; +use color_eyre::Result; +use omniqueue::QueueError; +use serde::{Deserialize, Serialize}; +use std::future::Future; +use std::time::Duration; +use tokio::time::sleep; +use tracing::log; +use uuid::Uuid; + +const JOB_PROCESSING_QUEUE: &str = "madara_orchestrator_job_processing_queue"; +const JOB_VERIFICATION_QUEUE: &str = "madara_orchestrator_job_verification_queue"; + +#[derive(Debug, Serialize, Deserialize)] +struct JobQueueMessage { + id: Uuid, +} + +pub async fn add_job_to_process_queue(id: Uuid) -> Result<()> { + log::info!("Adding job with id {:?} to processing queue", id); + add_job_to_queue(id, JOB_PROCESSING_QUEUE.to_string(), None).await +} + +pub async fn add_job_to_verification_queue(id: Uuid, delay: Duration) -> Result<()> { + log::info!("Adding job with id {:?} to verification queue", id); + add_job_to_queue(id, JOB_VERIFICATION_QUEUE.to_string(), Some(delay)).await +} + +pub async fn consume_job_from_queue(queue: String, handler: F) -> Result<()> +where + F: FnOnce(Uuid) -> Fut, + Fut: Future>, +{ + log::info!("Consuming from queue {:?}", queue); + let config = config().await; + let delivery = match config.queue().consume_message_from_queue(queue.clone()).await { + Ok(d) => d, + Err(QueueError::NoData) => { + return Ok(()); + } + Err(e) => { + return Err(eyre!("Failed to consume message from queue, error {}", e)); + } + }; + let job_message: Option = delivery.payload_serde_json()?; + + match job_message { + Some(job_message) => { + log::info!("Handling job with id {:?} for queue {:?}", job_message.id, queue); + match handler(job_message.id).await { + Ok(_) => delivery.ack().await.map_err(|(e, _)| e)?, + Err(e) => { + log::error!("Failed to handle job with id {:?}. Error: {:?}", job_message.id, e); + + // if the queue as a retry logic at the source, it will be attempted + // after the nack + delivery.nack().await.map_err(|(e, _)| e)?; + } + }; + } + None => return Ok(()), + }; + + Ok(()) +} + +pub async fn init_consumers() -> Result<()> { + // TODO: figure out a way to generalize this + tokio::spawn(async move { + loop { + match consume_job_from_queue(JOB_PROCESSING_QUEUE.to_string(), process_job).await { + Ok(_) => {} + Err(e) => log::error!("Failed to consume from queue {:?}. Error: {:?}", JOB_PROCESSING_QUEUE, e), + } + sleep(Duration::from_secs(1)).await; + } + }); + tokio::spawn(async move { + loop { + match consume_job_from_queue(JOB_VERIFICATION_QUEUE.to_string(), verify_job).await { + Ok(_) => {} + Err(e) => log::error!("Failed to consume from queue {:?}. Error: {:?}", JOB_VERIFICATION_QUEUE, e), + } + sleep(Duration::from_secs(1)).await; + } + }); + Ok(()) +} + +async fn add_job_to_queue(id: Uuid, queue: String, delay: Option) -> Result<()> { + let config = config().await; + let message = JobQueueMessage { id }; + config.queue().send_message_to_queue(queue, serde_json::to_string(&message)?, delay).await?; + Ok(()) +} diff --git a/src/queue/mod.rs b/src/queue/mod.rs new file mode 100644 index 0000000..54b7df7 --- /dev/null +++ b/src/queue/mod.rs @@ -0,0 +1,18 @@ +pub mod job_queue; +pub mod sqs; + +use async_trait::async_trait; +use color_eyre::Result; +use omniqueue::{Delivery, QueueError}; +use std::hash::Hash; +use std::time::Duration; + +#[async_trait] +pub trait QueueProvider: Send + Sync { + async fn send_message_to_queue(&self, queue: String, payload: String, delay: Option) -> Result<()>; + async fn consume_message_from_queue(&self, queue: String) -> std::result::Result; +} + +pub async fn init_consumers() -> Result<()> { + Ok(job_queue::init_consumers().await?) +} diff --git a/src/queue/sqs/mod.rs b/src/queue/sqs/mod.rs new file mode 100644 index 0000000..3f9d183 --- /dev/null +++ b/src/queue/sqs/mod.rs @@ -0,0 +1,39 @@ +use crate::queue::QueueProvider; +use async_trait::async_trait; +use color_eyre::Result; +use omniqueue::backends::{SqsBackend, SqsConfig, SqsConsumer, SqsProducer}; +use omniqueue::{Delivery, QueueError}; +use std::time::Duration; +pub struct SqsQueue; + +#[async_trait] +impl QueueProvider for SqsQueue { + async fn send_message_to_queue(&self, queue: String, payload: String, delay: Option) -> Result<()> { + let producer = get_producer(queue).await?; + + match delay { + Some(d) => producer.send_raw_scheduled(payload.as_str(), d).await?, + None => producer.send_raw(payload.as_str()).await?, + } + + Ok(()) + } + + async fn consume_message_from_queue(&self, queue: String) -> std::result::Result { + let mut consumer = get_consumer(queue).await?; + consumer.receive().await + } +} + +// TODO: store the producer and consumer in memory to avoid creating a new one every time +async fn get_producer(queue: String) -> Result { + let (producer, _) = + SqsBackend::builder(SqsConfig { queue_dsn: queue, override_endpoint: false }).build_pair().await?; + Ok(producer) +} + +async fn get_consumer(queue: String) -> std::result::Result { + let (_, consumer) = + SqsBackend::builder(SqsConfig { queue_dsn: queue, override_endpoint: false }).build_pair().await?; + Ok(consumer) +} diff --git a/src/routes.rs b/src/routes.rs new file mode 100644 index 0000000..4feda37 --- /dev/null +++ b/src/routes.rs @@ -0,0 +1,30 @@ +use crate::controllers::jobs_controller; +use crate::AppState; +use axum::http::StatusCode; +use axum::response::IntoResponse; +use axum::routing::{get, post}; +use axum::Router; + +pub fn app_router(state: AppState) -> Router { + Router::new() + .route("/health", get(root)) + .nest("/v1/dev", dev_routes(state.clone())) + .nest("/v1/job", job_routes(state.clone())) + .fallback(handler_404) +} + +async fn root() -> &'static str { + "UP" +} + +async fn handler_404() -> impl IntoResponse { + (StatusCode::NOT_FOUND, "The requested resource was not found") +} + +fn job_routes(state: AppState) -> Router { + Router::new().route("/create_job", post(jobs_controller::create_job)).with_state(state) +} + +fn dev_routes(state: AppState) -> Router { + Router::new().with_state(state) +} diff --git a/src/utils/env_utils.rs b/src/utils/env_utils.rs new file mode 100644 index 0000000..78e1160 --- /dev/null +++ b/src/utils/env_utils.rs @@ -0,0 +1,13 @@ +use color_eyre::Result; + +pub fn get_env_var(key: &str) -> Result { + std::env::var(key).map_err(|e| e.into()) +} + +pub fn get_env_var_or_panic(key: &str) -> String { + get_env_var(key).unwrap_or_else(|e| panic!("Failed to get env var {}: {}", key, e)) +} + +pub fn get_env_var_or_default(key: &str, default: &str) -> String { + get_env_var(key).unwrap_or(default.to_string()) +} diff --git a/src/utils/job_utils.rs b/src/utils/job_utils.rs new file mode 100644 index 0000000..dfa0906 --- /dev/null +++ b/src/utils/job_utils.rs @@ -0,0 +1,18 @@ +use crate::config::Config; +use crate::jobs::types::JobItem; +use color_eyre::eyre::eyre; +use color_eyre::Result; +use tracing::log; +use uuid::Uuid; + +pub async fn get_job_or_log_error(config: &Config, id: Uuid) -> Result { + let job = config.database().get_job_by_id(id).await?; + let job = match job { + Some(job) => job, + None => { + log::error!("Job with id {} not found when processing", id); + return Err(eyre!("Job with id {} not found when processing", id)); + } + }; + Ok(job) +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..314f29f --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod env_utils; +pub mod job_utils; From 3e9b41c06c748ec1dec757042c99dd958a13bbd5 Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Fri, 8 Mar 2024 23:51:15 +0530 Subject: [PATCH 2/9] add workflows --- .DS_Store | Bin 6148 -> 6148 bytes .github/.DS_Store | Bin 0 -> 6148 bytes .github/workflows/coverage.yml | 112 ++++++++++++++++++++++++++++ .github/workflows/linters-cargo.yml | 23 ++++++ .github/workflows/linters.yml | 33 ++++++++ .github/workflows/pull-request.yml | 28 +++++++ .github/workflows/rust-build.yml | 22 ++++++ src/main.rs | 5 +- 8 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 .github/.DS_Store create mode 100644 .github/workflows/coverage.yml create mode 100644 .github/workflows/linters-cargo.yml create mode 100644 .github/workflows/linters.yml create mode 100644 .github/workflows/pull-request.yml create mode 100644 .github/workflows/rust-build.yml diff --git a/.DS_Store b/.DS_Store index da9842491bd242e2715c5a6ac7f01fb2a746897c..46ac84b9977a672a88bca8142940d3ecd61f3d71 100644 GIT binary patch delta 363 zcmZoMXfc@J&nUAoU^g?P%w!%G$$B=osSFGZEDU-K=?s|+CAs-7E=f80NkB1l`qIJ3{K9^Edc6aVBiCj>@c$#G8jr3l5*0KR4~-*8vqrdDM5CG^u)JJ zP)A^>LO2DtDijAXfZfFkbWkQk3PUPGVvZiNYnYzS13Cst8rdOLH_Qx?25DGL-olo`yxOl}Vq(l@c81tBgrzoiDF=oWk8Zfw*2%O x-u7dg16gYr8M7y!V-uUq#4a@X8=Du)GJBO}lU>+Tm{){dn3(uxGdss$egMruH!%PJ diff --git a/.github/.DS_Store b/.github/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b0c90a58a7a168a2ef66233394e9dd0e2ffdc6f2 GIT binary patch literal 6148 zcmeHKy-EZz5T4O1R&1`*G7n&LZxD~Q7w!e*JXCOx9E#ZH&8$QlU&q>Sew15`U?Czh z1IahZ%p|iPY?2`&p5LuzL{lQ_&;(hOhRAf&wBybbAnO_zG*F>?x*aYX3;o3@$$bwQ z7rLQq+RA^nI4|psrF?MI_F9*|Uk+snYxnx_%ug?m$6tA_zUjHS+TQup5{Nz+2nK?I zU?3RyIR- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + localstack: + image: localstack/localstack:latest + ports: + - 4566:4566 + - 4571:4571 + - 8080:8080 + options: >- + --health-cmd "curl -k https://localhost:4566" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + etcd: + image: bitnami/etcd:3.5.0 + ports: + - 2379:2379 + - 2380:2380 + env: + ALLOW_NONE_AUTHENTICATION: yes + + steps: + - uses: actions/checkout@v3 + + # selecting a toolchain either by action or manual `rustup` calls should happen + # before the plugin, as the cache uses the current rustc version as its cache key + - run: rustup show + + - uses: taiki-e/install-action@cargo-llvm-cov + - uses: taiki-e/install-action@nextest + + - name: Download sink binaries + run: | + wget https://github.com/apibara/dna/releases/download/sink-webhook/v0.3.3/sink-webhook-x86_64-linux.gz + gunzip sink-webhook-x86_64-linux.gz + sudo cp sink-webhook-x86_64-linux /bin/sink-webhook + sudo chmod 777 /bin/sink-webhook + + wget https://github.com/apibara/dna/releases/download/sink-postgres/v0.4.3/sink-postgres-x86_64-linux.gz + gunzip sink-postgres-x86_64-linux.gz + sudo cp sink-postgres-x86_64-linux /bin/sink-postgres + sudo chmod 777 /bin/sink-postgres + + - name: Start LocalStack + run: | + pip install awscli-local + + - name: Create S3 Bucket and SQS Queues + run: | + awslocal s3api create-bucket --bucket indexer-service --region eu-west-3 --create-bucket-configuration LocationConstraint=eu-west-3 + awslocal s3api put-object --bucket indexer-service --key apibara-scripts/ + awslocal s3api list-buckets + awslocal sqs create-queue --queue-name indexer-service-start-indexer + awslocal sqs create-queue --queue-name indexer-service-failed-indexer + awslocal sqs create-queue --queue-name indexer-service-stop-indexer + awslocal sqs list-queues + + - name: Clean workspace + run: | + cargo llvm-cov clean --workspace + + - name: Run llvm-cov + run: | + cargo llvm-cov nextest --release --test-threads=1 --lcov --output-path lcov.info + + - name: Upload coverage to codecov.io + uses: codecov/codecov-action@v3 + with: + files: lcov.info + fail_ci_if_error: false + + - uses: colpal/actions-clean@v1 + if: ${{ always() }} # To ensure this step runs even when earlier steps fail diff --git a/.github/workflows/linters-cargo.yml b/.github/workflows/linters-cargo.yml new file mode 100644 index 0000000..9617223 --- /dev/null +++ b/.github/workflows/linters-cargo.yml @@ -0,0 +1,23 @@ +--- +name: Task - Linters Cargo + +on: + workflow_dispatch: + workflow_call: + +jobs: + cargo-lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + # selecting a toolchain either by action or manual `rustup` calls should happen + # before the plugin, as the cache uses the current rustc version as its cache key + - run: rustup show + + - uses: Swatinem/rust-cache@v2 + - name: Format and clippy + run: | + cargo fmt -- --check + cargo clippy --no-deps -- -D warnings + cargo clippy --tests --no-deps -- -D warnings diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml new file mode 100644 index 0000000..42f8c8d --- /dev/null +++ b/.github/workflows/linters.yml @@ -0,0 +1,33 @@ +--- +name: Task - Linters + +on: + workflow_dispatch: + workflow_call: + +jobs: + prettier: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Run prettier + run: |- + npx prettier --check . + + markdown-lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: avto-dev/markdown-lint@v1 + with: + config: "./.markdownlint.json" + args: "." + ignore: "./target" + + toml-lint: + runs-on: ubuntu-latest + steps: + - name: Checkout toml files + uses: actions/checkout@v3 + - name: Run toml check + run: npx @taplo/cli fmt --config ./taplo/taplo.toml --check diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 0000000..588c3af --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,28 @@ +--- +name: Workflow - Pull Request + +on: + workflow_dispatch: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + linters: + name: Run linters + uses: ./.github/workflows/linters.yml + + rust_build: + name: Build Rust project + uses: ./.github/workflows/rust-build.yml + + linters_cargo: + name: Run Cargo linters + uses: ./.github/workflows/linters-cargo.yml + needs: rust_build + + coverage: + name: Run coverage + uses: ./.github/workflows/coverage.yml + needs: rust_build diff --git a/.github/workflows/rust-build.yml b/.github/workflows/rust-build.yml new file mode 100644 index 0000000..f7cb3e0 --- /dev/null +++ b/.github/workflows/rust-build.yml @@ -0,0 +1,22 @@ +--- +name: Task - Build Rust + +on: + workflow_dispatch: + workflow_call: + +jobs: + rust_build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + # selecting a toolchain either by action or manual `rustup` calls should happen + # before the plugin, as the cache uses the current rustc version as its cache key + - run: rustup show + + - uses: Swatinem/rust-cache@v2 + + - name: Build the project + run: | + cargo build --release --workspace diff --git a/src/main.rs b/src/main.rs index bd15f98..ce4692c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,14 @@ +#![warn(missing_docs)] +#![warn(clippy::missing_docs_in_private_items)] + mod config; +mod controllers; mod da_clients; mod database; mod jobs; mod queue; mod routes; mod utils; -mod controllers; use crate::config::config; use crate::queue::init_consumers; From 06e79646b0ba3aeacef2b2ed29140b63f6c12370 Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Fri, 8 Mar 2024 23:51:37 +0530 Subject: [PATCH 3/9] cliipy fix --- .DS_Store | Bin 6148 -> 6148 bytes src/.DS_Store | Bin 6148 -> 6148 bytes src/config.rs | 4 ++-- src/controllers/jobs_controller.rs | 2 +- src/da_clients/ethereum/config.rs | 10 +++++----- src/da_clients/ethereum/mod.rs | 4 ++-- src/database/mongodb/mod.rs | 2 +- src/jobs/da_job/mod.rs | 14 +++++++------- src/jobs/mod.rs | 2 +- src/queue/mod.rs | 4 ++-- 10 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.DS_Store b/.DS_Store index 46ac84b9977a672a88bca8142940d3ecd61f3d71..2b5ad1862985fcd2db9a4e94b0cf0056b03ffc4d 100644 GIT binary patch delta 57 zcmV-90LK4>FoZC$CIkXU*^?*)S^;3Qg9J$e0-nB;&IT3(KJ4$4=LT5>syBEUlSBt( P1FSR9kzri32MGNSLunMc delta 57 zcmV-90LK4>FoZC$CIkXTm6Iq0S^)sFg9J$e0-v*!&IT3(htdF(=LT5>sZuC9lSBt( P1FKGekzri32MGNS4-OLm diff --git a/src/.DS_Store b/src/.DS_Store index 69a7bb33078a152e2fc509172b26d1b5b0bb1e45..34e160d1e62c06c6add8feec29d88e56c9f668c6 100644 GIT binary patch delta 51 zcmV-30L=e{FoZC$H3R{{lMDnJlTZYb0tfVy5Cs~O{sf5u^^>p#7L%R@c>zh27zTL( J-LsMgauK;p5lR36 delta 51 zcmV-30L=e{FoZC$H3R{`lMDnJlTZYb0tjuB5Cs~O{sf5u`;)K*7L%R@c>#};7zTL( J_Op@(auKY<5hwrv diff --git a/src/config.rs b/src/config.rs index ccdbe5d..d152a08 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,7 +5,7 @@ use crate::database::mongodb::config::MongoDbConfig; use crate::database::mongodb::MongoDb; use crate::database::{Database, DatabaseConfig}; use crate::queue::sqs::SqsQueue; -use crate::queue::{init_consumers, QueueProvider}; +use crate::queue::{QueueProvider}; use crate::utils::env_utils::get_env_var_or_panic; use dotenvy::dotenv; use starknet::providers::jsonrpc::HttpTransport; @@ -65,7 +65,7 @@ fn build_da_client() -> Box { match get_env_var_or_panic("DA_LAYER").as_str() { "ethereum" => { let config = EthereumDaConfig::new_from_env(); - return Box::new(EthereumDaClient::from(config)); + Box::new(EthereumDaClient::from(config)) } _ => panic!("Unsupported DA layer"), } diff --git a/src/controllers/jobs_controller.rs b/src/controllers/jobs_controller.rs index 9d0d117..e581796 100644 --- a/src/controllers/jobs_controller.rs +++ b/src/controllers/jobs_controller.rs @@ -12,7 +12,7 @@ pub struct CreateJobRequest { } pub async fn create_job( - State(state): State, + State(_state): State, Json(payload): Json, ) -> Result, AppError> { crate::jobs::create_job(payload.job_type, payload.internal_id).await?; diff --git a/src/da_clients/ethereum/config.rs b/src/da_clients/ethereum/config.rs index 9a7278b..bf61cf0 100644 --- a/src/da_clients/ethereum/config.rs +++ b/src/da_clients/ethereum/config.rs @@ -1,10 +1,10 @@ use crate::da_clients::DaConfig; use crate::utils::env_utils::get_env_var_or_panic; -use alloy::rpc::client::RpcClient; -use alloy::transports::http::Http; -use reqwest::Client; -use std::str::FromStr; -use url::Url; + + + + + #[derive(Clone, Debug)] pub struct EthereumDaConfig { diff --git a/src/da_clients/ethereum/mod.rs b/src/da_clients/ethereum/mod.rs index 8b3064d..39318d0 100644 --- a/src/da_clients/ethereum/mod.rs +++ b/src/da_clients/ethereum/mod.rs @@ -18,11 +18,11 @@ pub struct EthereumDaClient { #[async_trait] impl DaClient for EthereumDaClient { - async fn publish_state_diff(&self, state_diff: Vec) -> Result { + async fn publish_state_diff(&self, _state_diff: Vec) -> Result { unimplemented!() } - async fn verify_inclusion(&self, external_id: &String) -> Result { + async fn verify_inclusion(&self, _external_id: &String) -> Result { todo!() } } diff --git a/src/database/mongodb/mod.rs b/src/database/mongodb/mod.rs index 1e77866..d4362af 100644 --- a/src/database/mongodb/mod.rs +++ b/src/database/mongodb/mod.rs @@ -4,7 +4,7 @@ use crate::jobs::types::{JobItem, JobStatus, JobType}; use async_trait::async_trait; use color_eyre::eyre::eyre; use color_eyre::Result; -use mongodb::bson::{Bson, Document}; +use mongodb::bson::{Document}; use mongodb::options::UpdateOptions; use mongodb::{ bson::doc, diff --git a/src/jobs/da_job/mod.rs b/src/jobs/da_job/mod.rs index a879dac..405e874 100644 --- a/src/jobs/da_job/mod.rs +++ b/src/jobs/da_job/mod.rs @@ -1,6 +1,6 @@ use crate::config::Config; use crate::jobs::types::{JobItem, JobStatus, JobType, JobVerificationStatus}; -use crate::jobs::{increment_key_in_metadata, Job}; +use crate::jobs::{Job}; use async_trait::async_trait; use color_eyre::eyre::eyre; use color_eyre::Result; @@ -14,7 +14,7 @@ pub struct DaJob; #[async_trait] impl Job for DaJob { - async fn create_job(&self, config: &Config, internal_id: String) -> Result { + async fn create_job(&self, _config: &Config, internal_id: String) -> Result { Ok(JobItem { id: Uuid::new_v4(), internal_id, @@ -89,7 +89,7 @@ fn state_update_to_blob_data(block_no: u64, state_update: StateUpdate) -> Vec Vec Vec Vec Result { Some(job) => Ok(job), None => { log::error!("Failed to find job with id {:?}", id); - return Err(eyre!("Failed to process job with id {:?}", id)); + Err(eyre!("Failed to process job with id {:?}", id)) } } } diff --git a/src/queue/mod.rs b/src/queue/mod.rs index 54b7df7..1f7791f 100644 --- a/src/queue/mod.rs +++ b/src/queue/mod.rs @@ -4,7 +4,7 @@ pub mod sqs; use async_trait::async_trait; use color_eyre::Result; use omniqueue::{Delivery, QueueError}; -use std::hash::Hash; + use std::time::Duration; #[async_trait] @@ -14,5 +14,5 @@ pub trait QueueProvider: Send + Sync { } pub async fn init_consumers() -> Result<()> { - Ok(job_queue::init_consumers().await?) + job_queue::init_consumers().await } From 6e14ef09e71bf49b3d132c5622a96a8970e385ca Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Sat, 9 Mar 2024 00:06:25 +0530 Subject: [PATCH 4/9] more clippy fixes --- .DS_Store | Bin 6148 -> 6148 bytes src/.DS_Store | Bin 6148 -> 6148 bytes src/da_clients/mod.rs | 5 ----- src/jobs/mod.rs | 13 ++++++++++++- src/utils/job_utils.rs | 18 ------------------ src/utils/mod.rs | 1 - 6 files changed, 12 insertions(+), 25 deletions(-) delete mode 100644 src/utils/job_utils.rs diff --git a/.DS_Store b/.DS_Store index 2b5ad1862985fcd2db9a4e94b0cf0056b03ffc4d..40fc4307c3b8f1d3421cd96dcb7402a9441cbe91 100644 GIT binary patch delta 241 zcmZoMXffEJ#u8gNgMop8g+Y%YogtHo}Abm$Xd>Pjj0Y4^0<^TWy delta 250 zcmZoMXffEJ#uDp(lYxPOg+Y%YogtHKAi_-vjT0%WJqC1Wk^J}qw0p4!ST(3tksN6^Y%?X$0jzJ ziCxGqHy>fk0Xf-En;@=WW+-MTVn{}@gK-1MCN_o=hD4xTI?()*oOFa6R+(2wPIh5W RVP0c=VPay;W_FIh`~Z@TLw^7O diff --git a/src/.DS_Store b/src/.DS_Store index 34e160d1e62c06c6add8feec29d88e56c9f668c6..ff4eb0c33b430ed976969bec1bf2d9c26102ed49 100644 GIT binary patch delta 173 zcmZoMXffFEn1yliWC2#G$^Tfm*nVcP^&CIDnU9r&QQpRcfq{XAA&ViOA&H?lH{Zo2 zDJMS(D8}(M(QNUF$);?#lNqN0`K%133?&Si3^}N(wDQkBIdS%=Bf5$dxH%i6j-AF- aQIKI6oSdIq0MrKr3KI*bY-Z>9%MSpAurkU3 delta 169 zcmZoMXffFEn1%7nWC2#G$^TfmCY!J-Ox9q1CvWM=z`(%5kj0SCki<}&oA2V1l#`zX z6ytcl_vhOqlTF!fCo>-f@>v;58A=#38FEln`5xJM+xN^-M|2e_aC5M$D9A7jPR`FQ S0O|t*gNcPxHnVg5) -> Result; diff --git a/src/jobs/mod.rs b/src/jobs/mod.rs index 469034e..b502c77 100644 --- a/src/jobs/mod.rs +++ b/src/jobs/mod.rs @@ -1,5 +1,5 @@ use crate::config::{config, Config}; -use crate::jobs::constants::JOB_PROCESS_ATTEMPT_METADATA_KEY; +use crate::jobs::constants::{JOB_PROCESS_ATTEMPT_METADATA_KEY, JOB_VERIFICATION_ATTEMPT_METADATA_KEY}; use crate::jobs::types::{JobItem, JobStatus, JobType, JobVerificationStatus}; use crate::queue::job_queue::{add_job_to_process_queue, add_job_to_verification_queue}; use async_trait::async_trait; @@ -112,10 +112,21 @@ pub async fn verify_job(id: Uuid) -> Result<()> { ); add_job_to_process_queue(job.id).await?; return Ok(()); + } else { + // TODO: send alert } } JobVerificationStatus::PENDING => { log::info!("Inclusion is still pending for job {}. Pushing back to queue.", job.id); + let verify_attempts = get_u64_from_metadata(&job.metadata, JOB_VERIFICATION_ATTEMPT_METADATA_KEY)?; + if verify_attempts >= job_handler.max_verification_attempts() { + // TODO: send alert + log::info!("Verification attempts exceeded for job {}. Marking as timedout.", job.id); + config.database().update_job_status(&job, JobStatus::VerificationTimeout).await?; + return Ok(()); + } + let metadata = increment_key_in_metadata(&job.metadata, JOB_VERIFICATION_ATTEMPT_METADATA_KEY)?; + config.database().update_metadata(&job, metadata).await?; add_job_to_verification_queue( job.id, Duration::from_secs(job_handler.verification_polling_delay_seconds()), diff --git a/src/utils/job_utils.rs b/src/utils/job_utils.rs deleted file mode 100644 index dfa0906..0000000 --- a/src/utils/job_utils.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::config::Config; -use crate::jobs::types::JobItem; -use color_eyre::eyre::eyre; -use color_eyre::Result; -use tracing::log; -use uuid::Uuid; - -pub async fn get_job_or_log_error(config: &Config, id: Uuid) -> Result { - let job = config.database().get_job_by_id(id).await?; - let job = match job { - Some(job) => job, - None => { - log::error!("Job with id {} not found when processing", id); - return Err(eyre!("Job with id {} not found when processing", id)); - } - }; - Ok(job) -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 314f29f..6a65fdc 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1 @@ pub mod env_utils; -pub mod job_utils; From c81d279d11d0f7557fd75f72b409aacae9720fdc Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Sat, 9 Mar 2024 01:06:39 +0530 Subject: [PATCH 5/9] more clippy fixes --- .DS_Store | Bin 6148 -> 6148 bytes src/.DS_Store | Bin 6148 -> 6148 bytes src/config.rs | 29 ++++++++++++++++++++++------- src/controllers/errors.rs | 3 +++ src/controllers/jobs_controller.rs | 13 +++++++------ src/controllers/mod.rs | 3 +++ src/da_clients/ethereum/mod.rs | 5 ++++- src/da_clients/mod.rs | 9 ++++++++- src/database/mod.rs | 7 ++----- src/database/mongodb/mod.rs | 8 ++------ src/jobs/da_job/mod.rs | 4 ++-- src/jobs/mod.rs | 29 +++++++++++++++++++++++++---- src/jobs/types.rs | 9 ++++++--- src/main.rs | 20 ++++++++++++-------- src/queue/mod.rs | 3 +++ src/routes.rs | 15 +++++++-------- 16 files changed, 106 insertions(+), 51 deletions(-) diff --git a/.DS_Store b/.DS_Store index 40fc4307c3b8f1d3421cd96dcb7402a9441cbe91..e93761e4822fbfebf12d62afebd666e6d3a819b5 100644 GIT binary patch delta 264 zcmZoMXffEJ#uB@80s{jB3xgg*IzuKyNp8N2OHxjL5>Sj|d+c%H3uliyqROY>l`qIJ z3{K9^Edc6aU=R$L+|068@l7L;%?h+3lOcs6l_3$?j`Q5o>=!l%vQ{%Ptz9|!9Gh6e zkuN_Y&O>ZvW+-MTVo1)-N7#uei((_=29UjM3?&SSK%MD8+e&iM5iVLSI&I}-7xon9 Qb#(_OCdO=L=lIJH0I~i|YXATM delta 263 zcmZoMXffEJ#u8gNgMop8g+Y%YogtHo}Abm$Xd zUng&16`MSdm22_^R+-61ScB?qOc)p#SQxSx@)?pCigWW_T#|C~lYn9zUlYw1pE!He z5mi0~E+4p8;fXeyd_jg`aB_Zb0Z>, + /// The DA client to interact with the DA layer da_client: Box, + /// The database client database: Box, + /// The queue provider queue: Box, } impl Config { + /// Returns the starknet client pub fn starknet_client(&self) -> &Arc> { &self.starknet_client } - pub fn da_client(&self) -> &Box { - &self.da_client + /// Returns the DA client + pub fn da_client(&self) -> &dyn DaClient { + self.da_client.as_ref() } - pub fn database(&self) -> &Box { - &self.database + /// Returns the database client + pub fn database(&self) -> &dyn Database { + self.database.as_ref() } - pub fn queue(&self) -> &Box { - &self.queue + /// Returns the queue provider + pub fn queue(&self) -> &dyn QueueProvider { + self.queue.as_ref() } } +/// The app config. It can be accessed from anywhere inside the service. +/// It's initialized only once. pub static CONFIG: OnceCell = OnceCell::const_new(); +/// Initializes the app config async fn init_config() -> Config { dotenv().ok(); @@ -57,10 +70,12 @@ async fn init_config() -> Config { Config { starknet_client: Arc::new(provider), da_client: build_da_client(), database, queue } } +/// Returns the app config. Initializes if not already done. pub async fn config() -> &'static Config { CONFIG.get_or_init(init_config).await } +/// Builds the DA client based on the environment variable DA_LAYER fn build_da_client() -> Box { match get_env_var_or_panic("DA_LAYER").as_str() { "ethereum" => { diff --git a/src/controllers/errors.rs b/src/controllers/errors.rs index 6bd3d4c..fd120f9 100644 --- a/src/controllers/errors.rs +++ b/src/controllers/errors.rs @@ -4,12 +4,15 @@ use color_eyre::eyre::ErrReport; use serde_json::json; use tracing::log; +/// Root level error which is sent back to the client #[derive(thiserror::Error, Debug)] pub enum AppError { + /// Internal server error #[error("Internal Server Error {0}")] InternalServerError(#[from] ErrReport), } +/// Convert the error into a response so that it can be sent back to the client impl IntoResponse for AppError { fn into_response(self) -> axum::http::Response { log::error!("Error: {:?}", self); diff --git a/src/controllers/jobs_controller.rs b/src/controllers/jobs_controller.rs index e581796..199ff63 100644 --- a/src/controllers/jobs_controller.rs +++ b/src/controllers/jobs_controller.rs @@ -1,20 +1,21 @@ use crate::controllers::errors::AppError; use crate::jobs::types::JobType; -use crate::AppState; use axum::extract::Json; -use axum::extract::State; use serde::Deserialize; +/// Client request to create a job #[derive(Debug, Deserialize)] pub struct CreateJobRequest { + /// Job type job_type: JobType, + /// Internal id must be a way to identify the job. For example + /// block_no, transaction_hash etc. The (job_type, internal_id) + /// pair must be unique. internal_id: String, } -pub async fn create_job( - State(_state): State, - Json(payload): Json, -) -> Result, AppError> { +/// Create a job +pub async fn create_job(Json(payload): Json) -> Result, AppError> { crate::jobs::create_job(payload.job_type, payload.internal_id).await?; Ok(Json::from(())) } diff --git a/src/controllers/mod.rs b/src/controllers/mod.rs index 2246a30..aadb38b 100644 --- a/src/controllers/mod.rs +++ b/src/controllers/mod.rs @@ -1,2 +1,5 @@ +/// Errors mod errors; + +/// Job controllers pub mod jobs_controller; diff --git a/src/da_clients/ethereum/mod.rs b/src/da_clients/ethereum/mod.rs index 39318d0..10f8781 100644 --- a/src/da_clients/ethereum/mod.rs +++ b/src/da_clients/ethereum/mod.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] +#![allow(clippy::missing_docs_in_private_items)] use alloy::rpc::client::RpcClient; use alloy::transports::http::Http; use async_trait::async_trait; @@ -13,6 +15,7 @@ use crate::jobs::types::JobVerificationStatus; pub mod config; pub struct EthereumDaClient { + #[allow(dead_code)] provider: RpcClient>, } @@ -22,7 +25,7 @@ impl DaClient for EthereumDaClient { unimplemented!() } - async fn verify_inclusion(&self, _external_id: &String) -> Result { + async fn verify_inclusion(&self, _external_id: &str) -> Result { todo!() } } diff --git a/src/da_clients/mod.rs b/src/da_clients/mod.rs index 003bee3..4e86654 100644 --- a/src/da_clients/mod.rs +++ b/src/da_clients/mod.rs @@ -3,14 +3,21 @@ use axum::async_trait; use color_eyre::Result; use starknet::core::types::FieldElement; +/// Ethereum client pub mod ethereum; +/// Trait for every new DaClient to implement #[async_trait] pub trait DaClient: Send + Sync { + /// Should publish the state diff to the DA layer and return an external id + /// which can be used to track the status of the DA transaction. async fn publish_state_diff(&self, state_diff: Vec) -> Result; - async fn verify_inclusion(&self, external_id: &String) -> Result; + /// Should verify the inclusion of the state diff in the DA layer and return the status + async fn verify_inclusion(&self, external_id: &str) -> Result; } +/// Trait for every new DaConfig to implement pub trait DaConfig { + /// Should create a new instance of the DaConfig from the environment variables fn new_from_env() -> Self; } diff --git a/src/database/mod.rs b/src/database/mod.rs index a55874a..83869d5 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -4,6 +4,7 @@ use color_eyre::Result; use std::collections::HashMap; use uuid::Uuid; +/// MongoDB pub mod mongodb; /// The Database trait is used to define the methods that a database @@ -19,11 +20,7 @@ pub mod mongodb; pub trait Database: Send + Sync { async fn create_job(&self, job: JobItem) -> Result; async fn get_job_by_id(&self, id: Uuid) -> Result>; - async fn get_job_by_internal_id_and_type( - &self, - internal_id: &String, - job_type: &JobType, - ) -> Result>; + async fn get_job_by_internal_id_and_type(&self, internal_id: &str, job_type: &JobType) -> Result>; async fn update_job_status(&self, job: &JobItem, new_status: JobStatus) -> Result<()>; async fn update_external_id_and_status_and_metadata( &self, diff --git a/src/database/mongodb/mod.rs b/src/database/mongodb/mod.rs index d4362af..b86d4bd 100644 --- a/src/database/mongodb/mod.rs +++ b/src/database/mongodb/mod.rs @@ -4,7 +4,7 @@ use crate::jobs::types::{JobItem, JobStatus, JobType}; use async_trait::async_trait; use color_eyre::eyre::eyre; use color_eyre::Result; -use mongodb::bson::{Document}; +use mongodb::bson::Document; use mongodb::options::UpdateOptions; use mongodb::{ bson::doc, @@ -70,11 +70,7 @@ impl Database for MongoDb { Ok(self.get_job_collection().find_one(filter, None).await?) } - async fn get_job_by_internal_id_and_type( - &self, - internal_id: &String, - job_type: &JobType, - ) -> Result> { + async fn get_job_by_internal_id_and_type(&self, internal_id: &str, job_type: &JobType) -> Result> { let filter = doc! { "internal_id": internal_id, "job_type": mongodb::bson::to_bson(&job_type)?, diff --git a/src/jobs/da_job/mod.rs b/src/jobs/da_job/mod.rs index 405e874..77b217f 100644 --- a/src/jobs/da_job/mod.rs +++ b/src/jobs/da_job/mod.rs @@ -1,6 +1,6 @@ use crate::config::Config; use crate::jobs::types::{JobItem, JobStatus, JobType, JobVerificationStatus}; -use crate::jobs::{Job}; +use crate::jobs::Job; use async_trait::async_trait; use color_eyre::eyre::eyre; use color_eyre::Result; @@ -49,7 +49,7 @@ impl Job for DaJob { } async fn verify_job(&self, config: &Config, job: &JobItem) -> Result { - Ok(config.da_client().verify_inclusion(&job.external_id).await?) + Ok(config.da_client().verify_inclusion(job.external_id.as_str()).await?) } fn max_process_attempts(&self) -> u64 { diff --git a/src/jobs/mod.rs b/src/jobs/mod.rs index b502c77..46cbb5b 100644 --- a/src/jobs/mod.rs +++ b/src/jobs/mod.rs @@ -14,19 +14,35 @@ mod constants; pub mod da_job; pub mod types; +/// The Job trait is used to define the methods that a job +/// should implement to be used as a job for the orchestrator. The orchestrator automatically +/// handles queueing and processing of jobs as long as they implement the trait. #[async_trait] pub trait Job: Send + Sync { + /// Should build a new job item and return it async fn create_job(&self, config: &Config, internal_id: String) -> Result; + /// Should process the job and return the external_id which can be used to + /// track the status of the job. For example, a DA job will submit the state diff + /// to the DA layer and return the txn hash. async fn process_job(&self, config: &Config, job: &JobItem) -> Result; + /// Should verify the job and return the status of the verification. For example, + /// a DA job will verify the inclusion of the state diff in the DA layer and return + /// the status of the verification. async fn verify_job(&self, config: &Config, job: &JobItem) -> Result; + /// Should return the maximum number of attempts to process the job. A new attempt is made + /// every time the verification returns `JobVerificationStatus::Rejected` fn max_process_attempts(&self) -> u64; + /// Should return the maximum number of attempts to verify the job. A new attempt is made + /// every few seconds depending on the result `verification_polling_delay_seconds` fn max_verification_attempts(&self) -> u64; + /// Should return the number of seconds to wait before polling for verification fn verification_polling_delay_seconds(&self) -> u64; } +/// Creates the job in the DB in the created state and adds it to the process queue pub async fn create_job(job_type: JobType, internal_id: String) -> Result<()> { let config = config().await; - let existing_job = config.database().get_job_by_internal_id_and_type(&internal_id, &job_type).await?; + let existing_job = config.database().get_job_by_internal_id_and_type(internal_id.as_str(), &job_type).await?; if existing_job.is_some() { log::debug!("Job already exists for internal_id {:?} and job_type {:?}. Skipping.", internal_id, job_type); return Err(eyre!( @@ -44,6 +60,8 @@ pub async fn create_job(job_type: JobType, internal_id: String) -> Result<()> { Ok(()) } +/// Processes the job, increments the process attempt count and updates the status of the job in the DB. +/// It then adds the job to the verification queue. pub async fn process_job(id: Uuid) -> Result<()> { let config = config().await; let job = get_job(id).await?; @@ -78,6 +96,9 @@ pub async fn process_job(id: Uuid) -> Result<()> { Ok(()) } +/// Verifies the job and updates the status of the job in the DB. If the verification fails, it retries +/// processing the job if the max attempts have not been exceeded. If the max attempts have been exceeded, +/// it marks the job as timedout. If the verification is still pending, it pushes the job back to the queue. pub async fn verify_job(id: Uuid) -> Result<()> { let config = config().await; let job = get_job(id).await?; @@ -96,10 +117,10 @@ pub async fn verify_job(id: Uuid) -> Result<()> { let verification_status = job_handler.verify_job(config, &job).await?; match verification_status { - JobVerificationStatus::VERIFIED => { + JobVerificationStatus::Verified => { config.database().update_job_status(&job, JobStatus::Completed).await?; } - JobVerificationStatus::REJECTED => { + JobVerificationStatus::Rejected => { config.database().update_job_status(&job, JobStatus::VerificationFailed).await?; // retry job processing if we haven't exceeded the max limit @@ -116,7 +137,7 @@ pub async fn verify_job(id: Uuid) -> Result<()> { // TODO: send alert } } - JobVerificationStatus::PENDING => { + JobVerificationStatus::Pending => { log::info!("Inclusion is still pending for job {}. Pushing back to queue.", job.id); let verify_attempts = get_u64_from_metadata(&job.metadata, JOB_VERIFICATION_ATTEMPT_METADATA_KEY)?; if verify_attempts >= job_handler.max_verification_attempts() { diff --git a/src/jobs/types.rs b/src/jobs/types.rs index a6ee471..f48b237 100644 --- a/src/jobs/types.rs +++ b/src/jobs/types.rs @@ -55,7 +55,10 @@ pub struct JobItem { #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum JobVerificationStatus { - PENDING, - VERIFIED, - REJECTED, + #[allow(dead_code)] + Pending, + #[allow(dead_code)] + Verified, + #[allow(dead_code)] + Rejected, } diff --git a/src/main.rs b/src/main.rs index ce4692c..83b9cdd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,20 @@ -#![warn(missing_docs)] -#![warn(clippy::missing_docs_in_private_items)] - +/// Config of the service. Contains configurations for DB, Queues and other services. mod config; +/// Controllers for the routes mod controllers; +/// Contains the trait that all DA clients must implement mod da_clients; +/// Contains the trait that all database clients must implement mod database; +/// Contains the trait that all jobs must implement. Also +/// contains the root level functions for which detect the job +/// type and call the corresponding job mod jobs; +/// Contains the trait that all queues must implement mod queue; +/// Contains the routes for the service mod routes; +/// Contains the utils mod utils; use crate::config::config; @@ -16,9 +23,7 @@ use crate::routes::app_router; use crate::utils::env_utils::get_env_var_or_default; use dotenvy::dotenv; -#[derive(Clone)] -pub struct AppState {} - +/// Start the server #[tokio::main] async fn main() { dotenv().ok(); @@ -30,8 +35,7 @@ async fn main() { let port = get_env_var_or_default("PORT", "3000").parse::().expect("PORT must be a u16"); let address = format!("{}:{}", host, port); let listener = tokio::net::TcpListener::bind(address.clone()).await.expect("Failed to get listener"); - let state = AppState {}; - let app = app_router(state.clone()).with_state(state); + let app = app_router(); // init consumer init_consumers().await.expect("Failed to init consumers"); diff --git a/src/queue/mod.rs b/src/queue/mod.rs index 1f7791f..653f0fb 100644 --- a/src/queue/mod.rs +++ b/src/queue/mod.rs @@ -7,6 +7,9 @@ use omniqueue::{Delivery, QueueError}; use std::time::Duration; +/// The QueueProvider trait is used to define the methods that a queue +/// should implement to be used as a queue for the orchestrator. The +/// purpose of this trait is to allow developers to use any queue of their choice. #[async_trait] pub trait QueueProvider: Send + Sync { async fn send_message_to_queue(&self, queue: String, payload: String, delay: Option) -> Result<()>; diff --git a/src/routes.rs b/src/routes.rs index 4feda37..41e1803 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1,15 +1,14 @@ use crate::controllers::jobs_controller; -use crate::AppState; use axum::http::StatusCode; use axum::response::IntoResponse; use axum::routing::{get, post}; use axum::Router; -pub fn app_router(state: AppState) -> Router { +pub fn app_router() -> Router { Router::new() .route("/health", get(root)) - .nest("/v1/dev", dev_routes(state.clone())) - .nest("/v1/job", job_routes(state.clone())) + .nest("/v1/dev", dev_routes()) + .nest("/v1/job", job_routes()) .fallback(handler_404) } @@ -21,10 +20,10 @@ async fn handler_404() -> impl IntoResponse { (StatusCode::NOT_FOUND, "The requested resource was not found") } -fn job_routes(state: AppState) -> Router { - Router::new().route("/create_job", post(jobs_controller::create_job)).with_state(state) +fn job_routes() -> Router { + Router::new().route("/create_job", post(jobs_controller::create_job)) } -fn dev_routes(state: AppState) -> Router { - Router::new().with_state(state) +fn dev_routes() -> Router { + Router::new() } From 1ee102bed67b27165011c006266dca3549f5f51a Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Sat, 9 Mar 2024 01:07:27 +0530 Subject: [PATCH 6/9] remove .idea --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 1 + .idea/.gitignore | 8 -------- .idea/GitLink.xml | 6 ------ .idea/dataSources.xml | 19 ------------------- .idea/madara-orchestrator.iml | 11 ----------- .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ 8 files changed, 1 insertion(+), 58 deletions(-) delete mode 100644 .DS_Store delete mode 100644 .idea/.gitignore delete mode 100644 .idea/GitLink.xml delete mode 100644 .idea/dataSources.xml delete mode 100644 .idea/madara-orchestrator.iml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index e93761e4822fbfebf12d62afebd666e6d3a819b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKJ!@1!6g{*1OqOi3q5)w=UuPH1ACPC*^gO(n?lAE-qdTZ;ry zL<>o0p===%{U3@T7M7knb9HC-?P{fn%!QdVJNMpq&z$!$I{?heUT+y_0I0DECJXGQ znE0iYtfDh#iAJum-Ctho=7XJ5WSoc!L*iY68^4UTUH_#5aR6gD%7tibSIIcJ6Rf`~E%;7`*(ZlDCsTUE{uRaq!64uVq z#cohNS$g36{Mw%z7e>RkdLJ~`U;Q+HP&dh>?g9o}cOSRV#*m{NHzzpYd~;Tu&*$>F z<`-S*)NA_Oeis|?#D?&!VwW7dfjW3{IQIBlUVr^|?bxZVd4Bb>H>hXq{g|T~ZC32_ zi3r|}$BX+?HSqhjuOHk#{le9rh#5Z>vtoQ6Pw%{9nLlRSv&Cw4hp~?eL`3`bZ;#! wPWIZAZG%lr;tGd0g`IB4b|72v88&P5r7|F9iiJbY(BdBfD?{v}0)JJ3@Aq=-Pyhe` diff --git a/.gitignore b/.gitignore index fedaa2b..29cbe47 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target .env +.idea \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/GitLink.xml b/.idea/GitLink.xml deleted file mode 100644 index 009597c..0000000 --- a/.idea/GitLink.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml deleted file mode 100644 index 089ad98..0000000 --- a/.idea/dataSources.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - postgresql - true - org.postgresql.Driver - jdbc:postgresql://localhost:5432/postgres - $ProjectFileDir$ - - - mongo - true - com.dbschema.MongoJdbcDriver - mongodb+srv://cluster0.dztzhor.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0 - $ProjectFileDir$ - - - \ No newline at end of file diff --git a/.idea/madara-orchestrator.iml b/.idea/madara-orchestrator.iml deleted file mode 100644 index cf84ae4..0000000 --- a/.idea/madara-orchestrator.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index fbaa916..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 9062d2112ad5811c9c84d7b3a22e40d47ec615f8 Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Sat, 9 Mar 2024 01:12:43 +0530 Subject: [PATCH 7/9] fix ci --- .markdownlint.json | 9 +++++++++ Cargo.toml | 32 +++++++++++++++++------------- README.md | 8 +++++--- taplo/README.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++ taplo/taplo.toml | 11 +++++++++++ 5 files changed, 92 insertions(+), 17 deletions(-) create mode 100644 .markdownlint.json create mode 100644 taplo/README.md create mode 100644 taplo/taplo.toml diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..68e7410 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,9 @@ +{ + "MD033": false, + "MD041": false, + "MD045": false, + "MD003": false, + "MD013": { + "code_blocks": false + } +} diff --git a/Cargo.toml b/Cargo.toml index 83ac7ef..b63d871 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,29 +7,33 @@ authors = ["Apoorv Sadana <@apoorvsadana>"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +alloy = { git = "https://github.com/alloy-rs/alloy", rev = "86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6", features = [ + "providers", + "rpc-client", + "transport-http", +], optional = true } +async-trait = "0.1.77" axum = { version = "0.7.4", features = ["macros"] } axum-macros = "0.4.1" -tokio = { version = "1.36.0", features = ["sync", "macros", "rt-multi-thread"] } -tracing = "0.1.40" -tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } -dotenvy = "0.15.7" -starknet = "0.9.0" color-eyre = "0.6.2" -rstest = "0.18.2" -async-trait = "0.1.77" -alloy = { git = "https://github.com/alloy-rs/alloy", rev = "86027c9bb984f3a12a30ffd2a3c5f2f06595f1d6", features = ["providers", "rpc-client", "transport-http"], optional = true } -reqwest = { version = "0.11.24", optional = true } -url = "2.5.0" -uuid = { version = "1.7.0", features = ["v4", "serde"] } -serde = { version = "1.0.197" } +dotenvy = "0.15.7" futures = "0.3.30" mongodb = { version = "2.8.1", features = ["bson-uuid-1"], optional = true } omniqueue = { version = "0.2.0", optional = true } -thiserror = "1.0.57" +reqwest = { version = "0.11.24", optional = true } +rstest = "0.18.2" +serde = { version = "1.0.197" } serde_json = "1.0.114" +starknet = "0.9.0" +thiserror = "1.0.57" +tokio = { version = "1.36.0", features = ["sync", "macros", "rt-multi-thread"] } +tracing = "0.1.40" +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } +url = "2.5.0" +uuid = { version = "1.7.0", features = ["v4", "serde"] } [features] default = ["ethereum", "with_mongdb", "with_sqs"] ethereum = ["alloy", "reqwest"] with_mongdb = ["mongodb"] -with_sqs = ["omniqueue"] \ No newline at end of file +with_sqs = ["omniqueue"] diff --git a/README.md b/README.md index 33eb453..374b343 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # Madara Orchestrator -The Madara orchestrator is designed to be an additional service which runs in parallel to Madara and handles +The Madara orchestrator is designed to be an additional service which runs in +parallel to Madara and handles 1. publishing data to the respective DA layer 2. running SNOS and submitting jobs to the prover 3. updating the state on Cairo core contracts -As a v1, the orchestrator handles the DA publishing. The architecture for the same is as follows +As a v1, the orchestrator handles the DA publishing. The architecture for the +same is as follows -![orchestrator_da_sequencer_diagram](./docs/orchestrator_da_sequencer_diagram.png) \ No newline at end of file +![orchestrator_da_sequencer_diagram](./docs/orchestrator_da_sequencer_diagram.png) diff --git a/taplo/README.md b/taplo/README.md new file mode 100644 index 0000000..0d097bf --- /dev/null +++ b/taplo/README.md @@ -0,0 +1,49 @@ +# Taplo + +[Taplo](https://github.com/tamasfe/taplo) is a TOML validator and formatter. It +provides a command-line interface (CLI) for working with TOML files. + +## Installation + +You can install Taplo using either cargo or Yarn or NPM. + +### Cargo + +```bash +cargo install taplo-cli --locked +``` + +### Yarn + +```bash +yarn global add @taplo/cli +``` + +### NPM + +```bash +npm install -g @taplo/cli +``` + +### Usage + +To check your TOML files for formatting issues, use the following command: + +```bash +npx @taplo/cli fmt --config taplo.toml --check +``` + +To format all TOML files in your project, use the following command: + +```bash +npx @taplo/cli fmt --config taplo.toml +``` + +This command will automatically format the TOML files, ensuring consistent and +readable formatting. + +### Configuration + +Taplo allows you to customize the formatting rules by adding configuration +options. You can find the available options and how to use them +[here](https://taplo.tamasfe.dev/configuration/formatter-options.html). diff --git a/taplo/taplo.toml b/taplo/taplo.toml new file mode 100644 index 0000000..e49b662 --- /dev/null +++ b/taplo/taplo.toml @@ -0,0 +1,11 @@ +include = ["**/*.toml"] +exclude = ["**/bad.toml"] + +[formatting] +align_entries = false + +[[rule]] +keys = ["dependencies"] + +[rule.formatting] +reorder_keys = true From b04bfddbc7fa057ca4ac65ef58b02b0132519bf6 Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Sat, 9 Mar 2024 01:13:08 +0530 Subject: [PATCH 8/9] add .DS_store to ignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 29cbe47..0100788 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target .env -.idea \ No newline at end of file +.idea +.DS_Store \ No newline at end of file From eaf571f853a8fc3ba464967e2c8973b1582074f0 Mon Sep 17 00:00:00 2001 From: apoorvsadana <95699312+apoorvsadana@users.noreply.github.com> Date: Sat, 9 Mar 2024 01:22:04 +0530 Subject: [PATCH 9/9] remove coverage --- .github/.DS_Store | Bin 6148 -> 6148 bytes .github/workflows/coverage.yml | 112 ----------------------------- .github/workflows/pull-request.yml | 5 -- src/.DS_Store | Bin 6148 -> 6148 bytes src/da_clients/ethereum/config.rs | 5 -- 5 files changed, 122 deletions(-) delete mode 100644 .github/workflows/coverage.yml diff --git a/.github/.DS_Store b/.github/.DS_Store index b0c90a58a7a168a2ef66233394e9dd0e2ffdc6f2..daf430c92957832b27a3a56edcd4965cb3f86351 100644 GIT binary patch delta 53 zcmZoMXffDez{teWGC77(VzL(_7whGFJ6>Fz9LcB(Wi>OZGdgVE$QZ^pv4L$fJI7ys E02ZkfO#lD@ delta 53 zcmZoMXffDez{n)7GdYG)VzL(_7wfnECm4@Uj$~AYvYHvy83Q(NWDH}Q*ub`#o#QV* E0N$e#S^xk5 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml deleted file mode 100644 index 8040977..0000000 --- a/.github/workflows/coverage.yml +++ /dev/null @@ -1,112 +0,0 @@ ---- -name: Task - Rust Tests & Coverage - -on: - workflow_dispatch: - workflow_call: - -jobs: - coverage: - # sadly, for now we have to "rebuild" for the coverage - runs-on: self-hosted - - env: - HOST: 0.0.0.0 - PORT: 8080 - DATABASE_URL: postgres://postgres:postgres@localhost:5432 - AWS_REGION: eu-west-3 - LOCALSTACK_ENDPOINT: http://localhost:4566 - BINARY_BASE_PATH: /bin - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - APIBARA_AUTH_TOKEN: ${{ secrets.APIBARA_AUTH_TOKEN }} - APIBARA_ETCD_URL: http://localhost:2379 - - services: - postgres: - image: postgres:latest - env: - POSTGRES_DB: postgres - POSTGRES_USER: postgres - POSTGRES_HOST_AUTH_METHOD: trust - ports: - - 5432:5432 - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - localstack: - image: localstack/localstack:latest - ports: - - 4566:4566 - - 4571:4571 - - 8080:8080 - options: >- - --health-cmd "curl -k https://localhost:4566" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - etcd: - image: bitnami/etcd:3.5.0 - ports: - - 2379:2379 - - 2380:2380 - env: - ALLOW_NONE_AUTHENTICATION: yes - - steps: - - uses: actions/checkout@v3 - - # selecting a toolchain either by action or manual `rustup` calls should happen - # before the plugin, as the cache uses the current rustc version as its cache key - - run: rustup show - - - uses: taiki-e/install-action@cargo-llvm-cov - - uses: taiki-e/install-action@nextest - - - name: Download sink binaries - run: | - wget https://github.com/apibara/dna/releases/download/sink-webhook/v0.3.3/sink-webhook-x86_64-linux.gz - gunzip sink-webhook-x86_64-linux.gz - sudo cp sink-webhook-x86_64-linux /bin/sink-webhook - sudo chmod 777 /bin/sink-webhook - - wget https://github.com/apibara/dna/releases/download/sink-postgres/v0.4.3/sink-postgres-x86_64-linux.gz - gunzip sink-postgres-x86_64-linux.gz - sudo cp sink-postgres-x86_64-linux /bin/sink-postgres - sudo chmod 777 /bin/sink-postgres - - - name: Start LocalStack - run: | - pip install awscli-local - - - name: Create S3 Bucket and SQS Queues - run: | - awslocal s3api create-bucket --bucket indexer-service --region eu-west-3 --create-bucket-configuration LocationConstraint=eu-west-3 - awslocal s3api put-object --bucket indexer-service --key apibara-scripts/ - awslocal s3api list-buckets - awslocal sqs create-queue --queue-name indexer-service-start-indexer - awslocal sqs create-queue --queue-name indexer-service-failed-indexer - awslocal sqs create-queue --queue-name indexer-service-stop-indexer - awslocal sqs list-queues - - - name: Clean workspace - run: | - cargo llvm-cov clean --workspace - - - name: Run llvm-cov - run: | - cargo llvm-cov nextest --release --test-threads=1 --lcov --output-path lcov.info - - - name: Upload coverage to codecov.io - uses: codecov/codecov-action@v3 - with: - files: lcov.info - fail_ci_if_error: false - - - uses: colpal/actions-clean@v1 - if: ${{ always() }} # To ensure this step runs even when earlier steps fail diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 588c3af..93081bc 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -21,8 +21,3 @@ jobs: name: Run Cargo linters uses: ./.github/workflows/linters-cargo.yml needs: rust_build - - coverage: - name: Run coverage - uses: ./.github/workflows/coverage.yml - needs: rust_build diff --git a/src/.DS_Store b/src/.DS_Store index 6ac5d21921b28d467c9c9ffbbea7ec69ecc02d05..f65d017c9b8be6884dde14e4d3f395cdaa77379f 100644 GIT binary patch delta 28 kcmZoMXffFEn1ylOWC2#G$^TfmSf^C5HeA@u%lcgi0G3J$L;wH) delta 28 kcmZoMXffFEn1ylkWC2#G$^TfmSRK|{ZauS^m-V|40GK`sj{pDw diff --git a/src/da_clients/ethereum/config.rs b/src/da_clients/ethereum/config.rs index bf61cf0..29da4f3 100644 --- a/src/da_clients/ethereum/config.rs +++ b/src/da_clients/ethereum/config.rs @@ -1,11 +1,6 @@ use crate::da_clients::DaConfig; use crate::utils::env_utils::get_env_var_or_panic; - - - - - #[derive(Clone, Debug)] pub struct EthereumDaConfig { pub rpc_url: String,