diff --git a/.gitignore b/.gitignore index 4195f06..0500924 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,6 @@ debug/ target/ -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - # These are backup files generated by rustfmt **/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..21e6633 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3481 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-compression" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c90a406b4495d129f00461241616194cb8a032c8d1c53c657f0961d5f8e0498" +dependencies = [ + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-trait" +version = "0.1.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "bigdecimal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +dependencies = [ + "serde", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cc" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.5", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "color-eyre" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "config" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" +dependencies = [ + "async-trait", + "convert_case", + "json5", + "lazy_static", + "nom", + "pathdiff", + "ron", + "rust-ini", + "serde", + "serde_json", + "toml", + "yaml-rust", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cookie" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387461abbc748185c3a6e1673d826918b450b87ff22639429c694619a83b6cf6" +dependencies = [ + "cookie", + "idna 0.3.0", + "log", + "publicsuffix", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "ctrlc" +version = "3.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" +dependencies = [ + "nix", + "windows-sys 0.52.0", +] + +[[package]] +name = "darling" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.65", +] + +[[package]] +name = "darling_macro" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest", + "hex", + "hmac", + "pbkdf2", + "rand", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3", + "thiserror", + "uuid", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gatling" +version = "0.1.4" +dependencies = [ + "clap", + "color-eyre", + "config", + "crossbeam-queue", + "dotenvy", + "env_logger", + "futures", + "goose", + "lazy_static", + "log", + "rand", + "serde", + "serde_json", + "starknet", + "sysinfo", + "tokio", + "url", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "goose" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cfeedc01d217935e1371901ea642ea6693d68893c67336d146eba23be04bf11" +dependencies = [ + "async-trait", + "chrono", + "ctrlc", + "downcast-rs", + "flume", + "futures", + "gumdrop", + "http", + "itertools 0.11.0", + "lazy_static", + "log", + "num-format", + "rand", + "regex", + "reqwest", + "serde", + "serde_json", + "simplelog", + "strum", + "strum_macros", + "tokio", + "tokio-tungstenite", + "tungstenite", + "url", +] + +[[package]] +name = "gumdrop" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bc700f989d2f6f0248546222d9b4258f5b02a171a431f8285a81c08142629e3" +dependencies = [ + "gumdrop_derive", +] + +[[package]] +name = "gumdrop_derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729f9bd3449d77e7831a18abfb7ba2f99ee813dfd15b8c2167c9a54ba20aa99d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.2.6", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +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.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[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 = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec", + "itoa", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +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 = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-multimap" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" +dependencies = [ + "dlv-list", + "hashbrown 0.13.2", +] + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.5", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "pest_meta" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro2" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] +name = "publicsuffix" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +dependencies = [ + "idna 0.3.0", + "psl-types", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "async-compression", + "base64 0.21.7", + "bytes", + "cookie", + "cookie_store", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.5.0", + "serde", + "serde_derive", +] + +[[package]] +name = "rust-ini" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2", + "salsa20", + "sha2", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags 2.5.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.202" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.202" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "indexmap 2.2.6", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_json_pythonic" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62212da9872ca2a0cad0093191ee33753eddff9266cbbc1b4a602d13a3a768db" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "base64 0.13.1", + "chrono", + "hex", + "indexmap 1.9.3", + "serde", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[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]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "simplelog" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" +dependencies = [ + "log", + "termcolor", + "time", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "starknet" +version = "0.10.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "starknet-accounts", + "starknet-contract", + "starknet-core", + "starknet-crypto", + "starknet-ff", + "starknet-macros", + "starknet-providers", + "starknet-signers", +] + +[[package]] +name = "starknet-accounts" +version = "0.9.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "async-trait", + "auto_impl", + "starknet-core", + "starknet-providers", + "starknet-signers", + "thiserror", +] + +[[package]] +name = "starknet-contract" +version = "0.9.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "serde", + "serde_json", + "serde_with", + "starknet-accounts", + "starknet-core", + "starknet-providers", + "thiserror", +] + +[[package]] +name = "starknet-core" +version = "0.10.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "base64 0.21.7", + "flate2", + "hex", + "serde", + "serde_json", + "serde_json_pythonic", + "serde_with", + "sha3", + "starknet-crypto", + "starknet-ff", +] + +[[package]] +name = "starknet-crypto" +version = "0.6.2" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "crypto-bigint", + "hex", + "hmac", + "num-bigint", + "num-integer", + "num-traits", + "rfc6979", + "sha2", + "starknet-crypto-codegen", + "starknet-curve", + "starknet-ff", + "zeroize", +] + +[[package]] +name = "starknet-crypto-codegen" +version = "0.3.3" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "starknet-curve", + "starknet-ff", + "syn 2.0.65", +] + +[[package]] +name = "starknet-curve" +version = "0.4.2" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "starknet-ff", +] + +[[package]] +name = "starknet-ff" +version = "0.3.7" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "ark-ff", + "bigdecimal", + "crypto-bigint", + "getrandom", + "hex", + "num-bigint", + "serde", +] + +[[package]] +name = "starknet-macros" +version = "0.1.7" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "starknet-core", + "syn 2.0.65", +] + +[[package]] +name = "starknet-providers" +version = "0.10.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "async-trait", + "auto_impl", + "ethereum-types", + "flate2", + "log", + "reqwest", + "serde", + "serde_json", + "serde_with", + "starknet-core", + "thiserror", + "url", +] + +[[package]] +name = "starknet-signers" +version = "0.8.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "async-trait", + "auto_impl", + "crypto-bigint", + "eth-keystore", + "rand", + "starknet-core", + "starknet-crypto", + "thiserror", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.65", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" +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 = "sysinfo" +version = "0.30.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732ffa00f53e6b2af46208fba5718d9662a421049204e156328b66791ffa15ae" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "windows", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.13", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +dependencies = [ + "indexmap 2.2.6", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.8", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna 0.5.0", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.65", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", +] diff --git a/Cargo.toml b/Cargo.toml index ba3eecf..9710116 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,24 +13,27 @@ description = "Gomu Gomu No Gatling is a blazing fast tool to benchmark Starknet opt-level = 3 [dependencies] -# Starknet dependencies -starknet = "0.6.0" +# Starknet dependencies, currently the same starknet revision as the one in +# madara https://github.com/keep-starknet-strange/madara/blob/main/Cargo.toml#L268 +starknet = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "2d59636911628260fa460179010bbd00e89de06e" } goose = "0.17.2" -env_logger = "0.10.0" -log = "0.4.17" +env_logger = "0.11.3" +log = "0.4.21" tokio = { version = "1", features = ["full"] } futures = "0.3" -clap = { version = "4.2.7", features = ["derive"] } -color-eyre = "0.6.2" -config = "0.13.3" +clap = { version = "4.5.4", features = ["derive"] } +color-eyre = "0.6.3" +config = "0.14.0" dotenvy = "0.15.7" -serde = "1.0.163" -serde_derive = "1.0.163" -serde_json = { version = "1.0.96", features = ["preserve_order"] } -url = "2.4.0" +serde = { version = "1.0.202", features = ["derive"] } +serde_json = { version = "1.0.117", features = ["preserve_order"] } +url = "2.5.0" rand = { version = "0.8.5", features = ["rand_chacha"] } lazy_static = "1.4.0" -colored = "2.0.4" -sysinfo = "0.29.8" +sysinfo = "0.30.12" crossbeam-queue = "0.3.11" + +[features] +default = [] +with_sps = [] diff --git a/README.md b/README.md index d9ef196..21e239e 100644 --- a/README.md +++ b/README.md @@ -83,9 +83,18 @@ The configuration is defined by the following spec - `run` - - `num_erc20_transfers`: Number of ERC20 `transfer` transactions - - `num_erc721_mints`: Number of ERC721 `mint` transactions - `concurrency`: How many transactions to do simultaneously + - `shooter`: A list of write shooter benchmarks to run + + - `name`: The name of the shooter, must be either `transfer` or `mint` + - `shoot`: How many transactions to do + + - `read_benches`: A list of read benchmarks to run + + - `name`: The name to write on the output report + - `num_requests`: How many times to call this request + - `method`: What method to call on the rpc node + - `parameters_location`: A file with a array of multiple parameters to use for requests - `report` @@ -104,6 +113,12 @@ The configuration is defined by the following spec gatling shoot -c config/default.yaml ``` +For read tests: + +```bash +gatling read -c config/default.yaml +``` + ### Output The main output of gomu gomu is the report output location specified in specified in the configuration file. diff --git a/config/default.yaml b/config/default.yaml index d8dcd0f..72680e8 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -13,12 +13,20 @@ setup: fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" num_accounts: 1 - chain_id: "SN_GOERLI" + chain_id: "MADARA" run: - num_erc20_transfers: 1000 - num_erc721_mints: 1000 concurrency: 5 + shooters: + - name: "transfer" + shoot: 5000 + - name: "mint" + shoot: 5000 + read_benches: + - name: "Get Events" + num_requests: 100 + method: "starknet_getEvents" + parameters_location: "config/read_params/get_events.json" report: num_blocks: 4 diff --git a/config/katana.yaml b/config/katana.yaml index d13c008..4322d62 100644 --- a/config/katana.yaml +++ b/config/katana.yaml @@ -16,9 +16,17 @@ setup: chain_id: "KATANA" run: - num_erc20_transfers: 300 - num_erc721_mints: 300 concurrency: 5 + shooters: + - name: "transfer" + shoot: 300 + - name: "mint" + shoot: 300 + read_benches: + - name: "Get Events" + num_requests: 100 + method: "starknet_getEvents" + parameters_location: "config/read_params/get_events.json" report: num_blocks: 4 diff --git a/config/read_params/get_events.json b/config/read_params/get_events.json new file mode 100644 index 0000000..59beec5 --- /dev/null +++ b/config/read_params/get_events.json @@ -0,0 +1,10 @@ +[ + { + "from_block": { "block_number": null }, + "to_block": { "block_number": null }, + "address": null, + "keys": [], + "continuation_token": null, + "chunk_size": 10 + } +] diff --git a/config/sharingan.yaml b/config/sharingan.yaml index 5a18d48..79ec236 100644 --- a/config/sharingan.yaml +++ b/config/sharingan.yaml @@ -16,9 +16,17 @@ setup: chain_id: "SN_GOERLI" run: - num_erc20_transfers: 1200 - num_erc721_mints: 1200 concurrency: 5 + shooters: + - name: "transfer" + shoot: 1200 + - name: "mint" + shoot: 1200 + read_benches: + - name: "Get Events" + num_requests: 100 + method: "starknet_getEvents" + parameters_location: "config/read_params/get_events.json" report: num_blocks: 4 diff --git a/config/v2.1.0.yaml b/config/v2.1.0.yaml index 68b92ce..cec932f 100644 --- a/config/v2.1.0.yaml +++ b/config/v2.1.0.yaml @@ -22,9 +22,17 @@ setup: chain_id: "SN_GOERLI" run: - num_erc20_transfers: 100 - num_erc721_mints: 100 concurrency: 5 + shooters: + - name: "transfer" + shoot: 100 + - name: "mint" + shoot: 100 + read_benches: + - name: "Get Events" + num_requests: 100 + method: "starknet_getEvents" + parameters_location: "config/read_params/get_events.json" report: num_blocks: 3 diff --git a/src/actions/goose.rs b/src/actions/goose.rs index 78acc81..ec59d11 100644 --- a/src/actions/goose.rs +++ b/src/actions/goose.rs @@ -1,207 +1,81 @@ use std::{ mem, - sync::Arc, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, time::{Duration, SystemTime}, }; use color_eyre::eyre::ensure; use crossbeam_queue::ArrayQueue; use goose::{config::GooseConfiguration, metrics::GooseRequestMetric, prelude::*}; +use rand::prelude::SliceRandom; use serde::{de::DeserializeOwned, Serialize}; +use starknet::core::types::{SequencerTransactionStatus, TransactionReceipt, TransactionStatus}; use starknet::{ accounts::{ Account, Call, ConnectedAccount, ExecutionEncoder, RawExecution, SingleOwnerAccount, }, core::types::{ - ExecutionResult, FieldElement, InvokeTransactionResult, MaybePendingTransactionReceipt, + BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV1, ExecutionResult, + FieldElement, MaybePendingTransactionReceipt, }, - macros::{felt, selector}, providers::{ - jsonrpc::{ - HttpTransport, HttpTransportError, JsonRpcClientError, JsonRpcError, JsonRpcMethod, - JsonRpcResponse, - }, + jsonrpc::{HttpTransport, JsonRpcError, JsonRpcMethod, JsonRpcResponse}, JsonRpcClient, ProviderError, }, signers::LocalWallet, }; use crate::{ - actions::shoot::{GatlingShooterSetup, CHECK_INTERVAL, MAX_FEE}, - generators::get_rng, + actions::setup::{GatlingSetup, CHECK_INTERVAL, MAX_FEE}, + config::{GatlingConfig, ParametersFile}, }; -use super::shoot::StarknetAccount; - -pub async fn erc20(shooter: &GatlingShooterSetup) -> color_eyre::Result { - let environment = shooter.environment()?; - let erc20_address = environment.erc20_address; - let config = shooter.config(); +use super::setup::StarknetAccount; +pub fn make_goose_config( + config: &GatlingConfig, + amount: u64, + name: &'static str, +) -> color_eyre::Result { ensure!( - config.run.num_erc20_transfers >= config.run.concurrency, - "Too few erc20 transfers for the amount of concurrency" + amount >= config.run.concurrency, + "Too few {name} for the amount of concurrent users" ); // div_euclid will truncate integers when not evenly divisable - let user_iterations = config - .run - .num_erc20_transfers - .div_euclid(config.run.concurrency); - // this will always be a multiple of concurrency, unlike num_erc20_transfers + let user_iterations = amount.div_euclid(config.run.concurrency); + // this will always be a multiple of concurrency, unlike the provided amount let total_transactions = user_iterations * config.run.concurrency; // If these are not equal that means user_iterations was truncated - if total_transactions != config.run.num_erc20_transfers { - log::warn!("Number of erc20 transfers is not evenly divisble by concurrency, doing {total_transactions} transfers instead"); + if total_transactions != amount { + log::warn!("Number of {name} is not evenly divisble by concurrency, doing {total_transactions} calls instead"); } - let goose_config = { + Ok({ let mut default = GooseConfiguration::default(); - default.host = config.rpc.url.clone(); + default.host.clone_from(&config.rpc.url); default.iterations = user_iterations as usize; default.users = Some(config.run.concurrency as usize); default - }; - - let transfer_setup: TransactionFunction = - setup(environment.accounts.clone(), user_iterations as usize).await?; - - let transfer: TransactionFunction = - Arc::new(move |user| Box::pin(transfer(user, erc20_address))); - - let transfer_wait: TransactionFunction = goose_user_wait_last_tx(); - - let metrics = GooseAttack::initialize_with_config(goose_config.clone())? - .register_scenario( - scenario!("Transfer") - .register_transaction( - Transaction::new(transfer_setup) - .set_name("Transfer Setup") - .set_on_start(), - ) - .register_transaction( - Transaction::new(transfer) - .set_name("Transfer") - .set_sequence(1), - ) - .register_transaction( - Transaction::new(transfer_wait) - .set_name("Transfer Finalizing") - .set_sequence(2) - .set_on_stop(), - ) - .register_transaction( - transaction!(verify_transactions) - .set_name("Verification") - .set_sequence(3) - .set_on_stop(), - ), - ) - .execute() - .await?; - - Ok(metrics) -} - -pub async fn erc721(shooter: &GatlingShooterSetup) -> color_eyre::Result { - let config = shooter.config(); - let environment = shooter.environment()?; - - ensure!( - config.run.num_erc721_mints >= config.run.concurrency, - "Too few erc721 mints for the amount of concurrency" - ); - - // div_euclid will truncate integers when not evenly divisable - let user_iterations = config - .run - .num_erc721_mints - .div_euclid(config.run.concurrency); - // this will always be a multiple of concurrency, unlike num_erc721_mints - let total_transactions = user_iterations * config.run.concurrency; - - // If these are not equal that means user_iterations was truncated - if total_transactions != config.run.num_erc721_mints { - log::warn!("Number of erc721 mints is not evenly divisble by concurrency, doing {total_transactions} mints instead"); - } - - let goose_mint_config = { - let mut default = GooseConfiguration::default(); - default.host = config.rpc.url.clone(); - default.iterations = user_iterations as usize; - default.users = Some(config.run.concurrency as usize); - default - }; - - let nonces = Arc::new(ArrayQueue::new(total_transactions as usize)); - let erc721_address = environment.erc721_address; - let mut nonce = shooter.deployer_account().get_nonce().await?; - - for _ in 0..total_transactions { - nonces - .push(nonce) - .expect("ArrayQueue has capacity for all mints"); - nonce += FieldElement::ONE; - } - - let from_account = shooter.deployer_account().clone(); - - let mint_setup: TransactionFunction = - setup(environment.accounts.clone(), user_iterations as usize).await?; - - let mint: TransactionFunction = Arc::new(move |user| { - let nonce = nonces - .pop() - .expect("Nonce ArrayQueue should have enough nonces for all mints"); - let from_account = from_account.clone(); - Box::pin(async move { mint(user, erc721_address, nonce, &from_account).await }) - }); - - let mint_wait: TransactionFunction = goose_user_wait_last_tx(); - - let metrics = GooseAttack::initialize_with_config(goose_mint_config.clone())? - .register_scenario( - scenario!("Minting") - .register_transaction( - Transaction::new(mint_setup) - .set_name("Mint Setup") - .set_on_start(), - ) - .register_transaction(Transaction::new(mint).set_name("Minting").set_sequence(1)) - .register_transaction( - Transaction::new(mint_wait) - .set_name("Mint Finalizing") - .set_sequence(2) - .set_on_stop(), - ) - .register_transaction( - transaction!(verify_transactions) - .set_name("Verification") - .set_sequence(3) - .set_on_stop(), - ), - ) - .execute() - .await?; - - Ok(metrics) + }) } #[derive(Debug, Clone)] -struct GooseUserState { - account: StarknetAccount, - nonce: FieldElement, - prev_tx: Vec, +pub struct GooseWriteUserState { + pub account: StarknetAccount, + pub nonce: FieldElement, + pub prev_tx: Vec, } -pub type RpcError = ProviderError>; - -impl GooseUserState { +impl GooseWriteUserState { pub async fn new( account: StarknetAccount, transactions_amount: usize, - ) -> Result { + ) -> Result { Ok(Self { nonce: account.get_nonce().await?, account, @@ -210,14 +84,14 @@ impl GooseUserState { } } -async fn setup( +pub async fn setup( accounts: Vec, transactions_amount: usize, -) -> Result { +) -> Result { let queue = ArrayQueue::new(accounts.len()); for account in accounts { queue - .push(GooseUserState::new(account, transactions_amount).await?) + .push(GooseWriteUserState::new(account, transactions_amount).await?) .expect("Queue should have enough space for all accounts as it's length is from the accounts vec"); } let queue = Arc::new(queue); @@ -234,10 +108,10 @@ async fn setup( })) } -fn goose_user_wait_last_tx() -> TransactionFunction { +pub fn goose_write_user_wait_last_tx() -> TransactionFunction { Arc::new(move |user| { let tx = user - .get_session_data::() + .get_session_data::() .expect("Should be in a goose user with GooseUserState session data") .prev_tx .last() @@ -246,7 +120,7 @@ fn goose_user_wait_last_tx() -> TransactionFunction { Box::pin(async move { // If all transactions failed, we can skip this step if let Some(tx) = tx { - wait_for_tx(user, tx).await?; + wait_for_tx_with_goose(user, tx).await?; } Ok(()) @@ -254,118 +128,108 @@ fn goose_user_wait_last_tx() -> TransactionFunction { }) } -// Hex: 0xdead -// from_hex_be isn't const whereas from_mont is -const VOID_ADDRESS: FieldElement = FieldElement::from_mont([ - 18446744073707727457, - 18446744073709551615, - 18446744073709551615, - 576460752272412784, -]); - -async fn transfer(user: &mut GooseUser, erc20_address: FieldElement) -> TransactionResult { - let GooseUserState { account, nonce, .. } = user - .get_session_data::() - .expect("Should be in a goose user with GooseUserState session data"); - - let (amount_low, amount_high) = (felt!("1"), felt!("0")); - - let call = Call { - to: erc20_address, - selector: selector!("transfer"), - calldata: vec![VOID_ADDRESS, amount_low, amount_high], - }; +pub async fn read_method( + shooter: &GatlingSetup, + amount: u64, + method: JsonRpcMethod, + parameters_list: ParametersFile, +) -> color_eyre::Result { + let goose_read_config = make_goose_config(shooter.config(), amount, "read calls")?; - let response: InvokeTransactionResult = send_execution( - user, - vec![call], - *nonce, - &account.clone(), - JsonRpcMethod::AddInvokeTransaction, - ) - .await? - .0; - - let GooseUserState { nonce, prev_tx, .. } = - user.get_session_data_mut::().expect( - "Should be successful as we already asserted that the session data is a GooseUserState", - ); + let reads: TransactionFunction = Arc::new(move |user| { + let mut rng = rand::thread_rng(); - *nonce += FieldElement::ONE; + let mut params_list = parameters_list.clone(); + params_list.shuffle(&mut rng); // Make sure each goose user has their own order + let mut paramaters_cycle = params_list.into_iter().cycle(); - prev_tx.push(response.transaction_hash); + Box::pin(async move { + let params = paramaters_cycle + .next() + .expect("Cyclic iterator should never end"); - Ok(()) -} + let _: (serde_json::Value, _) = + send_request(user, method, serde_json::Value::Object(params)).await?; -async fn mint( - user: &mut GooseUser, - erc721_address: FieldElement, - nonce: FieldElement, - from_account: &SingleOwnerAccount>, LocalWallet>, -) -> TransactionResult { - let recipient = user - .get_session_data::() - .expect("Should be in a goose user with GooseUserState session data") - .account - .clone() - .address(); - - let (token_id_low, token_id_high) = (get_rng(), felt!("0x0000")); - - let call = Call { - to: erc721_address, - selector: selector!("mint"), - calldata: vec![recipient, token_id_low, token_id_high], - }; + Ok(()) + }) + }); - let response: InvokeTransactionResult = send_execution( - user, - vec![call], - nonce, - from_account, - JsonRpcMethod::AddInvokeTransaction, - ) - .await? - .0; - - user.get_session_data_mut::() - .expect( - "Should be successful as we already asserted that the session data is a GooseUserState", + let metrics = GooseAttack::initialize_with_config(goose_read_config)? + .register_scenario( + scenario!("Read Metric") + .register_transaction(Transaction::new(reads).set_name("Request")), ) - .prev_tx - .push(response.transaction_hash); + .execute() + .await?; - Ok(()) + Ok(metrics) } -async fn verify_transactions(user: &mut GooseUser) -> TransactionResult { +#[derive(Default, Debug)] +pub struct TransactionBlocks { + pub first: AtomicU64, + pub last: AtomicU64, +} + +pub async fn verify_transactions( + user: &mut GooseUser, + blocks: Arc, +) -> TransactionResult { let transactions = mem::take( &mut user - .get_session_data_mut::() + .get_session_data_mut::() .expect("Should be in a goose user with GooseUserState session data") .prev_tx, ); - for tx in transactions { - let (receipt, mut metrics) = - send_request(user, JsonRpcMethod::GetTransactionReceipt, tx).await?; + for (index, tx) in transactions.iter().enumerate() { + let (status, mut metrics) = + send_request::(user, JsonRpcMethod::GetTransactionStatus, tx) + .await?; - match receipt { - MaybePendingTransactionReceipt::Receipt(receipt) => match receipt.execution_result() { - ExecutionResult::Succeeded => {} - ExecutionResult::Reverted { reason } => { - let tag = format!("Transaction {tx:#064x} has been rejected/reverted"); + match status.finality_status() { + SequencerTransactionStatus::Rejected => { + let tag = format!("Transaction {tx:#064x} has been rejected/reverted"); - return user.set_failure(&tag, &mut metrics, None, Some(reason)); - } - }, - MaybePendingTransactionReceipt::PendingReceipt(pending) => { + return user.set_failure(&tag, &mut metrics, None, None); + } + SequencerTransactionStatus::Received => { let tag = format!("Transaction {tx:#064x} is pending when no transactions should be"); - let body = format!("{pending:?}"); - return user.set_failure(&tag, &mut metrics, None, Some(&body)); + return user.set_failure(&tag, &mut metrics, None, None); + } + SequencerTransactionStatus::AcceptedOnL1 | SequencerTransactionStatus::AcceptedOnL2 => { + if index == 0 || index == transactions.len() - 1 { + let (receipt, mut metrics) = send_request::( + user, + JsonRpcMethod::GetTransactionReceipt, + tx, + ) + .await?; + let block_number = match receipt { + MaybePendingTransactionReceipt::Receipt(TransactionReceipt::Invoke( + receipt, + )) => receipt.block_number, + _ => { + return user.set_failure( + "Receipt is not of type InvokeTransactionReceipt or is Pending", + &mut metrics, + None, + None, + ); + } + }; + + if index == 0 { + blocks.first.store(block_number, Ordering::Relaxed); + } + + if index == transactions.len() - 1 { + blocks.last.store(block_number, Ordering::Relaxed); + } + } } } } @@ -373,9 +237,10 @@ async fn verify_transactions(user: &mut GooseUser) -> TransactionResult { Ok(()) } -const WAIT_FOR_TX_TIMEOUT: Duration = Duration::from_secs(60); +const WAIT_FOR_TX_TIMEOUT: Duration = Duration::from_secs(600); -pub async fn wait_for_tx( +/// This function is different then `crate::utils::wait_for_tx` due to it using the goose requester +pub async fn wait_for_tx_with_goose( user: &mut GooseUser, tx_hash: FieldElement, ) -> Result<(), Box> { @@ -403,7 +268,12 @@ pub async fn wait_for_tx( return Ok(()); } ExecutionResult::Reverted { reason } => { - return user.set_failure(&reverted_tag(), &mut metric, None, Some(reason)); + return user.set_failure( + &(reverted_tag() + reason), + &mut metric, + None, + Some(reason), + ); } }, JsonRpcResponse::Success { @@ -411,7 +281,12 @@ pub async fn wait_for_tx( .. } => { if let ExecutionResult::Reverted { reason } = pending.execution_result() { - return user.set_failure(&reverted_tag(), &mut metric, None, Some(reason)); + return user.set_failure( + &(reverted_tag() + reason), + &mut metric, + None, + Some(reason), + ); } log::debug!("Waiting for transaction {tx_hash:#064x} to be accepted"); tokio::time::sleep(CHECK_INTERVAL).await; @@ -428,7 +303,7 @@ pub async fn wait_for_tx( tokio::time::sleep(CHECK_INTERVAL).await; } JsonRpcResponse::Error { - error: JsonRpcError { code, message }, + error: JsonRpcError { code, message, .. }, .. } => { let tag = format!("Error Code {code} while waiting for tx {tx_hash:#064x}"); @@ -466,17 +341,17 @@ pub async fn send_execution( // see https://github.com/xJonathanLEI/starknet-rs/issues/538 let raw_exec = unsafe { mem::transmute::(raw_exec) }; - let param = starknet::core::types::BroadcastedInvokeTransaction { + let param = BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { sender_address: from_account.address(), calldata, max_fee: MAX_FEE, signature: from_account - .sign_execution(&raw_exec) + .sign_execution(&raw_exec, false) .await .expect("Raw Execution should be correctly constructed for signature"), nonce, is_query: false, - }; + }); send_request(user, method, param).await } diff --git a/src/actions/mod.rs b/src/actions/mod.rs index 2c0bb8d..1585b04 100644 --- a/src/actions/mod.rs +++ b/src/actions/mod.rs @@ -1,101 +1,155 @@ -use ::goose::metrics::GooseMetrics; -use futures::Future; -use starknet::providers::{jsonrpc::HttpTransport, JsonRpcClient, Provider}; +use std::{fs::File, mem, sync::Arc}; + +use color_eyre::eyre::bail; +use log::info; use crate::{ config::GatlingConfig, metrics::{BenchmarkReport, GlobalReport}, }; -use self::shoot::GatlingShooterSetup; +use self::{ + setup::GatlingSetup, + shooters::{mint::MintShooter, transfer::TransferShooter, Shooter, ShooterAttack}, +}; mod goose; -mod shoot; +mod setup; +mod shooters; -pub async fn shoot(config: GatlingConfig) -> color_eyre::Result<()> { - let run_erc20 = config.run.num_erc20_transfers != 0; - let run_erc721 = config.run.num_erc721_mints != 0; - let total_txs = config.run.num_erc20_transfers + config.run.num_erc721_mints; - let num_blocks = config.report.num_blocks; +pub async fn shoot(mut config: GatlingConfig) -> color_eyre::Result<()> { + let shooters = mem::take(&mut config.run.shooters); + let total_txs: u64 = shooters.iter().map(|s| s.shoot).sum(); - let mut shooter = GatlingShooterSetup::from_config(config).await?; - shooter.setup().await?; + let mut shooter_setup = GatlingSetup::from_config(config).await?; + shooter_setup.setup_accounts().await?; let mut global_report = GlobalReport { - users: shooter.config().run.concurrency, - all_bench_report: BenchmarkReport::new("".into(), total_txs as usize), + users: shooter_setup.config().run.concurrency, + all_bench_report: None, benches: Vec::new(), extra: crate::utils::sysinfo_string(), }; - let start_block = shooter.rpc_client().block_number().await?; - - if run_erc20 { - let report = make_report_over_bench( - goose::erc20(&shooter), - "Erc20 Transfers".into(), - shooter.rpc_client(), - num_blocks, - ) - .await?; + let mut blocks = Option::<(u64, u64)>::None; + + for shooter in shooters { + if shooter.shoot == 0 { + log::info!("Skipping {} transfers", shooter.name); + continue; + } + + let (report, first_block, last_block) = match shooter.name.as_str() { + "transfer" => { + make_report_over_shooter::(&mut shooter_setup, shooter.shoot) + .await? + } + "mint" => { + make_report_over_shooter::(&mut shooter_setup, shooter.shoot).await? + } + name => bail!("Shooter `{name}` not found!"), + }; global_report.benches.push(report); - } else { - log::info!("Skipping erc20 transfers") + blocks.get_or_insert((first_block, last_block)).1 = last_block; } - if run_erc721 { - let report = make_report_over_bench( - goose::erc721(&shooter), - "Erc721 Mints".into(), - shooter.rpc_client(), - num_blocks, - ) - .await?; + let mut all_bench_report = BenchmarkReport::new("".into(), total_txs as usize); - global_report.benches.push(report); - } else { - log::info!("Skipping erc721 mints") - } + if let Some((start_block, end_block)) = blocks { + info!("Start and End Blocks: {start_block}, {end_block}"); - let end_block = shooter.rpc_client().block_number().await?; + let rpc_result = all_bench_report + .with_block_range(shooter_setup.rpc_client(), start_block, end_block) + .await; - global_report - .all_bench_report - .with_block_range(shooter.rpc_client(), start_block, end_block) - .await?; + global_report.all_bench_report = Some(all_bench_report); - let report_path = shooter + if let Err(error) = rpc_result { + log::error!("Failed to get block range: {error}") + } + } + + let report_path = shooter_setup .config() .report .output_location .with_extension("json"); - let writer = std::fs::File::create(report_path)?; - serde_json::to_writer_pretty(writer, &global_report)?; + serde_json::to_writer_pretty(File::create(report_path)?, &global_report)?; Ok(()) } -async fn make_report_over_bench( - bench: impl Future>, - name: String, - rpc_client: &JsonRpcClient, - num_blocks: u64, -) -> color_eyre::Result { - let start_block = rpc_client.block_number().await?; - let goose_metrics = bench.await?; - let end_block = rpc_client.block_number().await?; - - let mut report = BenchmarkReport::new(name, goose_metrics.scenarios[0].counter); - report - .with_block_range(rpc_client, start_block + 1, end_block) +async fn make_report_over_shooter( + setup: &mut GatlingSetup, + amount: u64, +) -> color_eyre::Result<(BenchmarkReport, u64, u64)> { + let shooter = S::setup(setup).await?; + let goose_config = S::get_goose_config(setup.config(), amount)?; + + let ShooterAttack { + goose_metrics, + first_block, + last_block, + } = Arc::new(shooter) + .goose_attack(goose_config, setup.accounts().to_vec()) + .await?; + + let mut report = BenchmarkReport::new(S::NAME.to_string(), goose_metrics.scenarios[0].counter); + + let rpc_result = report + .with_block_range(setup.rpc_client(), first_block + 1, last_block) + .await; + + let num_blocks = setup.config().report.num_blocks; + + if let Err(error) = rpc_result { + log::error!("Failed to get block range: {error}") + } else if num_blocks != 0 { + report + .with_last_x_blocks(setup.rpc_client(), num_blocks) + .await?; + } + + report.with_goose_write_metrics(&goose_metrics)?; + Ok((report, first_block, last_block)) +} + +pub async fn read(config: GatlingConfig) -> color_eyre::Result<()> { + let shooter_setup = GatlingSetup::from_config(config).await?; + + let mut global_report = GlobalReport { + users: shooter_setup.config().run.concurrency, + all_bench_report: None, + benches: Vec::new(), + extra: crate::utils::sysinfo_string(), + }; + + for read_bench in &shooter_setup.config().run.read_benches { + let metrics = goose::read_method( + &shooter_setup, + read_bench.num_requests, + read_bench.method, + read_bench.parameters_location.clone(), + ) .await?; - if num_blocks != 0 { - report.with_last_x_blocks(rpc_client, num_blocks).await?; + let mut report = + BenchmarkReport::new(read_bench.name.clone(), metrics.scenarios[0].counter); + + report.with_goose_read_metrics(&metrics)?; + + global_report.benches.push(report); } - report.with_goose_metrics(&goose_metrics)?; - Ok(report) + let report_path = shooter_setup + .config() + .report + .output_location + .with_extension("json"); + + serde_json::to_writer_pretty(File::create(report_path)?, &global_report)?; + + Ok(()) } diff --git a/src/actions/shoot.rs b/src/actions/setup.rs similarity index 53% rename from src/actions/shoot.rs rename to src/actions/setup.rs index 01d17be..e6a581d 100644 --- a/src/actions/shoot.rs +++ b/src/actions/setup.rs @@ -1,28 +1,29 @@ use crate::config::{ContractSourceConfig, GatlingConfig}; -use crate::utils::{compute_contract_address, wait_for_tx}; -use color_eyre::eyre::Context; -use color_eyre::{eyre::eyre, Result}; +use crate::utils::wait_for_tx; +use color_eyre::{ + eyre::{ + Context, {bail, eyre}, + }, + Result, +}; use log::{debug, info, warn}; use starknet::core::types::contract::SierraClass; +use tokio::task::JoinSet; -use std::collections::HashMap; use std::path::Path; use starknet::accounts::{ Account, AccountFactory, Call, ConnectedAccount, ExecutionEncoding, OpenZeppelinAccountFactory, SingleOwnerAccount, }; -use starknet::contract::ContractFactory; use starknet::core::types::{ contract::legacy::LegacyContractClass, BlockId, BlockTag, FieldElement, StarknetError, }; use starknet::macros::{felt, selector}; use starknet::providers::ProviderError; use starknet::providers::{jsonrpc::HttpTransport, JsonRpcClient, Provider}; -use starknet::providers::{MaybeUnknownErrorCode, StarknetErrorWithMessage}; use starknet::signers::{LocalWallet, SigningKey}; -use std::str; use std::sync::Arc; use std::time::Duration; @@ -34,23 +35,15 @@ pub static CHECK_INTERVAL: Duration = Duration::from_millis(500); pub type StarknetAccount = SingleOwnerAccount>, LocalWallet>; -pub struct GatlingShooterSetup { +pub struct GatlingSetup { config: GatlingConfig, starknet_rpc: Arc>, signer: LocalWallet, account: StarknetAccount, - nonces: HashMap, - environment: Option, // Will be populated in setup phase -} - -#[derive(Clone)] -pub struct GatlingEnvironment { - pub erc20_address: FieldElement, - pub erc721_address: FieldElement, - pub accounts: Vec, + accounts: Vec, } -impl GatlingShooterSetup { +impl GatlingSetup { pub async fn from_config(config: GatlingConfig) -> Result { let starknet_rpc: Arc> = Arc::new(starknet_rpc_provider(Url::parse(&config.clone().rpc.url)?)); @@ -69,28 +62,15 @@ impl GatlingShooterSetup { }, ); - // Fails if nonce is null (which is the case for 1st startup) - let cur_nonce = account.get_nonce().await?; - - let mut nonces: HashMap = HashMap::new(); - nonces.insert(config.deployer.address, cur_nonce); - Ok(Self { config, starknet_rpc, signer, account, - nonces, - environment: None, + accounts: vec![], }) } - pub fn environment(&self) -> Result<&GatlingEnvironment> { - self.environment.as_ref().ok_or(eyre!( - "Environment is not yet populated, you should run the setup function first" - )) - } - pub fn config(&self) -> &GatlingConfig { &self.config } @@ -103,201 +83,43 @@ impl GatlingShooterSetup { &self.account } - /// Setup the simulation. - pub async fn setup(&mut self) -> Result<()> { - let chain_id = self.starknet_rpc.chain_id().await?.to_bytes_be(); - let block_number = self.starknet_rpc.block_number().await?; - info!( - "Shoot - {} @ block number - {}", - str::from_utf8(&chain_id)?.trim_start_matches('\0'), - block_number - ); - - let setup_config = self.config.clone().setup; - - let erc20_class_hash = self.declare_contract(&setup_config.erc20_contract).await?; + pub fn accounts(&self) -> &[StarknetAccount] { + &self.accounts + } - let erc721_class_hash = self.declare_contract(&setup_config.erc721_contract).await?; + /// Setup the simulation. + pub async fn setup_accounts(&mut self) -> Result<()> { + let account_contract = self.config.setup.account_contract.clone(); - let account_class_hash = self - .declare_contract(&setup_config.account_contract) - .await?; + let account_class_hash = self.declare_contract(&account_contract).await?; - let execution_encoding = match setup_config.account_contract { + let execution_encoding = match account_contract { ContractSourceConfig::V0(_) => ExecutionEncoding::Legacy, ContractSourceConfig::V1(_) => ExecutionEncoding::New, }; - let erc20_address = self.deploy_erc20(erc20_class_hash).await?; - let erc721_address = self.deploy_erc721(erc721_class_hash).await?; - let accounts = self .create_accounts( account_class_hash, self.config.run.concurrency as usize, execution_encoding, - erc20_address, ) .await?; - let environment = GatlingEnvironment { - erc20_address, - erc721_address, - accounts, - }; - - self.environment = Some(environment); + self.accounts = accounts; Ok(()) } - async fn transfer( - &mut self, + pub async fn transfer( + &self, contract_address: FieldElement, account: StarknetAccount, recipient: FieldElement, amount: FieldElement, + nonce: FieldElement, ) -> Result { - let from_address = account.address(); - let nonce = match self.nonces.get(&from_address) { - Some(nonce) => *nonce, - None => account.get_nonce().await?, - }; - - debug!( - "Transferring {amount} of {contract_address:#064x} from address {from_address:#064x} to address {recipient:#064x} with nonce={}", - nonce, - ); - - let (amount_low, amount_high) = (amount, felt!("0")); - - let call = Call { - to: contract_address, - selector: selector!("transfer"), - calldata: vec![recipient, amount_low, amount_high], - }; - - let result = account - .execute(vec![call]) - .max_fee(MAX_FEE) - .nonce(nonce) - .send() - .await?; - - self.nonces.insert(from_address, nonce + FieldElement::ONE); - - Ok(result.transaction_hash) - } - - async fn deploy_erc721(&mut self, class_hash: FieldElement) -> Result { - let contract_factory = ContractFactory::new(class_hash, self.account.clone()); - let from_address = self.account.address(); - let nonce = match self.nonces.get(&from_address) { - Some(nonce) => *nonce, - None => self.account.get_nonce().await?, - }; - - let name = selector!("TestNFT"); - let symbol = selector!("TNFT"); - let recipient = self.account.address(); - - let constructor_args = vec![name, symbol, recipient]; - let unique = false; - - let address = - compute_contract_address(self.config.deployer.salt, class_hash, &constructor_args); - - if let Ok(contract_class_hash) = self - .starknet_rpc - .get_class_hash_at(BlockId::Tag(BlockTag::Pending), address) - .await - { - if contract_class_hash == class_hash { - warn!("ERC721 contract already deployed at address {address:#064x}"); - return Ok(address); - } else { - return Err(eyre!("ERC721 contract {address:#064x} already deployed with a different class hash {contract_class_hash:#064x}, expected {class_hash:#064x}")); - } - } - - let deploy = contract_factory.deploy(constructor_args, self.config.deployer.salt, unique); - - info!("Deploying ERC721 with nonce={}, address={address}", nonce); - - let result = deploy.nonce(nonce).max_fee(MAX_FEE).send().await?; - wait_for_tx(&self.starknet_rpc, result.transaction_hash, CHECK_INTERVAL).await?; - - self.nonces.insert(from_address, nonce + FieldElement::ONE); - - debug!( - "Deploy ERC721 transaction accepted {:#064x}", - result.transaction_hash - ); - - info!("ERC721 contract deployed at address {:#064x}", address); - Ok(address) - } - - async fn deploy_erc20(&mut self, class_hash: FieldElement) -> Result { - let contract_factory = ContractFactory::new(class_hash, self.account.clone()); - let from_address = self.account.address(); - let nonce = match self.nonces.get(&from_address) { - Some(nonce) => *nonce, - None => self.account.get_nonce().await?, - }; - - let name = selector!("TestToken"); - let symbol = selector!("TT"); - let decimals = felt!("128"); - let (initial_supply_low, initial_supply_high) = - (felt!("0xFFFFFFFFF"), felt!("0xFFFFFFFFF")); - let recipient = self.account.address(); - - let constructor_args = vec![ - name, - symbol, - decimals, - initial_supply_low, - initial_supply_high, - recipient, - ]; - let unique = false; - - let address = - compute_contract_address(self.config.deployer.salt, class_hash, &constructor_args); - - if let Ok(contract_class_hash) = self - .starknet_rpc - .get_class_hash_at(BlockId::Tag(BlockTag::Pending), address) - .await - { - if contract_class_hash == class_hash { - warn!("ERC20 contract already deployed at address {address:#064x}"); - return Ok(address); - } else { - return Err(eyre!("ERC20 contract {address:#064x} already deployed with a different class hash {contract_class_hash:#064x}, expected {class_hash:#064x}")); - } - } - - let deploy = contract_factory.deploy(constructor_args, self.config.deployer.salt, unique); - - info!( - "Deploying ERC20 contract with nonce={}, address={:#064x}", - nonce, address - ); - - let result = deploy.nonce(nonce).max_fee(MAX_FEE).send().await?; - wait_for_tx(&self.starknet_rpc, result.transaction_hash, CHECK_INTERVAL).await?; - - self.nonces.insert(from_address, nonce + FieldElement::ONE); - - debug!( - "Deploy ERC20 transaction accepted {:#064x}", - result.transaction_hash - ); - - info!("ERC20 contract deployed at address {:#064x}", address); - Ok(address) + transfer(account, nonce, amount, contract_address, recipient).await } /// Create accounts. @@ -317,12 +139,15 @@ impl GatlingShooterSetup { class_hash: FieldElement, num_accounts: usize, execution_encoding: ExecutionEncoding, - erc20_address: FieldElement, ) -> Result> { info!("Creating {} accounts", num_accounts); let mut deployed_accounts: Vec = Vec::with_capacity(num_accounts); + let mut nonce = self.account.get_nonce().await?; + + let mut deployment_joinset = JoinSet::new(); + for i in 0..num_accounts { self.account.set_block_id(BlockId::Tag(BlockTag::Pending)); @@ -362,23 +187,20 @@ impl GatlingShooterSetup { deployed_accounts.push(account); continue; } else { - return Err(eyre!("Account {i} already deployed at address {address:#064x} with a different class hash {account_class_hash:#064x}, expected {class_hash:#064x}")); + bail!("Account {i} already deployed at address {address:#064x} with a different class hash {account_class_hash:#064x}, expected {class_hash:#064x}"); } } - info!("Funding account {i} at address {address:#064x}"); - let tx_hash = self - .transfer(erc20_address, self.account.clone(), address, felt!("0xFFF")) - .await?; - wait_for_tx(&self.starknet_rpc, tx_hash, CHECK_INTERVAL).await?; let tx_hash = self .transfer( fee_token_address, self.account.clone(), address, felt!("0xFFFFFFFFFFFFFFFFFFFF"), + nonce, ) .await?; + nonce += FieldElement::ONE; wait_for_tx(&self.starknet_rpc, tx_hash, CHECK_INTERVAL).await?; let result = deploy.send().await?; @@ -393,11 +215,19 @@ impl GatlingShooterSetup { deployed_accounts.push(account); - wait_for_tx(&self.starknet_rpc, result.transaction_hash, CHECK_INTERVAL).await?; + let starknet_rpc = self.starknet_rpc.clone(); + + deployment_joinset.spawn(async move { + wait_for_tx(&starknet_rpc, result.transaction_hash, CHECK_INTERVAL).await + }); info!("Account {i} deployed at address {address:#064x}"); } + while let Some(result) = deployment_joinset.join_next().await { + result??; + } + Ok(deployed_accounts) } @@ -411,10 +241,7 @@ impl GatlingShooterSetup { warn!("Contract already declared at {class_hash:#064x}"); Ok(true) } - Err(ProviderError::StarknetError(StarknetErrorWithMessage { - code: MaybeUnknownErrorCode::Known(StarknetError::ClassHashNotFound), - .. - })) => Ok(false), + Err(ProviderError::StarknetError(StarknetError::ClassHashNotFound)) => Ok(false), Err(err) => Err(eyre!(err)), } } @@ -436,11 +263,7 @@ impl GatlingShooterSetup { } self.account.set_block_id(BlockId::Tag(BlockTag::Pending)); - let from_address = self.account.address(); - let nonce = match self.nonces.get(&from_address) { - Some(nonce) => *nonce, - None => self.account.get_nonce().await?, - }; + let nonce = self.account.get_nonce().await?; let tx_resp = self .account @@ -453,8 +276,6 @@ impl GatlingShooterSetup { wait_for_tx(&self.starknet_rpc, tx_resp.transaction_hash, CHECK_INTERVAL).await?; - self.nonces.insert(from_address, nonce + FieldElement::ONE); - info!( "Contract declared successfully at {:#064x}", tx_resp.class_hash @@ -478,11 +299,7 @@ impl GatlingShooterSetup { contract_path.as_ref().display(), class_hash ); - let from_address = self.account.address(); - let nonce = match self.nonces.get(&from_address) { - Some(nonce) => *nonce, - None => self.account.get_nonce().await?, - }; + let nonce = self.account.get_nonce().await?; if self.check_already_declared(class_hash).await? { return Ok(class_hash); @@ -511,12 +328,10 @@ impl GatlingShooterSetup { tx_resp.class_hash ); - self.nonces.insert(from_address, nonce + FieldElement::ONE); - Ok(tx_resp.class_hash) } - async fn declare_contract( + pub async fn declare_contract( &mut self, contract_source: &crate::config::ContractSourceConfig, ) -> Result { @@ -530,6 +345,38 @@ impl GatlingShooterSetup { } } +pub async fn transfer( + account: StarknetAccount, + nonce: FieldElement, + amount: FieldElement, + contract_address: FieldElement, + recipient: FieldElement, +) -> color_eyre::Result { + let from_address = account.address(); + + debug!( + "Transferring {amount} of {contract_address:#064x} from address {from_address:#064x} to address {recipient:#064x} with nonce={}", + nonce, + ); + + let (amount_low, amount_high) = (amount, felt!("0")); + + let call = Call { + to: contract_address, + selector: selector!("transfer"), + calldata: vec![recipient, amount_low, amount_high], + }; + + let result = account + .execute(vec![call]) + .max_fee(MAX_FEE) + .nonce(nonce) + .send() + .await?; + + Ok(result.transaction_hash) +} + /// Create a StarkNet RPC provider from a URL. /// # Arguments /// * `rpc` - The URL of the StarkNet RPC provider. diff --git a/src/actions/shooters.rs b/src/actions/shooters.rs new file mode 100644 index 0000000..9b35c98 --- /dev/null +++ b/src/actions/shooters.rs @@ -0,0 +1,147 @@ +use std::{boxed::Box, sync::Arc}; + +use color_eyre::eyre::OptionExt; +use goose::{ + config::GooseConfiguration, + goose::{Scenario, Transaction, TransactionFunction}, + metrics::GooseMetrics, + GooseAttack, +}; +use starknet::{ + accounts::Call, + core::types::{FieldElement, InvokeTransactionResult}, + providers::jsonrpc::JsonRpcMethod, +}; + +use crate::{ + actions::goose::{send_execution, GooseWriteUserState}, + config::GatlingConfig, +}; + +use super::{ + goose::{ + goose_write_user_wait_last_tx, make_goose_config, setup, verify_transactions, + TransactionBlocks, + }, + setup::{GatlingSetup, StarknetAccount}, +}; + +pub mod mint; +pub mod transfer; + +pub struct ShooterAttack { + pub goose_metrics: GooseMetrics, + pub first_block: u64, + pub last_block: u64, +} + +pub trait Shooter { + const NAME: &'static str; + + async fn setup(setup: &mut GatlingSetup) -> color_eyre::Result + where + Self: Sized; + + fn get_goose_config( + config: &GatlingConfig, + amount: u64, + ) -> color_eyre::Result { + make_goose_config(config, amount, Self::NAME) + } + + async fn goose_attack( + self: Arc, + config: GooseConfiguration, + accounts: Vec, + ) -> color_eyre::Result + where + Self: Send + Sync + 'static, + { + let setup: TransactionFunction = setup(accounts, config.iterations).await?; + + let submission: TransactionFunction = Self::execute(self.clone()); + + let finalizing: TransactionFunction = goose_write_user_wait_last_tx(); + + let blocks: Arc = Arc::default(); + let blocks_cloned = blocks.clone(); + + let verify_transactions = Transaction::new(Arc::new(move |user| { + Box::pin(verify_transactions(user, blocks_cloned.clone())) + })); + + let goose_attack = GooseAttack::initialize_with_config(config)?.register_scenario( + Scenario::new(Self::NAME) + .register_transaction(Transaction::new(setup).set_name("Setup").set_on_start()) + .register_transaction( + Transaction::new(submission) + .set_name("Transaction Submission") + .set_sequence(1), + ) + .register_transaction( + Transaction::new(finalizing) + .set_name("Finalizing") + .set_sequence(2) + .set_on_stop(), + ) + .register_transaction( + verify_transactions + .set_name("Verification") + .set_sequence(3) + .set_on_stop(), + ), + ); + + let metrics = goose_attack.execute().await?; + + let blocks = Arc::into_inner(blocks).ok_or_eyre( + "Transaction blocks arc has multiple references after goose verification", + )?; + + Ok(ShooterAttack { + goose_metrics: metrics, + first_block: blocks.first.into_inner(), + last_block: blocks.last.into_inner(), + }) + } + + fn execute(self: Arc) -> TransactionFunction + where + Self: Send + Sync + 'static, + { + Arc::new(move |user| { + let shooter = self.clone(); + + Box::pin(async move { + let GooseWriteUserState { account, nonce, .. } = user + .get_session_data::() + .expect("Should be in a goose user with GooseUserState session data"); + + let call = shooter.get_execution_data(account); + + let response: InvokeTransactionResult = send_execution( + user, + vec![call], + *nonce, + &account.clone(), + JsonRpcMethod::AddInvokeTransaction, + ) + .await? + .0; + + let GooseWriteUserState { nonce, prev_tx, .. } = + user.get_session_data_mut::().expect( + "Should be successful as we already asserted that the session data is a GooseUserState", + ); + + *nonce += FieldElement::ONE; + + prev_tx.push(response.transaction_hash); + + Ok(()) + }) + }) + } + + fn get_execution_data(&self, account: &StarknetAccount) -> Call; +} diff --git a/src/actions/shooters/mint.rs b/src/actions/shooters/mint.rs new file mode 100644 index 0000000..1c099c6 --- /dev/null +++ b/src/actions/shooters/mint.rs @@ -0,0 +1,122 @@ +use std::{collections::HashMap, sync::Arc}; + +use color_eyre::eyre::bail; +use log::{debug, info, warn}; +use starknet::{ + accounts::{Account, Call, ConnectedAccount}, + contract::ContractFactory, + core::types::{BlockId, BlockTag, FieldElement}, + macros::{felt, selector}, + providers::{jsonrpc::HttpTransport, JsonRpcClient, Provider}, +}; +use tokio::task::JoinSet; + +use crate::{ + actions::setup::{GatlingSetup, StarknetAccount, CHECK_INTERVAL, MAX_FEE}, + generators::get_rng, + utils::{compute_contract_address, wait_for_tx}, +}; + +use super::Shooter; + +pub struct MintShooter { + pub account_to_erc721_addresses: HashMap, + pub recipient: StarknetAccount, +} + +impl Shooter for MintShooter { + const NAME: &'static str = "Erc721 Mints"; + + async fn setup(setup: &mut GatlingSetup) -> color_eyre::Result { + let erc721_class_hash = setup + .declare_contract(&setup.config().setup.erc721_contract.clone()) + .await?; + + let deployer_salt = setup.config().deployer.salt; + let mut join_set = JoinSet::new(); + + for account in setup.accounts().iter().cloned() { + let address = account.address(); + let rpc_client = setup.rpc_client().clone(); + join_set.spawn(async move { + let contract = + Self::deploy_erc721(rpc_client, deployer_salt, erc721_class_hash, account) + .await; + + (address, contract) + }); + } + + let mut map = HashMap::with_capacity(setup.accounts().len()); + while let Some((account_address, contract_result)) = + join_set.join_next().await.transpose()? + { + map.insert(account_address, contract_result?); + } + + Ok(Self { + account_to_erc721_addresses: map, + recipient: setup.deployer_account().clone(), + }) + } + + fn get_execution_data(&self, account: &StarknetAccount) -> Call { + let recipient = account.address(); + + let (token_id_low, token_id_high) = (get_rng(), felt!("0x0000")); + + Call { + to: self.account_to_erc721_addresses[&account.address()], + selector: selector!("mint"), + calldata: vec![recipient, token_id_low, token_id_high], + } + } +} + +impl MintShooter { + async fn deploy_erc721( + starknet_rpc: Arc>, + deployer_salt: FieldElement, + class_hash: FieldElement, + recipient: StarknetAccount, + ) -> color_eyre::Result { + let contract_factory = ContractFactory::new(class_hash, &recipient); + + let name = selector!("TestNFT"); + let symbol = selector!("TNFT"); + + let constructor_args = vec![name, symbol, recipient.address()]; + let unique = false; + + let address = compute_contract_address(deployer_salt, class_hash, &constructor_args); + + if let Ok(contract_class_hash) = starknet_rpc + .get_class_hash_at(BlockId::Tag(BlockTag::Pending), address) + .await + { + if contract_class_hash == class_hash { + warn!("ERC721 contract already deployed at address {address:#064x}"); + return Ok(address); + } else { + bail!("ERC721 contract {address:#064x} already deployed with a different class hash {contract_class_hash:#064x}, expected {class_hash:#064x}"); + } + } + + let deploy = contract_factory.deploy(constructor_args, deployer_salt, unique); + + let nonce = recipient.get_nonce().await?; + + info!("Deploying ERC721 with nonce={}, address={address}", nonce); + + let result = deploy.nonce(nonce).max_fee(MAX_FEE).send().await?; + wait_for_tx(&starknet_rpc, result.transaction_hash, CHECK_INTERVAL).await?; + + debug!( + "Deploy ERC721 transaction accepted {:#064x}", + result.transaction_hash + ); + + info!("ERC721 contract deployed at address {:#064x}", address); + Ok(address) + } +} diff --git a/src/actions/shooters/transfer.rs b/src/actions/shooters/transfer.rs new file mode 100644 index 0000000..baccab2 --- /dev/null +++ b/src/actions/shooters/transfer.rs @@ -0,0 +1,140 @@ +use color_eyre::eyre::bail; +use log::{debug, info, warn}; +use starknet::{ + accounts::{Account, Call, ConnectedAccount}, + contract::ContractFactory, + core::types::{BlockId, BlockTag, FieldElement}, + macros::{felt, selector}, + providers::Provider, +}; +use tokio::task::JoinSet; + +use crate::{ + actions::setup::{self, GatlingSetup, StarknetAccount, CHECK_INTERVAL, MAX_FEE}, + utils::{compute_contract_address, wait_for_tx}, +}; + +use super::Shooter; + +pub struct TransferShooter { + pub erc20_address: FieldElement, + pub account: StarknetAccount, +} + +impl Shooter for TransferShooter { + const NAME: &'static str = "Erc20 Transfers"; + + async fn setup(setup: &mut GatlingSetup) -> color_eyre::Result + where + Self: Sized, + { + let class_hash = setup + .declare_contract(&setup.config().setup.erc20_contract.clone()) + .await?; + + let contract_factory = ContractFactory::new(class_hash, setup.deployer_account().clone()); + let mut nonce = setup.deployer_account().get_nonce().await?; + + let name = selector!("TestToken"); + let symbol = selector!("TT"); + let decimals = felt!("128"); + let (initial_supply_low, initial_supply_high) = + (felt!("0xFFFFFFFFF"), felt!("0xFFFFFFFFF")); + let recipient = setup.deployer_account().address(); + + let constructor_args = vec![ + name, + symbol, + decimals, + initial_supply_low, + initial_supply_high, + recipient, + ]; + let unique = false; + + let address = + compute_contract_address(setup.config().deployer.salt, class_hash, &constructor_args); + + if let Ok(contract_class_hash) = setup + .rpc_client() + .get_class_hash_at(BlockId::Tag(BlockTag::Pending), address) + .await + { + if contract_class_hash == class_hash { + warn!("ERC20 contract already deployed at address {address:#064x}"); + return Ok(TransferShooter { + erc20_address: address, + account: setup.deployer_account().clone(), + }); + } else { + bail!("ERC20 contract {address:#064x} already deployed with a different class hash {contract_class_hash:#064x}, expected {class_hash:#064x}"); + } + } + + let deploy = + contract_factory.deploy(constructor_args, setup.config().deployer.salt, unique); + + info!( + "Deploying ERC20 contract with nonce={}, address={:#064x}", + nonce, address + ); + + let result = deploy.nonce(nonce).max_fee(MAX_FEE).send().await?; + nonce += FieldElement::ONE; + wait_for_tx(setup.rpc_client(), result.transaction_hash, CHECK_INTERVAL).await?; + + debug!( + "Deploy ERC20 transaction accepted {:#064x}", + result.transaction_hash + ); + + info!("ERC20 contract deployed at address {:#064x}", address); + + let mut joinset = JoinSet::new(); + + for account in setup.accounts() { + info!("Funding account at address {address:#064x}"); + + let tx_hash = setup::transfer( + setup.deployer_account().clone(), + nonce, + felt!("0xFFFFF"), + address, + account.address(), + ) + .await?; + + nonce += FieldElement::ONE; + let rpc_client = setup.rpc_client().clone(); + joinset.spawn(async move { wait_for_tx(&rpc_client, tx_hash, CHECK_INTERVAL).await }); + } + + while let Some(result) = joinset.join_next().await { + result??; + } + + Ok(TransferShooter { + erc20_address: address, + account: setup.deployer_account().clone(), + }) + } + + fn get_execution_data(&self, _account: &StarknetAccount) -> Call { + let (amount_low, amount_high) = (felt!("1"), felt!("0")); + + // Hex: 0xdead + // from_hex_be isn't const whereas from_mont is + const VOID_ADDRESS: FieldElement = FieldElement::from_mont([ + 18446744073707727457, + 18446744073709551615, + 18446744073709551615, + 576460752272412784, + ]); + + Call { + to: self.erc20_address, + selector: selector!("transfer"), + calldata: vec![VOID_ADDRESS, amount_low, amount_high], + } + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 04d2f5e..020b3c3 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -25,8 +25,10 @@ pub struct Cli { /// Subcommands #[derive(Subcommand, Debug)] pub enum Command { - /// Trigger a load test. + /// Trigger a write load test. Shoot {}, + // Trigger a read load test + Read {}, } #[derive(Debug, Args)] diff --git a/src/config.rs b/src/config.rs index 715694e..cbb0e4b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,15 +1,21 @@ //! General configuration +use std::fs::File; +use std::io::BufReader; use std::path::PathBuf; use color_eyre::eyre::Result; -use config::{builder::DefaultState, Config, ConfigBuilder, File}; +use config::{builder::DefaultState, Config, ConfigBuilder}; -use serde::de::Error as DeError; use serde::Deserialize; -use starknet::core::{ - types::{contract::CompiledClass, FieldElement}, - utils::{cairo_short_string_to_felt, CairoShortStringToFeltError}, +use serde::{de::Error as DeError, Deserializer}; +use serde_json::{Map, Value}; +use starknet::{ + core::{ + types::{contract::CompiledClass, FieldElement}, + utils::{cairo_short_string_to_felt, CairoShortStringToFeltError}, + }, + providers::jsonrpc::JsonRpcMethod, }; /// Configuration for the application. @@ -103,11 +109,28 @@ pub struct DeployerConfig { #[derive(Debug, Deserialize, Clone)] pub struct RunConfig { - pub num_erc20_transfers: u64, - pub num_erc721_mints: u64, pub concurrency: u64, + pub shooters: Vec, + pub read_benches: Vec, } +#[derive(Debug, Deserialize, Clone)] +pub struct Shooters { + pub name: String, + pub shoot: u64, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct ReadBenchConfig { + pub name: String, + pub num_requests: u64, + pub method: JsonRpcMethod, + #[serde(deserialize_with = "parameters_file_deserializer")] + pub parameters_location: ParametersFile, +} + +pub type ParametersFile = Vec>; + #[derive(Debug, Deserialize, Clone)] pub struct ReportConfig { pub num_blocks: u64, @@ -127,7 +150,7 @@ impl GatlingConfig { /// Create a new configuration from a file. pub fn from_file(path: &str) -> Result { base_config_builder() - .add_source(File::with_name(path)) + .add_source(config::File::with_name(path)) .build() .unwrap() .try_deserialize() @@ -156,3 +179,16 @@ where CairoShortStringToFeltError::StringTooLong => D::Error::custom("string too long"), }) } + +fn parameters_file_deserializer<'de, D>(de: D) -> Result +where + D: Deserializer<'de>, +{ + let path = PathBuf::deserialize(de)?; + + let file = File::open(path).expect("Could not open file"); + let reader = BufReader::new(file); + let params = + serde_json::from_reader(reader).expect("Could not deserialize read params correctly"); + Ok(params) +} diff --git a/src/main.rs b/src/main.rs index c3d3643..87d8fbc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,9 @@ async fn main() -> Result<()> { Command::Shoot { .. } => { actions::shoot(cfg).await?; } + Command::Read { .. } => { + actions::read(cfg).await?; + } } Ok(()) diff --git a/src/metrics.rs b/src/metrics.rs index 942bef2..5352742 100644 --- a/src/metrics.rs +++ b/src/metrics.rs @@ -1,21 +1,25 @@ -use crate::utils::get_num_tx_per_block; - -use color_eyre::{ - eyre::{bail, eyre}, - Result, +use crate::utils::get_blocks_with_txs; + +use color_eyre::{eyre::OptionExt, Result}; + +use goose::metrics::{GooseMetrics, GooseRequestMetricAggregate, GooseRequestMetricTimingData}; +use serde::Serialize; +use starknet::{ + core::types::{ + BlockWithTxs, ExecutionResources, InvokeTransaction, InvokeTransactionV0, + InvokeTransactionV1, L1HandlerTransaction, Transaction, + }, + providers::{jsonrpc::HttpTransport, JsonRpcClient, Provider}, }; - -use goose::metrics::{GooseMetrics, TransactionMetricAggregate}; -use serde_derive::Serialize; -use starknet::providers::{jsonrpc::HttpTransport, JsonRpcClient, Provider}; -use std::fmt; +use std::{borrow::Cow, fmt, sync::Arc}; pub const BLOCK_TIME: u64 = 6; #[derive(Clone, Debug, Serialize)] pub struct GlobalReport { pub users: u64, - pub all_bench_report: BenchmarkReport, + #[serde(skip_serializing_if = "Option::is_none")] + pub all_bench_report: Option, pub benches: Vec, pub extra: String, } @@ -26,7 +30,7 @@ pub struct GlobalReport { /// and returns the metric value as a f64 /// The name and unit are used for displaying the metric /// -/// ### Example +/// ### Example /// { name: "Average TPS", unit: "transactions/second", compute: average_tps } /// "Average TPS: 1000 transactions/second" #[derive(PartialEq, Eq, Hash, Clone)] @@ -36,6 +40,8 @@ pub struct NodeMetrics { pub compute: fn(&[u64]) -> f64, } +const GOOSE_TIME_UNIT: &str = "milliseconds"; + /// A struct that contains the result of a metric computation alognside the name and unit /// This struct is used for displaying the metric result /// Example: @@ -43,7 +49,7 @@ pub struct NodeMetrics { /// "Average TPS: 1000 transactions/second" #[derive(Debug, Clone, Serialize)] pub struct MetricResult { - pub name: &'static str, + pub name: Cow<'static, str>, pub unit: &'static str, pub value: serde_json::Value, } @@ -80,7 +86,7 @@ impl BenchmarkReport { pub async fn with_block_range( &mut self, - starknet_rpc: &JsonRpcClient, + starknet_rpc: &Arc>, mut start_block: u64, mut end_block: u64, ) -> Result<()> { @@ -91,8 +97,8 @@ impl BenchmarkReport { end_block -= 1; } - let num_tx_per_block = get_num_tx_per_block(starknet_rpc, start_block, end_block).await?; - let metrics = compute_node_metrics(num_tx_per_block); + let blocks_with_txs = get_blocks_with_txs(starknet_rpc, start_block..=end_block).await?; + let metrics = compute_node_metrics(blocks_with_txs)?; self.metrics.extend_from_slice(&metrics); @@ -101,15 +107,15 @@ impl BenchmarkReport { pub async fn with_last_x_blocks( &mut self, - starknet_rpc: &JsonRpcClient, + starknet_rpc: &Arc>, num_blocks: u64, ) -> Result<()> { // The last block won't be full of transactions, so we skip it let end_block = starknet_rpc.block_number().await? - 1; let start_block = end_block - num_blocks; - let num_tx_per_block = get_num_tx_per_block(starknet_rpc, start_block, end_block).await?; - let metrics = compute_node_metrics(num_tx_per_block).to_vec(); + let blocks_with_txs = get_blocks_with_txs(starknet_rpc, start_block..=end_block).await?; + let metrics = compute_node_metrics(blocks_with_txs)?; self.last_x_blocks_metrics = Some(LastXBlocksMetric { num_blocks, @@ -119,82 +125,113 @@ impl BenchmarkReport { Ok(()) } - pub fn with_goose_metrics(&mut self, metrics: &GooseMetrics) -> Result<()> { - let transactions = metrics - .transactions - .first() - .ok_or(eyre!("Could no find scenario's transactions"))?; - - let [_setup, requests, _finalizing, verification] = transactions.as_slice() else { - bail!("Failed at getting all transaction aggragates") - }; + pub fn with_goose_write_metrics(&mut self, metrics: &GooseMetrics) -> Result<()> { + let submission_requests = metrics + .requests + .get("POST Transaction Submission") + .ok_or_eyre("Found no submission request metrics")?; let verification_requests = metrics .requests .get("POST Verification") - .ok_or(eyre!("Found no verification request metrics"))?; + .ok_or_eyre("Found no verification request metrics")?; + + self.with_request_metric_aggregate(submission_requests, Some("Submission")); + self.with_request_metric_aggregate(verification_requests, Some("Verifcation")); + + Ok(()) + } + + pub fn with_goose_read_metrics(&mut self, metrics: &GooseMetrics) -> color_eyre::Result<()> { + let requests = metrics + .requests + .get("POST Request") + .ok_or_eyre("Found no read request metrics")?; + + self.with_request_metric_aggregate(requests, None); - const GOOSE_TIME_UNIT: &str = "milliseconds"; + Ok(()) + } + + fn with_request_metric_aggregate( + &mut self, + requests: &GooseRequestMetricAggregate, + metric: Option<&str>, + ) { + fn fmt_with_name(template: &'static str, metric: Option<&str>) -> Cow<'static, str> { + if let Some(metric) = metric { + format!("{metric} {template}").into() + } else { + template.into() + } + } self.metrics.extend_from_slice(&[ MetricResult { - name: "Total Submission Time", + name: fmt_with_name("Total Time", metric), unit: GOOSE_TIME_UNIT, - value: requests.total_time.into(), + value: requests.raw_data.total_time.into(), }, MetricResult { - name: "Total Verification Time", + name: fmt_with_name("Max Time", metric), unit: GOOSE_TIME_UNIT, - value: verification.total_time.into(), - }, - MetricResult { - name: "Failed Transactions Verifications", - unit: "", - value: verification_requests.fail_count.into(), + value: requests.raw_data.maximum_time.into(), }, MetricResult { - name: "Failed Transaction Submissions", - unit: "", - value: requests.fail_count.into(), - }, - MetricResult { - name: "Max Submission Time", + name: fmt_with_name("Min Time", metric), unit: GOOSE_TIME_UNIT, - value: requests.max_time.into(), + value: requests.raw_data.minimum_time.into(), }, MetricResult { - name: "Min Submission Time", + name: fmt_with_name("Average Time", metric), unit: GOOSE_TIME_UNIT, - value: requests.min_time.into(), + value: transaction_average(&requests.raw_data).into(), }, MetricResult { - name: "Average Submission Time", - unit: GOOSE_TIME_UNIT, - value: transaction_average(requests).into(), - }, - MetricResult { - name: "Max Verification Time", - unit: GOOSE_TIME_UNIT, - value: verification_requests.raw_data.maximum_time.into(), - }, - MetricResult { - name: "Min Verification Time", - unit: GOOSE_TIME_UNIT, - value: verification_requests.raw_data.minimum_time.into(), - }, - MetricResult { - name: "Average Verification Time", - unit: GOOSE_TIME_UNIT, - value: transaction_average(requests).into(), + name: fmt_with_name("Failed Requests", metric), + unit: "", + value: requests.fail_count.into(), }, ]); - Ok(()) + if let Some((ver_p50, ver_p90)) = calculate_p50_and_p90(&requests.raw_data) { + self.metrics.extend_from_slice(&[ + MetricResult { + name: fmt_with_name("P90 Time", metric), + unit: GOOSE_TIME_UNIT, + value: ver_p90.into(), + }, + MetricResult { + name: fmt_with_name("P50 Time", metric), + unit: GOOSE_TIME_UNIT, + value: ver_p50.into(), + }, + ]) + } } } -fn transaction_average(requests: &TransactionMetricAggregate) -> f64 { - requests.total_time as f64 / requests.counter as f64 +fn transaction_average(timings: &GooseRequestMetricTimingData) -> f64 { + timings.total_time as f64 / timings.counter as f64 +} + +fn calculate_p50_and_p90(timing_data: &GooseRequestMetricTimingData) -> Option<(usize, usize)> { + let p50_idx = (timing_data.counter * 50) / 100; + + let p90_idx = (timing_data.counter * 90) / 100; + + let mut ordered_times = timing_data + .times + .iter() + .flat_map(|(time, &amount)| std::iter::repeat(time).take(amount)); + + // These should only return None when there is only 1 or 0 times in the data + let &p50 = ordered_times.nth(p50_idx)?; + + // p50 already iterated some out, so we subtract it's idx from here + let &p90 = ordered_times.nth(p90_idx - p50_idx)?; + + Some((p50, p90)) } impl fmt::Display for MetricResult { @@ -232,25 +269,75 @@ impl fmt::Display for BenchmarkReport { } } -pub fn compute_node_metrics(num_tx_per_block: Vec) -> [MetricResult; 2] { - [ +pub fn compute_node_metrics( + blocks_with_txs: Vec<(BlockWithTxs, Vec)>, +) -> Result> { + let total_transactions: usize = blocks_with_txs + .iter() + .map(|(b, _)| b.transactions.len()) + .sum(); + let avg_tpb = total_transactions as f64 / blocks_with_txs.len() as f64; + + let mut metrics = vec![ MetricResult { - name: "Average TPS", + name: "Average TPS".into(), unit: "transactions/second", - value: average_tps(&num_tx_per_block).into(), + value: (avg_tpb / BLOCK_TIME as f64).into(), }, MetricResult { - name: "Average Extrinsics per block", + name: "Average Extrinsics per block".into(), unit: "extrinsics/block", - value: average_tpb(&num_tx_per_block).into(), + value: avg_tpb.into(), }, - ] -} + ]; + + let (first_block, _) = blocks_with_txs.first().ok_or_eyre("No first block")?; + let (last_block, _) = blocks_with_txs.last().ok_or_eyre("No last block")?; + + if first_block.timestamp != last_block.timestamp { + let total_uops: u64 = blocks_with_txs + .iter() + .flat_map(|(b, _)| &b.transactions) + .map(tx_get_user_operations) + .collect::, _>>()? + .into_iter() + .sum(); + + let total_steps: u64 = blocks_with_txs + .iter() + .flat_map(|(_, r)| r) + .map(|resource| resource.steps) + .sum(); + + metrics.push(MetricResult { + name: "Average UOPS".into(), + unit: "operations/second", + value: (total_uops as f64 / blocks_with_txs.len() as f64 / BLOCK_TIME as f64).into(), + }); + + metrics.push(MetricResult { + name: "Average Steps Per Second".into(), + unit: "operations/second", + value: (total_steps as f64 / blocks_with_txs.len() as f64 / BLOCK_TIME as f64).into(), + }); + } -fn average_tps(num_tx_per_block: &[u64]) -> f64 { - average_tpb(num_tx_per_block) / BLOCK_TIME as f64 + Ok(metrics) } -fn average_tpb(num_tx_per_block: &[u64]) -> f64 { - num_tx_per_block.iter().sum::() as f64 / num_tx_per_block.len() as f64 +fn tx_get_user_operations(tx: &Transaction) -> Result { + Ok(match tx { + Transaction::Invoke( + InvokeTransaction::V0(InvokeTransactionV0 { calldata, .. }) + | InvokeTransaction::V1(InvokeTransactionV1 { calldata, .. }), + ) + | Transaction::L1Handler(L1HandlerTransaction { calldata, .. }) => { + let &user_operations = calldata + .first() + .ok_or_eyre("Expected calldata to have at least one field element")?; + + user_operations.try_into()? + } + _ => 1, // Other txs can be considered as 1 uop + }) } diff --git a/src/utils.rs b/src/utils.rs index 98d5424..0e941bb 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,21 +1,24 @@ use std::ops::Deref; +use std::sync::Arc; use std::time::SystemTime; +use color_eyre::eyre::{bail, OptionExt}; use color_eyre::{eyre::eyre, Result}; use lazy_static::lazy_static; use log::debug; -use starknet::core::types::{BlockId, ExecutionResult, StarknetError}; +use starknet::core::types::MaybePendingTransactionReceipt::{PendingReceipt, Receipt}; +use starknet::core::types::{ + BlockId, BlockWithTxs, ExecutionResources, ExecutionResult, MaybePendingBlockWithTxs, + StarknetError, +}; use starknet::core::{crypto::compute_hash_on_elements, types::FieldElement}; +use starknet::providers::ProviderError; use starknet::providers::{jsonrpc::HttpTransport, JsonRpcClient, Provider}; -use starknet::providers::{MaybeUnknownErrorCode, ProviderError}; -use starknet::{ - core::types::MaybePendingTransactionReceipt::{PendingReceipt, Receipt}, - providers::StarknetErrorWithMessage, -}; +use tokio::task::JoinSet; use std::time::Duration; -use sysinfo::{CpuExt, System, SystemExt}; +use sysinfo::System; lazy_static! { pub static ref SYSINFO: SysInfo = SysInfo::new(); @@ -70,8 +73,8 @@ impl SysInfo { let cpu = sys.global_cpu_info(); Self { - os_name: sys.long_os_version().unwrap().trim().to_string(), - kernel_version: sys.kernel_version().unwrap(), + os_name: System::long_os_version().unwrap().trim().to_string(), + kernel_version: System::kernel_version().unwrap(), arch: std::env::consts::ARCH.to_string(), cpu_count: sys.cpus().len(), cpu_frequency: cpu.frequency(), @@ -141,43 +144,117 @@ pub async fn wait_for_tx( debug!("Waiting for transaction {tx_hash:#064x} to be accepted"); tokio::time::sleep(check_interval).await; } - Err(ProviderError::StarknetError(StarknetErrorWithMessage { - code: MaybeUnknownErrorCode::Known(StarknetError::TransactionHashNotFound), - .. - })) => { + Err(ProviderError::StarknetError(StarknetError::TransactionHashNotFound)) => { debug!("Waiting for transaction {tx_hash:#064x} to show up"); tokio::time::sleep(check_interval).await; } Err(err) => { return Err(eyre!(err).wrap_err(format!( "Error while waiting for transaction {tx_hash:#064x}" - ))) + ))); } } } } -/// Get a Map of the number of transactions per block from `start_block` to -/// `end_block` (including both) -/// This is meant to be used to calculate multiple metrics such as TPS and TPB +/// Get a list of blocks with transaction information from +/// `start_block` to `end_block` (including both) +/// This is meant to be used to calculate multiple metrics such as TPS and UOPS /// without hitting the StarkNet RPC multiple times -// TODO: add a cache to avoid hitting the RPC for the same block -pub async fn get_num_tx_per_block( - starknet_rpc: &JsonRpcClient, - start_block: u64, - end_block: u64, -) -> Result> { - let mut num_tx_per_block = Vec::new(); - - for block_number in start_block..=end_block { - let n = starknet_rpc - .get_block_transaction_count(BlockId::Number(block_number)) - .await?; - - num_tx_per_block.push(n); +pub async fn get_blocks_with_txs( + starknet_rpc: &Arc>, + block_range: impl Iterator, +) -> Result)>> { + const MAX_CONCURRENT: usize = 50; + + // A collection of spawned tokio tasks + let mut join_set = JoinSet::new(); + + let mut results = Vec::with_capacity(block_range.size_hint().0); + + for block_number in block_range { + // Make sure we don't hit dev server with too many requests + while join_set.len() >= MAX_CONCURRENT { + let next = join_set + .join_next() + .await + .ok_or_eyre("JoinSet should have items")???; + + results.push(next); + } + + let starknet_rpc = starknet_rpc.clone(); + + join_set.spawn(get_block_info(starknet_rpc, block_number)); + } + + async fn get_block_info( + starknet_rpc: Arc>, + block_number: u64, + ) -> Result<(BlockWithTxs, Vec)> { + let block_with_txs = match starknet_rpc + .get_block_with_txs(BlockId::Number(block_number)) + .await? + { + MaybePendingBlockWithTxs::Block(b) => b, + MaybePendingBlockWithTxs::PendingBlock(pending) => { + bail!("Block should not be pending. Pending: {pending:?}") + } + }; + + let mut resources = Vec::with_capacity(block_with_txs.transactions.len()); + + #[cfg(with_sps)] + for tx in block_with_txs.transactions.iter() { + let maybe_receipt = starknet_rpc + .get_transaction_receipt(tx.transaction_hash()) + .await?; + + use starknet::core::types::TransactionReceipt as TR; + + let resource = match maybe_receipt { + Receipt(receipt) => match receipt { + TR::Invoke(receipt) => receipt.execution_resources, + TR::L1Handler(receipt) => receipt.execution_resources, + TR::Declare(receipt) => receipt.execution_resources, + TR::Deploy(receipt) => receipt.execution_resources, + TR::DeployAccount(receipt) => receipt.execution_resources, + }, + PendingReceipt(pending) => { + bail!("Transaction should not be pending. Pending: {pending:?}"); + } + }; + + resources.push(resource); + } + #[cfg(not(with_sps))] + for _ in block_with_txs.transactions.iter() { + resources.push(ExecutionResources { + steps: 0, + memory_holes: None, + range_check_builtin_applications: None, + pedersen_builtin_applications: None, + poseidon_builtin_applications: None, + ec_op_builtin_applications: None, + ecdsa_builtin_applications: None, + bitwise_builtin_applications: None, + keccak_builtin_applications: None, + segment_arena_builtin: None, + }); + } + + Ok((block_with_txs, resources)) } - Ok(num_tx_per_block) + // Process the rest + while let Some(next) = join_set.join_next().await { + results.push(next??) + } + + // Make sure blocks are in order + results.sort_unstable_by_key(|(block, _)| block.block_number); + + Ok(results) } /// Sanitize a string to be used as a filename by removing/replacing illegal chars