diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a19186588f..d04e934abe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,10 +34,11 @@ jobs: toolchain: ${{ env.RUST_VERSION }} targets: wasm32-unknown-unknown - uses: Swatinem/rust-cache@v2 - - name: "Ensure `torii-client` crate is wasmable" + - uses: arduino/setup-protoc@v2 + - name: "Ensure `torii-client` crate is WASM-able" run: | cargo build -r --target wasm32-unknown-unknown -p torii-client - - name: "Ensure `torii-client-wasm` crate is wasmable" + - name: "Ensure `torii-client-wasm` crate is WASM-able" run: | cargo build -r --target wasm32-unknown-unknown --manifest-path crates/torii/client/wasm/Cargo.toml @@ -61,6 +62,7 @@ jobs: with: toolchain: ${{ env.RUST_VERSION }} - uses: Swatinem/rust-cache@v2 + - uses: arduino/setup-protoc@v2 - run: cargo run --bin sozo -- --manifest-path crates/dojo-core/Scarb.toml test dojo-erc-test: @@ -71,6 +73,7 @@ jobs: with: toolchain: ${{ env.RUST_VERSION }} - uses: Swatinem/rust-cache@v2 + - uses: arduino/setup-protoc@v2 - run: cargo run --bin sozo -- --manifest-path crates/dojo-erc/Scarb.toml test dojo-ecs-example-test: @@ -81,6 +84,7 @@ jobs: with: toolchain: ${{ env.RUST_VERSION }} - uses: Swatinem/rust-cache@v2 + - uses: arduino/setup-protoc@v2 - run: cargo run --bin sozo -- --manifest-path examples/ecs/Scarb.toml test clippy: diff --git a/Cargo.lock b/Cargo.lock index 766167ad1e..9104c72952 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,9 +63,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.5" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" dependencies = [ "memchr", ] @@ -336,17 +336,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" -[[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", - "futures-core", -] - [[package]] name = "async-compression" version = "0.4.3" @@ -449,35 +438,6 @@ dependencies = [ "warp", ] -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-std" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" -dependencies = [ - "async-channel", - "async-lock", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - [[package]] name = "async-stream" version = "0.3.5" @@ -497,7 +457,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -508,7 +468,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -780,9 +740,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byte-slice-cast" @@ -830,7 +790,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afc7f7cb89bc3f52c2c738f3e87c8f8773bd3456cae1d322d100d4b0da584f3c" dependencies = [ "cairo-lang-utils", - "indoc 2.0.3", + "indoc 2.0.4", "num-bigint", "num-traits 0.2.16", "parity-scale-codec", @@ -974,11 +934,11 @@ dependencies = [ "cairo-lang-starknet", "cairo-lang-syntax", "cairo-lang-utils", - "indoc 2.0.3", + "indoc 2.0.4", "log", "lsp-types", "salsa", - "scarb-metadata 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scarb-metadata 1.8.0", "serde", "serde_json", "smol_str", @@ -1046,7 +1006,7 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-utils", "indent", - "indoc 2.0.3", + "indoc 2.0.4", "itertools 0.11.0", "num-bigint", "salsa", @@ -1061,7 +1021,7 @@ checksum = "170838817fc33ddb65e0a9480526df0b226b148a0fca0a5cd7071be4c6683157" dependencies = [ "cairo-lang-debug", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -1232,7 +1192,7 @@ dependencies = [ "cairo-lang-sierra-gas", "cairo-lang-sierra-type-size", "cairo-lang-utils", - "indoc 2.0.3", + "indoc 2.0.4", "itertools 0.11.0", "log", "num-bigint", @@ -1277,7 +1237,7 @@ dependencies = [ "convert_case 0.6.0", "genco", "indent", - "indoc 2.0.3", + "indoc 2.0.4", "itertools 0.11.0", "log", "num-bigint", @@ -1348,7 +1308,7 @@ dependencies = [ "itertools 0.11.0", "num-bigint", "num-traits 0.2.16", - "rayon", + "rayon 1.8.0", "salsa", "thiserror", ] @@ -1463,9 +1423,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1488,9 +1448,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.3" +version = "4.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6" +checksum = "824956d0dca8334758a5b7f7e50518d66ea319330cbceedcf76905c2f6ab30e3" dependencies = [ "clap_builder", "clap_derive", @@ -1508,9 +1468,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.2" +version = "4.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" +checksum = "122ec64120a49b4563ccaedcbea7818d069ed8e9aa6d829b82d8a4128936b2ab" dependencies = [ "anstream", "anstyle", @@ -1520,9 +1480,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4110a1e6af615a9e6d0a36f805d5c99099f8bab9b8042f5bc1fa220a4a89e36f" +checksum = "8baeccdb91cd69189985f87f3c7e453a3a451ab5746cf3be6acc92120bd16d24" dependencies = [ "clap", ] @@ -1536,7 +1496,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -1568,15 +1528,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "concurrent-queue" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "console" version = "0.15.7" @@ -1768,12 +1719,12 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f34ba9a9bcb8645379e9de8cb3ecfcf4d1c85ba66d90deb3259206fa5aa193b" +checksum = "37e366bff8cd32dd8754b0991fb66b279dc48f598c3a18914852a6673deef583" dependencies = [ "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -1840,7 +1791,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -1862,7 +1813,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -2216,9 +2167,9 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "dyn-clone" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfc4744c1b8f2a09adc0e55242f60b1af195d88596bd8700be74418c056c555" +checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd" [[package]] name = "either" @@ -2368,9 +2319,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "filetime" @@ -2537,7 +2488,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -2572,9 +2523,9 @@ dependencies = [ [[package]] name = "genco" -version = "0.17.5" +version = "0.17.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6973ce8518068a71d404f428f6a5b563088545546a6bd8f9c0a7f2608149bc8a" +checksum = "3597f99dbe04460775cb349299b9532123980b17d89faeaa2da42658b7767787" dependencies = [ "genco-macros", "relative-path", @@ -2583,9 +2534,9 @@ dependencies = [ [[package]] name = "genco-macros" -version = "0.17.5" +version = "0.17.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2c778cf01917d0fbed53900259d6604a421fab4916a2e738856ead9f1d926a" +checksum = "b029ca4c73c30f813e0e92754515585ccbede98014fb26644cc7488a3833706a" dependencies = [ "proc-macro2", "quote", @@ -3335,9 +3286,9 @@ dependencies = [ [[package]] name = "good_lp" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7f3b0e0de4e671b6ffc1274b153a9394cb58bf04ee67505b0cb9915513115f" +checksum = "869f19637130a4e8e1c3f3f83df4a00a169c1d3a77a2b2ff41736b14497c4027" dependencies = [ "fnv", "minilp", @@ -3468,9 +3419,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -3757,9 +3708,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.6" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" +checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" dependencies = [ "console", "instant", @@ -3776,9 +3727,9 @@ checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" [[package]] name = "indoc" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c785eefb63ebd0e33416dfcb8d6da0bf27ce752843a45632a67bf10d4d4b5c4" +checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" [[package]] name = "inotify" @@ -3992,7 +3943,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2735847566356cd2179a2a38264839308f7079fa96e6bd5a42d740460e003c56" dependencies = [ "crossbeam", - "rayon", + "rayon 1.8.0", ] [[package]] @@ -4157,9 +4108,9 @@ checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libmimalloc-sys" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25d058a81af0d1c22d7a1c948576bee6d673f7af3c0f35564abd6c81122f513d" +checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664" dependencies = [ "cc", "libc", @@ -4246,9 +4197,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed1202b2a6f884ae56f04cff409ab315c5ce26b5e58d7412e484f01fd52f52ef" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "matrixmultiply" @@ -4285,9 +4236,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.38" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "972e5f23f6716f62665760b0f4cbf592576a80c7b879ba9beaafc0e558894127" +checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c" dependencies = [ "libmimalloc-sys", ] @@ -4748,9 +4699,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.3" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a4d085fd991ac8d5b05a147b437791b4260b76326baf0fc60cf7c9c27ecd33" +checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" dependencies = [ "memchr", "thiserror", @@ -4759,9 +4710,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.3" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bee7be22ce7918f641a33f08e3f43388c7656772244e2bbb2477f44cc9021a" +checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" dependencies = [ "pest", "pest_generator", @@ -4769,22 +4720,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.3" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1511785c5e98d79a05e8a6bc34b4ac2168a0e3e92161862030ad84daa223141" +checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] name = "pest_meta" -version = "2.7.3" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f" +checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" dependencies = [ "once_cell", "pest", @@ -4831,7 +4782,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -4854,14 +4805,14 @@ dependencies = [ [[package]] name = "phonenumber" -version = "0.3.2+8.13.9" +version = "0.3.3+8.13.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34749f64ea9d76f10cdc8a859588b57775f59177c7dd91f744d620bd62982d6f" +checksum = "635f3e6288e4f01c049d89332a031bd74f25d64b6fb94703ca966e819488cd06" dependencies = [ "bincode 1.3.3", "either", "fnv", - "itertools 0.10.5", + "itertools 0.11.0", "lazy_static", "nom", "quick-xml", @@ -4869,6 +4820,7 @@ dependencies = [ "regex-cache", "serde", "serde_derive", + "strum", "thiserror", ] @@ -4895,7 +4847,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -4954,7 +4906,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -4977,13 +4929,13 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" +checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0" dependencies = [ "anstyle", "difflib", - "itertools 0.10.5", + "itertools 0.11.0", "predicates-core", ] @@ -5013,6 +4965,16 @@ dependencies = [ "yansi", ] +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + [[package]] name = "prettyplease" version = "0.2.15" @@ -5020,7 +4982,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -5072,9 +5034,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -5089,6 +5051,16 @@ dependencies = [ "human_format", ] +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", +] + [[package]] name = "prost" version = "0.12.1" @@ -5096,7 +5068,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4fdd22f3b9c31b53c060df4a0613a1c7f062d4115a2b984dd15b1858f7e340d" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.12.1", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools 0.10.5", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease 0.1.25", + "prost 0.11.9", + "prost-types 0.11.9", + "regex", + "syn 1.0.109", + "tempfile", + "which", ] [[package]] @@ -5112,15 +5106,28 @@ dependencies = [ "multimap", "once_cell", "petgraph", - "prettyplease", - "prost", - "prost-types", + "prettyplease 0.2.15", + "prost 0.12.1", + "prost-types 0.12.1", "regex", - "syn 2.0.32", + "syn 2.0.37", "tempfile", "which", ] +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "prost-derive" version = "0.12.1" @@ -5131,7 +5138,16 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost 0.11.9", ] [[package]] @@ -5140,7 +5156,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e081b29f63d83a4bc75cfc9f3fe424f9156cf92d8a4f0c9407cce9a1b67327cf" dependencies = [ - "prost", + "prost 0.12.1", ] [[package]] @@ -5205,9 +5221,19 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "ed02d09394c94ffbdfdc755ad62a132e94c3224a8354e78a1200ced34df12edf" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -5215,14 +5241,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] @@ -5428,9 +5452,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.13" +version = "0.38.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" dependencies = [ "bitflags 2.4.0", "errno", @@ -5474,9 +5498,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.5" +version = "0.101.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a27e3b59326c16e23d30aeb7a36a24cc0d29e71d68ff611cdfb4a01d013bed" +checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" dependencies = [ "ring", "untrusted", @@ -5596,13 +5620,13 @@ dependencies = [ "glob", "ignore", "include_dir", - "indoc 2.0.3", + "indoc 2.0.4", "itertools 0.11.0", "once_cell", "pathdiff", "petgraph", "scarb-build-metadata", - "scarb-metadata 1.7.0 (git+https://github.com/software-mansion/scarb?rev=7adb7fd)", + "scarb-metadata 1.7.0", "scarb-ui", "semver", "serde", @@ -5635,10 +5659,10 @@ dependencies = [ [[package]] name = "scarb-metadata" version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e1bb385b852343276fdfc1aad0e4c48e0c01106c209a602481f36c9b50c5f59" +source = "git+https://github.com/software-mansion/scarb?rev=7adb7fd#7adb7fd972e4ec95dc404650dec78099815392c9" dependencies = [ "camino", + "derive_builder", "semver", "serde", "serde_json", @@ -5647,11 +5671,11 @@ dependencies = [ [[package]] name = "scarb-metadata" -version = "1.7.0" -source = "git+https://github.com/software-mansion/scarb?rev=7adb7fd#7adb7fd972e4ec95dc404650dec78099815392c9" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a1939d4a36ba77bc4a23024f42e16e307b74fe451d8efa23aff8916fdde6a83" dependencies = [ "camino", - "derive_builder", "semver", "serde", "serde_json", @@ -5668,17 +5692,17 @@ dependencies = [ "clap", "console", "indicatif", - "indoc 2.0.3", - "scarb-metadata 1.7.0 (git+https://github.com/software-mansion/scarb?rev=7adb7fd)", + "indoc 2.0.4", + "scarb-metadata 1.7.0", "serde", "serde_json", ] [[package]] name = "schemars" -version = "0.8.13" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161" +checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c" dependencies = [ "dyn-clone", "indexmap 1.9.3", @@ -5689,9 +5713,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.13" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" +checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c" dependencies = [ "proc-macro2", "quote", @@ -5735,9 +5759,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" dependencies = [ "serde", ] @@ -5769,7 +5793,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -5785,9 +5809,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -5813,7 +5837,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -5862,7 +5886,7 @@ dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -5880,9 +5904,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -5897,9 +5921,9 @@ checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -5967,9 +5991,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "smol_str" @@ -6321,7 +6345,7 @@ checksum = "af6527b845423542c8a16e060ea1bc43f67229848e7cd4c4d80be994a84220ce" dependencies = [ "starknet-curve 0.4.0", "starknet-ff", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -6364,7 +6388,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef846b6bb48fc8c3e9a2aa9b5b037414f04a908d9db56493a3ae69a857eb2506" dependencies = [ "starknet-core", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -6461,6 +6485,9 @@ name = "strum" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] [[package]] name = "strum_macros" @@ -6494,9 +6521,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -6541,9 +6568,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" dependencies = [ "winapi-util", ] @@ -6567,22 +6594,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -6617,9 +6644,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" +checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" dependencies = [ "deranged", "itoa", @@ -6632,15 +6659,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] @@ -6706,7 +6733,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -6755,9 +6782,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" dependencies = [ "bytes", "futures-core", @@ -6802,6 +6829,29 @@ dependencies = [ "winnow", ] +[[package]] +name = "tonic" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" +dependencies = [ + "async-trait", + "base64 0.21.4", + "bytes", + "flate2", + "futures-core", + "futures-util", + "http", + "http-body", + "percent-encoding", + "pin-project", + "prost 0.11.9", + "tokio-stream", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tonic" version = "0.10.1" @@ -6820,7 +6870,7 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost", + "prost 0.12.1", "tokio", "tokio-stream", "tower", @@ -6829,17 +6879,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic-build" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6fdaae4c2c638bb70fe42803a26fbd6fc6ac8c72f5c59f67ecc2a2dcabf4b07" +dependencies = [ + "prettyplease 0.1.25", + "proc-macro2", + "prost-build 0.11.9", + "quote", + "syn 1.0.109", +] + [[package]] name = "tonic-build" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9d37bb15da06ae9bb945963066baca6561b505af93a52e949a85d28558459a2" dependencies = [ - "prettyplease", + "prettyplease 0.2.15", "proc-macro2", - "prost-build", + "prost-build 0.12.1", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -6855,31 +6918,64 @@ dependencies = [ "hyper", "pin-project", "tokio-stream", - "tonic", + "tonic 0.10.1", "tower-http", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "tonic-web-wasm-client" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5987e92915a51a4b05e69a0ef903a7b76f16674f7ee66534f87fd3323e2d3a" +dependencies = [ + "base64 0.21.4", + "byteorder", + "bytes", + "futures-util", + "http", + "http-body", + "httparse", + "js-sys", + "pin-project", + "thiserror", + "tonic 0.9.2", + "tower-service", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + [[package]] name = "torii-client" version = "0.2.1" dependencies = [ - "async-std", + "anyhow", "async-trait", "camino", "crypto-bigint", "dojo-test-utils", "dojo-types", "dojo-world", + "futures", + "futures-util", "js-sys", "parking_lot 0.12.1", + "prost 0.11.9", + "prost 0.12.1", "serde", + "serde_json", "starknet", "starknet-crypto 0.6.0", "thiserror", "tokio", + "tonic 0.10.1", + "tonic 0.9.2", + "torii-grpc", + "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -6951,10 +7047,31 @@ dependencies = [ name = "torii-grpc" version = "0.2.1" dependencies = [ - "prost", + "anyhow", + "bytes", + "dojo-types", + "futures", + "futures-util", + "hyper", + "parking_lot 0.12.1", + "prost 0.11.9", + "prost 0.12.1", + "rayon 0.9.0", "sqlx", - "tonic", - "tonic-build", + "starknet", + "starknet-crypto 0.6.0", + "thiserror", + "tokio", + "tokio-stream", + "tonic 0.10.1", + "tonic 0.9.2", + "tonic-build 0.10.1", + "tonic-build 0.9.2", + "tonic-web", + "tonic-web-wasm-client", + "tower", + "tracing", + "url", "warp", ] @@ -6987,6 +7104,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util", + "tonic 0.10.1", "tonic-web", "torii-client", "torii-core", @@ -7117,7 +7235,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -7201,14 +7319,14 @@ checksum = "29a3151c41d0b13e3d011f98adc24434560ef06673a155a6c7f66b9879eecce2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" @@ -7299,9 +7417,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "unicode-xid" @@ -7459,7 +7577,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", "wasm-bindgen-shared", ] @@ -7493,7 +7611,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7504,6 +7622,19 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +[[package]] +name = "wasm-streams" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.64" @@ -7569,9 +7700,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -7795,7 +7926,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 60515d099e..4236a73398 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,12 @@ tonic = "0.10" tonic-build = "0.10" tonic-web = "0.10.1" +# WASM-compatible gRPC deps +tonic-web-wasm-client = "0.4.0" +wasm-prost = { version = "0.11.9", package = "prost" } +wasm-tonic = { version = "0.9.2", default-features = false, features = [ "codegen", "gzip", "prost" ], package = "tonic" } +wasm-tonic-build = { version = "0.9.2", default-features = false, features = [ "prost" ], package = "tonic-build" } + [patch."https://github.com/starkware-libs/blockifier"] blockifier = { git = "https://github.com/dojoengine/blockifier", rev = "f7df9ba" } diff --git a/crates/dojo-lang/src/manifest_test_data/manifest b/crates/dojo-lang/src/manifest_test_data/manifest index d5975f8808..1721425fb2 100644 --- a/crates/dojo-lang/src/manifest_test_data/manifest +++ b/crates/dojo-lang/src/manifest_test_data/manifest @@ -531,7 +531,7 @@ test_manifest_file { "name": "player_actions", "address": null, - "class_hash": "0xf28d16dc402498e8e945a5762776172ee690e0c3445257b38d73844eadfb4f", + "class_hash": "0x4b8aedc50c01814ad20b7e976f9d4fe76d13f56fa57aabd2a6399c7fbc1a187", "abi": [ { "type": "impl", diff --git a/crates/dojo-types/src/lib.rs b/crates/dojo-types/src/lib.rs index a794e8a319..07f1b87f29 100644 --- a/crates/dojo-types/src/lib.rs +++ b/crates/dojo-types/src/lib.rs @@ -1,5 +1,23 @@ +use std::collections::HashMap; + +use model::ModelMetadata; +use serde::Serialize; +use starknet::core::types::FieldElement; +use system::SystemMetadata; + pub mod core; pub mod event; pub mod model; pub mod storage; pub mod system; + +/// Represents the metadata of a World +#[derive(Debug, Clone, Serialize, Default)] +pub struct WorldMetadata { + pub world_address: FieldElement, + pub world_class_hash: FieldElement, + pub executor_address: FieldElement, + pub executor_class_hash: FieldElement, + pub systems: HashMap, + pub components: HashMap, +} diff --git a/crates/dojo-types/src/model.rs b/crates/dojo-types/src/model.rs index c9cd6db080..4cb0ed2f75 100644 --- a/crates/dojo-types/src/model.rs +++ b/crates/dojo-types/src/model.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use starknet::core::types::FieldElement; /// Represents a model member. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] @@ -8,6 +9,20 @@ pub struct Member { pub key: bool, } +/// Represents a component of an entity +#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub struct EntityModel { + pub model: String, + pub keys: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ModelMetadata { + pub name: String, + pub size: u32, + pub class_hash: FieldElement, +} + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum Ty { Terminal(String), diff --git a/crates/dojo-types/src/system.rs b/crates/dojo-types/src/system.rs index 68472fe8c9..b873a3a7f1 100644 --- a/crates/dojo-types/src/system.rs +++ b/crates/dojo-types/src/system.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use starknet::core::types::FieldElement; /// Represents a system's model dependency. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] @@ -8,3 +9,9 @@ pub struct Dependency { pub read: bool, pub write: bool, } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SystemMetadata { + pub name: String, + pub class_hash: FieldElement, +} diff --git a/crates/torii/client/Cargo.toml b/crates/torii/client/Cargo.toml index 98efc1f82c..c1bc86f6c5 100644 --- a/crates/torii/client/Cargo.toml +++ b/crates/torii/client/Cargo.toml @@ -6,23 +6,32 @@ version = "0.2.1" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-std = { version = "1.12.0", default-features = false, features = [ "std" ] } +anyhow.workspace = true async-trait.workspace = true crypto-bigint = "0.5.3" dojo-types = { path = "../../dojo-types" } -parking_lot = "0.12.1" +futures-util = "0.3.28" +futures.workspace = true +parking_lot.workspace = true +serde.workspace = true +serde_json.workspace = true starknet-crypto.workspace = true starknet.workspace = true thiserror.workspace = true +tokio = { version = "1.32.0", default-features = false, features = [ "rt" ] } +torii-grpc = { path = "../grpc", features = [ "client" ] } +url.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -tokio = { version = "1.16", features = [ "time" ], default-features = false } +prost.workspace = true +tonic.workspace = true [target.'cfg(target_arch = "wasm32")'.dependencies] js-sys = "0.3.64" -serde.workspace = true wasm-bindgen = "0.2.87" wasm-bindgen-futures = "0.4.37" +wasm-prost.workspace = true +wasm-tonic.workspace = true web-sys = { version = "0.3.4", features = [ 'Window', 'WorkerGlobalScope' ] } [dev-dependencies] diff --git a/crates/torii/client/src/client/error.rs b/crates/torii/client/src/client/error.rs new file mode 100644 index 0000000000..50a052c60c --- /dev/null +++ b/crates/torii/client/src/client/error.rs @@ -0,0 +1,20 @@ +use starknet::core::types::FromStrError; +use starknet::providers::jsonrpc::HttpTransport; +use starknet::providers::{JsonRpcClient, Provider}; + +use crate::contract::model::ModelError; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Error originated from the gRPC client. + #[error(transparent)] + GrpcClient(#[from] torii_grpc::client::Error), + #[error(transparent)] + FromStr(#[from] FromStrError), + #[error(transparent)] + Other(#[from] anyhow::Error), + #[error(transparent)] + UrlParse(#[from] url::ParseError), + #[error(transparent)] + Model(#[from] ModelError< as Provider>::Error>), +} diff --git a/crates/torii/client/src/client/mod.rs b/crates/torii/client/src/client/mod.rs new file mode 100644 index 0000000000..3494a671cb --- /dev/null +++ b/crates/torii/client/src/client/mod.rs @@ -0,0 +1,144 @@ +pub mod error; +pub mod storage; +pub mod subscription; + +use std::sync::Arc; + +use dojo_types::model::EntityModel; +use dojo_types::WorldMetadata; +use futures::channel::mpsc; +use parking_lot::{Mutex, RwLock}; +use starknet::core::types::{BlockId, BlockTag}; +use starknet::providers::jsonrpc::HttpTransport; +use starknet::providers::JsonRpcClient; +use starknet_crypto::FieldElement; +#[cfg(not(target_arch = "wasm32"))] +use tokio::task::spawn as spawn_task; +use url::Url; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_futures::spawn_local as spawn_task; + +use self::error::Error; +use self::storage::ComponentStorage; +use self::subscription::{SubscribedEntities, SubscriptionClientHandle}; +use crate::client::subscription::SubscriptionClient; +use crate::contract::world::WorldContractReader; + +// TODO: expose the World interface from the `Client` +#[allow(unused)] +pub struct Client { + /// Metadata of the World that the client is connected to. + metadata: Arc>, + /// The grpc client. + inner: Mutex, + /// Entity storage + storage: Arc, + /// Entities the client are subscribed to. + entity_subscription: Arc, + /// The subscription client handle + subscription_client_handle: SubscriptionClientHandle, +} + +impl Client { + /// Returns the metadata of the world. + pub fn world_metadata(&self) -> WorldMetadata { + self.metadata.read().clone() + } + + /// Returns the component value of an entity. + pub fn entity(&self, component: String, keys: Vec) -> Option> { + self.storage.get_entity((component, keys)) + } + + /// Returns the list of entities that the client is subscribed to. + pub fn synced_entities(&self) -> Vec { + self.entity_subscription.entities.read().clone().into_iter().collect() + } +} + +// TODO: able to handle entities that has not been set yet, currently `build` will panic if the +// `entities_to_sync` has never been set (the sql table isnt exist) +pub struct ClientBuilder { + initial_entities_to_sync: Option>, +} + +impl ClientBuilder { + #[must_use] + pub fn new() -> Self { + Self { initial_entities_to_sync: None } + } + + pub async fn build( + self, + torii_endpoint: String, + // TODO: remove RPC + rpc_url: String, + world: FieldElement, + ) -> Result { + let mut grpc_client = torii_grpc::client::WorldClient::new(torii_endpoint, world).await?; + + let metadata = grpc_client.metadata().await?; + + let shared_metadata: Arc<_> = RwLock::new(metadata).into(); + let client_storage: Arc<_> = ComponentStorage::new(shared_metadata.clone()).into(); + let subbed_entities: Arc<_> = SubscribedEntities::new(shared_metadata.clone()).into(); + + if let Some(entities_to_sync) = self.initial_entities_to_sync.clone() { + subbed_entities.add_entities(entities_to_sync)?; + + // initialize the entities to be synced with the latest values + let provider = JsonRpcClient::new(HttpTransport::new(Url::parse(&rpc_url)?)); + let world_reader = WorldContractReader::new(world, &provider); + + // TODO: change this to querying the gRPC endpoint instead + let subbed_entities = subbed_entities.entities.read().clone(); + for EntityModel { model: component, keys } in subbed_entities { + let component_reader = + world_reader.model(&component, BlockId::Tag(BlockTag::Pending)).await?; + let values = + component_reader.entity(keys.clone(), BlockId::Tag(BlockTag::Pending)).await?; + client_storage.set_entity((component, keys), values)?; + } + } + + // initiate the stream any way, even if we don't have any initial entities to sync + let sub_res_stream = grpc_client + .subscribe_entities(self.initial_entities_to_sync.unwrap_or_default()) + .await?; + // setup the subscription client + let subscription_client_handle = { + let (sub_req_tx, sub_req_rcv) = mpsc::channel(128); + + spawn_task(SubscriptionClient { + sub_res_stream, + err_callback: None, + req_rcv: sub_req_rcv, + storage: client_storage.clone(), + world_metadata: shared_metadata.clone(), + subscribed_entities: subbed_entities.clone(), + }); + + SubscriptionClientHandle { event_handler: sub_req_tx } + }; + + Ok(Client { + storage: client_storage, + metadata: shared_metadata, + subscription_client_handle, + inner: Mutex::new(grpc_client), + entity_subscription: subbed_entities, + }) + } + + #[must_use] + pub fn set_entities_to_sync(mut self, entities: Vec) -> Self { + self.initial_entities_to_sync = Some(entities); + self + } +} + +impl Default for ClientBuilder { + fn default() -> Self { + Self::new() + } +} diff --git a/crates/torii/client/src/client/storage.rs b/crates/torii/client/src/client/storage.rs new file mode 100644 index 0000000000..7c61e2e912 --- /dev/null +++ b/crates/torii/client/src/client/storage.rs @@ -0,0 +1,200 @@ +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; + +use anyhow::bail; +use dojo_types::WorldMetadata; +use parking_lot::RwLock; +use starknet::core::utils::cairo_short_string_to_felt; +use starknet::macros::short_string; +use starknet_crypto::{poseidon_hash_many, FieldElement}; + +pub type EntityKeys = Vec; + +pub type StorageKey = FieldElement; +pub type StorageValue = FieldElement; + +/// An in-memory storage for storing the component values of entities. +/// TODO: check if we can use sql db instead. +pub(crate) struct ComponentStorage { + metadata: Arc>, + // TODO: change entity id to entity keys + component_index: RwLock>>, /* component -> list of + * entity ids */ + pub(crate) storage: RwLock>, +} + +impl ComponentStorage { + pub(crate) fn new(metadata: Arc>) -> Self { + Self { metadata, storage: Default::default(), component_index: Default::default() } + } + + pub fn set_entity( + &self, + key: (String, Vec), + values: Vec, + ) -> anyhow::Result<()> { + let (component, entity_keys) = key; + + let Some(component_size) = self.metadata.read().components.get(&component).map(|c| c.size) + else { + bail!("unknown component: {component}") + }; + + if values.len().cmp(&(component_size as usize)).is_gt() { + bail!("too many values for component: {component}") + } else if values.len().cmp(&(component_size as usize)).is_lt() { + bail!("not enough values for component: {component}") + } + + let hashed_key = poseidon_hash_many(&entity_keys); + let entity_id = poseidon_hash_many(&[ + short_string!("dojo_storage"), + cairo_short_string_to_felt(&component).expect("valid cairo short string"), + hashed_key, + ]); + + self.component_index.write().entry(component).or_default().insert(entity_keys); + + values.into_iter().enumerate().for_each(|(i, value)| { + self.storage.write().insert(entity_id + i.into(), value); + }); + + Ok(()) + } + + pub fn get_entity(&self, key: (String, Vec)) -> Option> { + let (component, entity_keys) = key; + + let Some(component_size) = self.metadata.read().components.get(&component).map(|c| c.size) + else { + return None; + }; + + let hashed_key = poseidon_hash_many(&entity_keys); + let entity_id = poseidon_hash_many(&[ + short_string!("dojo_storage"), + cairo_short_string_to_felt(&component).expect("valid cairo short string"), + hashed_key, + ]); + + let mut values = Vec::with_capacity(component_size as usize); + + for i in 0..component_size { + let value = self.storage.read().get(&(entity_id + i.into())).copied()?; + values.push(value); + } + + Some(values) + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + use std::sync::Arc; + + use dojo_types::WorldMetadata; + use parking_lot::RwLock; + use starknet::core::utils::cairo_short_string_to_felt; + use starknet::macros::{felt, short_string}; + use starknet_crypto::poseidon_hash_many; + + fn create_dummy_metadata() -> WorldMetadata { + let components = HashMap::from([( + "Position".into(), + dojo_types::model::ModelMetadata { + name: "Position".into(), + class_hash: felt!("1"), + size: 3, + }, + )]); + + WorldMetadata { components, ..Default::default() } + } + + fn create_dummy_storage() -> super::ComponentStorage { + let metadata = Arc::new(RwLock::new(create_dummy_metadata())); + super::ComponentStorage::new(metadata) + } + + #[test] + fn err_if_set_values_too_many() { + let storage = create_dummy_storage(); + let entity = dojo_types::model::EntityModel { + model: "Position".into(), + keys: vec![felt!("0x12345")], + }; + + let values = vec![felt!("1"), felt!("2"), felt!("3"), felt!("4")]; + let result = storage.set_entity((entity.model, entity.keys), values); + + assert!(result.is_err()); + assert!(storage.storage.read().is_empty()); + } + + #[test] + fn err_if_set_values_too_few() { + let storage = create_dummy_storage(); + let entity = dojo_types::model::EntityModel { + model: "Position".into(), + keys: vec![felt!("0x12345")], + }; + + let values = vec![felt!("1"), felt!("2")]; + let result = storage.set_entity((entity.model, entity.keys), values); + + assert!(result.is_err()); + assert!(storage.storage.read().is_empty()); + } + + #[test] + fn set_and_get_entity_value() { + let storage = create_dummy_storage(); + let entity = dojo_types::model::EntityModel { + model: "Position".into(), + keys: vec![felt!("0x12345")], + }; + + assert!(storage.storage.read().is_empty()); + + let component = storage.metadata.read().components.get("Position").cloned().unwrap(); + + let expected_storage_addresses = { + let base = poseidon_hash_many(&[ + short_string!("dojo_storage"), + cairo_short_string_to_felt(&entity.model).unwrap(), + poseidon_hash_many(&entity.keys), + ]); + + (0..component.size).map(|i| base + i.into()).collect::>() + }; + + let expected_values = vec![felt!("1"), felt!("2"), felt!("3")]; + + storage + .set_entity((entity.model.clone(), entity.keys.clone()), expected_values.clone()) + .expect("set storage values"); + + let actual_values = + storage.get_entity((entity.model, entity.keys.clone())).expect("get storage values"); + + let actual_storage_addresses = + storage.storage.read().clone().into_keys().collect::>(); + + assert!( + storage + .component_index + .read() + .get("Position") + .is_some_and(|e| e.contains(&entity.keys)), + "entity keys must be indexed" + ); + assert!(actual_values == expected_values); + assert!(storage.storage.read().len() == component.size as usize); + assert!( + actual_storage_addresses + .into_iter() + .all(|address| expected_storage_addresses.contains(&address)) + ); + } +} diff --git a/crates/torii/client/src/client/subscription.rs b/crates/torii/client/src/client/subscription.rs new file mode 100644 index 0000000000..d42520a802 --- /dev/null +++ b/crates/torii/client/src/client/subscription.rs @@ -0,0 +1,274 @@ +use std::collections::HashSet; +use std::future::Future; +use std::str::FromStr; +use std::sync::Arc; +use std::task::Poll; + +use anyhow::{anyhow, bail, Result}; +use dojo_types::model::EntityModel; +use dojo_types::WorldMetadata; +use futures::channel::mpsc::{Receiver, Sender}; +use futures_util::StreamExt; +use parking_lot::RwLock; +use starknet::core::utils::cairo_short_string_to_felt; +use starknet::macros::short_string; +use starknet_crypto::{poseidon_hash_many, FieldElement}; +use torii_grpc::protos; +use torii_grpc::protos::types::EntityDiff; +use torii_grpc::protos::world::SubscribeEntitiesResponse; + +use super::ComponentStorage; + +#[derive(Debug, Clone)] +pub enum SubscriptionEvent { + SubscribeEntity(EntityModel), + UnsubscribeEntity(EntityModel), +} + +pub struct SubscribedEntities { + pub(super) entities: RwLock>, + /// All the relevant storage addresses derived from the subscribed entities + pub(super) subscribed_storage_addresses: RwLock>, + metadata: Arc>, +} + +impl SubscribedEntities { + pub fn new(metadata: Arc>) -> Self { + Self { + metadata, + entities: Default::default(), + subscribed_storage_addresses: Default::default(), + } + } + + pub fn add_entities(&self, entities: Vec) -> anyhow::Result<()> { + for entity in entities { + if !self.entities.write().insert(entity.clone()) { + continue; + } + + let hashed_key = poseidon_hash_many(&entity.keys); + let base_address = poseidon_hash_many(&[ + short_string!("dojo_storage"), + cairo_short_string_to_felt(&entity.model).map_err(|e| anyhow!(e))?, + hashed_key, + ]); + + let Some(component_size) = + self.metadata.read().components.get(&entity.model).map(|c| c.size) + else { + bail!("unknown component {}", entity.model) + }; + + (0..component_size).for_each(|i| { + self.subscribed_storage_addresses.write().insert(base_address + i.into()); + }); + } + + Ok(()) + } + + pub fn remove_entities(&self, entities: Vec) -> anyhow::Result<()> { + for entity in entities { + if !self.entities.write().remove(&entity) { + continue; + } + + let hashed_key = poseidon_hash_many(&entity.keys); + let base_address = poseidon_hash_many(&[ + short_string!("dojo_storage"), + cairo_short_string_to_felt(&entity.model).map_err(|e| anyhow!(e))?, + hashed_key, + ]); + + let Some(component_size) = + self.metadata.read().components.get(&entity.model).map(|c| c.size) + else { + bail!("unknown component {}", entity.model) + }; + + (0..component_size).for_each(|i| { + self.subscribed_storage_addresses.write().remove(&(base_address + i.into())); + }); + } + + Ok(()) + } +} + +#[allow(unused)] +pub(crate) struct SubscriptionClientHandle { + pub(super) event_handler: Sender, +} + +#[must_use = "SubscriptionClient does nothing unless polled"] +pub struct SubscriptionClient { + pub(super) req_rcv: Receiver, + /// The stream returned by the subscription server to receive the response + pub(super) sub_res_stream: tonic::Streaming, + /// Callback to be called on error + pub(super) err_callback: Option>, + + // for processing the entity diff and updating the storage + pub(super) storage: Arc, + pub(super) world_metadata: Arc>, + pub(super) subscribed_entities: Arc, +} + +impl SubscriptionClient { + // TODO: handle the subscription events properly + fn handle_event(&self, event: SubscriptionEvent) -> Result<()> { + match event { + SubscriptionEvent::SubscribeEntity(entity) => { + self.subscribed_entities.add_entities(vec![entity]) + } + SubscriptionEvent::UnsubscribeEntity(entity) => { + self.subscribed_entities.remove_entities(vec![entity]) + } + } + } + + // handle the response from the subscription stream + fn handle_response(&self, response: Result) { + match response { + Ok(res) => { + let entity_diff = res + .entity_update + .and_then(|e| e.update) + .and_then(|update| match update { + protos::types::maybe_pending_entity_update::Update::EntityUpdate( + update, + ) => update.entity_diff, + protos::types::maybe_pending_entity_update::Update::PendingEntityUpdate( + update, + ) => update.entity_diff, + }) + .expect("have entity update"); + + self.process_entity_diff(entity_diff); + } + + Err(err) => { + if let Some(ref callback) = self.err_callback { + callback(err) + } + } + } + } + + fn process_entity_diff(&self, diff: EntityDiff) { + let storage_entries = diff.storage_diffs.into_iter().find_map(|d| { + let expected = self.world_metadata.read().world_address; + let current = FieldElement::from_str(&d.address).expect("valid FieldElement value"); + if current == expected { Some(d.storage_entries) } else { None } + }); + + let Some(entries) = storage_entries else { + return; + }; + + entries.into_iter().enumerate().for_each(|(i, entry)| { + let key = FieldElement::from_str(&entry.key).expect("valid FieldElement value"); + let value = FieldElement::from_str(&entry.value).expect("valid FieldElement value"); + + println!("[{i}] key: {key:#x} value: {value:#x}", key = key, value = value); + + if self.subscribed_entities.subscribed_storage_addresses.read().contains(&key) { + self.storage.storage.write().insert(key, value); + } else { + panic!("unknown storage address"); + } + }) + } +} + +impl Future for SubscriptionClient { + type Output = (); + + fn poll( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll { + let pin = self.get_mut(); + + loop { + while let Poll::Ready(Some(req)) = pin.req_rcv.poll_next_unpin(cx) { + let _ = pin.handle_event(req); + } + + match pin.sub_res_stream.poll_next_unpin(cx) { + Poll::Ready(Some(res)) => pin.handle_response(res), + + Poll::Ready(None) => return Poll::Ready(()), + Poll::Pending => return Poll::Pending, + } + } + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + use std::sync::Arc; + + use dojo_types::model::EntityModel; + use dojo_types::WorldMetadata; + use parking_lot::RwLock; + use starknet::core::utils::cairo_short_string_to_felt; + use starknet::macros::{felt, short_string}; + use starknet_crypto::poseidon_hash_many; + + fn create_dummy_metadata() -> WorldMetadata { + let components = HashMap::from([( + "Position".into(), + dojo_types::model::ModelMetadata { + name: "Position".into(), + class_hash: felt!("1"), + size: 3, + }, + )]); + + WorldMetadata { components, ..Default::default() } + } + + #[test] + fn add_and_remove_subscribed_entity() { + let component_name = String::from("Position"); + let component_size: u32 = 3; + let keys = vec![felt!("0x12345")]; + + let mut expected_storage_addresses = { + let base = poseidon_hash_many(&[ + short_string!("dojo_storage"), + cairo_short_string_to_felt(&component_name).unwrap(), + poseidon_hash_many(&keys), + ]); + + (0..component_size).map(|i| base + i.into()).collect::>() + } + .into_iter(); + + let metadata = self::create_dummy_metadata(); + let entity = EntityModel { model: component_name, keys }; + + let subscribed_entities = super::SubscribedEntities::new(Arc::new(RwLock::new(metadata))); + subscribed_entities.add_entities(vec![entity.clone()]).expect("able to add entity"); + + let actual_storage_addresses_count = + subscribed_entities.subscribed_storage_addresses.read().len(); + let actual_storage_addresses = + subscribed_entities.subscribed_storage_addresses.read().clone(); + + assert!(subscribed_entities.entities.read().contains(&entity)); + assert_eq!(actual_storage_addresses_count, expected_storage_addresses.len()); + assert!(expected_storage_addresses.all(|addr| actual_storage_addresses.contains(&addr))); + + subscribed_entities.remove_entities(vec![entity.clone()]).expect("able to remove entities"); + + let actual_storage_addresses_count_after = + subscribed_entities.subscribed_storage_addresses.read().len(); + + assert_eq!(actual_storage_addresses_count_after, 0); + assert!(!subscribed_entities.entities.read().contains(&entity)); + } +} diff --git a/crates/torii/client/src/lib.rs b/crates/torii/client/src/lib.rs index 43cf496b95..3e2de193b9 100644 --- a/crates/torii/client/src/lib.rs +++ b/crates/torii/client/src/lib.rs @@ -1,4 +1,7 @@ +#[cfg(target_arch = "wasm32")] +extern crate wasm_prost as prost; +#[cfg(target_arch = "wasm32")] +extern crate wasm_tonic as tonic; + +pub mod client; pub mod contract; -pub mod provider; -pub mod storage; -pub mod sync; diff --git a/crates/torii/client/src/provider/jsonrpc.rs b/crates/torii/client/src/provider/jsonrpc.rs deleted file mode 100644 index 2244855ee9..0000000000 --- a/crates/torii/client/src/provider/jsonrpc.rs +++ /dev/null @@ -1,70 +0,0 @@ -use async_trait::async_trait; -use starknet::core::types::{BlockId, BlockTag}; -use starknet::providers::jsonrpc::{JsonRpcClientError, JsonRpcTransport}; -use starknet::providers::JsonRpcClient; -use starknet_crypto::FieldElement; - -use super::Provider; -use crate::contract::model::ModelError; -use crate::contract::world::WorldContractReader; - -#[derive(Debug, thiserror::Error)] -pub enum JsonRpcProviderError

{ - #[error(transparent)] - ComponetReader(ModelError

), -} - -/// An implementation of [Provider] which uses a Starknet [JsonRpcClient] to query the World. -pub struct JsonRpcProvider { - /// Starknet JSON-RPC client. - client: JsonRpcClient, - /// The address of the World contract. - world_address: FieldElement, - /// The block id to query the World with. - block_id: BlockId, -} - -impl JsonRpcProvider -where - T: JsonRpcTransport + Sync + Send, -{ - pub fn new(client: JsonRpcClient, world_address: FieldElement) -> Self { - Self { client, world_address, block_id: BlockId::Tag(BlockTag::Latest) } - } - - fn world(&self) -> WorldContractReader<'_, JsonRpcClient> { - WorldContractReader::new(self.world_address, &self.client) - } -} - -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -impl Provider for JsonRpcProvider -where - T: JsonRpcTransport + Sync + Send, -{ - type Error = JsonRpcProviderError>; - - async fn model(&self, name: &str) -> Result { - let world = self.world(); - let class_hash = world - .model(name, self.block_id) - .await - .map_err(JsonRpcProviderError::ComponetReader)? - .class_hash(); - Ok(class_hash) - } - - async fn entity( - &self, - model: &str, - keys: Vec, - ) -> Result, Self::Error> { - let world = self.world(); - let model = world - .model(model, self.block_id) - .await - .map_err(JsonRpcProviderError::ComponetReader)?; - model.entity(keys, self.block_id).await.map_err(JsonRpcProviderError::ComponetReader) - } -} diff --git a/crates/torii/client/src/provider/mod.rs b/crates/torii/client/src/provider/mod.rs deleted file mode 100644 index 8863d2b9d0..0000000000 --- a/crates/torii/client/src/provider/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -use std::error::Error; - -use async_trait::async_trait; -use starknet_crypto::FieldElement; - -pub mod jsonrpc; - -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -pub trait Provider { - type Error: Error + Send + Sync; - - /// Get the class hash of a model. - async fn model(&self, name: &str) -> Result; - - /// Get the model values of an entity. - async fn entity( - &self, - model: &str, - keys: Vec, - ) -> Result, Self::Error>; -} diff --git a/crates/torii/client/src/storage.rs b/crates/torii/client/src/storage.rs deleted file mode 100644 index 4f7926e213..0000000000 --- a/crates/torii/client/src/storage.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::error::Error; - -use async_trait::async_trait; -use starknet::macros::short_string; -use starknet_crypto::{poseidon_hash_many, FieldElement}; - -// TODO: is this low level enough? -/// Low level storage interface -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -pub trait EntityStorage { - type Error: Error + Send + Sync; - - /// This function mimic `world::set_entity` of `dojo-core` - async fn set( - &mut self, - model: FieldElement, - keys: Vec, - values: Vec, - ) -> Result<(), Self::Error>; - - /// This function mimic `world::entity` of `dojo-core` - async fn get( - &self, - model: FieldElement, - keys: Vec, - length: usize, - ) -> Result, Self::Error>; -} - -pub fn model_storage_base_address(model: FieldElement, keys: &[FieldElement]) -> FieldElement { - let id = poseidon_hash_many(keys); - poseidon_hash_many(&[short_string!("dojo_storage"), model, id]) -} diff --git a/crates/torii/client/src/sync.rs b/crates/torii/client/src/sync.rs deleted file mode 100644 index f1162bb547..0000000000 --- a/crates/torii/client/src/sync.rs +++ /dev/null @@ -1,163 +0,0 @@ -use std::collections::HashSet; -use std::sync::Arc; - -#[cfg(target_arch = "wasm32")] -use async_std::sync::RwLock as AsyncRwLock; -use parking_lot::RwLock; -use starknet::core::utils::cairo_short_string_to_felt; -use starknet_crypto::FieldElement; -use thiserror::Error; -#[cfg(not(target_arch = "wasm32"))] -use tokio::{sync::RwLock as AsyncRwLock, time::Duration}; -#[cfg(target_arch = "wasm32")] -use web_sys::WorkerGlobalScope; - -use crate::provider::Provider; -use crate::storage::EntityStorage; - -#[derive(Debug, Error)] -pub enum ClientError { - #[error(transparent)] - Provider(P), - #[error(transparent)] - Storage(S), -} - -/// Request to sync a model of an entity. -#[cfg_attr(target_arch = "wasm32", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub struct Entity { - /// Model name - pub model: String, - /// The entity keys - pub keys: Vec, -} - -/// A client to sync entity models from the World. -pub struct Client { - // We wrap it in an Arc to allow sharing the storage between threads. - /// Storage to store the synced entity model values. - storage: Arc>, - /// A provider implementation to query the World for entity models. - provider: P, - /// The entity models to sync. - pub sync_entities: RwLock>, - - /// The interval to run the syncing loop. - // DEV: It's wrapped in [parking_lot::RwLock] to prevent from having the `Self::start()` to be - // `mut`. Having it on `mut` seems to be causing this issue https://github.com/rustwasm/wasm-bindgen/issues/1578 when compiled to wasm32. - #[cfg(not(target_arch = "wasm32"))] - interval: AsyncRwLock, - #[cfg(target_arch = "wasm32")] - interval: i32, -} - -impl Client -where - S: EntityStorage + Send + Sync, - P: Provider + Send + Sync + 'static, -{ - #[cfg(not(target_arch = "wasm32"))] - const DEFAULT_INTERVAL: Duration = Duration::from_secs(1); - - #[cfg(target_arch = "wasm32")] - const DEFAULT_INTERVAL: i32 = 1000; // 1 second - - pub fn new(storage: Arc>, provider: P, entities: Vec) -> Client { - Self { - storage, - provider, - sync_entities: RwLock::new(HashSet::from_iter(entities)), - #[cfg(not(target_arch = "wasm32"))] - interval: AsyncRwLock::new(tokio::time::interval_at( - tokio::time::Instant::now() + Self::DEFAULT_INTERVAL, - Self::DEFAULT_INTERVAL, - )), - #[cfg(target_arch = "wasm32")] - interval: Self::DEFAULT_INTERVAL, - } - } - - pub fn with_interval( - mut self, - #[cfg(not(target_arch = "wasm32"))] milisecond: u64, - #[cfg(target_arch = "wasm32")] milisecond: i32, - ) -> Self { - #[cfg(not(target_arch = "wasm32"))] - { - use tokio::time::{interval_at, Instant}; - let interval = Duration::from_millis(milisecond); - self.interval = AsyncRwLock::new(interval_at(Instant::now() + interval, interval)); - } - - #[cfg(target_arch = "wasm32")] - { - self.interval = milisecond; - } - - self - } - - /// Returns the storage instance used by the client. - pub fn storage(&self) -> Arc> { - self.storage.clone() - } - - /// Starts the syncing process. - /// This function will run forever. - pub async fn start(&self) -> Result<(), ClientError> { - loop { - #[cfg(not(target_arch = "wasm32"))] - self.interval.write().await.tick().await; - - #[cfg(target_arch = "wasm32")] - sleep(self.interval).await; - - let entities = self.sync_entities.read().clone(); - for entity in entities { - let values = self - .provider - .entity(&entity.model, entity.keys.clone()) - .await - .map_err(ClientError::Provider)?; - - #[cfg(not(target_arch = "wasm32"))] - self.storage - .write() - .await - .set(cairo_short_string_to_felt(&entity.model).unwrap(), entity.keys, values) - .await - .map_err(ClientError::Storage)?; - - #[cfg(target_arch = "wasm32")] - self.storage - .write() - .await - .set(cairo_short_string_to_felt(&entity.model).unwrap(), entity.keys, values) - .await - .map_err(ClientError::Storage)?; - } - } - } -} - -#[cfg(target_arch = "wasm32")] -async fn sleep(delay: i32) { - use wasm_bindgen::JsCast; - let mut cb = |resolve: js_sys::Function, _reject: js_sys::Function| { - // if we are in a worker, use the global worker's scope - // otherwise, use the window's scope - if let Ok(worker_scope) = js_sys::global().dyn_into::() { - worker_scope - .set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, delay) - .expect("should register `setTimeout`"); - } else { - web_sys::window() - .unwrap() - .set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, delay) - .expect("should register `setTimeout`"); - } - }; - let p = js_sys::Promise::new(&mut cb); - wasm_bindgen_futures::JsFuture::from(p).await.unwrap(); -} diff --git a/crates/torii/client/wasm/.cargo/config.toml b/crates/torii/client/wasm/.cargo/config.toml index f4e8c002fc..85c748284e 100644 --- a/crates/torii/client/wasm/.cargo/config.toml +++ b/crates/torii/client/wasm/.cargo/config.toml @@ -1,2 +1,5 @@ [build] target = "wasm32-unknown-unknown" + +[target.wasm32-unknown-unknown] +runner = 'wasm-bindgen-test-runner' diff --git a/crates/torii/client/wasm/Cargo.lock b/crates/torii/client/wasm/Cargo.lock index 367d14c307..da16f604d9 100644 --- a/crates/torii/client/wasm/Cargo.lock +++ b/crates/torii/client/wasm/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -28,6 +28,43 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -43,6 +80,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + [[package]] name = "ark-ff" version = "0.4.2" @@ -55,7 +98,7 @@ dependencies = [ "ark-std", "derivative", "digest", - "itertools", + "itertools 0.10.5", "num-bigint", "num-traits", "paste", @@ -153,6 +196,28 @@ dependencies = [ "wasm-bindgen-futures", ] +[[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.37", +] + [[package]] name = "async-trait" version = "0.1.73" @@ -161,7 +226,16 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.37", +] + +[[package]] +name = "atoi" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e" +dependencies = [ + "num-traits", ] [[package]] @@ -182,11 +256,56 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[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", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -205,9 +324,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "bigdecimal" @@ -227,6 +346,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "bitvec" version = "1.0.1" @@ -250,9 +375,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byte-slice-cast" @@ -268,15 +393,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] @@ -289,15 +414,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "winapi", + "windows-targets", ] [[package]] @@ -312,9 +437,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" dependencies = [ "crossbeam-utils", ] @@ -344,6 +469,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" + [[package]] name = "crc32fast" version = "1.3.2" @@ -353,6 +493,40 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.16" @@ -420,7 +594,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.29", + "syn 2.0.37", ] [[package]] @@ -431,14 +605,14 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.29", + "syn 2.0.37", ] [[package]] name = "deranged" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" dependencies = [ "serde", ] @@ -475,17 +649,26 @@ dependencies = [ "thiserror", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +dependencies = [ + "serde", +] [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] @@ -496,6 +679,27 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "eth-keystore" version = "0.5.0" @@ -515,7 +719,7 @@ dependencies = [ "sha2", "sha3", "thiserror", - "uuid", + "uuid 0.8.2", ] [[package]] @@ -551,6 +755,18 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[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" @@ -563,6 +779,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.27" @@ -573,6 +795,18 @@ dependencies = [ "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 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -594,6 +828,21 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.28" @@ -601,6 +850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -609,6 +859,28 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot 0.11.2", +] + [[package]] name = "futures-io" version = "0.3.28" @@ -623,7 +895,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.37", ] [[package]] @@ -644,9 +916,13 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ + "futures-channel", "futures-core", + "futures-io", "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -677,15 +953,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ "bytes", "fnv", @@ -711,6 +987,58 @@ name = "hashbrown" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "ahash 0.8.3", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.0", +] + +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.4", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -727,6 +1055,15 @@ dependencies = [ "digest", ] +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + [[package]] name = "http" version = "0.2.9" @@ -749,6 +1086,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + [[package]] name = "httparse" version = "1.8.0" @@ -794,9 +1137,21 @@ dependencies = [ "futures-util", "http", "hyper", - "rustls", + "rustls 0.21.7", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", "tokio", - "tokio-rustls", + "tokio-io-timeout", ] [[package]] @@ -907,12 +1262,21 @@ dependencies = [ ] [[package]] -name = "ipnet" -version = "2.8.0" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" - -[[package]] +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + +[[package]] name = "itertools" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -921,6 +1285,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -945,11 +1318,34 @@ dependencies = [ "cpufeatures", ] +[[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.147" +version = "0.2.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" + +[[package]] +name = "libsqlite3-sys" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" [[package]] name = "lock_api" @@ -967,11 +1363,26 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] [[package]] name = "mime" @@ -979,6 +1390,22 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[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.1" @@ -999,11 +1426,45 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "multer" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "memchr", + "mime", + "spin 0.9.8", + "version_check", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[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 = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -1029,11 +1490,21 @@ dependencies = [ "autocfg", ] +[[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.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] @@ -1046,9 +1517,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "parity-scale-codec" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" dependencies = [ "arrayvec", "bitvec", @@ -1060,9 +1531,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1070,6 +1541,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1077,7 +1559,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.8", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -1088,7 +1584,7 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", "windows-targets", ] @@ -1114,11 +1610,41 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap 2.0.0", +] + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1126,12 +1652,38 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.37", +] + [[package]] name = "primitive-types" version = "0.12.1" @@ -1181,13 +1733,121 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fdd22f3b9c31b53c060df4a0613a1c7f062d4115a2b984dd15b1858f7e340d" +dependencies = [ + "bytes", + "prost-derive 0.12.1", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck", + "itertools 0.10.5", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease 0.1.25", + "prost 0.11.9", + "prost-types 0.11.9", + "regex", + "syn 1.0.109", + "tempfile", + "which", +] + +[[package]] +name = "prost-build" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bdf592881d821b83d471f8af290226c8d51402259e9bb5be7f9f8bdebbb11ac" +dependencies = [ + "bytes", + "heck", + "itertools 0.11.0", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease 0.2.15", + "prost 0.12.1", + "prost-types 0.12.1", + "regex", + "syn 2.0.37", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32" +dependencies = [ + "anyhow", + "itertools 0.11.0", + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost 0.11.9", +] + +[[package]] +name = "prost-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e081b29f63d83a4bc75cfc9f3fe424f9156cf92d8a4f0c9407cce9a1b67327cf" +dependencies = [ + "prost 0.12.1", +] + [[package]] name = "quote" version = "1.0.33" @@ -1233,22 +1893,80 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rayon" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed02d09394c94ffbdfdc755ad62a132e94c3224a8354e78a1200ced34df12edf" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", ] +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ - "base64 0.21.2", + "base64 0.21.4", "bytes", "encoding_rs", "futures-core", @@ -1265,19 +1983,19 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", + "rustls 0.21.7", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.25.2", "winreg", ] @@ -1300,7 +2018,7 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", + "spin 0.5.2", "untrusted", "web-sys", "winapi", @@ -1337,11 +2055,36 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustls" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + [[package]] name = "rustls" -version = "0.21.6" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" dependencies = [ "log", "ring", @@ -1355,19 +2098,25 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.2", + "base64 0.21.4", ] [[package]] name = "rustls-webpki" -version = "0.101.3" +version = "0.101.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261e9e0888cba427c3316e6322805653c9425240b6fd96cee7cb671ab70ab8d0" +checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" dependencies = [ "ring", "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.15" @@ -1383,6 +2132,12 @@ dependencies = [ "cipher", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -1413,24 +2168,24 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" [[package]] name = "serde" -version = "1.0.183" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde-wasm-bindgen" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +checksum = "30c9933e5689bd420dc6c87b7a1835701810cbc10cd86a26e4da45b73e6b1d78" dependencies = [ "js-sys", "serde", @@ -1439,20 +2194,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.183" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.37", ] [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -1507,7 +2262,18 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.37", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", ] [[package]] @@ -1531,20 +2297,29 @@ dependencies = [ "keccak", ] +[[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 = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "socket2" @@ -1558,9 +2333,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" dependencies = [ "libc", "windows-sys", @@ -1572,6 +2347,118 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "sqlformat" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85" +dependencies = [ + "itertools 0.11.0", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8de3b03a925878ed54a954f621e64bf55a3c1bd29652d0d1a17830405350188" +dependencies = [ + "sqlx-core", + "sqlx-macros", +] + +[[package]] +name = "sqlx-core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029" +dependencies = [ + "ahash 0.7.6", + "atoi", + "bitflags 1.3.2", + "byteorder", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "dotenvy", + "either", + "event-listener", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "hashlink", + "hex", + "indexmap 1.9.3", + "itoa", + "libc", + "libsqlite3-sys", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "rustls 0.20.9", + "rustls-pemfile", + "serde", + "sha2", + "smallvec", + "sqlformat", + "sqlx-rt", + "stringprep", + "thiserror", + "tokio-stream", + "url", + "uuid 1.4.1", + "webpki-roots 0.22.6", +] + +[[package]] +name = "sqlx-macros" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9966e64ae989e7e575b19d7265cb79d7fc3cbbdf179835cb0d716f294c2049c9" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-rt", + "syn 1.0.109", + "url", +] + +[[package]] +name = "sqlx-rt" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024" +dependencies = [ + "once_cell", + "tokio", + "tokio-rustls 0.23.4", +] + [[package]] name = "starknet" version = "0.6.0" @@ -1623,7 +2510,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b796a32a7400f7d85e95d3900b5cee7a392b2adbf7ad16093ed45ec6f8d85de6" dependencies = [ - "base64 0.21.2", + "base64 0.21.4", "flate2", "hex", "serde", @@ -1663,7 +2550,7 @@ checksum = "af6527b845423542c8a16e060ea1bc43f67229848e7cd4c4d80be994a84220ce" dependencies = [ "starknet-curve", "starknet-ff", - "syn 2.0.29", + "syn 2.0.37", ] [[package]] @@ -1697,7 +2584,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef846b6bb48fc8c3e9a2aa9b5b037414f04a908d9db56493a3ae69a857eb2506" dependencies = [ "starknet-core", - "syn 2.0.29", + "syn 2.0.37", ] [[package]] @@ -1742,6 +2629,17 @@ 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" @@ -1767,46 +2665,65 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.29" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tempfile" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys", +] + [[package]] name = "thiserror" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.37", ] [[package]] name = "time" -version = "0.3.25" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" +checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" dependencies = [ "deranged", "itoa", @@ -1817,15 +2734,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] @@ -1864,26 +2781,85 @@ dependencies = [ "bytes", "libc", "mio", + "num_cpus", + "parking_lot 0.12.1", "pin-project-lite", - "socket2 0.5.3", + "signal-hook-registry", + "socket2 0.5.4", + "tokio-macros", "windows-sys", ] +[[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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls 0.20.9", + "tokio", + "webpki", +] + [[package]] name = "tokio-rustls" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.7", "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", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" dependencies = [ "bytes", "futures-core", @@ -1901,30 +2877,159 @@ checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.0.0", "toml_datetime", "winnow", ] +[[package]] +name = "tonic" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" +dependencies = [ + "async-trait", + "base64 0.21.4", + "bytes", + "flate2", + "futures-core", + "futures-util", + "http", + "http-body", + "percent-encoding", + "pin-project", + "prost 0.11.9", + "tokio-stream", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c00bc15e49625f3d2f20b17082601e5e17cf27ead69e805174026c194b6664" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.21.4", + "bytes", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost 0.12.1", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6fdaae4c2c638bb70fe42803a26fbd6fc6ac8c72f5c59f67ecc2a2dcabf4b07" +dependencies = [ + "prettyplease 0.1.25", + "proc-macro2", + "prost-build 0.11.9", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tonic-build" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d37bb15da06ae9bb945963066baca6561b505af93a52e949a85d28558459a2" +dependencies = [ + "prettyplease 0.2.15", + "proc-macro2", + "prost-build 0.12.1", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "tonic-web" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2953fe95664e86519e0d1c4bdd65007d93bc47a59c9af512280977aa9e46b871" +dependencies = [ + "base64 0.21.4", + "bytes", + "http", + "http-body", + "hyper", + "pin-project", + "tokio-stream", + "tonic 0.10.1", + "tower-http", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-web-wasm-client" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5987e92915a51a4b05e69a0ef903a7b76f16674f7ee66534f87fd3323e2d3a" +dependencies = [ + "base64 0.21.4", + "byteorder", + "bytes", + "futures-util", + "http", + "http-body", + "httparse", + "js-sys", + "pin-project", + "thiserror", + "tonic 0.9.2", + "tower-service", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + [[package]] name = "torii-client" version = "0.2.1" dependencies = [ - "async-std", + "anyhow", "async-trait", "crypto-bigint", "dojo-types", + "futures", + "futures-util", "js-sys", - "parking_lot", + "parking_lot 0.12.1", + "prost 0.11.9", + "prost 0.12.1", "serde", + "serde_json", "starknet", "starknet-crypto", "thiserror", "tokio", + "tonic 0.10.1", + "tonic 0.9.2", + "torii-grpc", + "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -1937,19 +3042,101 @@ dependencies = [ "async-std", "async-trait", "console_error_panic_hook", + "dojo-types", + "futures", "js-sys", - "parking_lot", + "parking_lot 0.12.1", "serde", "serde-wasm-bindgen", + "serde_json", "starknet", "thiserror", + "tokio", "torii-client", + "torii-grpc", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-bindgen-test", "web-sys", ] +[[package]] +name = "torii-grpc" +version = "0.2.1" +dependencies = [ + "anyhow", + "bytes", + "dojo-types", + "futures", + "futures-util", + "hyper", + "parking_lot 0.12.1", + "prost 0.11.9", + "prost 0.12.1", + "rayon", + "sqlx", + "starknet", + "starknet-crypto", + "thiserror", + "tokio", + "tokio-stream", + "tonic 0.10.1", + "tonic 0.9.2", + "tonic-build 0.10.1", + "tonic-build 0.9.2", + "tonic-web", + "tonic-web-wasm-client", + "tower", + "tracing", + "url", + "warp", +] + +[[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-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +dependencies = [ + "bitflags 2.4.0", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -1963,10 +3150,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", + "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "tracing-core" version = "0.1.31" @@ -1982,11 +3182,30 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "tungstenite" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" +dependencies = [ + "base64 0.13.1", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "uint" @@ -2000,6 +3219,15 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -2008,9 +3236,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2021,6 +3249,18 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "untrusted" version = "0.7.1" @@ -2029,15 +3269,21 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "uuid" version = "0.8.2" @@ -2048,6 +3294,18 @@ dependencies = [ "serde", ] +[[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" + +[[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" @@ -2063,6 +3321,37 @@ dependencies = [ "try-lock", ] +[[package]] +name = "warp" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba431ef570df1287f7f8b07e376491ad54f84d26ac473489427231e1718e1f69" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "headers", + "http", + "hyper", + "log", + "mime", + "mime_guess", + "multer", + "percent-encoding", + "pin-project", + "rustls-pemfile", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tokio-util", + "tower-service", + "tracing", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2090,7 +3379,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.37", "wasm-bindgen-shared", ] @@ -2124,7 +3413,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.37", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2135,6 +3424,43 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +[[package]] +name = "wasm-bindgen-test" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wasm-streams" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.64" @@ -2147,9 +3473,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +checksum = "f0e74f82d49d545ad128049b7e88f6576df2da6b02e9ce565c6f533be576957e" dependencies = [ "ring", "untrusted", @@ -2164,6 +3490,24 @@ dependencies = [ "webpki", ] +[[package]] +name = "webpki-roots" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2263,20 +3607,21 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d09770118a7eb1ccaf4a594a221334119a44a814fcb0d31c5b85e83e97227a97" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys", ] [[package]] @@ -2305,5 +3650,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.37", ] diff --git a/crates/torii/client/wasm/Cargo.toml b/crates/torii/client/wasm/Cargo.toml index d7df6350a1..f0573acd38 100644 --- a/crates/torii/client/wasm/Cargo.toml +++ b/crates/torii/client/wasm/Cargo.toml @@ -13,16 +13,20 @@ crate-type = [ "cdylib", "rlib" ] [dependencies] async-std = { version = "1.12.0", default-features = false, features = [ "std" ] } async-trait = "0.1.68" +dojo-types = { path = "../../../dojo-types" } parking_lot = "0.12.1" serde = { version = "1.0.156", features = [ "derive" ] } +serde_json = "1.0.64" starknet = "0.6.0" thiserror = "1.0.32" +tokio = { version = "1.32.0", default-features = false, features = [ "rt" ] } torii-client = { path = ".." } +torii-grpc = { path = "../../grpc", features = [ "client" ] } url = "2.4.0" -# wasm +# WASM js-sys = "0.3.64" -serde-wasm-bindgen = "0.5.0" +serde-wasm-bindgen = "0.6.0" wasm-bindgen = "0.2.87" wasm-bindgen-futures = "0.4.37" web-sys = { version = "0.3.4", features = [ 'MessageEvent', 'Window', 'Worker', 'WorkerGlobalScope', 'console' ] } @@ -31,3 +35,7 @@ web-sys = { version = "0.3.4", features = [ 'MessageEvent', 'Window', 'Worker', # all the `std::fmt` and `std::panicking` infrastructure, so isn't great for # code size when deploying. console_error_panic_hook = "0.1.7" +futures = "0.3.28" + +[dev-dependencies] +wasm-bindgen-test = "0.3.0" diff --git a/crates/torii/client/wasm/index.html b/crates/torii/client/wasm/index.html index ffe6ed72d6..85de016375 100644 --- a/crates/torii/client/wasm/index.html +++ b/crates/torii/client/wasm/index.html @@ -1,23 +1,13 @@ - - - - - - - -

-

Main Thread/Wasm Web Worker Interaction

- - - -
-
- - - - - - - - \ No newline at end of file + + + + + + + + + + + + diff --git a/crates/torii/client/wasm/index.js b/crates/torii/client/wasm/index.js index 62419c9f8b..af79a2b9ff 100644 --- a/crates/torii/client/wasm/index.js +++ b/crates/torii/client/wasm/index.js @@ -1,8 +1,3 @@ -// We only need `startup` here which is the main entry point -// In theory, we could also use all other functions/struct types from Rust which we have bound with -// `#[wasm_bindgen]` -const { setup } = wasm_bindgen; - async function run_wasm() { // Load the wasm file by awaiting the Promise returned by `wasm_bindgen` // `wasm_bindgen` was imported in `index.html` @@ -10,9 +5,9 @@ async function run_wasm() { console.log("index.js loaded"); - const syncWorker = new Worker("./worker.js"); + const clientWorker = new Worker("./worker.js"); - syncWorker.onmessage = function (e) { + clientWorker.onmessage = function (e) { const event = e.data.type; const data = e.data.data; @@ -31,30 +26,18 @@ async function run_wasm() { }; setTimeout(() => { - // Add the entity to sync - syncWorker.postMessage({ - type: "addEntityToSync", - data: { - model: "Position", - keys: [ - "0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973", - ], - }, - }); - setInterval(() => { // Get the entity values from the sync worker - syncWorker.postMessage({ + clientWorker.postMessage({ type: "getModelValue", data: { model: "Position", keys: [ "0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973", ], - length: 2, }, }); - }, 1000); + }, 2000); }, 1000); } diff --git a/crates/torii/client/wasm/rust-toolchain.toml b/crates/torii/client/wasm/rust-toolchain.toml new file mode 100644 index 0000000000..5d56faf9ae --- /dev/null +++ b/crates/torii/client/wasm/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/crates/torii/client/wasm/src/lib.rs b/crates/torii/client/wasm/src/lib.rs index 15a4fea46f..bbc4f251f5 100644 --- a/crates/torii/client/wasm/src/lib.rs +++ b/crates/torii/client/wasm/src/lib.rs @@ -1,92 +1,88 @@ -use std::sync::Arc; +use std::str::FromStr; -use async_std::sync::RwLock as AsyncRwLock; use starknet::core::types::FieldElement; -use starknet::core::utils::cairo_short_string_to_felt; -use starknet::providers::jsonrpc::HttpTransport; -use starknet::providers::JsonRpcClient; -use torii_client::provider::jsonrpc::JsonRpcProvider; -use torii_client::storage::EntityStorage; -use torii_client::sync::{self, Client, Entity}; -use url::Url; use wasm_bindgen::prelude::*; -mod storage; +type JsFieldElement = JsValue; +type JsEntityComponent = JsValue; -use storage::InMemoryStorage; - -/// A type wrapper to expose the client to WASM. #[wasm_bindgen] -pub struct WasmClient(Client>); +extern "C" { + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); +} #[wasm_bindgen] -impl WasmClient { - /// Create an instance of the client. This will create an instance of the client - /// without any entity models to sync. - /// - /// # Arguments - /// * `url` - The url of the Starknet JSON-RPC provider. - /// * `world_address` - The address of the World contract to sync with. - #[wasm_bindgen(constructor)] - pub fn new(url: &str, world_address: &str) -> Self { - let world_address = FieldElement::from_hex_be(world_address).unwrap(); - - let storage = Arc::new(AsyncRwLock::new(InMemoryStorage::new())); - let provider = JsonRpcProvider::new( - JsonRpcClient::new(HttpTransport::new(Url::parse(url).unwrap())), - world_address, - ); - - Self(sync::Client::new(storage, provider, vec![])) - } - - /// Start the syncing loop. - pub async fn start(&self) -> Result<(), JsValue> { - console_error_panic_hook::set_once(); - self.0.start().await.map_err(|e| JsValue::from_str(&e.to_string())) - } +pub struct Client(torii_client::client::Client); - /// Returns the model values of the requested entity keys. +#[wasm_bindgen] +impl Client { + /// Returns the model values of the requested entity. #[wasm_bindgen(js_name = getModelValue)] pub async fn get_model_value( &self, model: &str, - keys: JsValue, - length: usize, - ) -> Result { + keys: Vec, + ) -> Result, JsValue> { console_error_panic_hook::set_once(); - let keys = serde_wasm_bindgen::from_value::>(keys)?; - let values = self - .0 - .storage() - .read() - .await - .get( - cairo_short_string_to_felt(model) - .map_err(|e| JsValue::from_str(&e.to_string()))?, - keys, - length, - ) - .await - .map_err(|e| JsValue::from_str(&e.to_string()))?; + let keys = keys + .into_iter() + .map(serde_wasm_bindgen::from_value::) + .collect::, _>>() + .map_err(|err| { + JsValue::from_str(format!("failed to parse entity keys: {err}").as_str()) + })?; - Ok(serde_wasm_bindgen::to_value(&values)?) + match self.0.entity(model.to_string(), keys) { + Some(values) => Ok(Some(serde_wasm_bindgen::to_value(&values)?)), + None => Ok(None), + } } /// Add a new entity to be synced by the client. #[wasm_bindgen(js_name = addEntityToSync)] - pub fn add_entity_to_sync(&self, entity: JsValue) -> Result<(), JsValue> { + pub fn add_entities_to_sync(&self, entities: Vec) -> Result<(), JsValue> { console_error_panic_hook::set_once(); - let entity = serde_wasm_bindgen::from_value::(entity)?; - self.0.sync_entities.write().insert(entity); - Ok(()) + let _entities = entities + .into_iter() + .map(serde_wasm_bindgen::from_value::) + .collect::, _>>()?; + unimplemented!("add_entity_to_sync"); } /// Returns the list of entities that are currently being synced. #[wasm_bindgen(getter, js_name = syncedEntities)] pub fn synced_entities(&self) -> Result { console_error_panic_hook::set_once(); - Ok(serde_wasm_bindgen::to_value(&self.0.sync_entities.read().iter().collect::>())?) + let entities = self.0.synced_entities(); + serde_wasm_bindgen::to_value(&entities).map_err(|e| e.into()) } } + +#[wasm_bindgen] +pub async fn spawn_client( + torii_url: &str, + rpc_url: &str, + world_address: &str, + initial_entities_to_sync: Vec, +) -> Result { + console_error_panic_hook::set_once(); + + let entities = initial_entities_to_sync + .into_iter() + .map(serde_wasm_bindgen::from_value::) + .collect::, _>>()?; + + let world_address = FieldElement::from_str(world_address).map_err(|err| { + JsValue::from_str(format!("failed to parse World address: {err}").as_str()) + })?; + + let client = torii_client::client::ClientBuilder::new() + .set_entities_to_sync(entities) + .build(torii_url.into(), rpc_url.into(), world_address) + .await + .map_err(|err| JsValue::from_str(format!("failed to build client: {err}").as_str()))?; + + Ok(Client(client)) +} diff --git a/crates/torii/client/wasm/src/storage.rs b/crates/torii/client/wasm/src/storage.rs deleted file mode 100644 index df87cb387c..0000000000 --- a/crates/torii/client/wasm/src/storage.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::collections::HashMap; - -use async_trait::async_trait; -use serde::{Deserialize, Serialize}; -use starknet::core::types::FieldElement; -use torii_client::storage::{model_storage_base_address, EntityStorage}; - -/// Simple in memory implementation of [EntityStorage] -#[derive(Serialize, Deserialize)] -pub struct InMemoryStorage { - /// storage key -> Model value - pub inner: HashMap, -} - -impl InMemoryStorage { - pub fn new() -> Self { - Self { inner: HashMap::new() } - } -} - -#[derive(Debug, thiserror::Error)] -pub enum InMemoryStorageError {} - -// Example implementation of [EntityStorage] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -impl EntityStorage for InMemoryStorage { - type Error = InMemoryStorageError; - - async fn set( - &mut self, - model: FieldElement, - keys: Vec, - values: Vec, - ) -> Result<(), Self::Error> { - let base_address = model_storage_base_address(model, &keys); - for (offset, value) in values.into_iter().enumerate() { - self.inner.insert(base_address + offset.into(), value); - } - Ok(()) - } - - async fn get( - &self, - model: FieldElement, - keys: Vec, - length: usize, - ) -> Result, Self::Error> { - let base_address = model_storage_base_address(model, &keys); - let mut values = Vec::with_capacity(length); - for i in 0..length { - let address = base_address + i.into(); - let value = self.inner.get(&address).cloned(); - values.push(value.unwrap_or(FieldElement::ZERO)); - } - Ok(values) - } -} diff --git a/crates/torii/client/wasm/worker.js b/crates/torii/client/wasm/worker.js index 5beb1b6af0..737cd8f34f 100644 --- a/crates/torii/client/wasm/worker.js +++ b/crates/torii/client/wasm/worker.js @@ -3,42 +3,53 @@ // available which we need to initialize our Wasm code. importScripts("./pkg/torii_client_wasm.js"); -console.log("Initializing worker"); +console.log("Initializing client worker..."); // In the worker, we have a different struct that we want to use as in // `index.js`. -const { WasmClient } = wasm_bindgen; +const { spawn_client } = wasm_bindgen; async function setup() { // Load the wasm file by awaiting the Promise returned by `wasm_bindgen`. await wasm_bindgen("./pkg/torii_client_wasm_bg.wasm"); - const client = new WasmClient( - "http://localhost:5050", - "0x398c6b4f479e2a6181ae895ad34333b44e419e48098d2a9622f976216d044dd" - ); + try { + const client = await spawn_client( + "http://localhost:8080/grpc", + "http://localhost:5050", + "0x2430f23de0cd9a957e1beb7aa8ef2db2af872cc7bb3058b9be833111d5518f5", + [ + { + model: "Position", + keys: [ + "0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973", + ], + }, + ] + ); - client.start(); + // setup the message handler for the worker + self.onmessage = function (e) { + const event = e.data.type; + const data = e.data.data; - // setup the message handler for the worker - self.onmessage = function (e) { - const event = e.data.type; - const data = e.data.data; - - if (event === "getModelValue") { - getModelValueHandler(client, data); - } else if (event === "addEntityToSync") { - addEntityToSyncHandler(client, data); - } else { - console.log("Sync Worker: Unknown event type", event); - } - }; + if (event === "getModelValue") { + getModelValueHandler(client, data); + } else if (event === "addEntityToSync") { + addEntityToSyncHandler(client, data); + } else { + console.log("Sync Worker: Unknown event type", event); + } + }; + } catch (e) { + console.error("error spawning client: ", e); + } } -function addEntityToSyncHandler(client, data) { - console.log("Sync Worker | Adding new entity to sync | data: ", data); - client.addEntityToSync(data); -} +// function addEntityToSyncHandler(client, data) { +// console.log("Sync Worker | Adding new entity to sync | data: ", data); +// client.addEntityToSync(data); +// } /// Handler for the `get_entity` event from the main thread. /// Returns back the entity data to the main thread via `postMessage`. @@ -47,9 +58,8 @@ async function getModelValueHandler(client, data) { const model = data.model; const keys = data.keys; - const length = data.length; - const values = await client.getModelValue(model, keys, length); + const values = await client.getModelValue(model, keys); self.postMessage({ type: "getModelValue", diff --git a/crates/torii/core/Cargo.toml b/crates/torii/core/Cargo.toml index 166ea4d4ea..12591f12f5 100644 --- a/crates/torii/core/Cargo.toml +++ b/crates/torii/core/Cargo.toml @@ -27,9 +27,9 @@ slab = "0.4.2" sqlx = { version = "0.6.2", features = [ "chrono", "macros", "offline", "runtime-actix-rustls", "sqlite", "uuid" ] } starknet-crypto.workspace = true starknet.workspace = true +tokio = { version = "1.32.0", features = [ "sync" ], default-features = true } tokio-stream = "0.1.11" tokio-util = "0.7.7" -tokio.workspace = true torii-client = { path = "../client" } tracing.workspace = true diff --git a/crates/torii/core/src/engine.rs b/crates/torii/core/src/engine.rs index 398b17902a..5207b8b130 100644 --- a/crates/torii/core/src/engine.rs +++ b/crates/torii/core/src/engine.rs @@ -7,6 +7,7 @@ use starknet::core::types::{ }; use starknet::core::utils::get_selector_from_name; use starknet::providers::Provider; +use tokio::sync::mpsc::Sender as BoundedSender; use tokio::time::sleep; use tokio_util::sync::CancellationToken; use torii_client::contract::world::WorldContractReader; @@ -48,6 +49,7 @@ where provider: &'a P, processors: Processors

, config: EngineConfig, + block_sender: Option>, } impl<'a, P: Provider + Sync> Engine<'a, P> @@ -60,8 +62,9 @@ where provider: &'a P, processors: Processors

, config: EngineConfig, + block_sender: Option>, ) -> Self { - Self { world, db, provider, processors, config } + Self { world, db, provider, processors, config, block_sender } } pub async fn start(&self, cts: CancellationToken) -> Result<(), Box> { @@ -113,6 +116,11 @@ where } }; + // send the current block number + if let Some(ref block_sender) = self.block_sender { + block_sender.send(from).await.expect("failed to send block number to gRPC server"); + } + self.process(block_with_txs).await?; self.db.set_head(from).await?; diff --git a/crates/torii/core/src/simple_broker.rs b/crates/torii/core/src/simple_broker.rs index 4615137fda..d254c3008b 100644 --- a/crates/torii/core/src/simple_broker.rs +++ b/crates/torii/core/src/simple_broker.rs @@ -12,7 +12,7 @@ use slab::Slab; static SUBSCRIBERS: Lazy>>> = Lazy::new(Default::default); -struct Senders(Slab>); +pub struct Senders(pub Slab>); struct BrokerStream(usize, UnboundedReceiver); @@ -63,4 +63,13 @@ impl SimpleBroker { BrokerStream(id, rx) }) } + + /// Execute the given function with the _subscribers_ of the specified subscription type. + pub fn with_subscribers(f: F) -> R + where + T: Sync + Send + Clone + 'static, + F: FnOnce(&mut Senders) -> R, + { + with_senders(f) + } } diff --git a/crates/torii/core/src/sql.rs b/crates/torii/core/src/sql.rs index 144dcdc09d..768b9f67be 100644 --- a/crates/torii/core/src/sql.rs +++ b/crates/torii/core/src/sql.rs @@ -220,7 +220,7 @@ impl Sql { // keys are part of model members, so combine keys and model values array let mut member_values: Vec = Vec::new(); - member_values.extend(keys); + member_values.extend(keys.clone()); member_values.extend(values); let insert_models: Vec<_> = primitive_members diff --git a/crates/torii/graphql/src/tests/mod.rs b/crates/torii/graphql/src/tests/mod.rs index e5ed72f2c5..37b23363a1 100644 --- a/crates/torii/graphql/src/tests/mod.rs +++ b/crates/torii/graphql/src/tests/mod.rs @@ -117,6 +117,7 @@ pub async fn bootstrap_engine<'a>( ..Processors::default() }, EngineConfig::default(), + None, ); let _ = engine.sync_to_head(0).await?; diff --git a/crates/torii/grpc/Cargo.toml b/crates/torii/grpc/Cargo.toml index 7c86677292..9b3dbc8030 100644 --- a/crates/torii/grpc/Cargo.toml +++ b/crates/torii/grpc/Cargo.toml @@ -6,10 +6,41 @@ repository.workspace = true version.workspace = true [dependencies] +anyhow.workspace = true +bytes = "1.0" +dojo-types = { path = "../../dojo-types" } +futures.workspace = true +parking_lot.workspace = true +rayon.workspace = true +starknet-crypto.workspace = true +starknet.workspace = true +thiserror.workspace = true + +# server +hyper = "0.14.27" +tonic-web.workspace = true +tower = "0.4.13" +tracing.workspace = true + +[target.'cfg(target_arch = "wasm32")'.dependencies] +tonic-web-wasm-client.workspace = true +wasm-prost.workspace = true +wasm-tonic.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +futures-util = "0.3.28" prost.workspace = true sqlx = { version = "0.6.2", features = [ "chrono", "macros", "offline", "runtime-actix-rustls", "sqlite", "uuid" ] } +tokio-stream = "0.1.14" +tokio.workspace = true tonic.workspace = true +url.workspace = true warp.workspace = true [build-dependencies] tonic-build.workspace = true +wasm-tonic-build.workspace = true + +[features] +client = [ ] +server = [ ] # this feature can't be build on wasm32 diff --git a/crates/torii/grpc/build.rs b/crates/torii/grpc/build.rs index 97ef8bcd78..095d64820b 100644 --- a/crates/torii/grpc/build.rs +++ b/crates/torii/grpc/build.rs @@ -1,4 +1,22 @@ fn main() -> Result<(), Box> { - tonic_build::compile_protos("proto/world.proto")?; + let target = std::env::var("TARGET").expect("failed to get TARGET environment variable"); + let feature_client = std::env::var("CARGO_FEATURE_CLIENT"); + let feature_server = std::env::var("CARGO_FEATURE_SERVER"); + + if target.contains("wasm32") { + if feature_server.is_ok() { + panic!("feature `server` is not supported on target `{}`", target); + } + + wasm_tonic_build::configure() + .build_server(false) + .build_client(feature_client.is_ok()) + .compile(&["proto/world.proto"], &["proto"])?; + } else { + tonic_build::configure() + .build_server(feature_server.is_ok()) + .build_client(feature_client.is_ok()) + .compile(&["proto/world.proto"], &["proto"])?; + } Ok(()) } diff --git a/crates/torii/grpc/proto/types.proto b/crates/torii/grpc/proto/types.proto new file mode 100644 index 0000000000..57827fd96f --- /dev/null +++ b/crates/torii/grpc/proto/types.proto @@ -0,0 +1,76 @@ +syntax = "proto3"; +package types; + +message WorldMetadata { + // The hex-encoded address of the world. + string world_address = 1; + // The hex-encoded class hash of the world. + string world_class_hash = 2; + // The hex-encoded address of the executor. + string executor_address = 3; + // The hex-encoded class hash of the executor. + string executor_class_hash = 4; + // A list of metadata for all registered components in the world. + repeated ModelMetadata models = 5; + // A list of metadata for all registered systems in the world. + repeated SystemMetadata systems = 6; +} + +message SystemMetadata { + // System name + string name = 1; + // hex-encoded class hash of the system + string class_hash = 2; +} + +message ModelMetadata { + // Model name + string name = 1; + // Model size + uint32 size = 2; + // hex-encoded class hash of the component + string class_hash = 3; +} + +/// Represents a component for a given entity. +message EntityModel { + /// Model name + string model = 1; + /// Entity keys + repeated string keys = 2; +} + +message StorageEntry { + // The key of the changed value + string key = 1; + // The new value applied to the given address + string value = 2; +} + +message StorageDiff { + // The contract address for which the storage changed + string address = 1; + // The changes in the storage of the contract + repeated StorageEntry storage_entries = 2; +} + +message EntityDiff { + // Storage diffs + repeated StorageDiff storage_diffs = 1; +} + +message EntityUpdate { + string block_hash = 1; + EntityDiff entity_diff = 2; +} + +message PendingEntityUpdate { + EntityDiff entity_diff = 1; +} + +message MaybePendingEntityUpdate { + oneof update { + EntityUpdate entity_update = 1; + PendingEntityUpdate pending_entity_update = 2; + } +} \ No newline at end of file diff --git a/crates/torii/grpc/proto/world.proto b/crates/torii/grpc/proto/world.proto index 720a66d6d8..a170ddaf59 100644 --- a/crates/torii/grpc/proto/world.proto +++ b/crates/torii/grpc/proto/world.proto @@ -1,26 +1,55 @@ syntax = "proto3"; package world; +import "types.proto"; + // The World service provides information about the world. service World { - // Retrieves metadata about the world. - rpc Meta (MetaRequest) returns (MetaReply); + // Retrieves metadata about the World including all the registered components and systems. + rpc WorldMetadata (MetadataRequest) returns (MetadataResponse); + + // rpc ComponentMetadata () returns (); + // rpc SystemMetadata () returns (); + + // Retrieve the component values of the requested entity. + rpc GetEntity (GetEntityRequest) returns (GetEntityResponse); + + /* + * Subscribes to entity updates. + * Bidirectional streaming as we want to allow user to change the list of entities to subscribe to without closing the connection. + */ + rpc SubscribeEntities (SubscribeEntitiesRequest) returns (stream SubscribeEntitiesResponse); } + // A request to retrieve metadata for a specific world ID. -message MetaRequest { - // The address of the world. - string id = 1; +message MetadataRequest { + } // The metadata response contains addresses and class hashes for the world. -message MetaReply { - // The hex-encoded address of the world. - string world_address = 1; - // The hex-encoded class hash of the world. - string world_class_hash = 2; - // The hex-encoded address of the executor. - string executor_address = 3; - // The hex-encoded class hash of the executor. - string executor_class_hash = 4; +message MetadataResponse { + types.WorldMetadata metadata = 1; +} + +// A request to retrieve a component value of an entity. +message GetEntityRequest { + types.EntityModel entity = 1; +} + +// The entity response contains the component values for the requested entities. +message GetEntityResponse { + repeated string values = 1; +} + +message SubscribeEntitiesRequest { + // The address of the World whose entities to subscribe to. + string world = 1; + // The list of entities to subscribe to. + repeated types.EntityModel entities = 2; +} + +message SubscribeEntitiesResponse { + // List of entities that have been updated. + types.MaybePendingEntityUpdate entity_update = 1; } diff --git a/crates/torii/grpc/src/client.rs b/crates/torii/grpc/src/client.rs new file mode 100644 index 0000000000..3c9b4052bf --- /dev/null +++ b/crates/torii/grpc/src/client.rs @@ -0,0 +1,112 @@ +//! Client implementation for the gRPC service. + +use std::str::FromStr; + +use protos::world::{world_client, SubscribeEntitiesRequest}; +use starknet::core::types::FromStrError; +use starknet_crypto::FieldElement; + +use crate::protos::world::{GetEntityRequest, MetadataRequest, SubscribeEntitiesResponse}; +use crate::protos::{self, types}; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error(transparent)] + Grpc(tonic::Status), + #[error("Missing expected data")] + MissingExpectedData, + #[error(transparent)] + Parsing(FromStrError), + + #[cfg(not(target_arch = "wasm32"))] + #[error(transparent)] + Transport(tonic::transport::Error), +} + +/// A lightweight wrapper around the grpc client. +pub struct WorldClient { + world_address: FieldElement, + #[cfg(not(target_arch = "wasm32"))] + inner: world_client::WorldClient, + #[cfg(target_arch = "wasm32")] + inner: world_client::WorldClient, +} + +impl WorldClient { + #[cfg(not(target_arch = "wasm32"))] + pub async fn new(dst: D, world_address: FieldElement) -> Result + where + D: TryInto, + D::Error: Into>, + { + Ok(Self { + world_address, + inner: world_client::WorldClient::connect(dst).await.map_err(Error::Transport)?, + }) + } + + // we make this function async so that we can keep the function signature similar + #[cfg(target_arch = "wasm32")] + pub async fn new(endpoint: String, world_address: FieldElement) -> Result { + Ok(Self { + world_address, + inner: world_client::WorldClient::new(tonic_web_wasm_client::Client::new(endpoint)), + }) + } + + /// Retrieve the metadata of the World. + pub async fn metadata(&mut self) -> Result { + self.inner + .world_metadata(MetadataRequest {}) + .await + .map_err(Error::Grpc) + .and_then(|res| res.into_inner().metadata.ok_or(Error::MissingExpectedData)) + .and_then(|metadata| metadata.try_into().map_err(Error::Parsing)) + } + + /// Retrieves the latest model value of the requested entity keys + pub async fn get_entity( + &mut self, + model: String, + keys: Vec, + ) -> Result, Error> { + let values = self + .inner + .get_entity(GetEntityRequest { + entity: Some(types::EntityModel { + model, + keys: keys.into_iter().map(|k| format!("{k:#x}")).collect(), + }), + }) + .await + .map(|res| res.into_inner().values) + .map_err(Error::Grpc)?; + + values + .iter() + .map(|v| FieldElement::from_str(v)) + .collect::, _>>() + .map_err(Error::Parsing) + } + + /// Subscribe to the state diff for a set of entities of a World. + pub async fn subscribe_entities( + &mut self, + entities: Vec, + ) -> Result, Error> { + self.inner + .subscribe_entities(SubscribeEntitiesRequest { + entities: entities + .into_iter() + .map(|e| protos::types::EntityModel { + model: e.model, + keys: e.keys.into_iter().map(|felt| format!("{felt:#x}")).collect(), + }) + .collect(), + world: format!("{:#x}", self.world_address), + }) + .await + .map_err(Error::Grpc) + .map(|res| res.into_inner()) + } +} diff --git a/crates/torii/grpc/src/conversion.rs b/crates/torii/grpc/src/conversion.rs new file mode 100644 index 0000000000..31d9884443 --- /dev/null +++ b/crates/torii/grpc/src/conversion.rs @@ -0,0 +1,60 @@ +use std::collections::HashMap; +use std::str::FromStr; + +use starknet::core::types::FromStrError; +use starknet_crypto::FieldElement; + +use crate::protos; + +impl TryFrom for dojo_types::model::ModelMetadata { + type Error = FromStrError; + fn try_from(value: protos::types::ModelMetadata) -> Result { + Ok(Self { + name: value.name, + size: value.size, + class_hash: FieldElement::from_str(&value.class_hash)?, + }) + } +} + +impl TryFrom for dojo_types::system::SystemMetadata { + type Error = FromStrError; + fn try_from(value: protos::types::SystemMetadata) -> Result { + Ok(Self { name: value.name, class_hash: FieldElement::from_str(&value.class_hash)? }) + } +} + +impl TryFrom for dojo_types::WorldMetadata { + type Error = FromStrError; + fn try_from(value: protos::types::WorldMetadata) -> Result { + let components = value + .models + .into_iter() + .map(|component| Ok((component.name.clone(), component.try_into()?))) + .collect::, _>>()?; + + let systems = value + .systems + .into_iter() + .map(|system| Ok((system.name.clone(), system.try_into()?))) + .collect::, _>>()?; + + Ok(dojo_types::WorldMetadata { + systems, + components, + world_address: FieldElement::from_str(&value.world_address)?, + world_class_hash: FieldElement::from_str(&value.world_class_hash)?, + executor_address: FieldElement::from_str(&value.executor_address)?, + executor_class_hash: FieldElement::from_str(&value.executor_class_hash)?, + }) + } +} + +impl From for protos::types::EntityModel { + fn from(value: dojo_types::model::EntityModel) -> Self { + Self { + model: value.model, + keys: value.keys.into_iter().map(|key| format!("{key:#}")).collect(), + } + } +} diff --git a/crates/torii/grpc/src/lib.rs b/crates/torii/grpc/src/lib.rs index 1b956ac6ee..56afad464c 100644 --- a/crates/torii/grpc/src/lib.rs +++ b/crates/torii/grpc/src/lib.rs @@ -1,55 +1,21 @@ -use sqlx::{Pool, Sqlite}; -use tonic::{Request, Response, Status}; -use world::world_server::World; -use world::{MetaReply, MetaRequest}; +#[cfg(target_arch = "wasm32")] +extern crate wasm_prost as prost; +#[cfg(target_arch = "wasm32")] +extern crate wasm_tonic as tonic; -pub mod world { - tonic::include_proto!("world"); -} - -#[derive(Clone, Debug)] -pub struct DojoWorld { - pool: Pool, -} - -impl DojoWorld { - pub fn new(pool: Pool) -> Self { - Self { pool } - } -} +pub mod conversion; -#[tonic::async_trait] -impl World for DojoWorld { - async fn meta( - &self, - request: Request, // Accept request of type MetaRequest - ) -> Result, Status> { - let id = request.into_inner().id; +#[cfg(feature = "client")] +pub mod client; - let (world_address, world_class_hash, executor_address, executor_class_hash): ( - String, - String, - String, - String, - ) = sqlx::query_as( - "SELECT world_address, world_class_hash, executor_address, executor_class_hash FROM \ - worlds WHERE id = ?", - ) - .bind(id) - .fetch_one(&self.pool) - .await - .map_err(|e| match e { - sqlx::Error::RowNotFound => Status::not_found("World not found"), - _ => Status::internal("Internal error"), - })?; +#[cfg(feature = "server")] +pub mod server; - let reply = world::MetaReply { - world_address, - world_class_hash, - executor_address, - executor_class_hash, - }; - - Ok(Response::new(reply)) // Send back our formatted greeting +pub mod protos { + pub mod world { + tonic::include_proto!("world"); + } + pub mod types { + tonic::include_proto!("types"); } } diff --git a/crates/torii/grpc/src/server/error.rs b/crates/torii/grpc/src/server/error.rs new file mode 100644 index 0000000000..747dc837c5 --- /dev/null +++ b/crates/torii/grpc/src/server/error.rs @@ -0,0 +1,25 @@ +use starknet::core::types::FromStrError; +use starknet::core::utils::CairoShortStringToFeltError; +use starknet::providers::jsonrpc::HttpTransport; +use starknet::providers::{JsonRpcClient, Provider}; + +type JsonRpcClientError = as Provider>::Error; +type ProviderError = starknet::providers::ProviderError; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("parsing error: {0}")] + Parse(#[from] ParseError), + #[error(transparent)] + Provider(#[from] ProviderError), + #[error(transparent)] + Sql(#[from] sqlx::Error), +} + +#[derive(Debug, thiserror::Error)] +pub enum ParseError { + #[error(transparent)] + FromStr(#[from] FromStrError), + #[error(transparent)] + CairoShortStringToFelt(#[from] CairoShortStringToFeltError), +} diff --git a/crates/torii/grpc/src/server/logger.rs b/crates/torii/grpc/src/server/logger.rs new file mode 100644 index 0000000000..093a5bb50d --- /dev/null +++ b/crates/torii/grpc/src/server/logger.rs @@ -0,0 +1,49 @@ +use std::task::{Context, Poll}; + +use hyper::Body; +use tonic::body::BoxBody; +use tower::{Layer, Service}; +use tracing::info; + +#[derive(Debug, Clone, Default)] +pub struct Logger { + inner: S, +} + +impl Layer for Logger { + type Service = Logger; + fn layer(&self, inner: S) -> Self::Service { + Logger { inner } + } +} + +impl Service> for Logger +where + S: Service, Response = hyper::Response> + Clone + Send + 'static, + S::Future: Send + 'static, +{ + type Response = S::Response; + type Error = S::Error; + type Future = futures::future::BoxFuture<'static, Result>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, req: hyper::Request) -> Self::Future { + // This is necessary because tonic internally uses `tower::buffer::Buffer`. + // See https://github.com/tower-rs/tower/issues/547#issuecomment-767629149 + // for details on why this is necessary + let clone = self.inner.clone(); + let mut inner = std::mem::replace(&mut self.inner, clone); + + Box::pin(async move { + // Do extra async work here... + let uri = req.uri().path(); + let method = req.method(); + + info!(target: "grpc", ?method, ?uri); + inner.call(req).await + }) + } +} diff --git a/crates/torii/grpc/src/server/mod.rs b/crates/torii/grpc/src/server/mod.rs new file mode 100644 index 0000000000..1ede07d180 --- /dev/null +++ b/crates/torii/grpc/src/server/mod.rs @@ -0,0 +1,255 @@ +pub mod error; +pub mod logger; +pub mod subscription; + +use std::pin::Pin; +use std::str::FromStr; +use std::sync::Arc; + +use futures::Stream; +use protos::world::{ + MetadataRequest, MetadataResponse, SubscribeEntitiesRequest, SubscribeEntitiesResponse, +}; +use sqlx::{Executor, Pool, Row, Sqlite}; +use starknet::core::types::FromStrError; +use starknet::core::utils::cairo_short_string_to_felt; +use starknet::providers::jsonrpc::HttpTransport; +use starknet::providers::JsonRpcClient; +use starknet_crypto::{poseidon_hash_many, FieldElement}; +use tokio::sync::mpsc::{Receiver, Sender}; +use tokio_stream::wrappers::ReceiverStream; +use tonic::{Request, Response, Status}; + +use self::error::Error; +use self::subscription::{EntityModelRequest, EntitySubscriptionService}; +use crate::protos::types::EntityModel; +use crate::protos::world::{GetEntityRequest, GetEntityResponse}; +use crate::protos::{self}; + +#[derive(Debug, Clone)] +pub struct DojoWorld { + world_address: FieldElement, + pool: Pool, + /// Sender<(subscription requests, oneshot sender to send back the response)> + subscription_req_sender: + Sender<(EntityModelRequest, Sender>)>, +} + +impl DojoWorld { + pub fn new( + pool: Pool, + block_rx: Receiver, + world_address: FieldElement, + provider: Arc>, + ) -> Self { + let (subscription_req_sender, rx) = tokio::sync::mpsc::channel(1); + // spawn thread for state update service + tokio::task::spawn(EntitySubscriptionService::new(provider, rx, block_rx)); + Self { pool, subscription_req_sender, world_address } + } +} + +impl DojoWorld { + pub async fn metadata(&self) -> Result { + let (world_address, world_class_hash, executor_address, executor_class_hash): ( + String, + String, + String, + String, + ) = sqlx::query_as(&format!( + "SELECT world_address, world_class_hash, executor_address, executor_class_hash FROM \ + worlds WHERE id = '{:#x}'", + self.world_address + )) + .fetch_one(&self.pool) + .await?; + + let models = sqlx::query_as( + "SELECT c.name, c.class_hash, COUNT(cm.id) FROM models c LEFT JOIN model_members cm \ + ON c.id = cm.model_id GROUP BY c.id", + ) + .fetch_all(&self.pool) + .await? + .into_iter() + .map(|(name, class_hash, size)| protos::types::ModelMetadata { name, class_hash, size }) + .collect::>(); + + let systems = sqlx::query_as("SELECT name, class_hash FROM systems") + .fetch_all(&self.pool) + .await? + .into_iter() + .map(|(name, class_hash)| protos::types::SystemMetadata { name, class_hash }) + .collect::>(); + + Ok(protos::types::WorldMetadata { + systems, + models, + world_address, + world_class_hash, + executor_address, + executor_class_hash, + }) + } + + #[allow(unused)] + pub async fn model_metadata( + &self, + component: String, + ) -> Result { + sqlx::query_as( + "SELECT c.name, c.class_hash, COUNT(cm.id) FROM models c LEFT JOIN model_members cm \ + ON c.id = cm.model_id WHERE c.id = ? GROUP BY c.id", + ) + .bind(component.to_lowercase()) + .fetch_one(&self.pool) + .await + .map(|(name, class_hash, size)| protos::types::ModelMetadata { name, size, class_hash }) + .map_err(Error::from) + } + + #[allow(unused)] + pub async fn system_metadata( + &self, + system: String, + ) -> Result { + sqlx::query_as("SELECT name, class_hash FROM systems WHERE id = ?") + .bind(system.to_lowercase()) + .fetch_one(&self.pool) + .await + .map(|(name, class_hash)| protos::types::SystemMetadata { name, class_hash }) + .map_err(Error::from) + } + + #[allow(unused)] + async fn entity( + &self, + component: String, + entity_keys: Vec, + ) -> Result, Error> { + let entity_id = format!("{:#x}", poseidon_hash_many(&entity_keys)); + // TODO: there's definitely a better way for doing this + self.pool + .fetch_one( + format!( + "SELECT * FROM external_{} WHERE entity_id = '{entity_id}'", + component.to_lowercase() + ) + .as_ref(), + ) + .await + .map_err(Error::from) + .map(|row| { + let size = row.columns().len() - 2; + let mut values = Vec::with_capacity(size); + for (i, _) in row.columns().iter().enumerate().skip(1).take(size) { + let value = match row.try_get::(i) { + Ok(value) => value, + Err(sqlx::Error::ColumnDecode { .. }) => { + row.try_get::(i).expect("decode failed").to_string() + } + Err(e) => panic!("{e}"), + }; + values.push(value); + } + values + }) + } +} + +type ServiceResult = Result, Status>; +type SubscribeEntitiesResponseStream = + Pin> + Send>>; + +#[tonic::async_trait] +impl protos::world::world_server::World for DojoWorld { + async fn world_metadata( + &self, + _request: Request, + ) -> Result, Status> { + let metadata = self.metadata().await.map_err(|e| match e { + Error::Sql(sqlx::Error::RowNotFound) => Status::not_found("World not found"), + e => Status::internal(e.to_string()), + })?; + + Ok(Response::new(MetadataResponse { metadata: Some(metadata) })) + } + + async fn get_entity( + &self, + request: Request, + ) -> Result, Status> { + let GetEntityRequest { entity } = request.into_inner(); + + let Some(EntityModel { model, keys }) = entity else { + return Err(Status::invalid_argument("Entity not specified")); + }; + + let entity_keys = keys + .iter() + .map(|k| FieldElement::from_str(k)) + .collect::, _>>() + .map_err(|e| Status::invalid_argument(format!("Invalid key: {e}")))?; + + let values = self.entity(model, entity_keys).await.map_err(|e| match e { + Error::Sql(sqlx::Error::RowNotFound) => Status::not_found("Entity not found"), + e => Status::internal(e.to_string()), + })?; + + Ok(Response::new(GetEntityResponse { values })) + } + + type SubscribeEntitiesStream = SubscribeEntitiesResponseStream; + + async fn subscribe_entities( + &self, + request: Request, + ) -> ServiceResult { + let SubscribeEntitiesRequest { entities: raw_entities, world } = request.into_inner(); + let (sender, rx) = tokio::sync::mpsc::channel(128); + + let world = FieldElement::from_str(&world) + .map_err(|e| Status::internal(format!("Invalid world address: {e}")))?; + + // in order to be able to compute all the storage address for all the requested entities, we + // need to know the size of the entity component. we can get this information from the + // sql database by querying the component metadata. + + let mut entities = Vec::with_capacity(raw_entities.len()); + for entity in raw_entities { + let keys = entity + .keys + .into_iter() + .map(|v| FieldElement::from_str(&v)) + .collect::, FromStrError>>() + .map_err(|e| Status::internal(format!("parsing error: {e}")))?; + + let model = cairo_short_string_to_felt(&entity.model) + .map_err(|e| Status::internal(format!("parsing error: {e}")))?; + + let (component_len,): (i64,) = + sqlx::query_as("SELECT COUNT(*) FROM model_members WHERE model_id = ?") + .bind(entity.model.to_lowercase()) + .fetch_one(&self.pool) + .await + .map_err(|e| match e { + sqlx::Error::RowNotFound => Status::not_found("Model not found"), + e => Status::internal(e.to_string()), + })?; + + entities.push(self::subscription::Entity { + model: self::subscription::ModelMetadata { + name: model, + len: component_len as usize, + }, + keys, + }) + } + + self.subscription_req_sender + .send((EntityModelRequest { world, entities }, sender)) + .await + .expect("should send subscriber request"); + + Ok(Response::new(Box::pin(ReceiverStream::new(rx)) as Self::SubscribeEntitiesStream)) + } +} diff --git a/crates/torii/grpc/src/server/subscription.rs b/crates/torii/grpc/src/server/subscription.rs new file mode 100644 index 0000000000..d6343d36c1 --- /dev/null +++ b/crates/torii/grpc/src/server/subscription.rs @@ -0,0 +1,286 @@ +//! TODO: move the subscription to a separate file + +use std::collections::{HashSet, VecDeque}; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll}; + +use futures::Future; +use futures_util::FutureExt; +use protos::types::maybe_pending_entity_update::Update; +use protos::world::SubscribeEntitiesResponse; +use rayon::prelude::*; +use starknet::core::types::{BlockId, ContractStorageDiffItem, MaybePendingStateUpdate}; +use starknet::macros::short_string; +use starknet::providers::{Provider, ProviderError}; +use starknet_crypto::{poseidon_hash_many, FieldElement}; +use tokio::sync::mpsc::{Receiver, Sender}; +use tonic::Status; + +use crate::protos::{self}; + +type GetStateUpdateResult

= + Result::Error>>; +type StateUpdateFuture

= Pin> + Send>>; +type PublishStateUpdateFuture = Pin + Send>>; + +pub struct ModelMetadata { + pub name: FieldElement, + pub len: usize, +} + +pub struct Entity { + pub model: ModelMetadata, + pub keys: Vec, +} + +pub struct EntityModelRequest { + pub world: FieldElement, + pub entities: Vec, +} + +pub struct Subscriber { + /// The world address that the subscriber is interested in. + world: FieldElement, + /// The storage addresses that the subscriber is interested in. + storage_addresses: HashSet, + /// The channel to send the response back to the subscriber. + sender: Sender>, +} + +pub struct SubscriberManager { + /// (set of storage addresses they care about, sender channel to send back the response) + pub subscribers: Vec>, +} + +impl SubscriberManager { + pub fn new() -> Self { + Self { subscribers: Vec::default() } + } + + fn add_subscriber( + &mut self, + request: (EntityModelRequest, Sender>), + ) { + let (EntityModelRequest { world, entities }, sender) = request; + + // convert the list of entites into a list storage addresses + let storage_addresses = entities + .par_iter() + .map(|entity| { + let base = poseidon_hash_many(&[ + short_string!("dojo_storage"), + entity.model.name, + poseidon_hash_many(&entity.keys), + ]); + + (0..entity.model.len) + .into_par_iter() + .map(|i| base + i.into()) + .collect::>() + }) + .flatten() + .collect::>(); + + self.subscribers.push(Arc::new(Subscriber { world, storage_addresses, sender })) + } +} + +impl Default for SubscriberManager { + fn default() -> Self { + Self::new() + } +} + +/// a service which handles entity subscription requests. it is an endless future where it awaits +/// for new blocks, fetch its state update, and publish them to the subscribers. +pub struct EntitySubscriptionService { + /// A channel to communicate with the indexer engine, in order to receive the block number that + /// the indexer engine is processing at any moment. This way, we can sync with the indexer and + /// request the state update of the current block that the indexer is currently processing. + block_rx: Receiver, + /// The Starknet provider. + provider: Arc

, + /// A list of state update futures, each corresponding to a block number that was received from + /// the indexer engine. + state_update_req_futs: VecDeque<(u64, StateUpdateFuture

)>, + + publish_update_fut: Option, + + block_num_queue: Vec, + /// Receive subscribers from gRPC server. + /// This receives streams of (sender channel, list of entities to subscribe) tuple + subscriber_recv: + Receiver<(EntityModelRequest, Sender>)>, + + subscriber_manager: SubscriberManager, +} + +impl

EntitySubscriptionService

+where + P: Provider, +{ + pub fn new( + provider: P, + subscriber_recv: Receiver<( + EntityModelRequest, + Sender>, + )>, + block_rx: Receiver, + ) -> Self { + Self { + block_rx, + subscriber_recv, + provider: Arc::new(provider), + block_num_queue: Default::default(), + publish_update_fut: Default::default(), + state_update_req_futs: Default::default(), + subscriber_manager: SubscriberManager::new(), + } + } + + /// Process the fetched state update, and publish to the subscribers, the relevant values for + /// them. + async fn publish_state_updates_to_subscribers( + subscribers: Vec>, + state_update: MaybePendingStateUpdate, + ) { + let state_diff = match &state_update { + MaybePendingStateUpdate::PendingUpdate(update) => &update.state_diff, + MaybePendingStateUpdate::Update(update) => &update.state_diff, + }; + + // iterate over the list of subscribers, and construct the relevant state diffs for each + // subscriber + for sub in subscribers { + // if there is no state diff for the current world, then skip, otherwise, extract the + // state diffs of the world + let Some(ContractStorageDiffItem { storage_entries: diff_entries, .. }) = + state_diff.storage_diffs.iter().find(|d| d.address == sub.world) + else { + continue; + }; + + let relevant_storage_entries = diff_entries + .iter() + .filter(|entry| sub.storage_addresses.contains(&entry.key)) + .map(|entry| protos::types::StorageEntry { + key: format!("{:#x}", entry.key), + value: format!("{:#x}", entry.value), + }) + .collect::>(); + + // if there is no state diffs relevant to the current subscriber, then skip + if relevant_storage_entries.is_empty() { + continue; + } + + let response = SubscribeEntitiesResponse { + entity_update: Some(protos::types::MaybePendingEntityUpdate { + update: Some(match &state_update { + MaybePendingStateUpdate::PendingUpdate(_) => { + Update::PendingEntityUpdate(protos::types::PendingEntityUpdate { + entity_diff: Some(protos::types::EntityDiff { + storage_diffs: vec![protos::types::StorageDiff { + address: format!("{:#x}", sub.world), + storage_entries: relevant_storage_entries, + }], + }), + }) + } + + MaybePendingStateUpdate::Update(update) => { + Update::EntityUpdate(protos::types::EntityUpdate { + block_hash: format!("{:#x}", update.block_hash), + entity_diff: Some(protos::types::EntityDiff { + storage_diffs: vec![protos::types::StorageDiff { + address: format!("{:#x}", sub.world), + storage_entries: relevant_storage_entries, + }], + }), + }) + } + }), + }), + }; + + match sub.sender.send(Ok(response)).await { + Ok(_) => { + println!("state diff sent") + } + Err(e) => { + println!("stream closed: {e:?}"); + } + } + } + } + + async fn do_get_state_update(provider: Arc

, block_number: u64) -> GetStateUpdateResult

{ + provider.get_state_update(BlockId::Number(block_number)).await + } +} + +// an endless future which will receive the block number from the indexer engine, and will +// request its corresponding state update. +impl

Future for EntitySubscriptionService

+where + P: Provider + Send + Sync + Unpin + 'static, +{ + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let pin = self.get_mut(); + + // drain the stream + while let Poll::Ready(Some(block_num)) = pin.block_rx.poll_recv(cx) { + // we still need to drain the stream, even if there are no subscribers. But dont have to + // queue for the block number + if !pin.subscriber_manager.subscribers.is_empty() { + pin.block_num_queue.push(block_num); + } + } + + // if there are any queued block numbers, then fetch the corresponding state updates + while let Some(block_num) = pin.block_num_queue.pop() { + let fut = Box::pin(Self::do_get_state_update(Arc::clone(&pin.provider), block_num)); + pin.state_update_req_futs.push_back((block_num, fut)); + } + + // handle incoming new subscribers + while let Poll::Ready(Some(request)) = pin.subscriber_recv.poll_recv(cx) { + println!("received new subscriber"); + pin.subscriber_manager.add_subscriber(request); + } + + // check if there's ongoing publish future, if yes, poll it and if its still not ready + // then return pending, + // dont request for state update, since we are still waiting for the previous state update + // to be published + if let Some(mut fut) = pin.publish_update_fut.take() { + if fut.poll_unpin(cx).is_pending() { + pin.publish_update_fut = Some(fut); + return Poll::Pending; + } + } + + // poll ongoing state update requests + if let Some((block_num, mut fut)) = pin.state_update_req_futs.pop_front() { + match fut.poll_unpin(cx) { + Poll::Ready(Ok(state_update)) => { + let subscribers = pin.subscriber_manager.subscribers.clone(); + pin.publish_update_fut = Some(Box::pin( + Self::publish_state_updates_to_subscribers(subscribers, state_update), + )); + } + + Poll::Ready(Err(e)) => { + println!("error fetching state update for block {block_num}: {:?}", e) + } + + Poll::Pending => pin.state_update_req_futs.push_back((block_num, fut)), + } + } + + Poll::Pending + } +} diff --git a/crates/torii/server/Cargo.toml b/crates/torii/server/Cargo.toml index 7ecd3f7e45..ce7267a860 100644 --- a/crates/torii/server/Cargo.toml +++ b/crates/torii/server/Cargo.toml @@ -16,7 +16,9 @@ clap.workspace = true ctrlc = "3.2.5" dojo-types = { path = "../../dojo-types" } dojo-world = { path = "../../dojo-world" } +either = "1.9.0" http = "0.2.9" +http-body = "0.4.5" hyper.workspace = true indexmap = "1.9.3" poem = "1.3.48" @@ -30,24 +32,23 @@ tokio-stream = "0.1.11" tokio-util = "0.7.7" tokio.workspace = true tonic-web.workspace = true +tonic.workspace = true torii-client = { path = "../client" } torii-core = { path = "../core" } torii-graphql = { path = "../graphql" } -torii-grpc = { path = "../grpc" } +torii-grpc = { path = "../grpc", features = [ "server" ] } tower = "0.4.13" tracing-subscriber.workspace = true tracing.workspace = true url.workspace = true warp.workspace = true -http-body = "0.4.5" -either = "1.9.0" [dev-dependencies] camino.workspace = true [features] -default = ["sqlite"] -sqlite = ["sqlx/sqlite"] +default = [ "sqlite" ] +sqlite = [ "sqlx/sqlite" ] [[bin]] name = "torii" diff --git a/crates/torii/server/src/cli.rs b/crates/torii/server/src/cli.rs index 80f73dd460..2017151a61 100644 --- a/crates/torii/server/src/cli.rs +++ b/crates/torii/server/src/cli.rs @@ -1,6 +1,7 @@ use std::env; use std::net::SocketAddr; use std::str::FromStr; +use std::sync::Arc; use anyhow::{anyhow, Context}; use camino::Utf8PathBuf; @@ -77,7 +78,7 @@ async fn main() -> anyhow::Result<()> { let pool = SqlitePoolOptions::new().max_connections(5).connect(database_url).await?; sqlx::migrate!("../migrations").run(&pool).await?; - let provider = JsonRpcClient::new(HttpTransport::new(Url::parse(&args.rpc).unwrap())); + let provider: Arc<_> = JsonRpcClient::new(HttpTransport::new(Url::parse(&args.rpc)?)).into(); let (manifest, env) = get_manifest_and_env(args.manifest.as_ref()) .with_context(|| "Failed to get manifest file".to_string())?; @@ -98,17 +99,18 @@ async fn main() -> anyhow::Result<()> { ..Processors::default() }; + let (block_sender, block_receiver) = tokio::sync::mpsc::channel(100); + let engine = Engine::new( &world, &db, &provider, processors, EngineConfig { start_block: args.start_block, ..Default::default() }, + Some(block_sender), ); - let addr = format!("{}:{}", args.host, args.port) - .parse::() - .expect("able to parse address"); + let addr: SocketAddr = format!("{}:{}", args.host, args.port).parse()?; tokio::select! { res = engine.start(cts) => { @@ -117,7 +119,7 @@ async fn main() -> anyhow::Result<()> { } } - res = server::spawn_server(&addr, &pool) => { + res = server::spawn_server(&addr, &pool, world_address, block_receiver, Arc::clone(&provider)) => { if let Err(e) = res { error!("Server failed with error: {e}"); } diff --git a/crates/torii/server/src/server.rs b/crates/torii/server/src/server.rs index bfe61bab4c..b906237d7e 100644 --- a/crates/torii/server/src/server.rs +++ b/crates/torii/server/src/server.rs @@ -2,19 +2,32 @@ use std::convert::Infallible; use std::net::SocketAddr; use std::pin::Pin; use std::str::FromStr; +use std::sync::Arc; use std::task::Poll; use either::Either; use hyper::service::{make_service_fn, Service}; use hyper::Uri; use sqlx::{Pool, Sqlite}; +use starknet::providers::jsonrpc::HttpTransport; +use starknet::providers::JsonRpcClient; +use starknet_crypto::FieldElement; +use tokio::sync::mpsc::Receiver as BoundedReceiver; +use torii_grpc::protos; use warp::Filter; type Error = Box; // TODO: check if there's a nicer way to implement this -pub async fn spawn_server(addr: &SocketAddr, pool: &Pool) -> anyhow::Result<()> { - let world_server = torii_grpc::DojoWorld::new(pool.clone()); +pub async fn spawn_server( + addr: &SocketAddr, + pool: &Pool, + world_address: FieldElement, + block_receiver: BoundedReceiver, + provider: Arc>, +) -> anyhow::Result<()> { + let world_server = + torii_grpc::server::DojoWorld::new(pool.clone(), block_receiver, world_address, provider); let base_route = warp::path::end() .and(warp::get()) @@ -22,7 +35,7 @@ pub async fn spawn_server(addr: &SocketAddr, pool: &Pool) -> anyhow::Res let routes = torii_graphql::route::filter(pool).await.or(base_route); let warp = warp::service(routes); - let tonic = tonic_web::enable(torii_grpc::world::world_server::WorldServer::new(world_server)); + let tonic = tonic_web::enable(protos::world::world_server::WorldServer::new(world_server)); hyper::Server::bind(addr) .serve(make_service_fn(move |_| { diff --git a/examples/ecs/Scarb.toml b/examples/ecs/Scarb.toml index d9ef9bfbee..0fc9f4616f 100644 --- a/examples/ecs/Scarb.toml +++ b/examples/ecs/Scarb.toml @@ -21,4 +21,4 @@ rpc_url = "http://localhost:5050/" # Default account for katana with seed = 0 account_address = "0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973" -private_key = "0x1800000000300000180000000000030000000000003006001800006600" \ No newline at end of file +private_key = "0x1800000000300000180000000000030000000000003006001800006600" diff --git a/examples/ecs/src/systems/with_decorator.cairo b/examples/ecs/src/systems/with_decorator.cairo index 4214e1026d..e7b60e3383 100644 --- a/examples/ecs/src/systems/with_decorator.cairo +++ b/examples/ecs/src/systems/with_decorator.cairo @@ -39,7 +39,9 @@ mod player_actions { world, ( Moves { player, remaining: 10, last_direction: Direction::None(()) }, - Position { player, vec: Vec2 { x: 10, y: 10 } }, + Position { + player, vec: Vec2 { x: position.vec.x + 10, y: position.vec.y + 10 } + }, ) ); }