diff --git a/.github/workflows/crates.yml b/.github/workflows/crates.yml deleted file mode 100644 index 08ffc7e..0000000 --- a/.github/workflows/crates.yml +++ /dev/null @@ -1,51 +0,0 @@ -on: - push: - branch: ["master"] - -name: Publish to crates.io - -env: - CRATES_DEPLOY: false - -jobs: - build_and_test: - name: Build the client - runs-on: ubuntu-latest - environment: dev - steps: - - uses: actions/checkout@v2 - - - name: Install Nightly toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - - run: rustup toolchain list - - uses: actions-rs/cargo@v1 - with: - command: build - args: --release --all-features - - check_and_publish: - name: Check semver and publish to crates.io - runs-on: ubuntu-latest - environment: dev - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Install Nightly toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - - name: Publish to crates.io - if: "contains(${{ env.CRATES_DEPLOY }},'true')" - run: cargo publish -p tinydancer --token ${CRATES_TOKEN} --no-verify - env: - CRATES_DEPLOY: ${{ secrets.CRATES_DEPLOY }} - CRATES_TOKEN: ${{ secrets.CRATES_TOKEN }} diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..7a56bc2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "solana-spv-plugin"] + path = solana-spv-plugin + url = https://github.com/tinydancer-io/solana-spv-plugin + branch = "master" diff --git a/Cargo.lock b/Cargo.lock index 76a37b7..c161783 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,40 @@ dependencies = [ "regex", ] +[[package]] +name = "account_proof_geyser" +version = "0.1.0" +source = "git+https://github.com/tinydancer-io/solana-spv-plugin#a11f5004efae5030937571033a29d640b24fb79b" +dependencies = [ + "anyhow", + "bincode", + "blake3", + "borsh 1.4.0", + "crossbeam", + "crossbeam-channel", + "log", + "lru 0.12.3", + "rayon", + "serde", + "serde_json", + "solana-accounts-db", + "solana-geyser-plugin-interface", + "solana-logger 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-runtime", + "solana-sdk", + "solana-transaction-status 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "tokio", +] + +[[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" @@ -34,7 +68,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", - "cipher 0.3.0", + "cipher", "cpufeatures", "opaque-debug", ] @@ -47,7 +81,7 @@ checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc" dependencies = [ "aead", "aes", - "cipher 0.3.0", + "cipher", "ctr", "polyval", "subtle", @@ -56,20 +90,33 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.12", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ - "getrandom 0.2.8", + "cfg-if", + "getrandom 0.2.12", "once_cell", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -95,6 +142,170 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "anchor-attribute-access-control" +version = "0.28.0" +source = "git+https://github.com/tinydancer-io/anchor?branch=patch-dep#e35378d431e9e5324a0d3d62eebb22ac752b850c" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-account" +version = "0.28.0" +source = "git+https://github.com/tinydancer-io/anchor?branch=patch-dep#e35378d431e9e5324a0d3d62eebb22ac752b850c" +dependencies = [ + "anchor-syn", + "anyhow", + "bs58 0.5.1", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-constant" +version = "0.28.0" +source = "git+https://github.com/tinydancer-io/anchor?branch=patch-dep#e35378d431e9e5324a0d3d62eebb22ac752b850c" +dependencies = [ + "anchor-syn", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.28.0" +source = "git+https://github.com/tinydancer-io/anchor?branch=patch-dep#e35378d431e9e5324a0d3d62eebb22ac752b850c" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.28.0" +source = "git+https://github.com/tinydancer-io/anchor?branch=patch-dep#e35378d431e9e5324a0d3d62eebb22ac752b850c" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-program" +version = "0.28.0" +source = "git+https://github.com/tinydancer-io/anchor?branch=patch-dep#e35378d431e9e5324a0d3d62eebb22ac752b850c" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-client" +version = "0.28.0" +source = "git+https://github.com/tinydancer-io/anchor?branch=patch-dep#e35378d431e9e5324a0d3d62eebb22ac752b850c" +dependencies = [ + "anchor-lang", + "anyhow", + "futures", + "regex", + "serde", + "solana-account-decoder 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-client 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.28.0" +source = "git+https://github.com/tinydancer-io/anchor?branch=patch-dep#e35378d431e9e5324a0d3d62eebb22ac752b850c" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-space" +version = "0.28.0" +source = "git+https://github.com/tinydancer-io/anchor?branch=patch-dep#e35378d431e9e5324a0d3d62eebb22ac752b850c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-lang" +version = "0.28.0" +source = "git+https://github.com/tinydancer-io/anchor?branch=patch-dep#e35378d431e9e5324a0d3d62eebb22ac752b850c" +dependencies = [ + "anchor-attribute-access-control", + "anchor-attribute-account", + "anchor-attribute-constant", + "anchor-attribute-error", + "anchor-attribute-event", + "anchor-attribute-program", + "anchor-derive-accounts", + "anchor-derive-space", + "arrayref", + "base64 0.13.1", + "bincode", + "borsh 0.10.3", + "bytemuck", + "getrandom 0.2.12", + "solana-program", + "thiserror", +] + +[[package]] +name = "anchor-syn" +version = "0.28.0" +source = "git+https://github.com/tinydancer-io/anchor?branch=patch-dep#e35378d431e9e5324a0d3d62eebb22ac752b850c" +dependencies = [ + "anyhow", + "bs58 0.5.1", + "heck 0.3.3", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.8", + "syn 1.0.109", + "thiserror", +] + +[[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" @@ -115,21 +326,29 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.69" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] -name = "arc-swap" -version = "1.6.0" +name = "aquamarine" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" +dependencies = [ + "include_dir", + "itertools", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] name = "ark-bn254" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea691771ebbb28aea556c044e2e5c5227398d840cee0c34d4d20fa8eb2689e8c" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" dependencies = [ "ark-ec", "ark-ff", @@ -138,95 +357,121 @@ dependencies = [ [[package]] name = "ark-ec" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea978406c4b1ca13c2db2373b05cc55429c3575b8b21f1b9ee859aa5b03dd42" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" dependencies = [ "ark-ff", + "ark-poly", "ark-serialize", "ark-std", "derivative", + "hashbrown 0.13.2", + "itertools", "num-traits", "zeroize", ] [[package]] name = "ark-ff" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" dependencies = [ "ark-ff-asm", "ark-ff-macros", "ark-serialize", "ark-std", "derivative", - "num-bigint 0.4.3", + "digest 0.10.7", + "itertools", + "num-bigint 0.4.4", "num-traits", "paste", - "rustc_version 0.3.3", + "rustc_version", "zeroize", ] [[package]] name = "ark-ff-asm" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" dependencies = [ - "quote 1.0.23", - "syn 1.0.107", + "quote", + "syn 1.0.109", ] [[package]] name = "ark-ff-macros" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "num-bigint 0.4.3", + "num-bigint 0.4.4", "num-traits", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", ] [[package]] name = "ark-serialize" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ + "ark-serialize-derive", "ark-std", - "digest 0.9.0", + "digest 0.10.7", + "num-bigint 0.4.4", ] [[package]] -name = "ark-std" -version = "0.3.0" +name = "ark-serialize-derive" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "num-traits", - "rand 0.8.5", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "array-bytes" -version = "1.4.1" +name = "ark-std" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ad284aeb45c13f2fb4f084de4a420ebf447423bdf9386c0540ce33cb3ef4b8c" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] [[package]] name = "arrayref" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "ascii" @@ -236,9 +481,9 @@ checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" [[package]] name = "asn1-rs" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf6690c370453db30743b373a60ba498fc0d6d83b11f4abfd87a84a075db5dd4" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -247,7 +492,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.17", + "time", ] [[package]] @@ -256,9 +501,9 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", "synstructure", ] @@ -268,9 +513,9 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -281,9 +526,9 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "async-channel" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", "event-listener", @@ -292,9 +537,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.3.15" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" +checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" dependencies = [ "brotli", "flate2", @@ -302,17 +547,8 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "zstd", - "zstd-safe", -] - -[[package]] -name = "async-lock" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" -dependencies = [ - "event-listener", + "zstd 0.13.1", + "zstd-safe 7.1.0", ] [[package]] @@ -324,36 +560,15 @@ dependencies = [ "event-listener", ] -[[package]] -name = "async-stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" -dependencies = [ - "async-stream-impl", - "futures-core", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" -dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", -] - [[package]] name = "async-trait" -version = "0.1.64" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] @@ -369,77 +584,23 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] -name = "autotools" -version = "0.2.5" +name = "backtrace" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8138adefca3e5d2e73bfba83bd6eeaf904b26a7ac1b4a19892cfe16cc7e1701" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ + "addr2line", "cc", -] - -[[package]] -name = "axum" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5694b64066a2459918d8074c2ce0d5a88f409431994c2356617c8ae0c4721fc" -dependencies = [ - "async-trait", - "axum-core", - "bitflags", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower", - "tower-http 0.3.5", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cae3e661676ffbacb30f1a824089a8c9150e71017f7e1e38f2aa32009188d34" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backoff" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" -dependencies = [ - "futures-core", - "getrandom 0.2.8", - "instant", - "pin-project-lite", - "rand 0.8.5", - "tokio", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", ] [[package]] @@ -456,30 +617,15 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" - -[[package]] -name = "base64" -version = "0.21.0" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64ct" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" - -[[package]] -name = "beef" -version = "0.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" -dependencies = [ - "serde", -] +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bincode" @@ -492,21 +638,23 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.60.1" +version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", "lazycell", "peeking_take_while", - "proc-macro2 1.0.51", - "quote 1.0.23", + "prettyplease", + "proc-macro2", + "quote", "regex", "rustc-hash", "shlex", + "syn 2.0.57", ] [[package]] @@ -516,26 +664,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "bitmaps" -version = "2.1.0" +name = "bitflags" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" dependencies = [ - "typenum", + "serde", +] + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", ] [[package]] name = "blake3" -version = "1.3.3" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -550,9 +707,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -569,21 +726,68 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" dependencies = [ - "borsh-derive", + "borsh-derive 0.9.3", "hashbrown 0.11.2", ] +[[package]] +name = "borsh" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive 0.10.3", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0901fc8eb0aca4c83be0106d6f2db17d86a08dfc2c25f0e84464bf381158add6" +dependencies = [ + "borsh-derive 1.4.0", + "cfg_aliases", +] + [[package]] name = "borsh-derive" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", + "borsh-derive-internal 0.9.3", + "borsh-schema-derive-internal 0.9.3", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +dependencies = [ + "borsh-derive-internal 0.10.3", + "borsh-schema-derive-internal 0.10.3", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.51", - "syn 1.0.107", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51670c3aa053938b0ee3bd67c3817e471e626151131b934038e83c5bf8de48f5" +dependencies = [ + "once_cell", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.57", + "syn_derive", ] [[package]] @@ -592,9 +796,20 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -603,16 +818,27 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] name = "brotli" -version = "3.3.4" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -621,9 +847,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.4" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -636,20 +862,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] -name = "bstr" -version = "1.3.0" +name = "bs58" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "memchr", - "serde", + "tinyvec", ] [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "bv" @@ -663,35 +888,35 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aca418a974d83d40a0c1f0c5cba6ff4bc28d8df099109ca459a2118d40b6322" +checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bzip2" @@ -724,19 +949,14 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cassowary" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" - [[package]] name = "cc" -version = "1.0.79" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -754,29 +974,25 @@ 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.23" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", "serde", - "time 0.1.45", "wasm-bindgen", - "winapi", -] - -[[package]] -name = "chrono-humanize" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32dce1ea1988dbdf9f9815ff11425828523bd2a134ec0805d2ac8af26ee6096e" -dependencies = [ - "chrono", + "windows-targets 0.52.4", ] [[package]] @@ -788,21 +1004,11 @@ dependencies = [ "generic-array", ] -[[package]] -name = "cipher" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clang-sys" -version = "1.4.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" dependencies = [ "glob", "libc", @@ -817,7 +1023,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.3.2", "strsim 0.8.0", "textwrap 0.11.0", "unicode-width", @@ -826,32 +1032,32 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.23" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_derive", "clap_lex", - "indexmap", + "indexmap 1.9.3", "once_cell", "strsim 0.10.0", "termcolor", - "textwrap 0.16.0", + "textwrap 0.16.1", ] [[package]] name = "clap_derive" -version = "3.2.18" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -863,25 +1069,14 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "colored" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "atty", "lazy_static", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -899,24 +1094,24 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.1.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" dependencies = [ "crossbeam-utils", ] [[package]] name = "console" -version = "0.15.5" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.42.0", + "windows-sys 0.52.0", ] [[package]] @@ -931,9 +1126,9 @@ dependencies = [ [[package]] name = "console_log" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" dependencies = [ "log", "web-sys", @@ -960,22 +1155,29 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a4f51209740b5e1589e702b3044cdd4562cef41b6da404904192ffffb852d62" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] name = "constant_time_eq" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "copy" +version = "0.1.0" +dependencies = [ + "anchor-lang", +] [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -983,35 +1185,34 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" dependencies = [ - "cfg-if", "crossbeam-channel", "crossbeam-deque", "crossbeam-epoch", @@ -1021,84 +1222,58 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset 0.7.1", - "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossterm" -version = "0.25.0" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" -dependencies = [ - "bitflags", - "crossterm_winapi", - "libc", - "mio", - "parking_lot 0.12.1", - "signal-hook", - "signal-hook-mio", - "winapi", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crossterm" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f67c7faacd4db07a939f55d66a983a5355358a1f17d32cc9a8d01d1266b9ce" +checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crossterm_winapi", "libc", "mio", - "parking_lot 0.12.1", + "parking_lot", "signal-hook", "signal-hook-mio", "winapi", @@ -1106,9 +1281,9 @@ dependencies = [ [[package]] name = "crossterm_winapi" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ "winapi", ] @@ -1145,7 +1320,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher 0.3.0", + "cipher", ] [[package]] @@ -1162,55 +1337,11 @@ dependencies = [ "zeroize", ] -[[package]] -name = "cxx" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2 1.0.51", - "quote 1.0.23", - "scratch", - "syn 1.0.107", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" -dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", -] - [[package]] name = "darling" -version = "0.14.2" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" dependencies = [ "darling_core", "darling_macro", @@ -1218,58 +1349,48 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.14.2" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "strsim 0.10.0", - "syn 1.0.107", + "syn 2.0.57", ] [[package]] name = "darling_macro" -version = "0.14.2" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "dashmap" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" -dependencies = [ - "cfg-if", - "num_cpus", - "rayon", + "quote", + "syn 2.0.57", ] [[package]] name = "dashmap" -version = "5.4.0" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.12.3", + "hashbrown 0.14.3", "lock_api", "once_cell", - "parking_lot_core 0.9.7", + "parking_lot_core", + "rayon", ] [[package]] name = "data-encoding" -version = "2.3.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "der" @@ -1282,18 +1403,27 @@ dependencies = [ [[package]] name = "der-parser" -version = "8.1.0" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d4bc9b0db0a0df9ae64634ac5bdefb7afcb534e182275ca0beadbe486701c1" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" dependencies = [ "asn1-rs", "displaydoc", "nom", - "num-bigint 0.4.3", + "num-bigint 0.4.4", "num-traits", "rusticata-macros", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "derivation-path" version = "0.2.0" @@ -1306,16 +1436,16 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] name = "dialoguer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af3c796f3b0b408d9fd581611b47fa850821fcb84aa640b83a3c1a5be2d691f2" +checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" dependencies = [ "console", "shell-words", @@ -1323,6 +1453,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" version = "0.9.0" @@ -1334,56 +1470,56 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.3", + "block-buffer 0.10.4", "crypto-common", "subtle", ] [[package]] name = "dir-diff" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2860407d7d7e2e004bb2128510ad9e8d669e76fa005ccf567977b5d71b8b4a0b" +checksum = "a7ad16bf5f84253b50d6557681c58c3ab67c47c77d39fed9aeb56e947290bd10" dependencies = [ "walkdir", ] [[package]] name = "displaydoc" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] -name = "dlopen" -version = "0.1.8" +name = "dlopen2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e80ad39f814a9abe68583cd50a2d45c8a67561c3361ab8da240587dda80937" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" dependencies = [ - "dlopen_derive", - "lazy_static", + "dlopen2_derive", "libc", + "once_cell", "winapi", ] [[package]] -name = "dlopen_derive" -version = "0.1.4" +name = "dlopen2_derive" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f236d9e1b1fbd81cea0f9cbdc8dcc7e8ebcd80e6659cd7cb2ad5f6c05946c581" +checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ - "libc", - "quote 0.6.13", - "syn 0.15.44", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] @@ -1392,6 +1528,12 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + [[package]] name = "eager" version = "0.1.0" @@ -1430,14 +1572,14 @@ dependencies = [ "derivation-path", "ed25519-dalek", "hmac 0.12.1", - "sha2 0.10.6", + "sha2 0.10.8", ] [[package]] name = "either" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "encode_unicode" @@ -1447,43 +1589,31 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] [[package]] name = "enum-iterator" -version = "1.2.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91a4ec26efacf4aeff80887a175a419493cb6f8b5480d26387eb0bd038976187" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" dependencies = [ "enum-iterator-derive", ] [[package]] name = "enum-iterator-derive" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "828de45d0ca18782232dfb8f3ea9cc428e8ced380eb26a520baaacfc70de39ce" -dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "enum_dispatch" -version = "0.3.11" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f36e95862220b211a6e2aa5eca09b4fa391b13cd52ceb8035a24bf65a79de2" +checksum = "03cdc46ec28bd728e67540c528013c6a10eb69a02eb31078a1bda695438cbfb8" dependencies = [ - "once_cell", - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] @@ -1500,28 +1630,32 @@ dependencies = [ ] [[package]] -name = "event-listener" -version = "2.5.3" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "fast-math" -version = "0.1.1" +name = "errno" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2465292146cdfc2011350fe3b1c616ac83cf0faeedb33463ba1c332ed8948d66" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "ieee754", + "libc", + "windows-sys 0.52.0", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "fastrand" -version = "1.8.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "feature-probe" @@ -1531,35 +1665,38 @@ checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" [[package]] name = "filetime" -version = "0.2.19" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys 0.42.0", + "windows-sys 0.52.0", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "miniz_oxide", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" @@ -1580,24 +1717,24 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] -name = "fs_extra" -version = "1.3.0" +name = "fragile" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "futures" -version = "0.3.26" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -1610,9 +1747,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -1620,15 +1757,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.26" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -1637,48 +1774,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.26" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" - -[[package]] -name = "futures-timer" -version = "3.0.2" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" -dependencies = [ - "gloo-timers", - "send_wrapper", -] +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -1692,20 +1819,11 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "serde", "typenum", @@ -1737,9 +1855,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "js-sys", @@ -1749,87 +1867,16 @@ dependencies = [ ] [[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "globset" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "gloo-net" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" -dependencies = [ - "futures-channel", - "futures-core", - "futures-sink", - "gloo-utils", - "js-sys", - "pin-project", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "gloo-utils" -version = "0.1.6" +name = "gimli" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5" -dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] -name = "goauth" -version = "0.13.1" +name = "glob" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8af59a261bcf42f45d1b261232847b9b850ba0a1419d6100698246fb66e9240" -dependencies = [ - "arc-swap", - "futures", - "log", - "reqwest", - "serde", - "serde_derive", - "serde_json", - "simpl", - "smpl_jwt", - "time 0.3.17", - "tokio", -] +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "goblin" @@ -1844,9 +1891,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.15" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" dependencies = [ "bytes", "fnv", @@ -1854,7 +1901,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -1876,7 +1923,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash", + "ahash 0.7.8", ] [[package]] @@ -1885,32 +1932,35 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.8", ] [[package]] -name = "headers" -version = "0.3.8" +name = "hashbrown" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "base64 0.13.1", - "bitflags", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1", + "ahash 0.8.11", ] [[package]] -name = "headers-core" -version = "0.2.0" +name = "hashbrown" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "http", + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", ] [[package]] @@ -1930,12 +1980,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "histogram" @@ -1959,7 +2006,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -1975,18 +2022,18 @@ dependencies = [ [[package]] name = "home" -version = "0.5.4" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] name = "http" -version = "0.2.8" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1995,9 +2042,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -2006,9 +2053,9 @@ dependencies = [ [[package]] name = "http-range-header" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" [[package]] name = "httparse" @@ -2018,9 +2065,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" @@ -2030,9 +2077,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.25" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -2052,50 +2099,18 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-proxy" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" -dependencies = [ - "bytes", - "futures", - "headers", - "http", - "hyper", - "hyper-tls", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-rustls" -version = "0.23.2" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ + "futures-util", "http", "hyper", - "log", "rustls", - "rustls-native-certs", "tokio", "tokio-rustls", - "webpki-roots", -] - -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper", - "pin-project-lite", - "tokio", - "tokio-io-timeout", ] [[package]] @@ -2113,26 +2128,25 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows-core", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -2143,20 +2157,14 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", ] -[[package]] -name = "ieee754" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9007da9cacbd3e6343da136e98b0d2df013f553d35bdec8b518f07bea768e19c" - [[package]] name = "im" version = "15.1.0" @@ -2173,41 +2181,62 @@ dependencies = [ "version_check", ] +[[package]] +name = "include_dir" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "index_list" -version = "0.2.7" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9d968042a4902e08810946fc7cd5851eb75e80301342305af755ca06cb82ce" +checksum = "70891286cb8e844fdfcf1178b47569699f9e20b5ecc4b45a6240a64771444638" [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", ] [[package]] -name = "indicatif" -version = "0.17.3" +name = "indexmap" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ - "console", - "number_prefix", - "portable-atomic", - "unicode-width", + "equivalent", + "hashbrown 0.14.3", ] [[package]] -name = "inout" -version = "0.1.3" +name = "indicatif" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ - "generic-array", + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", ] [[package]] @@ -2221,9 +2250,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "iri-string" @@ -2246,24 +2275,24 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.25" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -2284,222 +2313,55 @@ dependencies = [ ] [[package]] -name = "jsonrpsee" -version = "0.16.2" +name = "keccak" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ - "jsonrpsee-client-transport", - "jsonrpsee-core", - "jsonrpsee-http-client", - "jsonrpsee-proc-macros", - "jsonrpsee-server", - "jsonrpsee-types", - "jsonrpsee-wasm-client", - "jsonrpsee-ws-client", - "tracing", + "cpufeatures", ] [[package]] -name = "jsonrpsee-client-transport" -version = "0.16.2" +name = "lazy_static" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965de52763f2004bc91ac5bcec504192440f0b568a5d621c59d9dbd6f886c3fb" -dependencies = [ - "anyhow", - "futures-channel", - "futures-timer", - "futures-util", - "gloo-net", - "http", - "jsonrpsee-core", - "jsonrpsee-types", - "pin-project", - "rustls-native-certs", - "soketto", - "thiserror", - "tokio", - "tokio-rustls", - "tokio-util", - "tracing", - "webpki-roots", -] +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] -name = "jsonrpsee-core" -version = "0.16.2" +name = "lazycell" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e70b4439a751a5de7dd5ed55eacff78ebf4ffe0fc009cb1ebb11417f5b536b" -dependencies = [ - "anyhow", - "arrayvec", - "async-lock", - "async-trait", - "beef", - "futures-channel", - "futures-timer", - "futures-util", - "globset", - "hyper", - "jsonrpsee-types", - "parking_lot 0.12.1", - "rand 0.8.5", - "rustc-hash", - "serde", - "serde_json", - "soketto", - "thiserror", - "tokio", - "tracing", - "wasm-bindgen-futures", -] +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] -name = "jsonrpsee-http-client" -version = "0.16.2" +name = "libc" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc345b0a43c6bc49b947ebeb936e886a419ee3d894421790c969cc56040542ad" -dependencies = [ - "async-trait", - "hyper", - "hyper-rustls", - "jsonrpsee-core", - "jsonrpsee-types", - "rustc-hash", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", -] +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] -name = "jsonrpsee-proc-macros" -version = "0.16.2" +name = "libloading" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baa6da1e4199c10d7b1d0a6e5e8bd8e55f351163b6f4b3cbb044672a69bd4c1c" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ - "heck", - "proc-macro-crate 1.3.0", - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "cfg-if", + "windows-targets 0.52.4", ] [[package]] -name = "jsonrpsee-server" -version = "0.16.2" +name = "librocksdb-sys" +version = "0.11.0+8.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb69dad85df79527c019659a992498d03f8495390496da2f07e6c24c2b356fc" +checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e" dependencies = [ - "futures-channel", - "futures-util", - "http", - "hyper", - "jsonrpsee-core", - "jsonrpsee-types", - "serde", - "serde_json", - "soketto", - "tokio", - "tokio-stream", - "tokio-util", - "tower", - "tracing", -] - -[[package]] -name = "jsonrpsee-types" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd522fe1ce3702fd94812965d7bb7a3364b1c9aba743944c5a00529aae80f8c" -dependencies = [ - "anyhow", - "beef", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "jsonrpsee-wasm-client" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77310456f43c6c89bcba1f6b2fc2a28300da7c341f320f5128f8c83cc63232d" -dependencies = [ - "jsonrpsee-client-transport", - "jsonrpsee-core", - "jsonrpsee-types", -] - -[[package]] -name = "jsonrpsee-ws-client" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b83daeecfc6517cfe210df24e570fb06213533dfb990318fae781f4c7119dd9" -dependencies = [ - "http", - "jsonrpsee-client-transport", - "jsonrpsee-core", - "jsonrpsee-types", -] - -[[package]] -name = "keccak" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "libm" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" - -[[package]] -name = "librocksdb-sys" -version = "0.8.0+7.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" -dependencies = [ - "bindgen", - "bzip2-sys", - "cc", - "glob", - "libc", - "libz-sys", + "bindgen", + "bzip2-sys", + "cc", + "glob", + "libc", + "libz-sys", + "lz4-sys", ] [[package]] @@ -2552,9 +2414,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.8" +version = "1.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" dependencies = [ "cc", "pkg-config", @@ -2562,19 +2424,28 @@ dependencies = [ ] [[package]] -name = "link-cplusplus" -version = "1.0.8" +name = "light-poseidon" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" dependencies = [ - "cc", + "ark-bn254", + "ark-ff", + "num-bigint 0.4.4", + "thiserror", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -2582,12 +2453,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "lru" @@ -2598,6 +2466,15 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "lru" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +dependencies = [ + "hashbrown 0.14.3", +] + [[package]] name = "lz4" version = "1.24.0" @@ -2618,42 +2495,21 @@ dependencies = [ "libc", ] -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "matchit" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" - [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.7.1" @@ -2665,9 +2521,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -2686,9 +2542,9 @@ dependencies = [ [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" @@ -2708,23 +2564,50 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.5" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "mockall" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -2743,17 +2626,11 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", ] -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - [[package]] name = "native-tls" version = "0.2.11" @@ -2774,15 +2651,14 @@ dependencies = [ [[package]] name = "nix" -version = "0.25.1" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ - "autocfg", - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", - "memoffset 0.6.5", + "memoffset 0.7.1", "pin-utils", ] @@ -2797,13 +2673,10 @@ dependencies = [ ] [[package]] -name = "nom8" -version = "0.2.0" +name = "normalize-line-endings" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "nu-ansi-term" @@ -2842,9 +2715,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -2861,32 +2734,48 @@ dependencies = [ "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-derive" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", "num-integer", @@ -2907,42 +2796,63 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.9", "libc", ] [[package]] name = "num_enum" -version = "0.5.9" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", +] + +[[package]] +name = "num_enum" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d829733185c1ca374f17e52b762f24f535ec625d2cc1f070e34c8a9068f341b" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "num_enum_derive", + "num_enum_derive 0.7.2", ] [[package]] name = "num_enum_derive" -version = "0.5.9" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 2.0.57", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 1.3.0", - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] @@ -2951,6 +2861,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "oid-registry" version = "0.6.1" @@ -2962,23 +2881,23 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.45" +version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags", + "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", @@ -2989,13 +2908,13 @@ dependencies = [ [[package]] name = "openssl-macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] @@ -3004,40 +2923,29 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "openssl-src" -version = "111.24.0+1.1.1s" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3498f259dab01178c6228c6b00dcef0ed2a2d5e20d648c017861227773ea4abd" -dependencies = [ - "cc", -] - [[package]] name = "openssl-sys" -version = "0.9.80" +version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ - "autocfg", "cc", "libc", - "openssl-src", "pkg-config", "vcpkg", ] [[package]] name = "os_str_bytes" -version = "6.4.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "ouroboros" -version = "0.15.5" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbb50b356159620db6ac971c6d5c9ab788c9cc38a6f49619fca2a27acb062ca" +checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" dependencies = [ "aliasable", "ouroboros_macro", @@ -3045,15 +2953,15 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.15.5" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0d9d1a6191c4f391f87219d1ea42b23f09ee84d64763cd05ee6ea88d9f384d" +checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" dependencies = [ "Inflector", "proc-macro-error", - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -3062,17 +2970,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -3080,41 +2977,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.7", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.48.5", ] [[package]] name = "paste" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pbkdf2" @@ -3131,7 +3014,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -3151,9 +3034,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "percentage" @@ -3164,51 +3047,31 @@ dependencies = [ "num", ] -[[package]] -name = "pest" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f" -dependencies = [ - "thiserror", - "ucd-trie", -] - -[[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" -dependencies = [ - "fixedbitset", - "indexmap", -] - [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -3229,9 +3092,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plain" @@ -3253,9 +3116,15 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "0.3.19" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" @@ -3263,14 +3132,44 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "predicates" +version = "2.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +dependencies = [ + "difflib", + "float-cmp", + "itertools", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "prettyplease" -version = "0.1.23" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" +checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" dependencies = [ - "proc-macro2 1.0.51", - "syn 1.0.107", + "proc-macro2", + "syn 2.0.57", ] [[package]] @@ -3284,24 +3183,33 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] -name = "proc-macro-error" +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-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 1.0.109", "version_check", ] @@ -3311,192 +3219,95 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "version_check", ] [[package]] name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - -[[package]] -name = "proc-macro2" -version = "1.0.51" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] [[package]] -name = "prometheus" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" -dependencies = [ - "cfg-if", - "fnv", - "lazy_static", - "memchr", - "parking_lot 0.12.1", - "protobuf", - "thiserror", -] - -[[package]] -name = "prost" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21dc42e00223fc37204bd4aa177e69420c604ca4a183209a8f9de30c6d934698" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f8ad728fb08fe212df3c05169e940fbb6d9d16a877ddde14644a983ba2012e" -dependencies = [ - "bytes", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 1.0.107", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda8c0881ea9f722eb9629376db3d0b903b462477c1aafcb0566610ac28ac5d" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "prost-types" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e0526209433e96d83d750dd81a99118edbc55739e7e61a46764fd2ad537788" -dependencies = [ - "bytes", - "prost", -] - -[[package]] -name = "protobuf" -version = "2.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" - -[[package]] -name = "protobuf-src" -version = "1.1.0+21.5" +name = "qstring" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7ac8852baeb3cc6fb83b93646fb93c0ffe5d14bf138c945ceb4b9948ee0e3c1" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" dependencies = [ - "autotools", + "percent-encoding", ] [[package]] -name = "qstring" -version = "0.7.2" +name = "qualifier_attr" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ - "percent-encoding", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] name = "quinn" -version = "0.8.5" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b435e71d9bfa0d8889927231970c51fb89c58fa63bffcab117c9c7a41e5ef8f" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" dependencies = [ "bytes", - "futures-channel", - "futures-util", - "fxhash", + "pin-project-lite", "quinn-proto", "quinn-udp", + "rustc-hash", "rustls", "thiserror", "tokio", "tracing", - "webpki", ] [[package]] name = "quinn-proto" -version = "0.8.4" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fce546b9688f767a57530652488420d419a8b1f44a478b451c3d1ab6d992a55" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" dependencies = [ "bytes", - "fxhash", "rand 0.8.5", - "ring", + "ring 0.16.20", + "rustc-hash", "rustls", "rustls-native-certs", - "rustls-pemfile 0.2.1", "slab", "thiserror", "tinyvec", "tracing", - "webpki", ] [[package]] name = "quinn-udp" -version = "0.1.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07946277141531aea269befd949ed16b2c85a780ba1043244eda0969e538e54" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" dependencies = [ - "futures-util", + "bytes", "libc", - "quinn-proto", "socket2", - "tokio", "tracing", + "windows-sys 0.48.0", ] [[package]] name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - -[[package]] -name = "quote" -version = "1.0.23" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "proc-macro2 1.0.51", + "proc-macro2", ] [[package]] @@ -3558,7 +3369,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.12", ] [[package]] @@ -3581,9 +3392,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.6.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -3591,14 +3402,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.2" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] @@ -3608,40 +3417,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", - "ring", - "time 0.3.17", + "ring 0.16.20", + "time", "yasna", ] [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] -name = "reed-solomon-erasure" -version = "6.0.0" +name = "regex" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7263373d500d4d4f505d43a2a662d475a894aa94503a1ee28e9188b5f3960d4f" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ - "cc", - "libc", - "libm", - "lru", - "parking_lot 0.11.2", - "smallvec", - "spin 0.9.4", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "regex" -version = "1.7.1" +name = "regex-automata" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -3650,27 +3456,18 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" -version = "0.11.14" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "async-compression", - "base64 0.21.0", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -3690,10 +3487,12 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls", - "rustls-pemfile 1.0.2", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", + "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", @@ -3703,7 +3502,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.25.4", "winreg", ] @@ -3717,16 +3516,31 @@ dependencies = [ "libc", "once_cell", "spin 0.5.2", - "untrusted", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.12", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + [[package]] name = "rocksdb" -version = "0.19.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9562ea1d70c0cc63a34a22d977753b50cca91cc6b6527750463bd5dd8697bc" +checksum = "bb6f170a4041d50a0ce04b0d2e14916d6ca863ea2e422689a5b694395d299ffe" dependencies = [ "libc", "librocksdb-sys", @@ -3734,30 +3548,30 @@ dependencies = [ [[package]] name = "rpassword" -version = "7.2.0" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", "rtoolbox", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "rtoolbox" -version = "0.0.1" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustc-hash" @@ -3765,22 +3579,13 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.16", + "semver", ] [[package]] @@ -3792,59 +3597,73 @@ dependencies = [ "nom", ] +[[package]] +name = "rustix" +version = "0.38.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring", + "ring 0.17.8", + "rustls-webpki", "sct", - "webpki", ] [[package]] name = "rustls-native-certs" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.2", + "rustls-pemfile", "schannel", "security-framework", ] [[package]] name = "rustls-pemfile" -version = "0.2.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.13.1", + "base64 0.21.7", ] [[package]] -name = "rustls-pemfile" -version = "1.0.2" +name = "rustls-webpki" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "base64 0.21.0", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -3857,24 +3676,18 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.52.0", ] [[package]] name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "scratch" -version = "1.0.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scroll" @@ -3887,32 +3700,32 @@ dependencies = [ [[package]] name = "scroll_derive" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] name = "security-framework" -version = "2.8.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -3921,9 +3734,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.8.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", @@ -3931,68 +3744,53 @@ dependencies = [ [[package]] name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.16" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] -name = "semver-parser" -version = "0.10.2" +name = "seqlock" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "b5c67b6f14ecc5b86c66fa63d76b5092352678545a8a3cdae80aef5128371910" dependencies = [ - "pest", + "parking_lot", ] -[[package]] -name = "send_wrapper" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" - [[package]] name = "serde" -version = "1.0.152" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.9" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] name = "serde_json" -version = "1.0.92" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -4013,9 +3811,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "2.2.0" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d904179146de381af4c93d3af6ca4984b3152db687dacb9c3c35e86f39809c" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" dependencies = [ "serde", "serde_with_macros", @@ -4023,49 +3821,25 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "2.2.0" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1966009f3c05f095697c537312f5415d1e3ed31ce0a56942bac4c771c5c335e" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ "darling", - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "sha-1" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.6", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -4083,13 +3857,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -4106,19 +3880,19 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "keccak", ] [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -4131,15 +3905,15 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "shlex" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", @@ -4158,9 +3932,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -4172,10 +3946,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" [[package]] -name = "simpl" -version = "0.1.0" +name = "siphasher" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a30f10c911c0355f80f1c2faa8096efc4a58cdf8590b954d5b395efa071c711" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "sized-chunks" @@ -4189,147 +3963,220 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "smpl_jwt" -version = "0.7.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b6ff8c21c74ce7744643a7cddbb02579a44f1f77e4316bff1ddb741aca8ac9" -dependencies = [ - "base64 0.13.1", - "log", - "openssl", - "serde", - "serde_derive", - "serde_json", - "simpl", - "time 0.3.17", -] +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.4.7" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "winapi", -] - -[[package]] -name = "soketto" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" -dependencies = [ - "base64 0.13.1", - "bytes", - "futures", - "http", - "httparse", - "log", - "rand 0.8.5", - "sha-1 0.9.8", + "windows-sys 0.52.0", ] [[package]] name = "solana-account-decoder" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9204641d327fc2dc7cebcd07bd63fccbc2695057040728924395d5e4ab491b17" dependencies = [ "Inflector", - "base64 0.13.1", + "base64 0.21.7", "bincode", - "bs58", + "bs58 0.4.0", "bv", "lazy_static", "serde", "serde_derive", "serde_json", - "solana-address-lookup-table-program", - "solana-config-program", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-config-program 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", "spl-token", "spl-token-2022", + "spl-token-group-interface", + "spl-token-metadata-interface", "thiserror", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] -name = "solana-address-lookup-table-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +name = "solana-account-decoder" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ + "Inflector", + "base64 0.21.7", "bincode", - "bytemuck", - "log", - "num-derive", - "num-traits", - "rustc_version 0.4.0", + "bs58 0.4.0", + "bv", + "lazy_static", "serde", - "solana-frozen-abi 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-frozen-abi-macro 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-program 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-program-runtime", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "serde_derive", + "serde_json", + "solana-config-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "spl-token", + "spl-token-2022", + "spl-token-group-interface", + "spl-token-metadata-interface", "thiserror", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] -name = "solana-bpf-loader-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +name = "solana-accounts-db" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ + "arrayref", "bincode", + "blake3", + "bv", + "bytemuck", "byteorder", - "libsecp256k1", + "bzip2", + "crossbeam-channel", + "dashmap", + "flate2", + "fnv", + "im", + "index_list", + "itertools", + "lazy_static", "log", - "rand 0.7.3", - "solana-measure 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-program-runtime", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-zk-token-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "lz4", + "memmap2", + "modular-bitfield", + "num-derive 0.4.2", + "num-traits", + "num_cpus", + "num_enum 0.7.2", + "ouroboros", + "percentage", + "qualifier_attr", + "rand 0.8.5", + "rayon", + "regex", + "rustc_version", + "seqlock", + "serde", + "serde_derive", + "smallvec", + "solana-bucket-map", + "solana-config-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-measure 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-metrics 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-nohash-hasher", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rayon-threadlimit 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-stake-program", + "solana-system-program", + "solana-vote-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "static_assertions", + "strum", + "strum_macros", + "tar", + "tempfile", + "thiserror", +] + +[[package]] +name = "solana-address-lookup-table-program" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "bincode", + "bytemuck", + "log", + "num-derive 0.4.2", + "num-traits", + "rustc_version", + "serde", + "solana-frozen-abi 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-program", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-bpf-loader-program" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "bincode", + "byteorder", + "libsecp256k1", + "log", + "scopeguard", + "solana-measure 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-zk-token-sdk", "solana_rbpf", "thiserror", ] [[package]] name = "solana-bucket-map" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ + "bv", + "bytemuck", "log", "memmap2", "modular-bitfield", - "rand 0.7.3", - "solana-measure 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "num_enum 0.7.2", + "rand 0.8.5", + "solana-measure 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", "tempfile", ] [[package]] name = "solana-clap-utils" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4155bd4c9165af8b5f4766f65fd04b42cc88288b55ebe07c0dd64792f4e9f7ea" dependencies = [ "chrono", "clap 2.34.0", "rpassword", - "solana-perf", - "solana-remote-wallet", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-remote-wallet 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "thiserror", + "tiny-bip39", + "uriparse", + "url", +] + +[[package]] +name = "solana-clap-utils" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "chrono", + "clap 2.34.0", + "rpassword", + "solana-remote-wallet 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", "thiserror", "tiny-bip39", "uriparse", @@ -4338,235 +4185,271 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34399d41bd2b8f50ee3d207556f6b38d22085bb6196fb3f8e09e1096366dbf70" dependencies = [ "async-trait", "bincode", - "enum_dispatch", + "dashmap", "futures", "futures-util", - "indexmap", + "indexmap 2.2.6", + "indicatif", + "log", + "quinn", + "rayon", + "solana-connection-cache 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-measure 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-metrics 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-pubsub-client 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-quic-client 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rpc-client 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rpc-client-api 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rpc-client-nonce-utils 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "solana-streamer 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-thin-client 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-tpu-client 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-udp-client 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-client" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "async-trait", + "bincode", + "dashmap", + "futures", + "futures-util", + "indexmap 2.2.6", "indicatif", "log", "quinn", - "rand 0.7.3", "rayon", - "solana-measure 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-metrics 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-net-utils", - "solana-pubsub-client", - "solana-quic-client", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-rpc-client-nonce-utils", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-streamer", - "solana-thin-client", - "solana-tpu-client", - "solana-udp-client", + "solana-connection-cache 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-measure 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-metrics 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-pubsub-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-quic-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client-api 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client-nonce-utils 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-streamer 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-thin-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-tpu-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-udp-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", "thiserror", "tokio", ] [[package]] name = "solana-compute-budget-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ - "solana-program-runtime", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", ] [[package]] name = "solana-config-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7bf92f66a8643b2a1da993a90d2fbd1860eda936d8ed0f931621360a0a707bf" dependencies = [ "bincode", "chrono", "serde", "serde_derive", - "solana-program-runtime", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-program-runtime 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", ] [[package]] -name = "solana-entry" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +name = "solana-config-program" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ + "bincode", + "chrono", + "serde", + "serde_derive", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", +] + +[[package]] +name = "solana-connection-cache" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95e4b344b0e5e36d72bfebcdca9c70ed5b8dfa0c57c6122c2915b9b0c33a52c4" +dependencies = [ + "async-trait", "bincode", "crossbeam-channel", - "dlopen", - "dlopen_derive", - "lazy_static", + "futures-util", + "indexmap 2.2.6", "log", - "rand 0.7.3", + "rand 0.8.5", "rayon", - "serde", - "solana-measure 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-merkle-tree", - "solana-metrics 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-perf", - "solana-rayon-threadlimit", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "rcgen", + "solana-measure 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-metrics 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-connection-cache" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "async-trait", + "bincode", + "crossbeam-channel", + "futures-util", + "indexmap 2.2.6", + "log", + "rand 0.8.5", + "rayon", + "rcgen", + "solana-measure 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-metrics 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-cost-model" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "lazy_static", + "log", + "rustc_version", + "solana-address-lookup-table-program", + "solana-bpf-loader-program", + "solana-compute-budget-program", + "solana-config-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-loader-v4-program", + "solana-metrics 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-stake-program", + "solana-system-program", + "solana-vote-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", ] [[package]] name = "solana-frozen-abi" -version = "1.15.0" +version = "1.18.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc55e72b77452b4469a7f46c3526cbddb4a43382370d5c1112dc108569cfe16" +checksum = "90bc310416403e8bd4f10799d7736a3a17126b217236983a884f0e1989b93040" dependencies = [ - "ahash", - "blake3", - "block-buffer 0.9.0", - "bs58", + "block-buffer 0.10.4", + "bs58 0.4.0", "bv", - "byteorder", - "cc", "either", "generic-array", - "getrandom 0.1.16", - "hashbrown 0.12.3", "im", "lazy_static", "log", "memmap2", - "once_cell", - "rand_core 0.6.4", - "rustc_version 0.4.0", + "rustc_version", "serde", "serde_bytes", "serde_derive", - "serde_json", - "sha2 0.10.6", - "solana-frozen-abi-macro 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.10.8", + "solana-frozen-abi-macro 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", "subtle", "thiserror", ] [[package]] name = "solana-frozen-abi" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ - "ahash", - "blake3", - "block-buffer 0.9.0", - "bs58", + "block-buffer 0.10.4", + "bs58 0.4.0", "bv", - "byteorder", - "cc", "either", "generic-array", - "getrandom 0.1.16", - "hashbrown 0.12.3", "im", "lazy_static", "log", "memmap2", - "once_cell", - "rand_core 0.6.4", - "rustc_version 0.4.0", + "rustc_version", "serde", "serde_bytes", "serde_derive", - "serde_json", - "sha2 0.10.6", - "solana-frozen-abi-macro 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "sha2 0.10.8", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", "subtle", "thiserror", ] [[package]] name = "solana-frozen-abi-macro" -version = "1.15.0" +version = "1.18.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7084605b674cf344312c3a2a9c0de05126c2ff4d3d77cc6746f236ca3c4cb53" +checksum = "7fc8882e99fb0589cafdd48690c0c1b589d419110630a25e221de68ee1c10fb3" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "rustc_version 0.4.0", - "syn 1.0.107", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.57", ] [[package]] name = "solana-frozen-abi-macro" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "rustc_version 0.4.0", - "syn 1.0.107", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.57", ] [[package]] -name = "solana-ledger" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +name = "solana-geyser-plugin-interface" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ - "assert_matches", - "bincode", - "bitflags", - "byteorder", - "chrono", - "chrono-humanize", - "crossbeam-channel", - "dashmap 4.0.2", - "fs_extra", - "futures", - "itertools", - "lazy_static", - "libc", "log", - "lru", - "num_cpus", - "num_enum", - "prost", - "rand 0.7.3", - "rand_chacha 0.2.2", - "rayon", - "reed-solomon-erasure", - "rocksdb", - "rustc_version 0.4.0", - "serde", - "serde_bytes", - "sha2 0.10.6", - "solana-account-decoder", - "solana-bpf-loader-program", - "solana-entry", - "solana-frozen-abi 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-frozen-abi-macro 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-measure 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-metrics 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-perf", - "solana-program-runtime", - "solana-rayon-threadlimit", - "solana-runtime", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-stake-program", - "solana-storage-bigtable", - "solana-storage-proto", - "solana-transaction-status", - "solana-vote-program", - "spl-token", - "spl-token-2022", - "static_assertions", - "tempfile", + "solana-sdk", + "solana-transaction-status 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", "thiserror", - "tokio", - "tokio-stream", - "trees", +] + +[[package]] +name = "solana-loader-v4-program" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "log", + "solana-measure 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana_rbpf", ] [[package]] name = "solana-logger" -version = "1.15.0" +version = "1.18.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dae1169570b4f086a42f340b86b698b8b64dfa0f931f2a4f0f3c5b18195d6711" +checksum = "d232989da2972107e5e40dcc179f8f4ca2ddcf1cb9ac2b27305ca97f2a0c0408" dependencies = [ "env_logger", "lazy_static", @@ -4575,8 +4458,8 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "env_logger", "lazy_static", @@ -4585,207 +4468,206 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.15.0" +version = "1.18.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bccce3b610490b860ef7796764afd9a3936591641257018835b9f790e58dbae" +checksum = "31ae59f9a98ff5d6e62a516f35a30035d57b07bca4330df265f964936ece573a" dependencies = [ "log", - "solana-sdk 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", ] [[package]] name = "solana-measure" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "log", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", -] - -[[package]] -name = "solana-merkle-tree" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" -dependencies = [ - "fast-math", - "matches", - "solana-program 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-sdk", ] [[package]] name = "solana-metrics" -version = "1.15.0" +version = "1.18.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f12ea36bad13f218fbce4a6625bd7eea1aad001281e53a5a2286858fa2b670a" +checksum = "0d80cc2dfca741baa590d11e9fbe2f9d5c10396b738b7224c276532ffb5ee2e0" dependencies = [ "crossbeam-channel", "gethostname", "lazy_static", "log", "reqwest", - "solana-sdk 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "thiserror", ] [[package]] name = "solana-metrics" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "crossbeam-channel", "gethostname", "lazy_static", "log", "reqwest", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-sdk", + "thiserror", ] [[package]] name = "solana-net-utils" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00567729bcfe4df80413c8f72245c85a0682f3d402a5a00c5c3bb6e4beb7ec87" dependencies = [ "bincode", - "clap 3.2.23", + "clap 3.2.25", "crossbeam-channel", "log", "nix", - "rand 0.7.3", + "rand 0.8.5", "serde", "serde_derive", "socket2", - "solana-logger 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-version", + "solana-logger 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "solana-version 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio", "url", ] +[[package]] +name = "solana-net-utils" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "bincode", + "clap 3.2.25", + "crossbeam-channel", + "log", + "nix", + "rand 0.8.5", + "serde", + "serde_derive", + "socket2", + "solana-logger 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-version 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "tokio", + "url", +] + +[[package]] +name = "solana-nohash-hasher" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" + [[package]] name = "solana-perf" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a8b8fe3664d85cbed462ad5c843f96d3f969e469f353a8082864aac4ee0e71" dependencies = [ - "ahash", + "ahash 0.8.11", "bincode", "bv", "caps", "curve25519-dalek", - "dlopen", - "dlopen_derive", + "dlopen2", "fnv", "lazy_static", "libc", "log", "nix", - "rand 0.7.3", + "rand 0.8.5", "rayon", + "rustc_version", "serde", - "solana-metrics 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-rayon-threadlimit", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-vote-program", + "solana-frozen-abi 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-frozen-abi-macro 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-metrics 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rayon-threadlimit 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "solana-vote-program 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "solana-program" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3442ab665ded18fd8526213027a2c05035164b7696e7bf535b7c2d7fa75536fe" +name = "solana-perf" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ - "ark-bn254", - "ark-ec", - "ark-ff", - "array-bytes", - "base64 0.13.1", + "ahash 0.8.11", "bincode", - "bitflags", - "blake3", - "borsh", - "borsh-derive", - "bs58", "bv", - "bytemuck", - "cc", - "console_error_panic_hook", - "console_log", + "caps", "curve25519-dalek", - "getrandom 0.2.8", - "itertools", - "js-sys", + "dlopen2", + "fnv", "lazy_static", "libc", - "libsecp256k1", "log", - "memoffset 0.8.0", - "num-bigint 0.4.3", - "num-derive", - "num-traits", - "parking_lot 0.12.1", - "rand 0.7.3", - "rand_chacha 0.2.2", - "rustc_version 0.4.0", - "rustversion", + "nix", + "rand 0.8.5", + "rayon", + "rustc_version", "serde", - "serde_bytes", - "serde_derive", - "serde_json", - "sha2 0.10.6", - "sha3 0.10.6", - "solana-frozen-abi 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-frozen-abi-macro 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-sdk-macro 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror", - "tiny-bip39", - "wasm-bindgen", - "zeroize", + "solana-frozen-abi 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-metrics 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rayon-threadlimit 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-vote-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", ] [[package]] name = "solana-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "ark-bn254", "ark-ec", "ark-ff", - "array-bytes", - "base64 0.13.1", + "ark-serialize", + "base64 0.21.7", "bincode", - "bitflags", + "bitflags 2.5.0", "blake3", - "borsh", - "borsh-derive", - "bs58", + "borsh 0.10.3", + "borsh 0.9.3", + "borsh 1.4.0", + "bs58 0.4.0", "bv", "bytemuck", "cc", "console_error_panic_hook", "console_log", "curve25519-dalek", - "getrandom 0.2.8", + "getrandom 0.2.12", "itertools", "js-sys", "lazy_static", "libc", "libsecp256k1", + "light-poseidon", "log", - "memoffset 0.6.5", - "num-derive", + "memoffset 0.9.1", + "num-bigint 0.4.4", + "num-derive 0.4.2", "num-traits", - "parking_lot 0.12.1", - "rand 0.7.3", - "rand_chacha 0.2.2", - "rustc_version 0.4.0", + "parking_lot", + "rand 0.8.5", + "rustc_version", "rustversion", "serde", "serde_bytes", "serde_derive", "serde_json", - "sha2 0.10.6", - "sha3 0.10.6", - "solana-frozen-abi 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-frozen-abi-macro 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-sdk-macro 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "sha2 0.10.8", + "sha3 0.10.8", + "solana-frozen-abi 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk-macro", "thiserror", "tiny-bip39", "wasm-bindgen", @@ -4794,59 +4676,113 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafb4bb43f3beaa971ca30fe6d7b6b15723f4cf67262c88e5ca62d520888e091" dependencies = [ - "base64 0.13.1", + "base64 0.21.7", "bincode", "eager", "enum-iterator", "itertools", "libc", - "libloading", "log", - "num-derive", + "num-derive 0.4.2", "num-traits", - "rand 0.7.3", - "rustc_version 0.4.0", + "percentage", + "rand 0.8.5", + "rustc_version", + "serde", + "solana-frozen-abi 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-frozen-abi-macro 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-measure 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-metrics 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "solana_rbpf", + "thiserror", +] + +[[package]] +name = "solana-program-runtime" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "base64 0.21.7", + "bincode", + "eager", + "enum-iterator", + "itertools", + "libc", + "log", + "num-derive 0.4.2", + "num-traits", + "percentage", + "rand 0.8.5", + "rustc_version", "serde", - "solana-frozen-abi 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-frozen-abi-macro 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-measure 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-metrics 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-frozen-abi 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-measure 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-metrics 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", "solana_rbpf", "thiserror", ] [[package]] name = "solana-pubsub-client" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03313fb4d946bb01f73cf01171e29d50083131c19e81e0e187195c35a66dcdc0" dependencies = [ "crossbeam-channel", "futures-util", "log", "reqwest", - "semver 1.0.16", + "semver", "serde", "serde_derive", "serde_json", - "solana-account-decoder", - "solana-rpc-client-api", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-account-decoder 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rpc-client-api 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", "thiserror", "tokio", "tokio-stream", "tokio-tungstenite", - "tungstenite 0.17.3", + "tungstenite", + "url", +] + +[[package]] +name = "solana-pubsub-client" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "crossbeam-channel", + "futures-util", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client-api 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "thiserror", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", "url", ] [[package]] name = "solana-quic-client" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e199439728b0d728c544ecc585e60b2db8794f4d20248330beb5fe43f88b78" dependencies = [ "async-mutex", "async-trait", @@ -4856,23 +4792,59 @@ dependencies = [ "log", "quinn", "quinn-proto", - "quinn-udp", + "rcgen", "rustls", - "solana-measure 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-metrics 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-net-utils", - "solana-rpc-client-api", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-streamer", - "solana-tpu-client", + "solana-connection-cache 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-measure 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-metrics 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-net-utils 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rpc-client-api 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "solana-streamer 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-quic-client" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "async-mutex", + "async-trait", + "futures", + "itertools", + "lazy_static", + "log", + "quinn", + "quinn-proto", + "rcgen", + "rustls", + "solana-connection-cache 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-measure 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-metrics 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-net-utils 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client-api 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-streamer 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", "thiserror", "tokio", ] [[package]] name = "solana-rayon-threadlimit" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b621985c5c457a4a74f8217e4b41f2674b3813864dc9e3fabb1a40091b76217d" +dependencies = [ + "lazy_static", + "num_cpus", +] + +[[package]] +name = "solana-rayon-threadlimit" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "lazy_static", "num_cpus", @@ -4880,88 +4852,168 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8badec322617e1df5b24595e4b820e2020079f97ff3323257eedcbd235ca6a94" dependencies = [ "console", "dialoguer", "log", - "num-derive", + "num-derive 0.4.2", "num-traits", - "parking_lot 0.12.1", + "parking_lot", "qstring", - "semver 1.0.16", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "semver", + "solana-sdk", + "thiserror", + "uriparse", +] + +[[package]] +name = "solana-remote-wallet" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "console", + "dialoguer", + "log", + "num-derive 0.4.2", + "num-traits", + "parking_lot", + "qstring", + "semver", + "solana-sdk", "thiserror", "uriparse", ] [[package]] name = "solana-rpc-client" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9fb3e19dfe95408b5852f01e27490f1b847372c989343bd869173ee897d484a" dependencies = [ "async-trait", - "base64 0.13.1", + "base64 0.21.7", "bincode", - "bs58", + "bs58 0.4.0", "indicatif", "log", "reqwest", - "semver 1.0.16", + "semver", "serde", "serde_derive", "serde_json", - "solana-account-decoder", - "solana-ledger", - "solana-rpc-client-api", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-transaction-status", - "solana-version", - "solana-vote-program", + "solana-account-decoder 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rpc-client-api 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "solana-transaction-status 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-version 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-vote-program 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio", +] + +[[package]] +name = "solana-rpc-client" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "async-trait", + "base64 0.21.7", + "bincode", + "bs58 0.4.0", + "indicatif", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client-api 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-transaction-status 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-version 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-vote-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", "tokio", ] [[package]] name = "solana-rpc-client-api" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3855f33ad8facd348440ada4e35c5217ce911e7aea06c773601243793abe42" dependencies = [ - "base64 0.13.1", - "bs58", + "base64 0.21.7", + "bs58 0.4.0", "jsonrpc-core", "reqwest", - "semver 1.0.16", + "semver", "serde", "serde_derive", "serde_json", - "solana-account-decoder", - "solana-ledger", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-transaction-status", - "solana-version", + "solana-account-decoder 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "solana-transaction-status 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-version 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-2022", + "thiserror", +] + +[[package]] +name = "solana-rpc-client-api" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "base64 0.21.7", + "bs58 0.4.0", + "jsonrpc-core", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-transaction-status 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-version 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", "spl-token-2022", "thiserror", ] [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ca470c2187e43ad54ce1edcfe32a8105329f3ea37b095658e67e62083968a9" +dependencies = [ + "clap 2.34.0", + "solana-clap-utils 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rpc-client 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "clap 2.34.0", - "solana-clap-utils", - "solana-rpc-client", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-clap-utils 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", "thiserror", ] [[package]] name = "solana-runtime" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ + "aquamarine", "arrayref", + "base64 0.21.7", "bincode", "blake3", "bv", @@ -4969,7 +5021,7 @@ dependencies = [ "byteorder", "bzip2", "crossbeam-channel", - "dashmap 4.0.2", + "dashmap", "dir-diff", "flate2", "fnv", @@ -4978,63 +5030,74 @@ dependencies = [ "itertools", "lazy_static", "log", - "lru", + "lru 0.7.8", "lz4", "memmap2", - "num-derive", + "mockall", + "modular-bitfield", + "num-derive 0.4.2", "num-traits", "num_cpus", - "once_cell", + "num_enum 0.7.2", "ouroboros", - "rand 0.7.3", + "percentage", + "qualifier_attr", + "rand 0.8.5", "rayon", "regex", - "rustc_version 0.4.0", + "rustc_version", "serde", "serde_derive", + "serde_json", + "solana-accounts-db", "solana-address-lookup-table-program", "solana-bpf-loader-program", "solana-bucket-map", "solana-compute-budget-program", - "solana-config-program", - "solana-frozen-abi 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-frozen-abi-macro 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-measure 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-metrics 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-perf", - "solana-program-runtime", - "solana-rayon-threadlimit", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-config-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-cost-model", + "solana-frozen-abi 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-loader-v4-program", + "solana-measure 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-metrics 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-perf 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rayon-threadlimit 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", "solana-stake-program", - "solana-vote-program", + "solana-system-program", + "solana-version 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-vote", + "solana-vote-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", "solana-zk-token-proof-program", - "solana-zk-token-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-zk-token-sdk", + "static_assertions", "strum", "strum_macros", "symlink", "tar", "tempfile", "thiserror", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] name = "solana-sdk" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73788ea1793a23a3d24d1d9ed81a64dbbdd02dac058e0e363a604135e351e670" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "assert_matches", - "base64 0.13.1", + "base64 0.21.7", "bincode", - "bitflags", - "borsh", - "bs58", + "bitflags 2.5.0", + "borsh 1.4.0", + "bs58 0.4.0", "bytemuck", "byteorder", "chrono", "derivation-path", - "digest 0.10.6", + "digest 0.10.7", "ed25519-dalek", "ed25519-dalek-bip32", "generic-array", @@ -5045,78 +5108,29 @@ dependencies = [ "libsecp256k1", "log", "memmap2", - "num-derive", + "num-derive 0.4.2", "num-traits", - "num_enum", + "num_enum 0.7.2", "pbkdf2 0.11.0", "qstring", + "qualifier_attr", "rand 0.7.3", - "rand_chacha 0.2.2", - "rustc_version 0.4.0", + "rand 0.8.5", + "rustc_version", "rustversion", "serde", "serde_bytes", "serde_derive", "serde_json", "serde_with", - "sha2 0.10.6", - "sha3 0.10.6", - "solana-frozen-abi 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-frozen-abi-macro 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-logger 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-program 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-sdk-macro 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror", - "uriparse", - "wasm-bindgen", -] - -[[package]] -name = "solana-sdk" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" -dependencies = [ - "assert_matches", - "base64 0.13.1", - "bincode", - "bitflags", - "borsh", - "bs58", - "bytemuck", - "byteorder", - "chrono", - "derivation-path", - "digest 0.10.6", - "ed25519-dalek", - "ed25519-dalek-bip32", - "generic-array", - "hmac 0.12.1", - "itertools", - "js-sys", - "lazy_static", - "libsecp256k1", - "log", - "memmap2", - "num-derive", - "num-traits", - "num_enum", - "pbkdf2 0.11.0", - "qstring", - "rand 0.7.3", - "rand_chacha 0.2.2", - "rustc_version 0.4.0", - "rustversion", - "serde", - "serde_bytes", - "serde_derive", - "serde_json", - "sha2 0.10.6", - "sha3 0.10.6", - "solana-frozen-abi 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-frozen-abi-macro 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-logger 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-program 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-sdk-macro 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "sha2 0.10.8", + "sha3 0.10.8", + "siphasher", + "solana-frozen-abi 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-logger 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-program", + "solana-sdk-macro", "thiserror", "uriparse", "wasm-bindgen", @@ -5124,101 +5138,79 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e216372c12c4bd820afd02ab90564472e14e1ff609b6737e9d832749370656" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ - "bs58", - "proc-macro2 1.0.51", - "quote 1.0.23", + "bs58 0.4.0", + "proc-macro2", + "quote", "rustversion", - "syn 1.0.107", + "syn 2.0.57", ] [[package]] -name = "solana-sdk-macro" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" -dependencies = [ - "bs58", - "proc-macro2 1.0.51", - "quote 1.0.23", - "rustversion", - "syn 1.0.107", -] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-stake-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "bincode", "log", - "rustc_version 0.4.0", - "solana-config-program", - "solana-program-runtime", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-vote-program", + "rustc_version", + "solana-config-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-vote-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", ] [[package]] -name = "solana-storage-bigtable" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +name = "solana-streamer" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8f3fabd1b9b65b2f32460b012689fa15f152f71bcf2967f22e846498615255f" dependencies = [ - "backoff", - "bincode", + "async-channel", "bytes", - "bzip2", - "enum-iterator", - "flate2", - "futures", - "goauth", - "http", - "hyper", - "hyper-proxy", + "crossbeam-channel", + "futures-util", + "histogram", + "indexmap 2.2.6", + "itertools", + "libc", "log", - "openssl", - "prost", - "prost-types", - "serde", - "serde_derive", - "smpl_jwt", - "solana-metrics 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-storage-proto", - "solana-transaction-status", + "nix", + "pem", + "percentage", + "pkcs8", + "quinn", + "quinn-proto", + "rand 0.8.5", + "rcgen", + "rustls", + "solana-metrics 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-perf 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", "thiserror", "tokio", - "tonic", - "zstd", -] - -[[package]] -name = "solana-storage-proto" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" -dependencies = [ - "bincode", - "bs58", - "prost", - "protobuf-src", - "serde", - "solana-account-decoder", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-transaction-status", - "tonic-build", + "x509-parser", ] [[package]] name = "solana-streamer" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ + "async-channel", + "bytes", "crossbeam-channel", "futures-util", "histogram", - "indexmap", + "indexmap 2.2.6", "itertools", "libc", "log", @@ -5228,73 +5220,148 @@ dependencies = [ "pkcs8", "quinn", "quinn-proto", - "quinn-udp", - "rand 0.7.3", + "rand 0.8.5", "rcgen", "rustls", - "solana-metrics 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-perf", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-metrics 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-perf 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", "thiserror", "tokio", "x509-parser", ] +[[package]] +name = "solana-system-program" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "bincode", + "log", + "serde", + "serde_derive", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", +] + [[package]] name = "solana-thin-client" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ac7df3ca84027a5fd127050ca84bf00bb23c7a65a5b546b7b55c64772bf028" +dependencies = [ + "bincode", + "log", + "rayon", + "solana-connection-cache 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rpc-client 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rpc-client-api 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", +] + +[[package]] +name = "solana-thin-client" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "bincode", "log", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-tpu-client", + "rayon", + "solana-connection-cache 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client-api 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", ] [[package]] name = "solana-tpu-client" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5540ea5fc6efa3c61d6b1677091a7ecc5587121da01046f51ab45051e9c231d5" dependencies = [ "async-trait", "bincode", "futures-util", - "indexmap", + "indexmap 2.2.6", + "indicatif", + "log", + "rayon", + "solana-connection-cache 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-measure 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-metrics 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-pubsub-client 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rpc-client 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-rpc-client-api 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-tpu-client" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap 2.2.6", "indicatif", "log", - "rand 0.7.3", "rayon", - "solana-measure 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-metrics 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-net-utils", - "solana-pubsub-client", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-connection-cache 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-measure 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-metrics 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-pubsub-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client-api 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", "thiserror", "tokio", ] [[package]] name = "solana-transaction-status" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce29d9356c0467d2659103ec9f13edb185be2919a3b034b7f602c6eb89fa1b9" dependencies = [ "Inflector", - "base64 0.13.1", + "base64 0.21.7", "bincode", - "borsh", - "bs58", + "borsh 0.10.3", + "bs58 0.4.0", "lazy_static", "log", "serde", "serde_derive", "serde_json", - "solana-account-decoder", - "solana-address-lookup-table-program", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-account-decoder 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "spl-associated-token-account", + "spl-memo", + "spl-token", + "spl-token-2022", + "thiserror", +] + +[[package]] +name = "solana-transaction-status" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "Inflector", + "base64 0.21.7", + "bincode", + "borsh 0.10.3", + "bs58 0.4.0", + "lazy_static", + "log", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", "spl-associated-token-account", "spl-memo", "spl-token", @@ -5304,124 +5371,161 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c319b9497d56475781c9b9b3ccc40f58238ffe9ded9d4f9faf20671a2e7c5f0c" +dependencies = [ + "async-trait", + "solana-connection-cache 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-net-utils 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", + "solana-streamer 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-udp-client" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "async-trait", - "solana-net-utils", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-streamer", - "solana-tpu-client", + "solana-connection-cache 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-net-utils 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-streamer 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", "thiserror", "tokio", ] [[package]] name = "solana-version" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be6493d5f1beabc4233083f863d1e4c9e32c48cb2bf5252e55a5df88de25ac4" +dependencies = [ + "log", + "rustc_version", + "semver", + "serde", + "serde_derive", + "solana-frozen-abi 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-frozen-abi-macro 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", +] + +[[package]] +name = "solana-version" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "log", - "rustc_version 0.4.0", - "semver 1.0.16", + "rustc_version", + "semver", "serde", "serde_derive", - "solana-frozen-abi 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-frozen-abi-macro 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-frozen-abi 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", +] + +[[package]] +name = "solana-vote" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" +dependencies = [ + "crossbeam-channel", + "itertools", + "log", + "rustc_version", + "serde", + "serde_derive", + "solana-frozen-abi 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-vote-program 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "thiserror", ] [[package]] name = "solana-vote-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631b62acd8fbee9c4a7977dc9ec7eb2df612a64f234599be708ccbc9978da969" dependencies = [ "bincode", "log", - "num-derive", + "num-derive 0.4.2", "num-traits", - "rustc_version 0.4.0", + "rustc_version", "serde", "serde_derive", - "solana-frozen-abi 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-frozen-abi-macro 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-metrics 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-program 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-program-runtime", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-frozen-abi 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-frozen-abi-macro 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-metrics 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-program", + "solana-program-runtime 1.18.7 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-sdk", "thiserror", ] [[package]] -name = "solana-zk-token-proof-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +name = "solana-vote-program" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ - "bytemuck", - "getrandom 0.1.16", - "num-derive", + "bincode", + "log", + "num-derive 0.4.2", "num-traits", - "solana-program-runtime", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-zk-token-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "rustc_version", + "serde", + "serde_derive", + "solana-frozen-abi 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-frozen-abi-macro 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-metrics 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-program", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "thiserror", ] [[package]] -name = "solana-zk-token-sdk" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffa4276fd41317c7367f665684410430c8ddae065af6e997b98a26a201ca2c1e" +name = "solana-zk-token-proof-program" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ - "aes-gcm-siv", - "arrayref", - "base64 0.13.1", - "bincode", "bytemuck", - "byteorder", - "cipher 0.4.3", - "curve25519-dalek", - "getrandom 0.1.16", - "itertools", - "lazy_static", - "merlin", - "num-derive", + "num-derive 0.4.2", "num-traits", - "rand 0.7.3", - "serde", - "serde_json", - "sha3 0.9.1", - "solana-program 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-sdk 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle", - "thiserror", - "zeroize", + "solana-program-runtime 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-zk-token-sdk", ] [[package]] name = "solana-zk-token-sdk" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#e7cf32239e3533fd4b280cb994c405452b585226" +version = "1.18.7" +source = "git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch#0d2342eaae65bac35d1d81cfeed4db5135974c93" dependencies = [ "aes-gcm-siv", - "arrayref", - "base64 0.13.1", + "base64 0.21.7", "bincode", "bytemuck", "byteorder", - "cipher 0.4.3", "curve25519-dalek", "getrandom 0.1.16", "itertools", "lazy_static", "merlin", - "num-derive", + "num-derive 0.4.2", "num-traits", "rand 0.7.3", "serde", "serde_json", "sha3 0.9.1", - "solana-program 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", + "solana-program", + "solana-sdk", "subtle", "thiserror", "zeroize", @@ -5429,9 +5533,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.2.38" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e9e5085099858adba23d0a0b5298da8803f89999cb567ecafab9c916cdf53d" +checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3" dependencies = [ "byteorder", "combine", @@ -5454,9 +5558,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.4" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spinoff" @@ -5481,62 +5585,211 @@ dependencies = [ [[package]] name = "spl-associated-token-account" -version = "1.1.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc000f0fdf1f12f99d77d398137c1751345b18c88258ce0f99b7872cf6c9bd6" +checksum = "992d9c64c2564cc8f63a4b508bf3ebcdf2254b0429b13cd1d31adb6162432a5f" dependencies = [ "assert_matches", - "borsh", - "num-derive", + "borsh 0.10.3", + "num-derive 0.4.2", "num-traits", - "solana-program 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-program", "spl-token", "spl-token-2022", "thiserror", ] +[[package]] +name = "spl-discriminator" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa600f2fe56f32e923261719bae640d873edadbc5237681a39b8e37bfd4d263" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07fd7858fc4ff8fb0e34090e41d7eb06a823e1057945c26d480bfc21d2338a93" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.57", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fea7be851bd98d10721782ea958097c03a0c2a07d8d4997041d0ece6319a63" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.57", + "thiserror", +] + [[package]] name = "spl-memo" -version = "3.0.1" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a" +dependencies = [ + "solana-program", +] + +[[package]] +name = "spl-pod" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5db7e4efb1107b0b8e52a13f035437cdcb36ef99c58f6d467f089d9b2915a" +dependencies = [ + "borsh 0.10.3", + "bytemuck", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error", +] + +[[package]] +name = "spl-program-error" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e0657b6490196971d9e729520ba934911ff41fbb2cb9004463dbe23cf8b4b4f" +dependencies = [ + "num-derive 0.4.2", + "num-traits", + "solana-program", + "spl-program-error-derive", + "thiserror", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1845dfe71fd68f70382232742e758557afe973ae19e6c06807b2c30f5d5cb474" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.57", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0dc6f70db6bacea7ff25870b016a65ba1d1b6013536f08e4fd79a8f9005325" +checksum = "56f335787add7fa711819f9e7c573f8145a5358a709446fe2d24bf2a88117c90" dependencies = [ - "solana-program 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", ] [[package]] name = "spl-token" -version = "3.5.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" +checksum = "08459ba1b8f7c1020b4582c4edf0f5c7511a5e099a7a97570c9698d4f2337060" dependencies = [ "arrayref", "bytemuck", - "num-derive", + "num-derive 0.3.3", "num-traits", - "num_enum", - "solana-program 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_enum 0.6.1", + "solana-program", "thiserror", ] [[package]] name = "spl-token-2022" -version = "0.5.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0edb869dbe159b018f17fb9bfa67118c30f232d7f54a73742bc96794dff77ed8" +checksum = "d697fac19fd74ff472dfcc13f0b442dd71403178ce1de7b5d16f83a33561c059" dependencies = [ "arrayref", "bytemuck", - "num-derive", + "num-derive 0.4.2", "num-traits", - "num_enum", - "solana-program 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-zk-token-sdk 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_enum 0.7.2", + "solana-program", + "solana-security-txt", + "solana-zk-token-sdk", "spl-memo", + "spl-pod", "spl-token", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", "thiserror", ] +[[package]] +name = "spl-token-group-interface" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b889509d49fa74a4a033ca5dae6c2307e9e918122d97e58562f5c4ffa795c75d" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f" +dependencies = [ + "borsh 0.10.3", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aabdb7c471566f6ddcee724beb8618449ea24b399e58d464d6b5bc7db550259" +dependencies = [ + "arrayref", + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value", +] + +[[package]] +name = "spl-type-length-value" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f9ebd75d29c5f48de5f6a9c114e08531030b75b8ac2c557600ac7da0b73b1e8" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -5570,11 +5823,11 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "heck", - "proc-macro2 1.0.51", - "quote 1.0.23", + "heck 0.4.1", + "proc-macro2", + "quote", "rustversion", - "syn 1.0.107", + "syn 1.0.109", ] [[package]] @@ -5591,26 +5844,38 @@ checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" [[package]] name = "syn" -version = "0.15.44" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "syn" -version = "1.0.107" +version = "2.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.57", +] + [[package]] name = "sync_wrapper" version = "0.1.2" @@ -5623,17 +5888,38 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", - "unicode-xid 0.2.4", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[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 = "tar" -version = "0.4.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" dependencies = [ "filetime", "libc", @@ -5642,27 +5928,31 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.3.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", + "rustix", + "windows-sys 0.52.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + [[package]] name = "textwrap" version = "0.11.0" @@ -5674,35 +5964,35 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -5710,22 +6000,14 @@ dependencies = [ [[package]] name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "time" -version = "0.3.17" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ + "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -5733,16 +6015,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] @@ -5778,26 +6061,27 @@ dependencies = [ name = "tinydancer" version = "0.0.8" dependencies = [ + "account_proof_geyser", + "anchor-client", + "anchor-lang", "anyhow", "async-channel", "async-trait", - "base64 0.21.0", + "base64 0.21.7", "bincode", - "bs58", - "clap 3.2.23", + "borsh 1.4.0", + "bs58 0.4.0", + "clap 3.2.25", "colored", "const_env", + "copy", "crossbeam", - "crossterm 0.26.0", - "dashmap 5.4.0", + "crossterm", "dotenv", "futures", "home", - "hyper", "itertools", - "jsonrpsee", "lazy_static", - "prometheus", "rand 0.8.5", "rayon", "reqwest", @@ -5805,27 +6089,18 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "solana-client", - "solana-ledger", - "solana-measure 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-metrics 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-quic-client", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-sdk 1.15.0 (git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master)", - "solana-tpu-client", - "solana-transaction-status", - "solana-version", + "solana-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-rpc-client-api 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", + "solana-sdk", + "solana-transaction-status 1.18.7 (git+https://github.com/tinydancer-io/solana-1.18?branch=v1.18.7-branch)", "spinoff", "thiserror", "tiny-logger", "tokio", - "tower", - "tower-http 0.4.0", + "tower-http", "tracing", "tracing-subscriber", - "tui", - "tungstenite 0.18.0", "url", ] @@ -5846,50 +6121,39 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.25.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", - "memchr", "mio", "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.42.0", -] - -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] name = "tokio-native-tls" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", "tokio", @@ -5897,20 +6161,19 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.23.4" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", - "webpki", ] [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -5919,29 +6182,27 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.17.2" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", "rustls", "tokio", "tokio-rustls", - "tungstenite 0.17.3", - "webpki", - "webpki-roots", + "tungstenite", + "webpki-roots 0.25.4", ] [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", - "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -5959,66 +6220,30 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.5.1" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" [[package]] name = "toml_edit" -version = "0.18.1" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap", - "nom8", + "indexmap 2.2.6", "toml_datetime", + "winnow", ] [[package]] -name = "tonic" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.13.1", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "prost-derive", - "rustls-pemfile 1.0.2", - "tokio", - "tokio-rustls", - "tokio-stream", - "tokio-util", - "tower", - "tower-layer", - "tower-service", - "tracing", - "tracing-futures", -] - -[[package]] -name = "tonic-build" -version = "0.8.4" +name = "toml_edit" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "prettyplease", - "proc-macro2 1.0.51", - "prost-build", - "quote 1.0.23", - "syn 1.0.107", + "indexmap 2.2.6", + "toml_datetime", + "winnow", ] [[package]] @@ -6029,13 +6254,8 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", - "indexmap", "pin-project", "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", "tower-layer", "tower-service", "tracing", @@ -6043,32 +6263,13 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" -dependencies = [ - "bitflags", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.4.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ "async-compression", - "base64 0.20.0", - "bitflags", + "base64 0.21.7", + "bitflags 2.5.0", "bytes", "futures-core", "futures-util", @@ -6104,11 +6305,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -6117,51 +6317,41 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "nu-ansi-term", "sharded-slab", @@ -6171,131 +6361,80 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "trees" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de5f738ceab88e2491a94ddc33c3feeadfa95fedc60363ef110845df12f3878" - [[package]] name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "tui" -version = "0.19.0" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" -dependencies = [ - "bitflags", - "cassowary", - "crossterm 0.25.0", - "unicode-segmentation", - "unicode-width", -] +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.17.3" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ - "base64 0.13.1", "byteorder", "bytes", + "data-encoding", "http", "httparse", "log", "rand 0.8.5", "rustls", - "sha-1 0.10.1", - "thiserror", - "url", - "utf-8", - "webpki", - "webpki-roots", -] - -[[package]] -name = "tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand 0.8.5", "sha1", "thiserror", "url", "utf-8", + "webpki-roots 0.24.0", ] [[package]] name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "ucd-trie" -version = "0.1.5" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicase" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ "version_check", ] [[package]] name = "unicode-bidi" -version = "0.3.10" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.1.0" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "unicode-xid" @@ -6328,6 +6467,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "uriparse" version = "0.6.4" @@ -6340,9 +6485,9 @@ dependencies = [ [[package]] name = "url" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -6357,11 +6502,11 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.3.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.12", ] [[package]] @@ -6396,22 +6541,20 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", - "winapi", "winapi-util", ] [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -6421,12 +6564,6 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -6435,9 +6572,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -6445,24 +6582,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -6472,72 +6609,57 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ - "quote 1.0.23", + "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", + "proc-macro2", + "quote", + "syn 2.0.57", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" -version = "0.22.6" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" dependencies = [ - "webpki", + "rustls-webpki", ] [[package]] -name = "which" -version = "4.4.0" +name = "webpki-roots" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" -dependencies = [ - "either", - "libc", - "once_cell", -] +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "winapi" @@ -6557,9 +6679,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -6570,94 +6692,164 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.4", +] + [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-targets 0.48.5", ] [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.4", ] [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winnow" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] @@ -6675,25 +6867,47 @@ dependencies = [ "oid-registry", "rusticata-macros", "thiserror", - "time 0.3.17", + "time", ] [[package]] name = "xattr" -version = "0.2.3" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", + "linux-raw-sys", + "rustix", ] [[package]] name = "yasna" -version = "0.5.1" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aed2e7a52e3744ab4d0c05c20aa065258e84c49fd4226f5191b2ed29712710b4" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "time 0.3.17", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] @@ -6707,14 +6921,13 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.3.3" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.107", - "synstructure", + "proc-macro2", + "quote", + "syn 2.0.57", ] [[package]] @@ -6723,7 +6936,16 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe", + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" +dependencies = [ + "zstd-safe 7.1.0", ] [[package]] @@ -6736,13 +6958,21 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" -version = "2.0.6+zstd.1.5.2" +version = "2.0.10+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a3f9792c0c3dc6c165840a75f47ae1f4da402c2d006881129579f6597e801b" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" dependencies = [ "cc", - "libc", "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index 0cdb1b2..07fcbb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,8 @@ [workspace] members=["tinydancer","logger", ] + + +[patch.crates-io] +solana-program = { git = "https://github.com/tinydancer-io/solana-1.18", branch="v1.18.7-branch", version="1.18.7"} +solana-zk-token-sdk = { git = "https://github.com/tinydancer-io/solana-1.18" ,branch="v1.18.7-branch", version="1.18.7"} +solana-sdk = { git = "https://github.com/tinydancer-io/solana-1.18", branch="v1.18.7-branch", version="1.18.7"} diff --git a/f b/f index 387266d..e929bf2 100755 --- a/f +++ b/f @@ -1 +1,7 @@ -RUST_LOG=info cargo r -r start "/tmp" +#! /bin/bash + +slotfull=$(RUST_LOG=info cargo r -r slot) +slot=${slotfull:5} +slot=$(echo $slot | sed -r 's/\x1B\[(;?[0-9]{1,3})+[mGK]//g') +echo $slot +RUST_LOG=info cargo r -r start --slot $slot diff --git a/gossip/Cargo.toml b/gossip/Cargo.toml deleted file mode 100644 index 6cb1b1d..0000000 --- a/gossip/Cargo.toml +++ /dev/null @@ -1,57 +0,0 @@ -[package] -name = "tiny-gossip" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -bincode = "1.3.3" -bv = { version = "0.11.1", features = ["serde"] } -clap = "2.33.1" -crossbeam-channel = "0.5" -flate2 = "1.0" -indexmap = { version = "1.9", features = ["rayon"] } -itertools = "0.10.5" -log = "0.4.17" -lru = "0.7.7" -matches = "0.1.9" -num-traits = "0.2" -rand = "0.7.0" -rand_chacha = "0.2.2" -rayon = "1.5.3" -serde = "1.0.152" -serde_bytes = "0.11" -serde_derive = "1.0.103" -solana-bloom = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-clap-utils = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-client = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-entry = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-frozen-abi = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-frozen-abi-macro = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-ledger = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-logger = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-measure = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-metrics = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-net-utils = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-perf = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-rayon-threadlimit = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-runtime = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-sdk = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-streamer = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-thin-client = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-tpu-client = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0", default-features = false } -solana-version = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -solana-vote-program = { git = "https://github.com/tinydancer-io/diet-rpc-validator", version = "=1.15.0" } -static_assertions = "1.1.0" -thiserror = "1.0" - - -[dev-dependencies] -num_cpus = "1.13.1" -regex = "1" -serial_test = "0.9.0" - -[[bin]] -name = "tiny-gossip" -git = "src/main.rs" diff --git a/gossip/src/cluster_info.rs b/gossip/src/cluster_info.rs deleted file mode 100644 index 8e1f619..0000000 --- a/gossip/src/cluster_info.rs +++ /dev/null @@ -1,4721 +0,0 @@ -//! The `cluster_info` module defines a data structure that is shared by all the nodes in the network over -//! a gossip control plane. The goal is to share small bits of off-chain information and detect and -//! repair partitions. -//! -//! This CRDT only supports a very limited set of types. A map of Pubkey -> Versioned Struct. -//! The last version is always picked during an update. -//! -//! The network is arranged in layers: -//! -//! * layer 0 - Leader. -//! * layer 1 - As many nodes as we can fit -//! * layer 2 - Everyone else, if layer 1 is `2^10`, layer 2 should be able to fit `2^20` number of nodes. -//! -//! Bank needs to provide an interface for us to query the stake weight - -#[deprecated( - since = "1.10.6", - note = "Please use `solana_net_utils::{MINIMUM_VALIDATOR_PORT_RANGE_WIDTH, VALIDATOR_PORT_RANGE}` instead" -)] -#[allow(deprecated)] -pub use solana_net_utils::{MINIMUM_VALIDATOR_PORT_RANGE_WIDTH, VALIDATOR_PORT_RANGE}; -use { - crate::{ - cluster_info_metrics::{ - submit_gossip_stats, Counter, GossipStats, ScopedTimer, TimedGuard, - }, - contact_info::ContactInfo, - crds::{Crds, Cursor, GossipRoute}, - crds_gossip::CrdsGossip, - crds_gossip_error::CrdsGossipError, - crds_gossip_pull::{CrdsFilter, ProcessPullStats, CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS}, - crds_value::{ - self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlotsIndex, IncrementalSnapshotHashes, - LowestSlot, NodeInstance, SnapshotHashes, Version, Vote, MAX_WALLCLOCK, - }, - duplicate_shred::DuplicateShred, - epoch_slots::EpochSlots, - gossip_error::GossipError, - ping_pong::{self, PingCache, Pong}, - socketaddr, socketaddr_any, - weighted_shuffle::WeightedShuffle, - }, - bincode::{serialize, serialized_size}, - crossbeam_channel::{Receiver, RecvTimeoutError, Sender}, - itertools::Itertools, - rand::{seq::SliceRandom, thread_rng, CryptoRng, Rng}, - rayon::{prelude::*, ThreadPool, ThreadPoolBuilder}, - serde::ser::Serialize, - solana_ledger::shred::Shred, - solana_measure::measure::Measure, - solana_net_utils::{ - bind_common, bind_common_in_range, bind_in_range, bind_two_in_range_with_offset, - find_available_port_in_range, multi_bind_in_range, PortRange, - }, - solana_perf::{ - data_budget::DataBudget, - packet::{Packet, PacketBatch, PacketBatchRecycler, PACKET_DATA_SIZE}, - }, - solana_rayon_threadlimit::get_thread_count, - solana_runtime::{bank_forks::BankForks, vote_parser}, - solana_sdk::{ - clock::{Slot, DEFAULT_MS_PER_SLOT, DEFAULT_SLOTS_PER_EPOCH}, - feature_set::FeatureSet, - hash::Hash, - pubkey::Pubkey, - quic::QUIC_PORT_OFFSET, - sanitize::{Sanitize, SanitizeError}, - signature::{Keypair, Signable, Signature, Signer}, - timing::timestamp, - transaction::Transaction, - }, - solana_streamer::{ - packet, - socket::SocketAddrSpace, - streamer::{PacketBatchReceiver, PacketBatchSender}, - }, - solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY, - std::{ - borrow::Cow, - collections::{hash_map::Entry, HashMap, HashSet, VecDeque}, - fmt::Debug, - fs::{self, File}, - io::BufReader, - iter::repeat, - net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener, UdpSocket}, - ops::{Deref, Div}, - path::{Path, PathBuf}, - result::Result, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, Mutex, RwLock, RwLockReadGuard, - }, - thread::{sleep, Builder, JoinHandle}, - time::{Duration, Instant}, - }, - thiserror::Error, -}; - -/// The Data plane fanout size, also used as the neighborhood size -pub const DATA_PLANE_FANOUT: usize = 200; -/// milliseconds we sleep for between gossip requests -pub const GOSSIP_SLEEP_MILLIS: u64 = 100; -/// The maximum size of a bloom filter -pub const MAX_BLOOM_SIZE: usize = MAX_CRDS_OBJECT_SIZE; -pub const MAX_CRDS_OBJECT_SIZE: usize = 928; -/// A hard limit on incoming gossip messages -/// Chosen to be able to handle 1Gbps of pure gossip traffic -/// 128MB/PACKET_DATA_SIZE -const MAX_GOSSIP_TRAFFIC: usize = 128_000_000 / PACKET_DATA_SIZE; -/// Max size of serialized crds-values in a Protocol::PushMessage packet. This -/// is equal to PACKET_DATA_SIZE minus serialized size of an empty push -/// message: Protocol::PushMessage(Pubkey::default(), Vec::default()) -const PUSH_MESSAGE_MAX_PAYLOAD_SIZE: usize = PACKET_DATA_SIZE - 44; -const DUPLICATE_SHRED_MAX_PAYLOAD_SIZE: usize = PACKET_DATA_SIZE - 115; -/// Maximum number of hashes in SnapshotHashes/AccountsHashes a node publishes -/// such that the serialized size of the push/pull message stays below -/// PACKET_DATA_SIZE. -// TODO: Update this to 26 once payload sizes are upgraded across fleet. -pub const MAX_SNAPSHOT_HASHES: usize = 16; -/// Maximum number of hashes in IncrementalSnapshotHashes a node publishes -/// such that the serialized size of the push/pull message stays below -/// PACKET_DATA_SIZE. -pub const MAX_INCREMENTAL_SNAPSHOT_HASHES: usize = 25; -/// Maximum number of origin nodes that a PruneData may contain, such that the -/// serialized size of the PruneMessage stays below PACKET_DATA_SIZE. -const MAX_PRUNE_DATA_NODES: usize = 32; -/// Number of bytes in the randomly generated token sent with ping messages. -const GOSSIP_PING_TOKEN_SIZE: usize = 32; -const GOSSIP_PING_CACHE_CAPACITY: usize = 65536; -const GOSSIP_PING_CACHE_TTL: Duration = Duration::from_secs(1280); -const GOSSIP_PING_CACHE_RATE_LIMIT_DELAY: Duration = Duration::from_secs(1280 / 64); -pub const DEFAULT_CONTACT_DEBUG_INTERVAL_MILLIS: u64 = 10_000; -pub const DEFAULT_CONTACT_SAVE_INTERVAL_MILLIS: u64 = 60_000; -/// Minimum serialized size of a Protocol::PullResponse packet. -const PULL_RESPONSE_MIN_SERIALIZED_SIZE: usize = 161; -// Limit number of unique pubkeys in the crds table. -pub(crate) const CRDS_UNIQUE_PUBKEY_CAPACITY: usize = 8192; -/// Minimum stake that a node should have so that its CRDS values are -/// propagated through gossip (few types are exempted). -const MIN_STAKE_FOR_GOSSIP: u64 = solana_sdk::native_token::LAMPORTS_PER_SOL; -/// Minimum number of staked nodes for enforcing stakes in gossip. -const MIN_NUM_STAKED_NODES: usize = 500; - -#[derive(Debug, PartialEq, Eq, Error)] -pub enum ClusterInfoError { - #[error("NoPeers")] - NoPeers, - #[error("NoLeader")] - NoLeader, - #[error("BadContactInfo")] - BadContactInfo, - #[error("BadGossipAddress")] - BadGossipAddress, - #[error("TooManyIncrementalSnapshotHashes")] - TooManyIncrementalSnapshotHashes, -} - -pub struct ClusterInfo { - /// The network - pub gossip: CrdsGossip, - /// set the keypair that will be used to sign crds values generated. It is unset only in tests. - keypair: RwLock>, - /// Network entrypoints - entrypoints: RwLock>, - outbound_budget: DataBudget, - my_contact_info: RwLock, - ping_cache: Mutex, - stats: GossipStats, - socket: UdpSocket, - local_message_pending_push_queue: Mutex>, - contact_debug_interval: u64, // milliseconds, 0 = disabled - contact_save_interval: u64, // milliseconds, 0 = disabled - instance: RwLock, - contact_info_path: PathBuf, - socket_addr_space: SocketAddrSpace, -} - -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub(crate) struct PruneData { - /// Pubkey of the node that sent this prune data - pubkey: Pubkey, - /// Pubkeys of nodes that should be pruned - prunes: Vec, - /// Signature of this Prune Message - signature: Signature, - /// The Pubkey of the intended node/destination for this message - destination: Pubkey, - /// Wallclock of the node that generated this message - wallclock: u64, -} - -impl PruneData { - /// New random PruneData for tests and benchmarks. - #[cfg(test)] - fn new_rand(rng: &mut R, self_keypair: &Keypair, num_nodes: Option) -> Self { - let wallclock = crds_value::new_rand_timestamp(rng); - let num_nodes = num_nodes.unwrap_or_else(|| rng.gen_range(0, MAX_PRUNE_DATA_NODES + 1)); - let prunes = std::iter::repeat_with(Pubkey::new_unique) - .take(num_nodes) - .collect(); - let mut prune_data = PruneData { - pubkey: self_keypair.pubkey(), - prunes, - signature: Signature::default(), - destination: Pubkey::new_unique(), - wallclock, - }; - prune_data.sign(self_keypair); - prune_data - } -} - -impl Sanitize for PruneData { - fn sanitize(&self) -> Result<(), SanitizeError> { - if self.wallclock >= MAX_WALLCLOCK { - return Err(SanitizeError::ValueOutOfBounds); - } - Ok(()) - } -} - -impl Signable for PruneData { - fn pubkey(&self) -> Pubkey { - self.pubkey - } - - fn signable_data(&self) -> Cow<[u8]> { - #[derive(Serialize)] - struct SignData<'a> { - pubkey: &'a Pubkey, - prunes: &'a [Pubkey], - destination: &'a Pubkey, - wallclock: u64, - } - let data = SignData { - pubkey: &self.pubkey, - prunes: &self.prunes, - destination: &self.destination, - wallclock: self.wallclock, - }; - Cow::Owned(serialize(&data).expect("serialize PruneData")) - } - - fn get_signature(&self) -> Signature { - self.signature - } - - fn set_signature(&mut self, signature: Signature) { - self.signature = signature - } -} - -struct PullData { - from_addr: SocketAddr, - caller: CrdsValue, - filter: CrdsFilter, -} - -// pub fn make_accounts_hashes_message( -// keypair: &Keypair, -// accounts_hashes: Vec<(Slot, Hash)>, -// ) -> Option { -// let message = CrdsData::AccountsHashes(SnapshotHashes::new(keypair.pubkey(), accounts_hashes)); -// Some(CrdsValue::new_signed(message, keypair)) -// } - -pub(crate) type Ping = ping_pong::Ping<[u8; GOSSIP_PING_TOKEN_SIZE]>; - -// TODO These messages should go through the gpu pipeline for spam filtering -#[frozen_abi(digest = "9YNaHHwzwQaAaXDXW5A8k47HDuUzRYNjTAdARoAgVvPU")] -#[derive(Serialize, Deserialize, Debug)] -#[allow(clippy::large_enum_variant)] -pub(crate) enum Protocol { - /// Gossip protocol messages - PullRequest(CrdsFilter, CrdsValue), - PullResponse(Pubkey, Vec), - PushMessage(Pubkey, Vec), - // TODO: Remove the redundant outer pubkey here, - // and use the inner PruneData.pubkey instead. - PruneMessage(Pubkey, PruneData), - PingMessage(Ping), - PongMessage(Pong), - // Update count_packets_received if new variants are added here. -} - -impl Protocol { - fn par_verify(self, stats: &GossipStats) -> Option { - match self { - Protocol::PullRequest(_, ref caller) => { - if caller.verify() { - Some(self) - } else { - stats.gossip_pull_request_verify_fail.add_relaxed(1); - None - } - } - Protocol::PullResponse(from, data) => { - let size = data.len(); - let data: Vec<_> = data.into_par_iter().filter(Signable::verify).collect(); - if size != data.len() { - stats - .gossip_pull_response_verify_fail - .add_relaxed((size - data.len()) as u64); - } - if data.is_empty() { - None - } else { - Some(Protocol::PullResponse(from, data)) - } - } - Protocol::PushMessage(from, data) => { - let size = data.len(); - let data: Vec<_> = data.into_par_iter().filter(Signable::verify).collect(); - if size != data.len() { - stats - .gossip_push_msg_verify_fail - .add_relaxed((size - data.len()) as u64); - } - if data.is_empty() { - None - } else { - Some(Protocol::PushMessage(from, data)) - } - } - Protocol::PruneMessage(_, ref data) => { - if data.verify() { - Some(self) - } else { - stats.gossip_prune_msg_verify_fail.add_relaxed(1); - None - } - } - Protocol::PingMessage(ref ping) => { - if ping.verify() { - Some(self) - } else { - stats.gossip_ping_msg_verify_fail.add_relaxed(1); - None - } - } - Protocol::PongMessage(ref pong) => { - if pong.verify() { - Some(self) - } else { - stats.gossip_pong_msg_verify_fail.add_relaxed(1); - None - } - } - } - } -} - -impl Sanitize for Protocol { - fn sanitize(&self) -> Result<(), SanitizeError> { - match self { - Protocol::PullRequest(filter, val) => { - filter.sanitize()?; - val.sanitize() - } - Protocol::PullResponse(_, val) => val.sanitize(), - Protocol::PushMessage(_, val) => val.sanitize(), - Protocol::PruneMessage(from, val) => { - if *from != val.pubkey { - Err(SanitizeError::InvalidValue) - } else { - val.sanitize() - } - } - Protocol::PingMessage(ping) => ping.sanitize(), - Protocol::PongMessage(pong) => pong.sanitize(), - } - } -} - -// Retains only CRDS values associated with nodes with enough stake. -// (some crds types are exempted) -fn retain_staked(values: &mut Vec, stakes: &HashMap) { - values.retain(|value| { - match value.data { - CrdsData::ContactInfo(_) => true, - // May Impact new validators starting up without any stake yet. - // CrdsData::Vote(_, _) => true, - // Unstaked nodes can still help repair. - CrdsData::EpochSlots(_, _) => true, - // Unstaked nodes can still serve snapshots. - // CrdsData::SnapshotHashes(_) | CrdsData::IncrementalSnapshotHashes(_) => true, - // Otherwise unstaked voting nodes will show up with no version in - // the various dashboards. - CrdsData::Version(_) => true, - CrdsData::NodeInstance(_) => true, - // getHealth fails if account hashes are not propagated. - // CrdsData::AccountsHashes(_) => true, - // CrdsData::LowestSlot(_, _) - // | CrdsData::LegacyVersion(_) - // | CrdsData::DuplicateShred(_, _) => { - // let stake = stakes.get(&value.pubkey()).copied(); - // stake.unwrap_or_default() >= MIN_STAKE_FOR_GOSSIP - // } - } - }) -} - -impl ClusterInfo { - pub fn new( - contact_info: ContactInfo, - keypair: Arc, - socket_addr_space: SocketAddrSpace, - ) -> Self { - let id = contact_info.id; - let me = Self { - gossip: CrdsGossip::default(), - keypair: RwLock::new(keypair), - entrypoints: RwLock::default(), - outbound_budget: DataBudget::default(), - my_contact_info: RwLock::new(contact_info), - ping_cache: Mutex::new(PingCache::new( - GOSSIP_PING_CACHE_TTL, - GOSSIP_PING_CACHE_RATE_LIMIT_DELAY, - GOSSIP_PING_CACHE_CAPACITY, - )), - stats: GossipStats::default(), - socket: UdpSocket::bind("0.0.0.0:0").unwrap(), - local_message_pending_push_queue: Mutex::default(), - contact_debug_interval: DEFAULT_CONTACT_DEBUG_INTERVAL_MILLIS, - instance: RwLock::new(NodeInstance::new(&mut thread_rng(), id, timestamp())), - contact_info_path: PathBuf::default(), - contact_save_interval: 0, // disabled - socket_addr_space, - }; - me.insert_self(); - me.push_self(); - me - } - - // Should only be used by tests and simulations - pub fn clone_with_id(&self, new_id: &Pubkey) -> Self { - let mut my_contact_info = self.my_contact_info.read().unwrap().clone(); - my_contact_info.id = *new_id; - ClusterInfo { - gossip: self.gossip.mock_clone(), - keypair: RwLock::new(self.keypair.read().unwrap().clone()), - entrypoints: RwLock::new(self.entrypoints.read().unwrap().clone()), - outbound_budget: self.outbound_budget.clone_non_atomic(), - my_contact_info: RwLock::new(my_contact_info), - ping_cache: Mutex::new(self.ping_cache.lock().unwrap().mock_clone()), - stats: GossipStats::default(), - socket: UdpSocket::bind("0.0.0.0:0").unwrap(), - local_message_pending_push_queue: Mutex::new( - self.local_message_pending_push_queue - .lock() - .unwrap() - .clone(), - ), - contact_debug_interval: self.contact_debug_interval, - instance: RwLock::new(NodeInstance::new(&mut thread_rng(), *new_id, timestamp())), - contact_info_path: PathBuf::default(), - contact_save_interval: 0, // disabled - ..*self - } - } - - pub fn set_contact_debug_interval(&mut self, new: u64) { - self.contact_debug_interval = new; - } - - pub fn socket_addr_space(&self) -> &SocketAddrSpace { - &self.socket_addr_space - } - - fn push_self(&self) { - let now = timestamp(); - self.my_contact_info.write().unwrap().wallclock = now; - let entries: Vec<_> = vec![ - CrdsData::ContactInfo(self.my_contact_info()), - CrdsData::NodeInstance(self.instance.read().unwrap().with_wallclock(now)), - ] - .into_iter() - .map(|v| CrdsValue::new_signed(v, &self.keypair())) - .collect(); - self.local_message_pending_push_queue - .lock() - .unwrap() - .extend(entries); - } - - fn refresh_push_active_set( - &self, - recycler: &PacketBatchRecycler, - stakes: &HashMap, - gossip_validators: Option<&HashSet>, - sender: &PacketBatchSender, - ) { - let ContactInfo { shred_version, .. } = *self.my_contact_info.read().unwrap(); - let self_keypair: Arc = self.keypair().clone(); - let mut pings = Vec::new(); - self.gossip.refresh_push_active_set( - &self_keypair, - shred_version, - stakes, - gossip_validators, - &self.ping_cache, - &mut pings, - &self.socket_addr_space, - ); - self.stats - .new_pull_requests_pings_count - .add_relaxed(pings.len() as u64); - let pings: Vec<_> = pings - .into_iter() - .map(|(addr, ping)| (addr, Protocol::PingMessage(ping))) - .collect(); - if !pings.is_empty() { - self.stats - .packets_sent_gossip_requests_count - .add_relaxed(pings.len() as u64); - let packet_batch = PacketBatch::new_unpinned_with_recycler_data_and_dests( - recycler.clone(), - "refresh_push_active_set", - &pings, - ); - let _ = sender.send(packet_batch); - } - } - - // TODO kill insert_info, only used by tests - pub fn insert_info(&self, contact_info: ContactInfo) { - let value = CrdsValue::new_signed(CrdsData::ContactInfo(contact_info), &self.keypair()); - let mut gossip_crds = self.gossip.crds.write().unwrap(); - let _ = gossip_crds.insert(value, timestamp(), GossipRoute::LocalMessage); - } - - pub fn set_entrypoint(&self, entrypoint: ContactInfo) { - self.set_entrypoints(vec![entrypoint]); - } - - pub fn set_entrypoints(&self, entrypoints: Vec) { - *self.entrypoints.write().unwrap() = entrypoints; - } - - pub fn save_contact_info(&self) { - let nodes = { - let entrypoint_gossip_addrs = self - .entrypoints - .read() - .unwrap() - .iter() - .map(|contact_info| contact_info.gossip) - .collect::>(); - let self_pubkey = self.id(); - let gossip_crds = self.gossip.crds.read().unwrap(); - gossip_crds - .get_nodes() - .filter_map(|v| { - // Don't save: - // 1. Our ContactInfo. No point - // 2. Entrypoint ContactInfo. This will avoid adopting the incorrect shred - // version on restart if the entrypoint shred version changes. Also - // there's not much point in saving entrypoint ContactInfo since by - // definition that information is already available - let contact_info = v.value.contact_info().unwrap(); - if contact_info.id != self_pubkey - && !entrypoint_gossip_addrs.contains(&contact_info.gossip) - { - return Some(v.value.clone()); - } - None - }) - .collect::>() - }; - - if nodes.is_empty() { - return; - } - - let filename = self.contact_info_path.join("contact-info.bin"); - let tmp_filename = &filename.with_extension("tmp"); - - match File::create(tmp_filename) { - Ok(mut file) => { - if let Err(err) = bincode::serialize_into(&mut file, &nodes) { - warn!( - "Failed to serialize contact info info {}: {}", - tmp_filename.display(), - err - ); - return; - } - } - Err(err) => { - warn!("Failed to create {}: {}", tmp_filename.display(), err); - return; - } - } - - match fs::rename(tmp_filename, &filename) { - Ok(()) => { - info!( - "Saved contact info for {} nodes into {}", - nodes.len(), - filename.display() - ); - } - Err(err) => { - warn!( - "Failed to rename {} to {}: {}", - tmp_filename.display(), - filename.display(), - err - ); - } - } - } - - pub fn restore_contact_info(&mut self, contact_info_path: &Path, contact_save_interval: u64) { - self.contact_info_path = contact_info_path.into(); - self.contact_save_interval = contact_save_interval; - - let filename = contact_info_path.join("contact-info.bin"); - if !filename.exists() { - return; - } - - let nodes: Vec = match File::open(&filename) { - Ok(file) => { - bincode::deserialize_from(&mut BufReader::new(file)).unwrap_or_else(|err| { - warn!("Failed to deserialize {}: {}", filename.display(), err); - vec![] - }) - } - Err(err) => { - warn!("Failed to open {}: {}", filename.display(), err); - vec![] - } - }; - - info!( - "Loaded contact info for {} nodes from {}", - nodes.len(), - filename.display() - ); - let now = timestamp(); - let mut gossip_crds = self.gossip.crds.write().unwrap(); - for node in nodes { - if let Err(err) = gossip_crds.insert(node, now, GossipRoute::LocalMessage) { - warn!("crds insert failed {:?}", err); - } - } - } - - pub fn id(&self) -> Pubkey { - self.my_contact_info.read().unwrap().id - } - - pub fn keypair(&self) -> RwLockReadGuard> { - self.keypair.read().unwrap() - } - - pub fn set_keypair(&self, new_keypair: Arc) { - let id = new_keypair.pubkey(); - { - let mut instance = self.instance.write().unwrap(); - *instance = NodeInstance::new(&mut thread_rng(), id, timestamp()); - } - *self.keypair.write().unwrap() = new_keypair; - self.my_contact_info.write().unwrap().id = id; - - self.insert_self(); - self.push_message(CrdsValue::new_signed( - CrdsData::Version(Version::new(self.id())), - &self.keypair(), - )); - self.push_self(); - } - - pub fn lookup_contact_info(&self, id: &Pubkey, map: F) -> Option - where - F: FnOnce(&ContactInfo) -> Y, - { - let gossip_crds = self.gossip.crds.read().unwrap(); - gossip_crds.get(*id).map(map) - } - - pub fn lookup_contact_info_by_gossip_addr( - &self, - gossip_addr: &SocketAddr, - ) -> Option { - let gossip_crds = self.gossip.crds.read().unwrap(); - let mut nodes = gossip_crds.get_nodes_contact_info(); - nodes.find(|node| node.gossip == *gossip_addr).cloned() - } - - pub fn my_contact_info(&self) -> ContactInfo { - self.my_contact_info.read().unwrap().clone() - } - - pub fn my_shred_version(&self) -> u16 { - self.my_contact_info.read().unwrap().shred_version - } - - fn lookup_epoch_slots(&self, ix: EpochSlotsIndex) -> EpochSlots { - let self_pubkey = self.id(); - let label = CrdsValueLabel::EpochSlots(ix, self_pubkey); - let gossip_crds = self.gossip.crds.read().unwrap(); - gossip_crds - .get::<&CrdsValue>(&label) - .and_then(|v| v.epoch_slots()) - .cloned() - .unwrap_or_else(|| EpochSlots::new(self_pubkey, timestamp())) - } - - pub fn rpc_info_trace(&self) -> String { - let now = timestamp(); - let my_pubkey = self.id(); - let my_shred_version = self.my_shred_version(); - let nodes: Vec<_> = self - .all_peers() - .into_iter() - .filter_map(|(node, last_updated)| { - if !ContactInfo::is_valid_address(&node.rpc, &self.socket_addr_space) { - return None; - } - - let node_version = self.get_node_version(&node.id); - if my_shred_version != 0 - && (node.shred_version != 0 && node.shred_version != my_shred_version) - { - return None; - } - - let addr_to_string = |default_ip: &IpAddr, addr: &SocketAddr| -> String { - if ContactInfo::is_valid_address(addr, &self.socket_addr_space) { - if &addr.ip() == default_ip { - addr.port().to_string() - } else { - addr.to_string() - } - } else { - "none".to_string() - } - }; - - let rpc_addr = node.rpc.ip(); - Some(format!( - "{:15} {:2}| {:5} | {:44} |{:^9}| {:5}| {:5}| {}\n", - rpc_addr.to_string(), - if node.id == my_pubkey { "me" } else { "" }, - now.saturating_sub(last_updated), - node.id, - if let Some(node_version) = node_version { - node_version.to_string() - } else { - "-".to_string() - }, - addr_to_string(&rpc_addr, &node.rpc), - addr_to_string(&rpc_addr, &node.rpc_pubsub), - node.shred_version, - )) - }) - .collect(); - - format!( - "RPC Address |Age(ms)| Node identifier \ - | Version | RPC |PubSub|ShredVer\n\ - ------------------+-------+----------------------------------------------\ - +---------+------+------+--------\n\ - {}\ - RPC Enabled Nodes: {}", - nodes.join(""), - nodes.len(), - ) - } - - pub fn contact_info_trace(&self) -> String { - let now = timestamp(); - let mut shred_spy_nodes = 0usize; - let mut total_spy_nodes = 0usize; - let mut different_shred_nodes = 0usize; - let my_pubkey = self.id(); - let my_shred_version = self.my_shred_version(); - let nodes: Vec<_> = self - .all_peers() - .into_iter() - .filter_map(|(node, last_updated)| { - let is_spy_node = Self::is_spy_node(&node, &self.socket_addr_space); - if is_spy_node { - total_spy_nodes = total_spy_nodes.saturating_add(1); - } - - let node_version = self.get_node_version(&node.id); - if my_shred_version != 0 && (node.shred_version != 0 && node.shred_version != my_shred_version) { - different_shred_nodes = different_shred_nodes.saturating_add(1); - None - } else { - if is_spy_node { - shred_spy_nodes = shred_spy_nodes.saturating_add(1); - } - let addr_to_string = |default_ip: &IpAddr, addr: &SocketAddr| -> String { - if ContactInfo::is_valid_address(addr, &self.socket_addr_space) { - if &addr.ip() == default_ip { - addr.port().to_string() - } else { - addr.to_string() - } - } else { - "none".to_string() - } - }; - let ip_addr = node.gossip.ip(); - Some(format!( - "{:15} {:2}| {:5} | {:44} |{:^9}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {}\n", - if ContactInfo::is_valid_address(&node.gossip, &self.socket_addr_space) { - ip_addr.to_string() - } else { - "none".to_string() - }, - if node.id == my_pubkey { "me" } else { "" }, - now.saturating_sub(last_updated), - node.id, - if let Some(node_version) = node_version { - node_version.to_string() - } else { - "-".to_string() - }, - addr_to_string(&ip_addr, &node.gossip), - addr_to_string(&ip_addr, &node.tpu_vote), - addr_to_string(&ip_addr, &node.tpu), - addr_to_string(&ip_addr, &node.tpu_forwards), - addr_to_string(&ip_addr, &node.tvu), - addr_to_string(&ip_addr, &node.tvu_forwards), - addr_to_string(&ip_addr, &node.repair), - addr_to_string(&ip_addr, &node.serve_repair), - node.shred_version, - )) - } - }) - .collect(); - - format!( - "IP Address |Age(ms)| Node identifier \ - | Version |Gossip|TPUvote| TPU |TPUfwd| TVU |TVUfwd|Repair|ServeR|ShredVer\n\ - ------------------+-------+----------------------------------------------\ - +---------+------+-------+------+------+------+------+------+------+--------\n\ - {}\ - Nodes: {}{}{}", - nodes.join(""), - nodes.len().saturating_sub(shred_spy_nodes), - if total_spy_nodes > 0 { - format!("\nSpies: {total_spy_nodes}") - } else { - "".to_string() - }, - if different_shred_nodes > 0 { - format!("\nNodes with different shred version: {different_shred_nodes}") - } else { - "".to_string() - } - ) - } - - // TODO: This has a race condition if called from more than one thread. - // pub fn push_lowest_slot(&self, min: Slot) { - // let self_pubkey = self.id(); - // let last = { - // let gossip_crds = self.gossip.crds.read().unwrap(); - // gossip_crds - // .get::<&LowestSlot>(self_pubkey) - // .map(|x| x.lowest) - // .unwrap_or_default() - // }; - // if min > last { - // let now = timestamp(); - // let entry = CrdsValue::new_signed( - // CrdsData::LowestSlot(0, LowestSlot::new(self_pubkey, min, now)), - // &self.keypair(), - // ); - // self.local_message_pending_push_queue - // .lock() - // .unwrap() - // .push(entry); - // } - // } - - // TODO: If two threads call into this function then epoch_slot_index has a - // race condition and the threads will overwrite each other in crds table. - pub fn push_epoch_slots(&self, mut update: &[Slot]) { - let self_pubkey = self.id(); - let current_slots: Vec<_> = { - let gossip_crds = - self.time_gossip_read_lock("lookup_epoch_slots", &self.stats.epoch_slots_lookup); - (0..crds_value::MAX_EPOCH_SLOTS) - .filter_map(|ix| { - let label = CrdsValueLabel::EpochSlots(ix, self_pubkey); - let crds_value = gossip_crds.get::<&CrdsValue>(&label)?; - let epoch_slots = crds_value.epoch_slots()?; - let first_slot = epoch_slots.first_slot()?; - Some((epoch_slots.wallclock, first_slot, ix)) - }) - .collect() - }; - let min_slot: Slot = current_slots - .iter() - .map(|(_wallclock, slot, _index)| *slot) - .min() - .unwrap_or_default(); - let max_slot: Slot = update.iter().max().cloned().unwrap_or(0); - let total_slots = max_slot as isize - min_slot as isize; - // WARN if CRDS is not storing at least a full epoch worth of slots - if DEFAULT_SLOTS_PER_EPOCH as isize > total_slots - && crds_value::MAX_EPOCH_SLOTS as usize <= current_slots.len() - { - self.stats.epoch_slots_filled.add_relaxed(1); - warn!( - "EPOCH_SLOTS are filling up FAST {}/{}", - total_slots, - current_slots.len() - ); - } - let mut reset = false; - let mut epoch_slot_index = match current_slots.iter().max() { - Some((_wallclock, _slot, index)) => *index, - None => 0, - }; - let mut entries = Vec::default(); - let keypair = self.keypair(); - while !update.is_empty() { - let ix = epoch_slot_index % crds_value::MAX_EPOCH_SLOTS; - let now = timestamp(); - let mut slots = if !reset { - self.lookup_epoch_slots(ix) - } else { - EpochSlots::new(self_pubkey, now) - }; - let n = slots.fill(update, now); - update = &update[n..]; - if n > 0 { - let epoch_slots = CrdsData::EpochSlots(ix, slots); - let entry = CrdsValue::new_signed(epoch_slots, &keypair); - entries.push(entry); - } - epoch_slot_index += 1; - reset = true; - } - let mut gossip_crds = self.gossip.crds.write().unwrap(); - let now = timestamp(); - for entry in entries { - if let Err(err) = gossip_crds.insert(entry, now, GossipRoute::LocalMessage) { - error!("push_epoch_slots failed: {:?}", err); - } - } - } - - fn time_gossip_read_lock<'a>( - &'a self, - label: &'static str, - counter: &'a Counter, - ) -> TimedGuard<'a, RwLockReadGuard> { - TimedGuard::new(self.gossip.crds.read().unwrap(), label, counter) - } - - pub fn push_message(&self, message: CrdsValue) { - self.local_message_pending_push_queue - .lock() - .unwrap() - .push(message); - } - - // pub fn push_accounts_hashes(&self, accounts_hashes: Vec<(Slot, Hash)>) { - // if accounts_hashes.len() > MAX_SNAPSHOT_HASHES { - // warn!( - // "accounts hashes too large, ignored: {}", - // accounts_hashes.len(), - // ); - // return; - // } - - // let message = CrdsData::AccountsHashes(SnapshotHashes::new(self.id(), accounts_hashes)); - // self.push_message(CrdsValue::new_signed(message, &self.keypair())); - // } - - // pub fn push_snapshot_hashes(&self, snapshot_hashes: Vec<(Slot, Hash)>) { - // if snapshot_hashes.len() > MAX_SNAPSHOT_HASHES { - // warn!( - // "snapshot hashes too large, ignored: {}", - // snapshot_hashes.len(), - // ); - // return; - // } - - // let message = CrdsData::SnapshotHashes(SnapshotHashes::new(self.id(), snapshot_hashes)); - // self.push_message(CrdsValue::new_signed(message, &self.keypair())); - // } - - // pub fn push_incremental_snapshot_hashes( - // &self, - // base: (Slot, Hash), - // hashes: Vec<(Slot, Hash)>, - // ) -> Result<(), ClusterInfoError> { - // if hashes.len() > MAX_INCREMENTAL_SNAPSHOT_HASHES { - // return Err(ClusterInfoError::TooManyIncrementalSnapshotHashes); - // } - - // let message = CrdsData::IncrementalSnapshotHashes(IncrementalSnapshotHashes { - // from: self.id(), - // base, - // hashes, - // wallclock: timestamp(), - // }); - // self.push_message(CrdsValue::new_signed(message, &self.keypair())); - - // Ok(()) - // } - - // pub fn push_vote_at_index(&self, vote: Transaction, vote_index: u8) { - // assert!((vote_index as usize) < MAX_LOCKOUT_HISTORY); - // let self_pubkey = self.id(); - // let now = timestamp(); - // let vote = Vote::new(self_pubkey, vote, now).unwrap(); - // let vote = CrdsData::Vote(vote_index, vote); - // let vote = CrdsValue::new_signed(vote, &self.keypair()); - // let mut gossip_crds = self.gossip.crds.write().unwrap(); - // if let Err(err) = gossip_crds.insert(vote, now, GossipRoute::LocalMessage) { - // error!("push_vote failed: {:?}", err); - // } - // } - - // pub fn push_vote(&self, tower: &[Slot], vote: Transaction) { - // debug_assert!(tower.iter().tuple_windows().all(|(a, b)| a < b)); - // // Find a crds vote which is evicted from the tower, and recycle its - // // vote-index. This can be either an old vote which is popped off the - // // deque, or recent vote which has expired before getting enough - // // confirmations. - // // If all votes are still in the tower, add a new vote-index. If more - // // than one vote is evicted, the oldest one by wallclock is returned in - // // order to allow more recent votes more time to propagate through - // // gossip. - // // TODO: When there are more than one vote evicted from the tower, only - // // one crds vote is overwritten here. Decide what to do with the rest. - // let mut num_crds_votes = 0; - // let self_pubkey = self.id(); - // // Returns true if the tower does not contain the vote.slot. - // let should_evict_vote = |vote: &Vote| -> bool { - // match vote.slot() { - // Some(slot) => !tower.contains(&slot), - // None => { - // error!("crds vote with no slots!"); - // true - // } - // } - // }; - // let vote_index = { - // let gossip_crds = - // self.time_gossip_read_lock("gossip_read_push_vote", &self.stats.push_vote_read); - // (0..MAX_LOCKOUT_HISTORY as u8) - // .filter_map(|ix| { - // let vote = CrdsValueLabel::Vote(ix, self_pubkey); - // let vote: &CrdsData = gossip_crds.get(&vote)?; - // num_crds_votes += 1; - // match &vote { - // CrdsData::Vote(_, vote) if should_evict_vote(vote) => { - // Some((vote.wallclock, ix)) - // } - // CrdsData::Vote(_, _) => None, - // _ => panic!("this should not happen!"), - // } - // }) - // .min() // Boot the oldest evicted vote by wallclock. - // .map(|(_ /*wallclock*/, ix)| ix) - // }; - // let vote_index = vote_index.unwrap_or(num_crds_votes); - // if (vote_index as usize) >= MAX_LOCKOUT_HISTORY { - // let (_, vote, hash, _) = vote_parser::parse_vote_transaction(&vote).unwrap(); - // panic!( - // "invalid vote index: {}, switch: {}, vote slots: {:?}, tower: {:?}", - // vote_index, - // hash.is_some(), - // vote.slots(), - // tower - // ); - // } - // self.push_vote_at_index(vote, vote_index); - // } - - // pub fn refresh_vote(&self, vote: Transaction, vote_slot: Slot) { - // let vote_index = { - // let self_pubkey = self.id(); - // let gossip_crds = - // self.time_gossip_read_lock("gossip_read_push_vote", &self.stats.push_vote_read); - // (0..MAX_LOCKOUT_HISTORY as u8).find(|ix| { - // let vote = CrdsValueLabel::Vote(*ix, self_pubkey); - // if let Some(vote) = gossip_crds.get::<&CrdsData>(&vote) { - // match &vote { - // CrdsData::Vote(_, prev_vote) => match prev_vote.slot() { - // Some(prev_vote_slot) => prev_vote_slot == vote_slot, - // None => { - // error!("crds vote with no slots!"); - // false - // } - // }, - // _ => panic!("this should not happen!"), - // } - // } else { - // false - // } - // }) - // }; - - // // If you don't see a vote with the same slot yet, this means you probably - // // restarted, and need to wait for your oldest vote to propagate back to you. - // // - // // We don't write to an arbitrary index, because it may replace one of this validator's - // // existing votes on the network. - // if let Some(vote_index) = vote_index { - // self.push_vote_at_index(vote, vote_index); - // } - // } - - // pub fn send_transaction( - // &self, - // transaction: &Transaction, - // tpu: Option, - // ) -> Result<(), GossipError> { - // let tpu = tpu.unwrap_or_else(|| self.my_contact_info().tpu); - // let buf = serialize(transaction)?; - // self.socket.send_to(&buf, tpu)?; - // Ok(()) - // } - - /// Returns votes inserted since the given cursor. - // pub fn get_votes(&self, cursor: &mut Cursor) -> Vec { - // let txs: Vec = self - // .time_gossip_read_lock("get_votes", &self.stats.get_votes) - // .get_votes(cursor) - // .map(|vote| { - // let transaction = match &vote.value.data { - // CrdsData::Vote(_, vote) => vote.transaction().clone(), - // _ => panic!("this should not happen!"), - // }; - // transaction - // }) - // .collect(); - // self.stats.get_votes_count.add_relaxed(txs.len() as u64); - // txs - // } - - /// Returns votes and the associated labels inserted since the given cursor. - // pub fn get_votes_with_labels( - // &self, - // cursor: &mut Cursor, - // ) -> (Vec, Vec) { - // let (labels, txs): (_, Vec<_>) = self - // .time_gossip_read_lock("get_votes", &self.stats.get_votes) - // .get_votes(cursor) - // .map(|vote| { - // let transaction = match &vote.value.data { - // CrdsData::Vote(_, vote) => vote.transaction().clone(), - // _ => panic!("this should not happen!"), - // }; - // (vote.value.label(), transaction) - // }) - // .unzip(); - // self.stats.get_votes_count.add_relaxed(txs.len() as u64); - // (labels, txs) - // } - - // pub fn push_duplicate_shred( - // &self, - // shred: &Shred, - // other_payload: &[u8], - // ) -> Result<(), GossipError> { - // self.gossip.push_duplicate_shred( - // &self.keypair(), - // shred, - // other_payload, - // None:: Option>, // Leader schedule - // DUPLICATE_SHRED_MAX_PAYLOAD_SIZE, - // )?; - // Ok(()) - // } - - // pub fn get_accounts_hash_for_node(&self, pubkey: &Pubkey, map: F) -> Option - // where - // F: FnOnce(&Vec<(Slot, Hash)>) -> Y, - // { - // self.time_gossip_read_lock("get_accounts_hash", &self.stats.get_accounts_hash) - // .get::<&CrdsValue>(&CrdsValueLabel::AccountsHashes(*pubkey)) - // .map(|x| &x.accounts_hash().unwrap().hashes) - // .map(map) - // } - - // pub fn get_snapshot_hash_for_node(&self, pubkey: &Pubkey, map: F) -> Option - // where - // F: FnOnce(&Vec<(Slot, Hash)>) -> Y, - // { - // let gossip_crds = self.gossip.crds.read().unwrap(); - // let hashes = &gossip_crds.get::<&SnapshotHashes>(*pubkey)?.hashes; - // Some(map(hashes)) - // } - - // pub fn get_incremental_snapshot_hashes_for_node( - // &self, - // pubkey: &Pubkey, - // ) -> Option { - // self.gossip - // .crds - // .read() - // .unwrap() - // .get::<&IncrementalSnapshotHashes>(*pubkey) - // .cloned() - // } - - /// Returns epoch-slots inserted since the given cursor. - /// Excludes entries from nodes with unkown or different shred version. - pub fn get_epoch_slots(&self, cursor: &mut Cursor) -> Vec { - let self_shred_version = Some(self.my_shred_version()); - let gossip_crds = self.gossip.crds.read().unwrap(); - gossip_crds - .get_epoch_slots(cursor) - .filter(|entry| { - let origin = entry.value.pubkey(); - gossip_crds.get_shred_version(&origin) == self_shred_version - }) - .map(|entry| match &entry.value.data { - CrdsData::EpochSlots(_, slots) => slots.clone(), - _ => panic!("this should not happen!"), - }) - .collect() - } - - // /// Returns duplicate-shreds inserted since the given cursor. - // #[allow(dead_code)] - // pub(crate) fn get_duplicate_shreds(&self, cursor: &mut Cursor) -> Vec { - // let gossip_crds = self.gossip.crds.read().unwrap(); - // gossip_crds - // .get_duplicate_shreds(cursor) - // .map(|entry| match &entry.value.data { - // CrdsData::DuplicateShred(_, dup) => dup.clone(), - // _ => panic!("this should not happen!"), - // }) - // .collect() - // } - - pub fn get_node_version(&self, pubkey: &Pubkey) -> Option { - let gossip_crds = self.gossip.crds.read().unwrap(); - // if let Some(version) = gossip_crds.get::<&Version>(*pubkey) { - // return Some(version.version.clone()); - // } - let version: &crds_value::Version = gossip_crds.get(*pubkey)?; - Some(version.version.clone().into()) - } - - /// all validators that have a valid rpc port regardless of `shred_version`. - pub fn all_rpc_peers(&self) -> Vec { - let self_pubkey = self.id(); - let gossip_crds = self.gossip.crds.read().unwrap(); - gossip_crds - .get_nodes_contact_info() - .filter(|x| { - x.id != self_pubkey - && ContactInfo::is_valid_address(&x.rpc, &self.socket_addr_space) - }) - .cloned() - .collect() - } - - // All nodes in gossip (including spy nodes) and the last time we heard about them - pub fn all_peers(&self) -> Vec<(ContactInfo, u64)> { - let gossip_crds = self.gossip.crds.read().unwrap(); - gossip_crds - .get_nodes() - .map(|x| (x.value.contact_info().unwrap().clone(), x.local_timestamp)) - .collect() - } - - pub fn gossip_peers(&self) -> Vec { - let me = self.id(); - let gossip_crds = self.gossip.crds.read().unwrap(); - gossip_crds - .get_nodes_contact_info() - // shred_version not considered for gossip peers (ie, spy nodes do not set shred_version) - .filter(|x| { - x.id != me && ContactInfo::is_valid_address(&x.gossip, &self.socket_addr_space) - }) - .cloned() - .collect() - } - - /// all validators that have a valid tvu port regardless of `shred_version`. - pub fn all_tvu_peers(&self) -> Vec { - let self_pubkey = self.id(); - self.time_gossip_read_lock("all_tvu_peers", &self.stats.all_tvu_peers) - .get_nodes_contact_info() - .filter(|x| { - ContactInfo::is_valid_address(&x.tvu, &self.socket_addr_space) - && x.id != self_pubkey - }) - .cloned() - .collect() - } - - /// all validators that have a valid tvu port and are on the same `shred_version`. - pub fn tvu_peers(&self) -> Vec { - let self_pubkey = self.id(); - let self_shred_version = self.my_shred_version(); - self.time_gossip_read_lock("tvu_peers", &self.stats.tvu_peers) - .get_nodes_contact_info() - .filter(|node| { - node.id != self_pubkey - && node.shred_version == self_shred_version - && ContactInfo::is_valid_tvu_address(&node.tvu) - }) - .cloned() - .collect() - } - - /// all tvu peers with valid gossip addrs that likely have the slot being requested - pub fn repair_peers(&self, slot: Slot) -> Vec { - let _st = ScopedTimer::from(&self.stats.repair_peers); - let self_pubkey = self.id(); - let self_shred_version = self.my_shred_version(); - let gossip_crds = self.gossip.crds.read().unwrap(); - gossip_crds - .get_nodes_contact_info() - .filter(|node| { - node.id != self_pubkey - && node.shred_version == self_shred_version - && ContactInfo::is_valid_tvu_address(&node.tvu) - && ContactInfo::is_valid_address(&node.serve_repair, &self.socket_addr_space) - // && match gossip_crds.get::<&LowestSlot>(node.id) { - // None => true, // fallback to legacy behavior - // Some(lowest_slot) => lowest_slot.lowest <= slot, - // } - }) - .cloned() - .collect() - } - - fn is_spy_node(contact_info: &ContactInfo, socket_addr_space: &SocketAddrSpace) -> bool { - !ContactInfo::is_valid_address(&contact_info.tpu, socket_addr_space) - || !ContactInfo::is_valid_address(&contact_info.gossip, socket_addr_space) - || !ContactInfo::is_valid_address(&contact_info.tvu, socket_addr_space) - } - - /// compute broadcast table - pub fn tpu_peers(&self) -> Vec { - let self_pubkey = self.id(); - let gossip_crds = self.gossip.crds.read().unwrap(); - gossip_crds - .get_nodes_contact_info() - .filter(|x| { - x.id != self_pubkey - && ContactInfo::is_valid_address(&x.tpu, &self.socket_addr_space) - }) - .cloned() - .collect() - } - - fn insert_self(&self) { - let value = CrdsValue::new_signed( - CrdsData::ContactInfo(self.my_contact_info()), - &self.keypair(), - ); - let mut gossip_crds = self.gossip.crds.write().unwrap(); - let _ = gossip_crds.insert(value, timestamp(), GossipRoute::LocalMessage); - } - - // If the network entrypoint hasn't been discovered yet, add it to the crds table - fn append_entrypoint_to_pulls( - &self, - thread_pool: &ThreadPool, - pulls: &mut HashMap>, - ) { - const THROTTLE_DELAY: u64 = CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS / 2; - let entrypoint = { - let mut entrypoints = self.entrypoints.write().unwrap(); - let entrypoint = match entrypoints.choose_mut(&mut rand::thread_rng()) { - Some(entrypoint) => entrypoint, - None => return, - }; - if !pulls.is_empty() { - let now = timestamp(); - if now <= entrypoint.wallclock.saturating_add(THROTTLE_DELAY) { - return; - } - entrypoint.wallclock = now; - if self - .time_gossip_read_lock("entrypoint", &self.stats.entrypoint) - .get_nodes_contact_info() - .any(|node| node.gossip == entrypoint.gossip) - { - return; // Found the entrypoint, no need to pull from it - } - } - entrypoint.clone() - }; - let filters = if pulls.is_empty() { - let _st = ScopedTimer::from(&self.stats.entrypoint2); - self.gossip - .pull - .build_crds_filters(thread_pool, &self.gossip.crds, MAX_BLOOM_SIZE) - } else { - pulls.values().flatten().cloned().collect() - }; - self.stats.pull_from_entrypoint_count.add_relaxed(1); - pulls.insert(entrypoint, filters); - } - - /// Splits an input feed of serializable data into chunks where the sum of - /// serialized size of values within each chunk is no larger than - /// max_chunk_size. - /// Note: some messages cannot be contained within that size so in the worst case this returns - /// N nested Vecs with 1 item each. - fn split_gossip_messages( - max_chunk_size: usize, - data_feed: I, - ) -> impl Iterator> - where - T: Serialize + Debug, - I: IntoIterator, - { - let mut data_feed = data_feed.into_iter().fuse(); - let mut buffer = vec![]; - let mut buffer_size = 0; // Serialized size of buffered values. - std::iter::from_fn(move || loop { - match data_feed.next() { - None => { - return if buffer.is_empty() { - None - } else { - Some(std::mem::take(&mut buffer)) - }; - } - Some(data) => { - let data_size = match serialized_size(&data) { - Ok(size) => size as usize, - Err(err) => { - error!("serialized_size failed: {}", err); - continue; - } - }; - if buffer_size + data_size <= max_chunk_size { - buffer_size += data_size; - buffer.push(data); - } else if data_size <= max_chunk_size { - buffer_size = data_size; - return Some(std::mem::replace(&mut buffer, vec![data])); - } else { - error!( - "dropping data larger than the maximum chunk size {:?}", - data - ); - } - } - } - }) - } - - #[allow(clippy::type_complexity)] - fn new_pull_requests( - &self, - thread_pool: &ThreadPool, - gossip_validators: Option<&HashSet>, - stakes: &HashMap, - ) -> ( - Vec<(SocketAddr, Ping)>, // Ping packets. - Vec<(SocketAddr, Protocol)>, // Pull requests - ) { - let now = timestamp(); - let mut pings = Vec::new(); - let mut pulls = { - let _st = ScopedTimer::from(&self.stats.new_pull_requests); - self.gossip - .new_pull_request( - thread_pool, - self.keypair().deref(), - self.my_shred_version(), - now, - gossip_validators, - stakes, - MAX_BLOOM_SIZE, - &self.ping_cache, - &mut pings, - &self.socket_addr_space, - ) - .unwrap_or_default() - }; - self.append_entrypoint_to_pulls(thread_pool, &mut pulls); - let num_requests = pulls.values().map(Vec::len).sum::() as u64; - self.stats.new_pull_requests_count.add_relaxed(num_requests); - { - let _st = ScopedTimer::from(&self.stats.mark_pull_request); - for peer in pulls.keys() { - self.gossip.mark_pull_request_creation_time(peer.id, now); - } - } - let self_info = CrdsData::ContactInfo(self.my_contact_info()); - let self_info = CrdsValue::new_signed(self_info, &self.keypair()); - let pulls = pulls - .into_iter() - .flat_map(|(peer, filters)| repeat(peer.gossip).zip(filters)) - .map(|(gossip_addr, filter)| { - let request = Protocol::PullRequest(filter, self_info.clone()); - (gossip_addr, request) - }); - self.stats - .new_pull_requests_pings_count - .add_relaxed(pings.len() as u64); - (pings, pulls.collect()) - } - - fn drain_push_queue(&self) -> Vec { - let mut push_queue = self.local_message_pending_push_queue.lock().unwrap(); - std::mem::take(&mut *push_queue) - } - // Used in tests - pub fn flush_push_queue(&self) { - let pending_push_messages = self.drain_push_queue(); - let mut gossip_crds = self.gossip.crds.write().unwrap(); - let now = timestamp(); - for entry in pending_push_messages { - let _ = gossip_crds.insert(entry, now, GossipRoute::LocalMessage); - } - } - fn new_push_requests(&self, stakes: &HashMap) -> Vec<(SocketAddr, Protocol)> { - let self_id = self.id(); - let (mut push_messages, num_entries, num_nodes) = { - let _st = ScopedTimer::from(&self.stats.new_push_requests); - self.gossip - .new_push_messages(self.drain_push_queue(), timestamp()) - }; - self.stats - .push_fanout_num_entries - .add_relaxed(num_entries as u64); - self.stats - .push_fanout_num_nodes - .add_relaxed(num_nodes as u64); - if self.require_stake_for_gossip(stakes) { - push_messages.retain(|_, data| { - retain_staked(data, stakes); - !data.is_empty() - }) - } - let push_messages: Vec<_> = { - let gossip_crds = - self.time_gossip_read_lock("push_req_lookup", &self.stats.new_push_requests2); - push_messages - .into_iter() - .filter_map(|(pubkey, messages)| { - let peer: &ContactInfo = gossip_crds.get(pubkey)?; - Some((peer.gossip, messages)) - }) - .collect() - }; - let messages: Vec<_> = push_messages - .into_iter() - .flat_map(|(peer, msgs)| { - Self::split_gossip_messages(PUSH_MESSAGE_MAX_PAYLOAD_SIZE, msgs) - .map(move |payload| (peer, Protocol::PushMessage(self_id, payload))) - }) - .collect(); - self.stats - .new_push_requests_num - .add_relaxed(messages.len() as u64); - messages - } - - // Generate new push and pull requests - fn generate_new_gossip_requests( - &self, - thread_pool: &ThreadPool, - gossip_validators: Option<&HashSet>, - stakes: &HashMap, - generate_pull_requests: bool, - ) -> Vec<(SocketAddr, Protocol)> { - self.trim_crds_table(CRDS_UNIQUE_PUBKEY_CAPACITY, stakes); - // This will flush local pending push messages before generating - // pull-request bloom filters, preventing pull responses to return the - // same values back to the node itself. Note that packets will arrive - // and are processed out of order. - let mut out: Vec<_> = self.new_push_requests(stakes); - self.stats - .packets_sent_push_messages_count - .add_relaxed(out.len() as u64); - if generate_pull_requests { - let (pings, pull_requests) = - self.new_pull_requests(thread_pool, gossip_validators, stakes); - self.stats - .packets_sent_pull_requests_count - .add_relaxed(pull_requests.len() as u64); - let pings = pings - .into_iter() - .map(|(addr, ping)| (addr, Protocol::PingMessage(ping))); - out.extend(pull_requests); - out.extend(pings); - } - out - } - - /// At random pick a node and try to get updated changes from them - fn run_gossip( - &self, - thread_pool: &ThreadPool, - gossip_validators: Option<&HashSet>, - recycler: &PacketBatchRecycler, - stakes: &HashMap, - sender: &PacketBatchSender, - generate_pull_requests: bool, - ) -> Result<(), GossipError> { - let _st = ScopedTimer::from(&self.stats.gossip_transmit_loop_time); - let reqs = self.generate_new_gossip_requests( - thread_pool, - gossip_validators, - stakes, - generate_pull_requests, - ); - if !reqs.is_empty() { - let packet_batch = PacketBatch::new_unpinned_with_recycler_data_and_dests( - recycler.clone(), - "run_gossip", - &reqs, - ); - self.stats - .packets_sent_gossip_requests_count - .add_relaxed(packet_batch.len() as u64); - sender.send(packet_batch)?; - } - self.stats - .gossip_transmit_loop_iterations_since_last_report - .add_relaxed(1); - Ok(()) - } - - fn process_entrypoints(&self) -> bool { - let mut entrypoints = self.entrypoints.write().unwrap(); - if entrypoints.is_empty() { - // No entrypoint specified. Nothing more to process - return true; - } - for entrypoint in entrypoints.iter_mut() { - if entrypoint.id == Pubkey::default() { - // If a pull from the entrypoint was successful it should exist in the CRDS table - if let Some(entrypoint_from_gossip) = - self.lookup_contact_info_by_gossip_addr(&entrypoint.gossip) - { - // Update the entrypoint's id so future entrypoint pulls correctly reference it - *entrypoint = entrypoint_from_gossip; - } - } - } - // Adopt an entrypoint's `shred_version` if ours is unset - if self.my_shred_version() == 0 { - if let Some(entrypoint) = entrypoints - .iter() - .find(|entrypoint| entrypoint.shred_version != 0) - { - info!( - "Setting shred version to {:?} from entrypoint {:?}", - entrypoint.shred_version, entrypoint.id - ); - self.my_contact_info.write().unwrap().shred_version = entrypoint.shred_version; - } - } - self.my_shred_version() != 0 - && entrypoints - .iter() - .all(|entrypoint| entrypoint.id != Pubkey::default()) - } - - fn handle_purge( - &self, - thread_pool: &ThreadPool, - bank_forks: Option<&RwLock>, - stakes: &HashMap, - ) { - let self_pubkey = self.id(); - let epoch_duration = get_epoch_duration(bank_forks, &self.stats); - let timeouts = self - .gossip - .make_timeouts(self_pubkey, stakes, epoch_duration); - let num_purged = { - let _st = ScopedTimer::from(&self.stats.purge); - self.gossip - .purge(&self_pubkey, thread_pool, timestamp(), &timeouts) - }; - self.stats.purge_count.add_relaxed(num_purged as u64); - } - - // Trims the CRDS table by dropping all values associated with the pubkeys - // with the lowest stake, so that the number of unique pubkeys are bounded. - fn trim_crds_table(&self, cap: usize, stakes: &HashMap) { - if !self.gossip.crds.read().unwrap().should_trim(cap) { - return; - } - let keep: Vec<_> = self - .entrypoints - .read() - .unwrap() - .iter() - .map(|k| k.id) - .chain(std::iter::once(self.id())) - .collect(); - self.stats.trim_crds_table.add_relaxed(1); - let mut gossip_crds = self.gossip.crds.write().unwrap(); - match gossip_crds.trim(cap, &keep, stakes, timestamp()) { - Err(err) => { - self.stats.trim_crds_table_failed.add_relaxed(1); - // TODO: Stakes are comming from the root-bank. Debug why/when - // they are empty/zero. - debug!("crds table trim failed: {:?}", err); - } - Ok(num_purged) => { - self.stats - .trim_crds_table_purged_values_count - .add_relaxed(num_purged as u64); - } - } - } - - /// randomly pick a node and ask them for updates asynchronously - pub fn gossip( - self: Arc, - bank_forks: Option>>, - sender: PacketBatchSender, - gossip_validators: Option>, - exit: Arc, - ) -> JoinHandle<()> { - let thread_pool = ThreadPoolBuilder::new() - .num_threads(std::cmp::min(get_thread_count(), 8)) - .thread_name(|i| format!("solRunGossip{i:02}")) - .build() - .unwrap(); - Builder::new() - .name("solGossip".to_string()) - .spawn(move || { - let mut last_push = 0; - let mut last_contact_info_trace = timestamp(); - let mut last_contact_info_save = timestamp(); - let mut entrypoints_processed = false; - let recycler = PacketBatchRecycler::default(); - let crds_data = vec![ - CrdsData::Version(Version::new(self.id())), - CrdsData::NodeInstance( - self.instance.read().unwrap().with_wallclock(timestamp()), - ), - ]; - for value in crds_data { - let value = CrdsValue::new_signed(value, &self.keypair()); - self.push_message(value); - } - let mut generate_pull_requests = true; - loop { - let start = timestamp(); - if self.contact_debug_interval != 0 - && start - last_contact_info_trace > self.contact_debug_interval - { - // Log contact info - info!( - "\n{}\n\n{}", - self.contact_info_trace(), - self.rpc_info_trace() - ); - last_contact_info_trace = start; - } - - if self.contact_save_interval != 0 - && start - last_contact_info_save > self.contact_save_interval - { - self.save_contact_info(); - last_contact_info_save = start; - } - - let (stakes, _feature_set) = match bank_forks { - Some(ref bank_forks) => { - let root_bank = bank_forks.read().unwrap().root_bank(); - ( - root_bank.staked_nodes(), - Some(root_bank.feature_set.clone()), - ) - } - None => (Arc::default(), None), - }; - let _ = self.run_gossip( - &thread_pool, - gossip_validators.as_ref(), - &recycler, - &stakes, - &sender, - generate_pull_requests, - ); - if exit.load(Ordering::Relaxed) { - return; - } - self.handle_purge(&thread_pool, bank_forks.as_deref(), &stakes); - entrypoints_processed = entrypoints_processed || self.process_entrypoints(); - //TODO: possibly tune this parameter - //we saw a deadlock passing an self.read().unwrap().timeout into sleep - if start - last_push > CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS / 2 { - self.push_self(); - self.refresh_push_active_set( - &recycler, - &stakes, - gossip_validators.as_ref(), - &sender, - ); - last_push = timestamp(); - } - let elapsed = timestamp() - start; - if GOSSIP_SLEEP_MILLIS > elapsed { - let time_left = GOSSIP_SLEEP_MILLIS - elapsed; - sleep(Duration::from_millis(time_left)); - } - generate_pull_requests = !generate_pull_requests; - } - }) - .unwrap() - } - - fn handle_batch_prune_messages(&self, messages: Vec) { - let _st = ScopedTimer::from(&self.stats.handle_batch_prune_messages_time); - if messages.is_empty() { - return; - } - self.stats - .prune_message_count - .add_relaxed(messages.len() as u64); - self.stats - .prune_message_len - .add_relaxed(messages.iter().map(|data| data.prunes.len() as u64).sum()); - let mut prune_message_timeout = 0; - let mut bad_prune_destination = 0; - let self_pubkey = self.id(); - { - let _st = ScopedTimer::from(&self.stats.process_prune); - let now = timestamp(); - for data in messages { - match self.gossip.process_prune_msg( - &self_pubkey, - &data.pubkey, - &data.destination, - &data.prunes, - data.wallclock, - now, - ) { - Err(CrdsGossipError::PruneMessageTimeout) => { - prune_message_timeout += 1; - } - Err(CrdsGossipError::BadPruneDestination) => { - bad_prune_destination += 1; - } - _ => (), - } - } - } - if prune_message_timeout != 0 { - self.stats - .prune_message_timeout - .add_relaxed(prune_message_timeout); - } - if bad_prune_destination != 0 { - self.stats - .bad_prune_destination - .add_relaxed(bad_prune_destination); - } - } - - fn handle_batch_pull_requests( - &self, - // from address, crds filter, caller contact info - requests: Vec<(SocketAddr, CrdsFilter, CrdsValue)>, - thread_pool: &ThreadPool, - recycler: &PacketBatchRecycler, - stakes: &HashMap, - response_sender: &PacketBatchSender, - ) { - let _st = ScopedTimer::from(&self.stats.handle_batch_pull_requests_time); - if requests.is_empty() { - return; - } - let self_pubkey = self.id(); - let requests: Vec<_> = thread_pool.install(|| { - requests - .into_par_iter() - .with_min_len(1024) - .filter(|(_, _, caller)| match caller.contact_info() { - None => false, - Some(caller) if caller.id == self_pubkey => { - warn!("PullRequest ignored, I'm talking to myself"); - self.stats.window_request_loopback.add_relaxed(1); - false - } - Some(_) => true, - }) - .map(|(from_addr, filter, caller)| PullData { - from_addr, - caller, - filter, - }) - .collect() - }); - if !requests.is_empty() { - self.stats - .pull_requests_count - .add_relaxed(requests.len() as u64); - let response = self.handle_pull_requests(thread_pool, recycler, requests, stakes); - if !response.is_empty() { - self.stats - .packets_sent_pull_responses_count - .add_relaxed(response.len() as u64); - let _ = response_sender.send(response); - } - } - } - - fn update_data_budget(&self, num_staked: usize) -> usize { - const INTERVAL_MS: u64 = 100; - // allow 50kBps per staked validator, epoch slots + votes ~= 1.5kB/slot ~= 4kB/s - const BYTES_PER_INTERVAL: usize = 5000; - const MAX_BUDGET_MULTIPLE: usize = 5; // allow budget build-up to 5x the interval default - let num_staked = num_staked.max(2); - self.outbound_budget.update(INTERVAL_MS, |bytes| { - std::cmp::min( - bytes + num_staked * BYTES_PER_INTERVAL, - MAX_BUDGET_MULTIPLE * num_staked * BYTES_PER_INTERVAL, - ) - }) - } - - // Returns a predicate checking if the pull request is from a valid - // address, and if the address have responded to a ping request. Also - // appends ping packets for the addresses which need to be (re)verified. - fn check_pull_request<'a, R>( - &'a self, - now: Instant, - mut rng: &'a mut R, - packet_batch: &'a mut PacketBatch, - ) -> impl FnMut(&PullData) -> bool + 'a - where - R: Rng + CryptoRng, - { - let mut cache = HashMap::<(Pubkey, SocketAddr), bool>::new(); - let mut pingf = move || Ping::new_rand(&mut rng, &self.keypair()).ok(); - let mut ping_cache = self.ping_cache.lock().unwrap(); - let mut hard_check = move |node| { - let (check, ping) = ping_cache.check(now, node, &mut pingf); - if let Some(ping) = ping { - let ping = Protocol::PingMessage(ping); - match Packet::from_data(Some(&node.1), ping) { - Ok(packet) => packet_batch.push(packet), - Err(err) => error!("failed to write ping packet: {:?}", err), - }; - } - if !check { - self.stats - .pull_request_ping_pong_check_failed_count - .add_relaxed(1) - } - check - }; - // Because pull-responses are sent back to packet.meta().socket_addr() of - // incoming pull-requests, pings are also sent to request.from_addr (as - // opposed to caller.gossip address). - move |request| { - ContactInfo::is_valid_address(&request.from_addr, &self.socket_addr_space) && { - let node = (request.caller.pubkey(), request.from_addr); - *cache.entry(node).or_insert_with(|| hard_check(node)) - } - } - } - - // Pull requests take an incoming bloom filter of contained entries from a node - // and tries to send back to them the values it detects are missing. - fn handle_pull_requests( - &self, - thread_pool: &ThreadPool, - recycler: &PacketBatchRecycler, - requests: Vec, - stakes: &HashMap, - ) -> PacketBatch { - const DEFAULT_EPOCH_DURATION_MS: u64 = DEFAULT_SLOTS_PER_EPOCH * DEFAULT_MS_PER_SLOT; - let mut time = Measure::start("handle_pull_requests"); - let callers = crds_value::filter_current(requests.iter().map(|r| &r.caller)); - { - let _st = ScopedTimer::from(&self.stats.process_pull_requests); - self.gossip - .process_pull_requests(callers.cloned(), timestamp()); - } - let output_size_limit = - self.update_data_budget(stakes.len()) / PULL_RESPONSE_MIN_SERIALIZED_SIZE; - let mut packet_batch = - PacketBatch::new_unpinned_with_recycler(recycler.clone(), 64, "handle_pull_requests"); - let (caller_and_filters, addrs): (Vec<_>, Vec<_>) = { - let mut rng = rand::thread_rng(); - let check_pull_request = - self.check_pull_request(Instant::now(), &mut rng, &mut packet_batch); - requests - .into_iter() - .filter(check_pull_request) - .map(|r| ((r.caller, r.filter), r.from_addr)) - .unzip() - }; - let now = timestamp(); - let self_id = self.id(); - let mut pull_responses = { - let _st = ScopedTimer::from(&self.stats.generate_pull_responses); - self.gossip.generate_pull_responses( - thread_pool, - &caller_and_filters, - output_size_limit, - now, - &self.stats, - ) - }; - if self.require_stake_for_gossip(stakes) { - for resp in &mut pull_responses { - retain_staked(resp, stakes); - } - } - let (responses, scores): (Vec<_>, Vec<_>) = addrs - .iter() - .zip(pull_responses) - .flat_map(|(addr, responses)| repeat(addr).zip(responses)) - .map(|(addr, response)| { - let age = now.saturating_sub(response.wallclock()); - let score = DEFAULT_EPOCH_DURATION_MS - .saturating_sub(age) - .div(CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS) - .max(1); - let score = if stakes.contains_key(&response.pubkey()) { - 2 * score - } else { - score - }; - let score = match response.data { - CrdsData::ContactInfo(_) => 2 * score, - _ => score, - }; - ((addr, response), score) - }) - .unzip(); - if responses.is_empty() { - return packet_batch; - } - let mut rng = rand::thread_rng(); - let shuffle = WeightedShuffle::new("handle-pull-requests", &scores).shuffle(&mut rng); - let mut total_bytes = 0; - let mut sent = 0; - for (addr, response) in shuffle.map(|i| &responses[i]) { - let response = vec![response.clone()]; - let response = Protocol::PullResponse(self_id, response); - match Packet::from_data(Some(addr), response) { - Err(err) => error!("failed to write pull-response packet: {:?}", err), - Ok(packet) => { - if self.outbound_budget.take(packet.meta().size) { - total_bytes += packet.meta().size; - packet_batch.push(packet); - sent += 1; - } else { - self.stats.gossip_pull_request_no_budget.add_relaxed(1); - break; - } - } - } - } - time.stop(); - let dropped_responses = responses.len() - sent; - self.stats - .gossip_pull_request_sent_requests - .add_relaxed(sent as u64); - self.stats - .gossip_pull_request_dropped_requests - .add_relaxed(dropped_responses as u64); - debug!( - "handle_pull_requests: {} sent: {} total: {} total_bytes: {}", - time, - sent, - responses.len(), - total_bytes - ); - packet_batch - } - - fn handle_batch_pull_responses( - &self, - responses: Vec<(Pubkey, Vec)>, - thread_pool: &ThreadPool, - stakes: &HashMap, - epoch_duration: Duration, - ) { - let _st = ScopedTimer::from(&self.stats.handle_batch_pull_responses_time); - if responses.is_empty() { - return; - } - fn extend(hash_map: &mut HashMap>, (key, mut value): (K, Vec)) - where - K: Eq + std::hash::Hash, - { - match hash_map.entry(key) { - Entry::Occupied(mut entry) => { - let entry_value = entry.get_mut(); - if entry_value.len() < value.len() { - std::mem::swap(entry_value, &mut value); - } - entry_value.extend(value); - } - Entry::Vacant(entry) => { - entry.insert(value); - } - } - } - fn merge( - mut hash_map: HashMap>, - other: HashMap>, - ) -> HashMap> - where - K: Eq + std::hash::Hash, - { - if hash_map.len() < other.len() { - return merge(other, hash_map); - } - for kv in other { - extend(&mut hash_map, kv); - } - hash_map - } - let responses = thread_pool.install(|| { - responses - .into_par_iter() - .with_min_len(1024) - .fold(HashMap::new, |mut hash_map, kv| { - extend(&mut hash_map, kv); - hash_map - }) - .reduce(HashMap::new, merge) - }); - if !responses.is_empty() { - let self_pubkey = self.id(); - let timeouts = self - .gossip - .make_timeouts(self_pubkey, stakes, epoch_duration); - for (from, data) in responses { - self.handle_pull_response(&from, data, &timeouts); - } - } - } - - // Returns (failed, timeout, success) - fn handle_pull_response( - &self, - from: &Pubkey, - crds_values: Vec, - timeouts: &HashMap, - ) -> (usize, usize, usize) { - let len = crds_values.len(); - trace!("PullResponse me: {} from: {} len={}", self.id(), from, len); - let mut pull_stats = ProcessPullStats::default(); - let (filtered_pulls, filtered_pulls_expired_timeout, failed_inserts) = { - let _st = ScopedTimer::from(&self.stats.filter_pull_response); - self.gossip - .filter_pull_responses(timeouts, crds_values, timestamp(), &mut pull_stats) - }; - if !filtered_pulls.is_empty() - || !filtered_pulls_expired_timeout.is_empty() - || !failed_inserts.is_empty() - { - let _st = ScopedTimer::from(&self.stats.process_pull_response); - self.gossip.process_pull_responses( - from, - filtered_pulls, - filtered_pulls_expired_timeout, - failed_inserts, - timestamp(), - &mut pull_stats, - ); - } - self.stats.process_pull_response_count.add_relaxed(1); - self.stats.process_pull_response_len.add_relaxed(len as u64); - self.stats - .process_pull_response_timeout - .add_relaxed(pull_stats.timeout_count as u64); - self.stats - .process_pull_response_fail_insert - .add_relaxed(pull_stats.failed_insert as u64); - self.stats - .process_pull_response_fail_timeout - .add_relaxed(pull_stats.failed_timeout as u64); - self.stats - .process_pull_response_success - .add_relaxed(pull_stats.success as u64); - - ( - pull_stats.failed_insert + pull_stats.failed_timeout, - pull_stats.timeout_count, - pull_stats.success, - ) - } - - fn handle_batch_ping_messages( - &self, - pings: I, - recycler: &PacketBatchRecycler, - response_sender: &PacketBatchSender, - ) where - I: IntoIterator, - { - let _st = ScopedTimer::from(&self.stats.handle_batch_ping_messages_time); - if let Some(response) = self.handle_ping_messages(pings, recycler) { - let _ = response_sender.send(response); - } - } - - fn handle_ping_messages( - &self, - pings: I, - recycler: &PacketBatchRecycler, - ) -> Option - where - I: IntoIterator, - { - let keypair = self.keypair(); - let pongs_and_dests: Vec<_> = pings - .into_iter() - .filter_map(|(addr, ping)| { - let pong = Pong::new(&ping, &keypair).ok()?; - let pong = Protocol::PongMessage(pong); - Some((addr, pong)) - }) - .collect(); - if pongs_and_dests.is_empty() { - None - } else { - let packet_batch = PacketBatch::new_unpinned_with_recycler_data_and_dests( - recycler.clone(), - "handle_ping_messages", - &pongs_and_dests, - ); - Some(packet_batch) - } - } - - fn handle_batch_pong_messages(&self, pongs: I, now: Instant) - where - I: IntoIterator, - { - let _st = ScopedTimer::from(&self.stats.handle_batch_pong_messages_time); - let mut pongs = pongs.into_iter().peekable(); - if pongs.peek().is_some() { - let mut ping_cache = self.ping_cache.lock().unwrap(); - for (addr, pong) in pongs { - ping_cache.add(&pong, addr, now); - } - } - } - - #[allow(clippy::needless_collect)] - fn handle_batch_push_messages( - &self, - messages: Vec<(Pubkey, Vec)>, - thread_pool: &ThreadPool, - recycler: &PacketBatchRecycler, - stakes: &HashMap, - response_sender: &PacketBatchSender, - ) { - let _st = ScopedTimer::from(&self.stats.handle_batch_push_messages_time); - if messages.is_empty() { - return; - } - self.stats - .push_message_count - .add_relaxed(messages.len() as u64); - let num_crds_values: u64 = messages.iter().map(|(_, data)| data.len() as u64).sum(); - self.stats - .push_message_value_count - .add_relaxed(num_crds_values); - // Origins' pubkeys of upserted crds values. - let origins: HashSet<_> = { - let _st = ScopedTimer::from(&self.stats.process_push_message); - let now = timestamp(); - self.gossip.process_push_message(messages, now) - }; - // Generate prune messages. - let self_pubkey = self.id(); - let prunes = { - let _st = ScopedTimer::from(&self.stats.prune_received_cache); - self.gossip - .prune_received_cache(&self_pubkey, origins, stakes) - }; - let prunes: Vec<(Pubkey /*from*/, Vec /*origins*/)> = prunes - .into_iter() - .flat_map(|(from, prunes)| { - repeat(from).zip( - prunes - .into_iter() - .chunks(MAX_PRUNE_DATA_NODES) - .into_iter() - .map(Iterator::collect) - .collect::>(), - ) - }) - .collect(); - - let prune_messages: Vec<_> = { - let gossip_crds = self.gossip.crds.read().unwrap(); - let wallclock = timestamp(); - thread_pool.install(|| { - prunes - .into_par_iter() - .with_min_len(256) - .filter_map(|(from, prunes)| { - let peer: &ContactInfo = gossip_crds.get(from)?; - let mut prune_data = PruneData { - pubkey: self_pubkey, - prunes, - signature: Signature::default(), - destination: from, - wallclock, - }; - prune_data.sign(&self.keypair()); - let prune_message = Protocol::PruneMessage(self_pubkey, prune_data); - Some((peer.gossip, prune_message)) - }) - .collect() - }) - }; - if prune_messages.is_empty() { - return; - } - let mut packet_batch = PacketBatch::new_unpinned_with_recycler_data_and_dests( - recycler.clone(), - "handle_batch_push_messages", - &prune_messages, - ); - let num_prune_packets = packet_batch.len(); - self.stats - .push_response_count - .add_relaxed(packet_batch.len() as u64); - let new_push_requests = self.new_push_requests(stakes); - self.stats - .push_message_pushes - .add_relaxed(new_push_requests.len() as u64); - for (address, request) in new_push_requests { - if ContactInfo::is_valid_address(&address, &self.socket_addr_space) { - match Packet::from_data(Some(&address), &request) { - Ok(packet) => packet_batch.push(packet), - Err(err) => error!("failed to write push-request packet: {:?}", err), - } - } else { - trace!("Dropping Gossip push response, as destination is unknown"); - } - } - self.stats - .packets_sent_prune_messages_count - .add_relaxed(num_prune_packets as u64); - self.stats - .packets_sent_push_messages_count - .add_relaxed((packet_batch.len() - num_prune_packets) as u64); - let _ = response_sender.send(packet_batch); - } - - fn require_stake_for_gossip(&self, stakes: &HashMap) -> bool { - if stakes.len() < MIN_NUM_STAKED_NODES { - self.stats - .require_stake_for_gossip_unknown_stakes - .add_relaxed(1); - false - } else { - true - } - } - - fn process_packets( - &self, - packets: VecDeque<(/*from:*/ SocketAddr, Protocol)>, - thread_pool: &ThreadPool, - recycler: &PacketBatchRecycler, - response_sender: &PacketBatchSender, - stakes: &HashMap, - _feature_set: Option<&FeatureSet>, - epoch_duration: Duration, - should_check_duplicate_instance: bool, - ) -> Result<(), GossipError> { - let _st = ScopedTimer::from(&self.stats.process_gossip_packets_time); - // Filter out values if the shred-versions are different. - let self_shred_version = self.my_shred_version(); - let packets = if self_shred_version == 0 { - packets - } else { - let gossip_crds = self.gossip.crds.read().unwrap(); - thread_pool.install(|| { - packets - .into_par_iter() - .with_min_len(1024) - .filter_map(|(from, msg)| { - let msg = filter_on_shred_version( - msg, - self_shred_version, - &gossip_crds, - &self.stats, - )?; - Some((from, msg)) - }) - .collect() - }) - }; - - // Check if there is a duplicate instance of - // this node with more recent timestamp. - let instance = self.instance.read().unwrap(); - let check_duplicate_instance = |values: &[CrdsValue]| { - if should_check_duplicate_instance { - for value in values { - if instance.check_duplicate(value) { - return Err(GossipError::DuplicateNodeInstance); - } - } - } - Ok(()) - }; - // Split packets based on their types. - let mut pull_requests = vec![]; - let mut pull_responses = vec![]; - let mut push_messages = vec![]; - let mut prune_messages = vec![]; - let mut ping_messages = vec![]; - let mut pong_messages = vec![]; - for (from_addr, packet) in packets { - match packet { - Protocol::PullRequest(filter, caller) => { - pull_requests.push((from_addr, filter, caller)) - } - Protocol::PullResponse(from, data) => { - check_duplicate_instance(&data)?; - pull_responses.push((from, data)); - } - Protocol::PushMessage(from, data) => { - check_duplicate_instance(&data)?; - push_messages.push((from, data)); - } - Protocol::PruneMessage(_from, data) => prune_messages.push(data), - Protocol::PingMessage(ping) => ping_messages.push((from_addr, ping)), - Protocol::PongMessage(pong) => pong_messages.push((from_addr, pong)), - } - } - if self.require_stake_for_gossip(stakes) { - for (_, data) in &mut pull_responses { - retain_staked(data, stakes); - } - for (_, data) in &mut push_messages { - retain_staked(data, stakes); - } - pull_responses.retain(|(_, data)| !data.is_empty()); - push_messages.retain(|(_, data)| !data.is_empty()); - } - self.handle_batch_ping_messages(ping_messages, recycler, response_sender); - self.handle_batch_prune_messages(prune_messages); - self.handle_batch_push_messages( - push_messages, - thread_pool, - recycler, - stakes, - response_sender, - ); - self.handle_batch_pull_responses(pull_responses, thread_pool, stakes, epoch_duration); - self.trim_crds_table(CRDS_UNIQUE_PUBKEY_CAPACITY, stakes); - self.handle_batch_pong_messages(pong_messages, Instant::now()); - self.handle_batch_pull_requests( - pull_requests, - thread_pool, - recycler, - stakes, - response_sender, - ); - self.stats - .process_gossip_packets_iterations_since_last_report - .add_relaxed(1); - Ok(()) - } - - // Consumes packets received from the socket, deserializing, sanitizing and - // verifying them and then sending them down the channel for the actual - // handling of requests/messages. - fn run_socket_consume( - &self, - receiver: &PacketBatchReceiver, - sender: &Sender>, - thread_pool: &ThreadPool, - ) -> Result<(), GossipError> { - const RECV_TIMEOUT: Duration = Duration::from_secs(1); - fn count_packets_received(packets: &PacketBatch, counts: &mut [u64; 7]) { - for packet in packets { - let k = match packet - .data(..4) - .and_then(|data| <[u8; 4]>::try_from(data).ok()) - .map(u32::from_le_bytes) - { - Some(k @ 0..=6) => k as usize, - None | Some(_) => 6, - }; - counts[k] += 1; - } - } - let packets = receiver.recv_timeout(RECV_TIMEOUT)?; - let mut counts = [0u64; 7]; - count_packets_received(&packets, &mut counts); - let packets = Vec::from(packets); - let mut packets = VecDeque::from(packets); - for packet_batch in receiver.try_iter() { - count_packets_received(&packet_batch, &mut counts); - packets.extend(packet_batch.iter().cloned()); - let excess_count = packets.len().saturating_sub(MAX_GOSSIP_TRAFFIC); - if excess_count > 0 { - packets.drain(0..excess_count); - self.stats - .gossip_packets_dropped_count - .add_relaxed(excess_count as u64); - } - } - let verify_packet = |packet: Packet| { - let protocol: Protocol = packet.deserialize_slice(..).ok()?; - protocol.sanitize().ok()?; - let protocol = protocol.par_verify(&self.stats)?; - Some((packet.meta().socket_addr(), protocol)) - }; - let packets: Vec<_> = { - let _st = ScopedTimer::from(&self.stats.verify_gossip_packets_time); - thread_pool.install(|| packets.into_par_iter().filter_map(verify_packet).collect()) - }; - self.stats - .packets_received_count - .add_relaxed(counts.iter().sum::()); - self.stats - .packets_received_pull_requests_count - .add_relaxed(counts[0]); - self.stats - .packets_received_pull_responses_count - .add_relaxed(counts[1]); - self.stats - .packets_received_push_messages_count - .add_relaxed(counts[2]); - self.stats - .packets_received_prune_messages_count - .add_relaxed(counts[3]); - self.stats - .packets_received_ping_messages_count - .add_relaxed(counts[4]); - self.stats - .packets_received_pong_messages_count - .add_relaxed(counts[5]); - self.stats - .packets_received_unknown_count - .add_relaxed(counts[6]); - self.stats - .packets_received_verified_count - .add_relaxed(packets.len() as u64); - Ok(sender.send(packets)?) - } - - /// Process messages from the network - fn run_listen( - &self, - recycler: &PacketBatchRecycler, - bank_forks: Option<&RwLock>, - receiver: &Receiver>, - response_sender: &PacketBatchSender, - thread_pool: &ThreadPool, - last_print: &mut Instant, - should_check_duplicate_instance: bool, - ) -> Result<(), GossipError> { - let _st = ScopedTimer::from(&self.stats.gossip_listen_loop_time); - const RECV_TIMEOUT: Duration = Duration::from_secs(1); - const SUBMIT_GOSSIP_STATS_INTERVAL: Duration = Duration::from_secs(2); - let mut packets = VecDeque::from(receiver.recv_timeout(RECV_TIMEOUT)?); - for payload in receiver.try_iter() { - packets.extend(payload); - let excess_count = packets.len().saturating_sub(MAX_GOSSIP_TRAFFIC); - if excess_count > 0 { - packets.drain(0..excess_count); - self.stats - .gossip_packets_dropped_count - .add_relaxed(excess_count as u64); - } - } - // Using root_bank instead of working_bank here so that an enbaled - // feature does not roll back (if the feature happens to get enabled in - // a minority fork). - let (feature_set, stakes) = match bank_forks { - None => (None, Arc::default()), - Some(bank_forks) => { - let bank = bank_forks.read().unwrap().root_bank(); - let feature_set = bank.feature_set.clone(); - (Some(feature_set), bank.staked_nodes()) - } - }; - self.process_packets( - packets, - thread_pool, - recycler, - response_sender, - &stakes, - feature_set.as_deref(), - get_epoch_duration(bank_forks, &self.stats), - should_check_duplicate_instance, - )?; - if last_print.elapsed() > SUBMIT_GOSSIP_STATS_INTERVAL { - submit_gossip_stats(&self.stats, &self.gossip, &stakes); - *last_print = Instant::now(); - } - self.stats - .gossip_listen_loop_iterations_since_last_report - .add_relaxed(1); - Ok(()) - } - - pub(crate) fn start_socket_consume_thread( - self: Arc, - receiver: PacketBatchReceiver, - sender: Sender>, - exit: Arc, - ) -> JoinHandle<()> { - let thread_pool = ThreadPoolBuilder::new() - .num_threads(get_thread_count().min(8)) - .thread_name(|i| format!("solGossipCons{i:02}")) - .build() - .unwrap(); - let run_consume = move || { - while !exit.load(Ordering::Relaxed) { - match self.run_socket_consume(&receiver, &sender, &thread_pool) { - Err(GossipError::RecvTimeoutError(RecvTimeoutError::Disconnected)) => break, - Err(GossipError::RecvTimeoutError(RecvTimeoutError::Timeout)) => (), - // A send operation can only fail if the receiving end of a - // channel is disconnected. - Err(GossipError::SendError) => break, - Err(err) => error!("gossip consume: {}", err), - Ok(()) => (), - } - } - }; - let thread_name = String::from("solGossipConsum"); - Builder::new().name(thread_name).spawn(run_consume).unwrap() - } - - pub(crate) fn listen( - self: Arc, - bank_forks: Option>>, - requests_receiver: Receiver>, - response_sender: PacketBatchSender, - should_check_duplicate_instance: bool, - exit: Arc, - ) -> JoinHandle<()> { - let mut last_print = Instant::now(); - let recycler = PacketBatchRecycler::default(); - let thread_pool = ThreadPoolBuilder::new() - .num_threads(get_thread_count().min(8)) - .thread_name(|i| format!("solGossipWork{i:02}")) - .build() - .unwrap(); - Builder::new() - .name("solGossipListen".to_string()) - .spawn(move || { - while !exit.load(Ordering::Relaxed) { - if let Err(err) = self.run_listen( - &recycler, - bank_forks.as_deref(), - &requests_receiver, - &response_sender, - &thread_pool, - &mut last_print, - should_check_duplicate_instance, - ) { - match err { - GossipError::RecvTimeoutError(RecvTimeoutError::Disconnected) => break, - GossipError::RecvTimeoutError(RecvTimeoutError::Timeout) => { - let table_size = self.gossip.crds.read().unwrap().len(); - debug!( - "{}: run_listen timeout, table size: {}", - self.id(), - table_size, - ); - } - GossipError::DuplicateNodeInstance => { - error!( - "duplicate running instances of the same validator node: {}", - self.id() - ); - exit.store(true, Ordering::Relaxed); - // TODO: Pass through Exit here so - // that this will exit cleanly. - std::process::exit(1); - } - _ => error!("gossip run_listen failed: {}", err), - } - } - } - }) - .unwrap() - } - - pub fn gossip_contact_info(id: Pubkey, gossip: SocketAddr, shred_version: u16) -> ContactInfo { - ContactInfo { - id, - gossip, - wallclock: timestamp(), - shred_version, - ..ContactInfo::default() - } - } - - /// An alternative to Spy Node that has a valid gossip address and fully participate in Gossip. - pub fn gossip_node( - id: Pubkey, - gossip_addr: &SocketAddr, - shred_version: u16, - ) -> (ContactInfo, UdpSocket, Option) { - let bind_ip_addr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); - let (port, (gossip_socket, ip_echo)) = - Node::get_gossip_port(gossip_addr, VALIDATOR_PORT_RANGE, bind_ip_addr); - let contact_info = - Self::gossip_contact_info(id, SocketAddr::new(gossip_addr.ip(), port), shred_version); - - (contact_info, gossip_socket, Some(ip_echo)) - } - - /// A Node with dummy ports to spy on gossip via pull requests - pub fn spy_node( - id: Pubkey, - shred_version: u16, - ) -> (ContactInfo, UdpSocket, Option) { - let bind_ip_addr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); - let (_, gossip_socket) = bind_in_range(bind_ip_addr, VALIDATOR_PORT_RANGE).unwrap(); - let contact_info = Self::gossip_contact_info(id, socketaddr_any!(), shred_version); - - (contact_info, gossip_socket, None) - } -} - -// Returns root bank's epoch duration. Falls back on -// DEFAULT_SLOTS_PER_EPOCH * DEFAULT_MS_PER_SLOT -// if there are no working banks. -fn get_epoch_duration(bank_forks: Option<&RwLock>, stats: &GossipStats) -> Duration { - let num_slots = match bank_forks { - None => { - stats.get_epoch_duration_no_working_bank.add_relaxed(1); - DEFAULT_SLOTS_PER_EPOCH - } - Some(bank_forks) => { - let bank = bank_forks.read().unwrap().root_bank(); - bank.get_slots_in_epoch(bank.epoch()) - } - }; - Duration::from_millis(num_slots * DEFAULT_MS_PER_SLOT) -} - -/// Turbine logic -/// 1 - For the current node find out if it is in layer 1 -/// 1.1 - If yes, then broadcast to all layer 1 nodes -/// 1 - using the layer 1 index, broadcast to all layer 2 nodes assuming you know neighborhood size -/// 1.2 - If no, then figure out what layer the node is in and who the neighbors are and only broadcast to them -/// 1 - also check if there are nodes in the next layer and repeat the layer 1 to layer 2 logic - -/// Returns Neighbor Nodes and Children Nodes `(neighbors, children)` for a given node based on its stake -pub fn compute_retransmit_peers( - fanout: usize, - index: usize, // Local node's index withing the nodes slice. - nodes: &[T], -) -> (Vec /*neighbors*/, Vec /*children*/) { - // 1st layer: fanout nodes starting at 0 - // 2nd layer: fanout**2 nodes starting at fanout - // 3rd layer: fanout**3 nodes starting at fanout + fanout**2 - // ... - // Each layer is divided into neighborhoods of fanout nodes each. - let offset = index % fanout; // Node's index within its neighborhood. - let anchor = index - offset; // First node in the neighborhood. - let neighbors = (anchor..) - .take(fanout) - .map(|i| nodes.get(i).copied()) - .while_some() - .collect(); - let children = ((anchor + 1) * fanout + offset..) - .step_by(fanout) - .take(fanout) - .map(|i| nodes.get(i).copied()) - .while_some() - .collect(); - (neighbors, children) -} - -#[derive(Debug)] -pub struct Sockets { - pub gossip: UdpSocket, - pub ip_echo: Option, - pub tvu: Vec, - pub tvu_forwards: Vec, - pub tpu: Vec, - pub tpu_forwards: Vec, - pub tpu_vote: Vec, - pub broadcast: Vec, - pub repair: UdpSocket, - pub retransmit_sockets: Vec, - pub serve_repair: UdpSocket, - pub ancestor_hashes_requests: UdpSocket, - pub tpu_quic: UdpSocket, - pub tpu_forwards_quic: UdpSocket, -} - -#[derive(Debug)] -pub struct Node { - pub info: ContactInfo, - pub sockets: Sockets, -} - -impl Node { - pub fn new_localhost() -> Self { - let pubkey = solana_sdk::pubkey::new_rand(); - Self::new_localhost_with_pubkey(&pubkey) - } - pub fn new_localhost_with_pubkey(pubkey: &Pubkey) -> Self { - let bind_ip_addr = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); - let port_range = (1024, 65535); - let ((_tpu_port, tpu), (_tpu_quic_port, tpu_quic)) = - bind_two_in_range_with_offset(bind_ip_addr, port_range, QUIC_PORT_OFFSET).unwrap(); - let (gossip_port, (gossip, ip_echo)) = - bind_common_in_range(bind_ip_addr, port_range).unwrap(); - let gossip_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), gossip_port); - let tvu = UdpSocket::bind("127.0.0.1:0").unwrap(); - let tvu_forwards = UdpSocket::bind("127.0.0.1:0").unwrap(); - let ((_tpu_forwards_port, tpu_forwards), (_tpu_forwards_quic_port, tpu_forwards_quic)) = - bind_two_in_range_with_offset(bind_ip_addr, port_range, QUIC_PORT_OFFSET).unwrap(); - let tpu_vote = UdpSocket::bind("127.0.0.1:0").unwrap(); - let repair = UdpSocket::bind("127.0.0.1:0").unwrap(); - let rpc_port = find_available_port_in_range(bind_ip_addr, port_range).unwrap(); - let rpc_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), rpc_port); - let rpc_pubsub_port = find_available_port_in_range(bind_ip_addr, port_range).unwrap(); - let rpc_pubsub_addr = - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), rpc_pubsub_port); - - let broadcast = vec![UdpSocket::bind("0.0.0.0:0").unwrap()]; - let retransmit_socket = UdpSocket::bind("0.0.0.0:0").unwrap(); - let serve_repair = UdpSocket::bind("127.0.0.1:0").unwrap(); - let ancestor_hashes_requests = UdpSocket::bind("0.0.0.0:0").unwrap(); - - let info = ContactInfo { - id: *pubkey, - gossip: gossip_addr, - tvu: tvu.local_addr().unwrap(), - tvu_forwards: tvu_forwards.local_addr().unwrap(), - repair: repair.local_addr().unwrap(), - tpu: tpu.local_addr().unwrap(), - tpu_forwards: tpu_forwards.local_addr().unwrap(), - tpu_vote: tpu_vote.local_addr().unwrap(), - rpc: rpc_addr, - rpc_pubsub: rpc_pubsub_addr, - serve_repair: serve_repair.local_addr().unwrap(), - wallclock: timestamp(), - shred_version: 0, - }; - Node { - info, - sockets: Sockets { - gossip, - ip_echo: Some(ip_echo), - tvu: vec![tvu], - tvu_forwards: vec![tvu_forwards], - tpu: vec![tpu], - tpu_forwards: vec![tpu_forwards], - tpu_vote: vec![tpu_vote], - broadcast, - repair, - retransmit_sockets: vec![retransmit_socket], - serve_repair, - ancestor_hashes_requests, - tpu_quic, - tpu_forwards_quic, - }, - } - } - - fn get_gossip_port( - gossip_addr: &SocketAddr, - port_range: PortRange, - bind_ip_addr: IpAddr, - ) -> (u16, (UdpSocket, TcpListener)) { - if gossip_addr.port() != 0 { - ( - gossip_addr.port(), - bind_common(bind_ip_addr, gossip_addr.port(), false).unwrap_or_else(|e| { - panic!("gossip_addr bind_to port {}: {}", gossip_addr.port(), e) - }), - ) - } else { - bind_common_in_range(bind_ip_addr, port_range).expect("Failed to bind") - } - } - fn bind(bind_ip_addr: IpAddr, port_range: PortRange) -> (u16, UdpSocket) { - bind_in_range(bind_ip_addr, port_range).expect("Failed to bind") - } - - pub fn new_single_bind( - pubkey: &Pubkey, - gossip_addr: &SocketAddr, - port_range: PortRange, - bind_ip_addr: IpAddr, - ) -> Self { - let (gossip_port, (gossip, ip_echo)) = - Self::get_gossip_port(gossip_addr, port_range, bind_ip_addr); - let (tvu_port, tvu) = Self::bind(bind_ip_addr, port_range); - let (tvu_forwards_port, tvu_forwards) = Self::bind(bind_ip_addr, port_range); - let ((tpu_port, tpu), (_tpu_quic_port, tpu_quic)) = - bind_two_in_range_with_offset(bind_ip_addr, port_range, QUIC_PORT_OFFSET).unwrap(); - let ((tpu_forwards_port, tpu_forwards), (_tpu_forwards_quic_port, tpu_forwards_quic)) = - bind_two_in_range_with_offset(bind_ip_addr, port_range, QUIC_PORT_OFFSET).unwrap(); - let (tpu_vote_port, tpu_vote) = Self::bind(bind_ip_addr, port_range); - let (_, retransmit_socket) = Self::bind(bind_ip_addr, port_range); - let (repair_port, repair) = Self::bind(bind_ip_addr, port_range); - let (serve_repair_port, serve_repair) = Self::bind(bind_ip_addr, port_range); - let (_, broadcast) = Self::bind(bind_ip_addr, port_range); - let (_, ancestor_hashes_requests) = Self::bind(bind_ip_addr, port_range); - - let rpc_port = find_available_port_in_range(bind_ip_addr, port_range).unwrap(); - let rpc_pubsub_port = find_available_port_in_range(bind_ip_addr, port_range).unwrap(); - - let info = ContactInfo { - id: *pubkey, - gossip: SocketAddr::new(gossip_addr.ip(), gossip_port), - tvu: SocketAddr::new(gossip_addr.ip(), tvu_port), - tvu_forwards: SocketAddr::new(gossip_addr.ip(), tvu_forwards_port), - repair: SocketAddr::new(gossip_addr.ip(), repair_port), - tpu: SocketAddr::new(gossip_addr.ip(), tpu_port), - tpu_forwards: SocketAddr::new(gossip_addr.ip(), tpu_forwards_port), - tpu_vote: SocketAddr::new(gossip_addr.ip(), tpu_vote_port), - rpc: SocketAddr::new(gossip_addr.ip(), rpc_port), - rpc_pubsub: SocketAddr::new(gossip_addr.ip(), rpc_pubsub_port), - serve_repair: SocketAddr::new(gossip_addr.ip(), serve_repair_port), - wallclock: timestamp(), - shred_version: 0, - }; - trace!("new ContactInfo: {:?}", info); - - Node { - info, - sockets: Sockets { - gossip, - ip_echo: Some(ip_echo), - tvu: vec![tvu], - tvu_forwards: vec![tvu_forwards], - tpu: vec![tpu], - tpu_forwards: vec![tpu_forwards], - tpu_vote: vec![tpu_vote], - broadcast: vec![broadcast], - repair, - retransmit_sockets: vec![retransmit_socket], - serve_repair, - ancestor_hashes_requests, - tpu_quic, - tpu_forwards_quic, - }, - } - } - - pub fn new_with_external_ip( - pubkey: &Pubkey, - gossip_addr: &SocketAddr, - port_range: PortRange, - bind_ip_addr: IpAddr, - overwrite_tpu_addr: Option, - ) -> Node { - let (gossip_port, (gossip, ip_echo)) = - Self::get_gossip_port(gossip_addr, port_range, bind_ip_addr); - - let (tvu_port, tvu_sockets) = - multi_bind_in_range(bind_ip_addr, port_range, 8).expect("tvu multi_bind"); - - let (tvu_forwards_port, tvu_forwards_sockets) = - multi_bind_in_range(bind_ip_addr, port_range, 8).expect("tvu_forwards multi_bind"); - - let (tpu_port, tpu_sockets) = - multi_bind_in_range(bind_ip_addr, port_range, 32).expect("tpu multi_bind"); - - let (_tpu_port_quic, tpu_quic) = Self::bind( - bind_ip_addr, - (tpu_port + QUIC_PORT_OFFSET, tpu_port + QUIC_PORT_OFFSET + 1), - ); - - let (tpu_forwards_port, tpu_forwards_sockets) = - multi_bind_in_range(bind_ip_addr, port_range, 8).expect("tpu_forwards multi_bind"); - - let (_tpu_forwards_port_quic, tpu_forwards_quic) = Self::bind( - bind_ip_addr, - ( - tpu_forwards_port + QUIC_PORT_OFFSET, - tpu_forwards_port + QUIC_PORT_OFFSET + 1, - ), - ); - - let (tpu_vote_port, tpu_vote_sockets) = - multi_bind_in_range(bind_ip_addr, port_range, 1).expect("tpu_vote multi_bind"); - - let (_, retransmit_sockets) = - multi_bind_in_range(bind_ip_addr, port_range, 8).expect("retransmit multi_bind"); - - let (repair_port, repair) = Self::bind(bind_ip_addr, port_range); - let (serve_repair_port, serve_repair) = Self::bind(bind_ip_addr, port_range); - - let (_, broadcast) = - multi_bind_in_range(bind_ip_addr, port_range, 4).expect("broadcast multi_bind"); - - let (_, ancestor_hashes_requests) = Self::bind(bind_ip_addr, port_range); - - let info = ContactInfo { - id: *pubkey, - gossip: SocketAddr::new(gossip_addr.ip(), gossip_port), - tvu: SocketAddr::new(gossip_addr.ip(), tvu_port), - tvu_forwards: SocketAddr::new(gossip_addr.ip(), tvu_forwards_port), - repair: SocketAddr::new(gossip_addr.ip(), repair_port), - tpu: overwrite_tpu_addr.unwrap_or_else(|| SocketAddr::new(gossip_addr.ip(), tpu_port)), - tpu_forwards: SocketAddr::new(gossip_addr.ip(), tpu_forwards_port), - tpu_vote: SocketAddr::new(gossip_addr.ip(), tpu_vote_port), - rpc: socketaddr_any!(), - rpc_pubsub: socketaddr_any!(), - serve_repair: SocketAddr::new(gossip_addr.ip(), serve_repair_port), - wallclock: 0, - shred_version: 0, - }; - trace!("new ContactInfo: {:?}", info); - - Node { - info, - sockets: Sockets { - gossip, - tvu: tvu_sockets, - tvu_forwards: tvu_forwards_sockets, - tpu: tpu_sockets, - tpu_forwards: tpu_forwards_sockets, - tpu_vote: tpu_vote_sockets, - broadcast, - repair, - retransmit_sockets, - serve_repair, - ip_echo: Some(ip_echo), - ancestor_hashes_requests, - tpu_quic, - tpu_forwards_quic, - }, - } - } -} - -pub fn push_messages_to_peer( - messages: Vec, - self_id: Pubkey, - peer_gossip: SocketAddr, - socket_addr_space: &SocketAddrSpace, -) -> Result<(), GossipError> { - let reqs: Vec<_> = ClusterInfo::split_gossip_messages(PUSH_MESSAGE_MAX_PAYLOAD_SIZE, messages) - .map(move |payload| (peer_gossip, Protocol::PushMessage(self_id, payload))) - .collect(); - let packet_batch = PacketBatch::new_unpinned_with_recycler_data_and_dests( - PacketBatchRecycler::default(), - "push_messages_to_peer", - &reqs, - ); - let sock = UdpSocket::bind("0.0.0.0:0").unwrap(); - packet::send_to(&packet_batch, &sock, socket_addr_space)?; - Ok(()) -} - -// Filters out values from nodes with different shred-version. -fn filter_on_shred_version( - mut msg: Protocol, - self_shred_version: u16, - crds: &Crds, - stats: &GossipStats, -) -> Option { - let filter_values = |from: &Pubkey, values: &mut Vec, skipped_counter: &Counter| { - let num_values = values.len(); - // Node-instances are always exempted from shred-version check so that: - // * their propagation across cluster is expedited. - // * prevent two running instances of the same identity key cross - // contaminate gossip between clusters. - if crds.get_shred_version(from) == Some(self_shred_version) { - values.retain(|value| match &value.data { - // Allow contact-infos so that shred-versions are updated. - CrdsData::ContactInfo(_) => true, - CrdsData::NodeInstance(_) => true, - // Only retain values with the same shred version. - _ => crds.get_shred_version(&value.pubkey()) == Some(self_shred_version), - }) - } else { - values.retain(|value| match &value.data { - // Allow node to update its own contact info in case their - // shred-version changes - CrdsData::ContactInfo(node) => node.id == *from, - CrdsData::NodeInstance(_) => true, - _ => false, - }) - } - let num_skipped = num_values - values.len(); - if num_skipped != 0 { - skipped_counter.add_relaxed(num_skipped as u64); - } - }; - match &mut msg { - Protocol::PullRequest(_, caller) => match &caller.data { - // Allow spy nodes with shred-verion == 0 to pull from other nodes. - CrdsData::ContactInfo(node) - if node.shred_version == 0 || node.shred_version == self_shred_version => - { - Some(msg) - } - _ => { - stats.skip_pull_shred_version.add_relaxed(1); - None - } - }, - Protocol::PullResponse(from, values) => { - filter_values(from, values, &stats.skip_pull_response_shred_version); - if values.is_empty() { - None - } else { - Some(msg) - } - } - Protocol::PushMessage(from, values) => { - filter_values(from, values, &stats.skip_push_message_shred_version); - if values.is_empty() { - None - } else { - Some(msg) - } - } - Protocol::PruneMessage(_, _) | Protocol::PingMessage(_) | Protocol::PongMessage(_) => { - Some(msg) - } - } -} - -// #[cfg(test)] -// mod tests { -// use { -// super::*, -// crate::{ -// crds_gossip_pull::tests::MIN_NUM_BLOOM_FILTERS, -// crds_value::{CrdsValue, CrdsValueLabel, Vote as CrdsVote}, -// duplicate_shred::{self, tests::new_rand_shred, MAX_DUPLICATE_SHREDS}, -// }, -// itertools::izip, -// rand::{seq::SliceRandom, SeedableRng}, -// rand_chacha::ChaChaRng, -// regex::Regex, -// solana_ledger::shred::Shredder, -// solana_net_utils::MINIMUM_VALIDATOR_PORT_RANGE_WIDTH, -// solana_sdk::signature::{Keypair, Signer}, -// solana_vote_program::{vote_instruction, vote_state::Vote}, -// std::{ -// iter::repeat_with, -// net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4}, -// sync::Arc, -// }, -// }; - -// #[test] -// fn test_gossip_node() { -// //check that a gossip nodes always show up as spies -// let (node, _, _) = ClusterInfo::spy_node(solana_sdk::pubkey::new_rand(), 0); -// assert!(ClusterInfo::is_spy_node( -// &node, -// &SocketAddrSpace::Unspecified -// )); -// let (node, _, _) = ClusterInfo::gossip_node( -// solana_sdk::pubkey::new_rand(), -// &"1.1.1.1:1111".parse().unwrap(), -// 0, -// ); -// assert!(ClusterInfo::is_spy_node( -// &node, -// &SocketAddrSpace::Unspecified -// )); -// } - -// #[test] -// fn test_cluster_info_trace() { -// solana_logger::setup(); -// let keypair = Keypair::from_base58_string("3jATNWfbii1btv6nCpToAXAJz6a4km5HsLSWiwLfNvHNQAmvksLFVAKGUz286bXb9N4ivXx8nuwkn91PFDTyoFEp"); - -// let node = { -// let tpu = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8900); -// let _tpu_quic = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8901); - -// let gossip = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8888); -// let tvu = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8902); -// let tvu_forwards = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8903); -// let tpu_forwards = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8904); - -// let tpu_vote = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8906); -// let repair = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8907); -// let rpc = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8908); -// let rpc_pubsub = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8909); - -// let serve_repair = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8910); - -// let info = ContactInfo { -// id: keypair.pubkey(), -// gossip, -// tvu, -// tvu_forwards, -// repair, -// tpu, -// tpu_forwards, -// tpu_vote, -// rpc, -// rpc_pubsub, -// serve_repair, -// wallclock: timestamp(), -// shred_version: 0, -// }; -// Node { -// info, -// sockets: Sockets { -// gossip: UdpSocket::bind("0.0.0.0:0").unwrap(), -// ip_echo: None, -// tvu: vec![], -// tvu_forwards: vec![], -// tpu: vec![], -// tpu_forwards: vec![], -// tpu_vote: vec![], -// broadcast: vec![], -// repair: UdpSocket::bind("0.0.0.0:0").unwrap(), -// retransmit_sockets: vec![], -// serve_repair: UdpSocket::bind("0.0.0.0:0").unwrap(), -// ancestor_hashes_requests: UdpSocket::bind("0.0.0.0:0").unwrap(), -// tpu_quic: UdpSocket::bind("0.0.0.0:0").unwrap(), -// tpu_forwards_quic: UdpSocket::bind("0.0.0.0:0").unwrap(), -// }, -// } -// }; - -// let cluster_info = Arc::new(ClusterInfo::new( -// node.info, -// Arc::new(keypair), -// SocketAddrSpace::Unspecified, -// )); - -// let golden = r#" -// IP Address |Age(ms)| Node identifier | Version |Gossip|TPUvote| TPU |TPUfwd| TVU |TVUfwd|Repair|ServeR|ShredVer -// ------------------+-------+----------------------------------------------+---------+------+-------+------+------+------+------+------+------+-------- -// 127.0.0.1 me| \d | 7fGBVaezz2YrTxAkwvLjBZpxrGEfNsd14Jxw9W5Df5zY | - | 8888 | 8906 | 8900 | 8904 | 8902 | 8903 | 8907 | 8910 | 0 -// Nodes: 1 - -// RPC Address |Age(ms)| Node identifier | Version | RPC |PubSub|ShredVer -// ------------------+-------+----------------------------------------------+---------+------+------+-------- -// 127.0.0.1 me| \d | 7fGBVaezz2YrTxAkwvLjBZpxrGEfNsd14Jxw9W5Df5zY | - | 8908 | 8909 | 0 -// RPC Enabled Nodes: 1"#; - -// let re = Regex::new(golden).unwrap(); - -// let output = format!( -// "\n{}\n\n{}", -// cluster_info.contact_info_trace(), -// cluster_info.rpc_info_trace() -// ); - -// assert!(re.is_match(&output)); -// } - -// #[test] -// fn test_handle_pull() { -// solana_logger::setup(); -// let node = Node::new_localhost(); -// let cluster_info = Arc::new(ClusterInfo::new( -// node.info, -// Arc::new(Keypair::new()), -// SocketAddrSpace::Unspecified, -// )); - -// let entrypoint_pubkey = solana_sdk::pubkey::new_rand(); -// let data = test_crds_values(entrypoint_pubkey); -// let timeouts = HashMap::new(); -// assert_eq!( -// (0, 0, 1), -// ClusterInfo::handle_pull_response( -// &cluster_info, -// &entrypoint_pubkey, -// data.clone(), -// &timeouts -// ) -// ); - -// let entrypoint_pubkey2 = solana_sdk::pubkey::new_rand(); -// assert_eq!( -// (1, 0, 0), -// ClusterInfo::handle_pull_response(&cluster_info, &entrypoint_pubkey2, data, &timeouts) -// ); -// } - -// fn new_rand_socket_addr(rng: &mut R) -> SocketAddr { -// let addr = if rng.gen_bool(0.5) { -// IpAddr::V4(Ipv4Addr::new(rng.gen(), rng.gen(), rng.gen(), rng.gen())) -// } else { -// IpAddr::V6(Ipv6Addr::new( -// rng.gen(), -// rng.gen(), -// rng.gen(), -// rng.gen(), -// rng.gen(), -// rng.gen(), -// rng.gen(), -// rng.gen(), -// )) -// }; -// SocketAddr::new(addr, /*port=*/ rng.gen()) -// } - -// fn new_rand_remote_node(rng: &mut R) -> (Keypair, SocketAddr) -// where -// R: Rng, -// { -// let keypair = Keypair::new(); -// let socket = new_rand_socket_addr(rng); -// (keypair, socket) -// } - -// #[test] -// fn test_handle_pong_messages() { -// let now = Instant::now(); -// let mut rng = rand::thread_rng(); -// let this_node = Arc::new(Keypair::new()); -// let cluster_info = ClusterInfo::new( -// ContactInfo::new_localhost(&this_node.pubkey(), timestamp()), -// this_node.clone(), -// SocketAddrSpace::Unspecified, -// ); -// let remote_nodes: Vec<(Keypair, SocketAddr)> = -// repeat_with(|| new_rand_remote_node(&mut rng)) -// .take(128) -// .collect(); -// let pings: Vec<_> = { -// let mut ping_cache = cluster_info.ping_cache.lock().unwrap(); -// let mut pingf = || Ping::new_rand(&mut rng, &this_node).ok(); -// remote_nodes -// .iter() -// .map(|(keypair, socket)| { -// let node = (keypair.pubkey(), *socket); -// let (check, ping) = ping_cache.check(now, node, &mut pingf); -// // Assert that initially remote nodes will not pass the -// // ping/pong check. -// assert!(!check); -// ping.unwrap() -// }) -// .collect() -// }; -// let pongs: Vec<(SocketAddr, Pong)> = pings -// .iter() -// .zip(&remote_nodes) -// .map(|(ping, (keypair, socket))| (*socket, Pong::new(ping, keypair).unwrap())) -// .collect(); -// let now = now + Duration::from_millis(1); -// cluster_info.handle_batch_pong_messages(pongs, now); -// // Assert that remote nodes now pass the ping/pong check. -// { -// let mut ping_cache = cluster_info.ping_cache.lock().unwrap(); -// for (keypair, socket) in &remote_nodes { -// let node = (keypair.pubkey(), *socket); -// let (check, _) = ping_cache.check(now, node, || -> Option { None }); -// assert!(check); -// } -// } -// // Assert that a new random remote node still will not pass the check. -// { -// let mut ping_cache = cluster_info.ping_cache.lock().unwrap(); -// let (keypair, socket) = new_rand_remote_node(&mut rng); -// let node = (keypair.pubkey(), socket); -// let (check, _) = ping_cache.check(now, node, || -> Option { None }); -// assert!(!check); -// } -// } - -// #[test] -// #[allow(clippy::needless_collect)] -// fn test_handle_ping_messages() { -// let mut rng = rand::thread_rng(); -// let this_node = Arc::new(Keypair::new()); -// let cluster_info = ClusterInfo::new( -// ContactInfo::new_localhost(&this_node.pubkey(), timestamp()), -// this_node.clone(), -// SocketAddrSpace::Unspecified, -// ); -// let remote_nodes: Vec<(Keypair, SocketAddr)> = -// repeat_with(|| new_rand_remote_node(&mut rng)) -// .take(128) -// .collect(); -// let pings: Vec<_> = remote_nodes -// .iter() -// .map(|(keypair, _)| Ping::new_rand(&mut rng, keypair).unwrap()) -// .collect(); -// let pongs: Vec<_> = pings -// .iter() -// .map(|ping| Pong::new(ping, &this_node).unwrap()) -// .collect(); -// let recycler = PacketBatchRecycler::default(); -// let packets = cluster_info -// .handle_ping_messages( -// remote_nodes -// .iter() -// .map(|(_, socket)| *socket) -// .zip(pings.into_iter()), -// &recycler, -// ) -// .unwrap(); -// assert_eq!(remote_nodes.len(), packets.len()); -// for (packet, (_, socket), pong) in izip!( -// packets.into_iter(), -// remote_nodes.into_iter(), -// pongs.into_iter() -// ) { -// assert_eq!(packet.meta().socket_addr(), socket); -// let bytes = serialize(&pong).unwrap(); -// match packet.deserialize_slice(..).unwrap() { -// Protocol::PongMessage(pong) => assert_eq!(serialize(&pong).unwrap(), bytes), -// _ => panic!("invalid packet!"), -// } -// } -// } - -// fn test_crds_values(pubkey: Pubkey) -> Vec { -// let entrypoint = ContactInfo::new_localhost(&pubkey, timestamp()); -// let entrypoint_crdsvalue = CrdsValue::new_unsigned(CrdsData::ContactInfo(entrypoint)); -// vec![entrypoint_crdsvalue] -// } - -// #[test] -// fn test_max_snapshot_hashes_with_push_messages() { -// let mut rng = rand::thread_rng(); -// for _ in 0..256 { -// let snapshot_hash = SnapshotHashes::new_rand(&mut rng, None); -// let crds_value = -// CrdsValue::new_signed(CrdsData::SnapshotHashes(snapshot_hash), &Keypair::new()); -// let message = Protocol::PushMessage(Pubkey::new_unique(), vec![crds_value]); -// let socket = new_rand_socket_addr(&mut rng); -// assert!(Packet::from_data(Some(&socket), message).is_ok()); -// } -// } - -// #[test] -// fn test_max_snapshot_hashes_with_pull_responses() { -// let mut rng = rand::thread_rng(); -// for _ in 0..256 { -// let snapshot_hash = SnapshotHashes::new_rand(&mut rng, None); -// let crds_value = -// CrdsValue::new_signed(CrdsData::AccountsHashes(snapshot_hash), &Keypair::new()); -// let response = Protocol::PullResponse(Pubkey::new_unique(), vec![crds_value]); -// let socket = new_rand_socket_addr(&mut rng); -// assert!(Packet::from_data(Some(&socket), response).is_ok()); -// } -// } - -// #[test] -// fn test_max_incremental_snapshot_hashes_with_push_messages() { -// let mut rng = rand::thread_rng(); -// let incremental_snapshot_hashes = IncrementalSnapshotHashes { -// from: Pubkey::new_unique(), -// base: (Slot::default(), Hash::default()), -// hashes: vec![(Slot::default(), Hash::default()); MAX_INCREMENTAL_SNAPSHOT_HASHES], -// wallclock: timestamp(), -// }; -// let crds_value = CrdsValue::new_signed( -// CrdsData::IncrementalSnapshotHashes(incremental_snapshot_hashes), -// &Keypair::new(), -// ); -// let message = Protocol::PushMessage(Pubkey::new_unique(), vec![crds_value]); -// let socket = new_rand_socket_addr(&mut rng); -// assert!(Packet::from_data(Some(&socket), message).is_ok()); -// } - -// #[test] -// fn test_max_incremental_snapshot_hashes_with_pull_responses() { -// let mut rng = rand::thread_rng(); -// let incremental_snapshot_hashes = IncrementalSnapshotHashes { -// from: Pubkey::new_unique(), -// base: (Slot::default(), Hash::default()), -// hashes: vec![(Slot::default(), Hash::default()); MAX_INCREMENTAL_SNAPSHOT_HASHES], -// wallclock: timestamp(), -// }; -// let crds_value = CrdsValue::new_signed( -// CrdsData::IncrementalSnapshotHashes(incremental_snapshot_hashes), -// &Keypair::new(), -// ); -// let response = Protocol::PullResponse(Pubkey::new_unique(), vec![crds_value]); -// let socket = new_rand_socket_addr(&mut rng); -// assert!(Packet::from_data(Some(&socket), response).is_ok()); -// } - -// #[test] -// fn test_max_prune_data_pubkeys() { -// let mut rng = rand::thread_rng(); -// for _ in 0..64 { -// let self_keypair = Keypair::new(); -// let prune_data = -// PruneData::new_rand(&mut rng, &self_keypair, Some(MAX_PRUNE_DATA_NODES)); -// let prune_message = Protocol::PruneMessage(self_keypair.pubkey(), prune_data); -// let socket = new_rand_socket_addr(&mut rng); -// assert!(Packet::from_data(Some(&socket), prune_message).is_ok()); -// } -// // Assert that MAX_PRUNE_DATA_NODES is highest possible. -// let self_keypair = Keypair::new(); -// let prune_data = -// PruneData::new_rand(&mut rng, &self_keypair, Some(MAX_PRUNE_DATA_NODES + 1)); -// let prune_message = Protocol::PruneMessage(self_keypair.pubkey(), prune_data); -// let socket = new_rand_socket_addr(&mut rng); -// assert!(Packet::from_data(Some(&socket), prune_message).is_err()); -// } - -// #[test] -// fn test_push_message_max_payload_size() { -// let header = Protocol::PushMessage(Pubkey::default(), Vec::default()); -// assert_eq!( -// PUSH_MESSAGE_MAX_PAYLOAD_SIZE, -// PACKET_DATA_SIZE - serialized_size(&header).unwrap() as usize -// ); -// } - -// #[test] -// fn test_duplicate_shred_max_payload_size() { -// let mut rng = rand::thread_rng(); -// let leader = Arc::new(Keypair::new()); -// let keypair = Keypair::new(); -// let (slot, parent_slot, reference_tick, version) = (53084024, 53084023, 0, 0); -// let shredder = Shredder::new(slot, parent_slot, reference_tick, version).unwrap(); -// let next_shred_index = rng.gen_range(0, 32_000); -// let shred = new_rand_shred(&mut rng, next_shred_index, &shredder, &leader); -// let other_payload = { -// let other_shred = new_rand_shred(&mut rng, next_shred_index, &shredder, &leader); -// other_shred.into_payload() -// }; -// let leader_schedule = |s| { -// if s == slot { -// Some(leader.pubkey()) -// } else { -// None -// } -// }; -// let chunks: Vec<_> = duplicate_shred::from_shred( -// shred, -// keypair.pubkey(), -// other_payload, -// Some(leader_schedule), -// timestamp(), -// DUPLICATE_SHRED_MAX_PAYLOAD_SIZE, -// ) -// .unwrap() -// .collect(); -// assert!(chunks.len() > 1); -// for chunk in chunks { -// let data = CrdsData::DuplicateShred(MAX_DUPLICATE_SHREDS - 1, chunk); -// let value = CrdsValue::new_signed(data, &keypair); -// let pull_response = Protocol::PullResponse(keypair.pubkey(), vec![value.clone()]); -// assert!(serialized_size(&pull_response).unwrap() < PACKET_DATA_SIZE as u64); -// let push_message = Protocol::PushMessage(keypair.pubkey(), vec![value.clone()]); -// assert!(serialized_size(&push_message).unwrap() < PACKET_DATA_SIZE as u64); -// } -// } - -// #[test] -// fn test_pull_response_min_serialized_size() { -// let mut rng = rand::thread_rng(); -// for _ in 0..100 { -// let crds_values = vec![CrdsValue::new_rand(&mut rng, None)]; -// let pull_response = Protocol::PullResponse(Pubkey::new_unique(), crds_values); -// let size = serialized_size(&pull_response).unwrap(); -// assert!( -// PULL_RESPONSE_MIN_SERIALIZED_SIZE as u64 <= size, -// "pull-response serialized size: {size}" -// ); -// } -// } - -// #[test] -// fn test_cluster_spy_gossip() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// //check that gossip doesn't try to push to invalid addresses -// let node = Node::new_localhost(); -// let (spy, _, _) = ClusterInfo::spy_node(solana_sdk::pubkey::new_rand(), 0); -// let cluster_info = Arc::new(ClusterInfo::new( -// node.info, -// Arc::new(Keypair::new()), -// SocketAddrSpace::Unspecified, -// )); -// cluster_info.insert_info(spy); -// cluster_info.gossip.refresh_push_active_set( -// &cluster_info.keypair(), -// cluster_info.my_shred_version(), -// &HashMap::new(), // stakes -// None, // gossip validators -// &cluster_info.ping_cache, -// &mut Vec::new(), // pings -// &SocketAddrSpace::Unspecified, -// ); -// let reqs = cluster_info.generate_new_gossip_requests( -// &thread_pool, -// None, // gossip_validators -// &HashMap::new(), // stakes -// true, // generate_pull_requests -// ); -// //assert none of the addrs are invalid. -// reqs.iter().all(|(addr, _)| { -// let res = ContactInfo::is_valid_address(addr, &SocketAddrSpace::Unspecified); -// assert!(res); -// res -// }); -// } - -// #[test] -// fn test_cluster_info_new() { -// let d = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), timestamp()); -// let cluster_info = ClusterInfo::new( -// d.clone(), -// Arc::new(Keypair::new()), -// SocketAddrSpace::Unspecified, -// ); -// assert_eq!(d.id, cluster_info.id()); -// } - -// #[test] -// fn insert_info_test() { -// let d = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), timestamp()); -// let cluster_info = -// ClusterInfo::new(d, Arc::new(Keypair::new()), SocketAddrSpace::Unspecified); -// let d = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), timestamp()); -// let label = CrdsValueLabel::ContactInfo(d.id); -// cluster_info.insert_info(d); -// let gossip_crds = cluster_info.gossip.crds.read().unwrap(); -// assert!(gossip_crds.get::<&CrdsValue>(&label).is_some()); -// } - -// fn assert_in_range(x: u16, range: (u16, u16)) { -// assert!(x >= range.0); -// assert!(x < range.1); -// } - -// fn check_sockets(sockets: &[UdpSocket], ip: IpAddr, range: (u16, u16)) { -// assert!(sockets.len() > 1); -// let port = sockets[0].local_addr().unwrap().port(); -// for socket in sockets.iter() { -// check_socket(socket, ip, range); -// assert_eq!(socket.local_addr().unwrap().port(), port); -// } -// } - -// fn check_socket(socket: &UdpSocket, ip: IpAddr, range: (u16, u16)) { -// let local_addr = socket.local_addr().unwrap(); -// assert_eq!(local_addr.ip(), ip); -// assert_in_range(local_addr.port(), range); -// } - -// fn check_node_sockets(node: &Node, ip: IpAddr, range: (u16, u16)) { -// check_socket(&node.sockets.gossip, ip, range); -// check_socket(&node.sockets.repair, ip, range); - -// check_sockets(&node.sockets.tvu, ip, range); -// check_sockets(&node.sockets.tpu, ip, range); -// } - -// #[test] -// fn new_with_external_ip_test_random() { -// let ip = Ipv4Addr::from(0); -// let node = Node::new_with_external_ip( -// &solana_sdk::pubkey::new_rand(), -// &socketaddr!(ip, 0), -// VALIDATOR_PORT_RANGE, -// IpAddr::V4(ip), -// None, -// ); - -// check_node_sockets(&node, IpAddr::V4(ip), VALIDATOR_PORT_RANGE); -// } - -// #[test] -// fn new_with_external_ip_test_gossip() { -// // Can't use VALIDATOR_PORT_RANGE because if this test runs in parallel with others, the -// // port returned by `bind_in_range()` might be snatched up before `Node::new_with_external_ip()` runs -// let port_range = ( -// VALIDATOR_PORT_RANGE.1 + MINIMUM_VALIDATOR_PORT_RANGE_WIDTH, -// VALIDATOR_PORT_RANGE.1 + (2 * MINIMUM_VALIDATOR_PORT_RANGE_WIDTH), -// ); - -// let ip = IpAddr::V4(Ipv4Addr::from(0)); -// let port = bind_in_range(ip, port_range).expect("Failed to bind").0; -// let node = Node::new_with_external_ip( -// &solana_sdk::pubkey::new_rand(), -// &socketaddr!(0, port), -// port_range, -// ip, -// None, -// ); - -// check_node_sockets(&node, ip, port_range); - -// assert_eq!(node.sockets.gossip.local_addr().unwrap().port(), port); -// } - -// //test that all cluster_info objects only generate signed messages -// //when constructed with keypairs -// #[test] -// fn test_gossip_signature_verification() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// //create new cluster info, leader, and peer -// let keypair = Keypair::new(); -// let peer_keypair = Keypair::new(); -// let contact_info = ContactInfo::new_localhost(&keypair.pubkey(), 0); -// let peer = ContactInfo::new_localhost(&peer_keypair.pubkey(), 0); -// let cluster_info = ClusterInfo::new( -// contact_info, -// Arc::new(keypair), -// SocketAddrSpace::Unspecified, -// ); -// cluster_info -// .ping_cache -// .lock() -// .unwrap() -// .mock_pong(peer.id, peer.gossip, Instant::now()); -// cluster_info.insert_info(peer); -// cluster_info.gossip.refresh_push_active_set( -// &cluster_info.keypair(), -// cluster_info.my_shred_version(), -// &HashMap::new(), // stakes -// None, // gossip validators -// &cluster_info.ping_cache, -// &mut Vec::new(), // pings -// &SocketAddrSpace::Unspecified, -// ); -// //check that all types of gossip messages are signed correctly -// let (push_messages, _, _) = cluster_info -// .gossip -// .new_push_messages(cluster_info.drain_push_queue(), timestamp()); -// // there should be some pushes ready -// assert!(!push_messages.is_empty()); -// push_messages -// .values() -// .for_each(|v| v.par_iter().for_each(|v| assert!(v.verify()))); - -// let mut pings = Vec::new(); -// cluster_info -// .gossip -// .new_pull_request( -// &thread_pool, -// cluster_info.keypair().deref(), -// cluster_info.my_shred_version(), -// timestamp(), -// None, -// &HashMap::new(), -// MAX_BLOOM_SIZE, -// &cluster_info.ping_cache, -// &mut pings, -// &cluster_info.socket_addr_space, -// ) -// .ok() -// .unwrap(); -// } - -// #[test] -// fn test_refresh_vote() { -// let keys = Keypair::new(); -// let contact_info = ContactInfo::new_localhost(&keys.pubkey(), 0); -// let cluster_info = ClusterInfo::new( -// contact_info, -// Arc::new(Keypair::new()), -// SocketAddrSpace::Unspecified, -// ); - -// // Construct and push a vote for some other slot -// let unrefresh_slot = 5; -// let unrefresh_tower = vec![1, 3, unrefresh_slot]; -// let unrefresh_vote = Vote::new(unrefresh_tower.clone(), Hash::new_unique()); -// let unrefresh_ix = vote_instruction::vote( -// &Pubkey::new_unique(), // vote_pubkey -// &Pubkey::new_unique(), // authorized_voter_pubkey -// unrefresh_vote, -// ); -// let unrefresh_tx = Transaction::new_with_payer( -// &[unrefresh_ix], // instructions -// None, // payer -// ); -// cluster_info.push_vote(&unrefresh_tower, unrefresh_tx.clone()); -// let mut cursor = Cursor::default(); -// let votes = cluster_info.get_votes(&mut cursor); -// assert_eq!(votes, vec![unrefresh_tx.clone()]); - -// // Now construct vote for the slot to be refreshed later -// let refresh_slot = 7; -// let refresh_tower = vec![1, 3, unrefresh_slot, refresh_slot]; -// let refresh_vote = Vote::new(refresh_tower.clone(), Hash::new_unique()); -// let refresh_ix = vote_instruction::vote( -// &Pubkey::new_unique(), // vote_pubkey -// &Pubkey::new_unique(), // authorized_voter_pubkey -// refresh_vote.clone(), -// ); -// let refresh_tx = Transaction::new_with_payer( -// &[refresh_ix], // instructions -// None, // payer -// ); - -// // Trying to refresh vote when it doesn't yet exist in gossip -// // shouldn't add the vote -// cluster_info.refresh_vote(refresh_tx.clone(), refresh_slot); -// let votes = cluster_info.get_votes(&mut cursor); -// assert_eq!(votes, vec![]); -// let votes = cluster_info.get_votes(&mut Cursor::default()); -// assert_eq!(votes.len(), 1); -// assert!(votes.contains(&unrefresh_tx)); - -// // Push the new vote for `refresh_slot` -// cluster_info.push_vote(&refresh_tower, refresh_tx.clone()); - -// // Should be two votes in gossip -// let votes = cluster_info.get_votes(&mut Cursor::default()); -// assert_eq!(votes.len(), 2); -// assert!(votes.contains(&unrefresh_tx)); -// assert!(votes.contains(&refresh_tx)); - -// // Refresh a few times, we should only have the latest update -// let mut latest_refresh_tx = refresh_tx; -// for _ in 0..10 { -// let latest_refreshed_recent_blockhash = Hash::new_unique(); -// let new_signer = Keypair::new(); -// let refresh_ix = vote_instruction::vote( -// &new_signer.pubkey(), // vote_pubkey -// &new_signer.pubkey(), // authorized_voter_pubkey -// refresh_vote.clone(), -// ); -// latest_refresh_tx = Transaction::new_signed_with_payer( -// &[refresh_ix], -// None, -// &[&new_signer], -// latest_refreshed_recent_blockhash, -// ); -// cluster_info.refresh_vote(latest_refresh_tx.clone(), refresh_slot); -// // Sleep to avoid votes with same timestamp causing later vote to not override prior vote -// std::thread::sleep(Duration::from_millis(1)); -// } -// // The diff since `max_ts` should only be the latest refreshed vote -// let votes = cluster_info.get_votes(&mut cursor); -// assert_eq!(votes.len(), 1); -// assert_eq!(votes[0], latest_refresh_tx); - -// // Should still be two votes in gossip -// let votes = cluster_info.get_votes(&mut Cursor::default()); -// assert_eq!(votes.len(), 2); -// assert!(votes.contains(&unrefresh_tx)); -// assert!(votes.contains(&latest_refresh_tx)); -// } - -// #[test] -// fn test_push_vote() { -// let mut rng = rand::thread_rng(); -// let keys = Keypair::new(); -// let contact_info = ContactInfo::new_localhost(&keys.pubkey(), 0); -// let cluster_info = ClusterInfo::new( -// contact_info, -// Arc::new(Keypair::new()), -// SocketAddrSpace::Unspecified, -// ); - -// // make sure empty crds is handled correctly -// let mut cursor = Cursor::default(); -// let votes = cluster_info.get_votes(&mut cursor); -// assert_eq!(votes, vec![]); - -// // add a vote -// let vote = Vote::new( -// vec![1, 3, 7], // slots -// solana_sdk::hash::new_rand(&mut rng), -// ); -// let ix = vote_instruction::vote( -// &Pubkey::new_unique(), // vote_pubkey -// &Pubkey::new_unique(), // authorized_voter_pubkey -// vote, -// ); -// let tx = Transaction::new_with_payer( -// &[ix], // instructions -// None, // payer -// ); -// let tower = vec![7]; // Last slot in the vote. -// cluster_info.push_vote(&tower, tx.clone()); - -// let (labels, votes) = cluster_info.get_votes_with_labels(&mut cursor); -// assert_eq!(votes, vec![tx]); -// assert_eq!(labels.len(), 1); -// match labels[0] { -// CrdsValueLabel::Vote(_, pubkey) => { -// assert_eq!(pubkey, keys.pubkey()); -// } - -// _ => panic!("Bad match"), -// } -// // make sure timestamp filter works -// let votes = cluster_info.get_votes(&mut cursor); -// assert_eq!(votes, vec![]); -// } - -// fn new_vote_transaction(rng: &mut R, slots: Vec) -> Transaction { -// let vote = Vote::new(slots, solana_sdk::hash::new_rand(rng)); -// let ix = vote_instruction::vote( -// &Pubkey::new_unique(), // vote_pubkey -// &Pubkey::new_unique(), // authorized_voter_pubkey -// vote, -// ); -// Transaction::new_with_payer( -// &[ix], // instructions -// None, // payer -// ) -// } - -// #[test] -// fn test_push_votes_with_tower() { -// let get_vote_slots = |cluster_info: &ClusterInfo| -> Vec { -// let (labels, _) = cluster_info.get_votes_with_labels(&mut Cursor::default()); -// let gossip_crds = cluster_info.gossip.crds.read().unwrap(); -// let mut vote_slots = HashSet::new(); -// for label in labels { -// match &gossip_crds.get::<&CrdsData>(&label).unwrap() { -// CrdsData::Vote(_, vote) => { -// assert!(vote_slots.insert(vote.slot().unwrap())); -// } -// _ => panic!("this should not happen!"), -// } -// } -// vote_slots.into_iter().collect() -// }; -// let mut rng = rand::thread_rng(); -// let keys = Keypair::new(); -// let contact_info = ContactInfo::new_localhost(&keys.pubkey(), 0); -// let cluster_info = ClusterInfo::new( -// contact_info, -// Arc::new(Keypair::new()), -// SocketAddrSpace::Unspecified, -// ); -// let mut tower = Vec::new(); -// for k in 0..MAX_LOCKOUT_HISTORY { -// let slot = k as Slot; -// tower.push(slot); -// let vote = new_vote_transaction(&mut rng, vec![slot]); -// cluster_info.push_vote(&tower, vote); -// } -// let vote_slots = get_vote_slots(&cluster_info); -// assert_eq!(vote_slots.len(), MAX_LOCKOUT_HISTORY); -// for vote_slot in vote_slots { -// assert!(vote_slot < MAX_LOCKOUT_HISTORY as u64); -// } -// // Push a new vote evicting one. -// let slot = MAX_LOCKOUT_HISTORY as Slot; -// tower.push(slot); -// tower.remove(23); -// let vote = new_vote_transaction(&mut rng, vec![slot]); -// // New versioned-crds-value should have wallclock later than existing -// // entries, otherwise might not get inserted into the table. -// sleep(Duration::from_millis(5)); -// cluster_info.push_vote(&tower, vote); -// let vote_slots = get_vote_slots(&cluster_info); -// assert_eq!(vote_slots.len(), MAX_LOCKOUT_HISTORY); -// for vote_slot in vote_slots { -// assert!(vote_slot <= slot); -// assert!(vote_slot != 23); -// } -// // Push a new vote evicting two. -// // Older one should be evicted from the crds table. -// let slot = slot + 1; -// tower.push(slot); -// tower.remove(17); -// tower.remove(5); -// let vote = new_vote_transaction(&mut rng, vec![slot]); -// cluster_info.push_vote(&tower, vote); -// let vote_slots = get_vote_slots(&cluster_info); -// assert_eq!(vote_slots.len(), MAX_LOCKOUT_HISTORY); -// for vote_slot in vote_slots { -// assert!(vote_slot <= slot); -// assert!(vote_slot != 23); -// assert!(vote_slot != 5); -// } -// } - -// #[test] -// fn test_push_epoch_slots() { -// let keys = Keypair::new(); -// let contact_info = ContactInfo::new_localhost(&keys.pubkey(), 0); -// let cluster_info = ClusterInfo::new( -// contact_info, -// Arc::new(Keypair::new()), -// SocketAddrSpace::Unspecified, -// ); -// let slots = cluster_info.get_epoch_slots(&mut Cursor::default()); -// assert!(slots.is_empty()); -// cluster_info.push_epoch_slots(&[0]); - -// let mut cursor = Cursor::default(); -// let slots = cluster_info.get_epoch_slots(&mut cursor); -// assert_eq!(slots.len(), 1); - -// let slots = cluster_info.get_epoch_slots(&mut cursor); -// assert!(slots.is_empty()); - -// // Test with different shred versions. -// let mut rng = rand::thread_rng(); -// let node_pubkey = Pubkey::new_unique(); -// let mut node = ContactInfo::new_rand(&mut rng, Some(node_pubkey)); -// node.shred_version = 42; -// let epoch_slots = EpochSlots::new_rand(&mut rng, Some(node_pubkey)); -// let entries = vec![ -// CrdsValue::new_unsigned(CrdsData::ContactInfo(node)), -// CrdsValue::new_unsigned(CrdsData::EpochSlots(0, epoch_slots)), -// ]; -// { -// let mut gossip_crds = cluster_info.gossip.crds.write().unwrap(); -// for entry in entries { -// assert!(gossip_crds -// .insert(entry, /*now=*/ 0, GossipRoute::LocalMessage) -// .is_ok()); -// } -// } -// // Should exclude other node's epoch-slot because of different -// // shred-version. -// let slots = cluster_info.get_epoch_slots(&mut Cursor::default()); -// assert_eq!(slots.len(), 1); -// assert_eq!(slots[0].from, cluster_info.id()); -// // Match shred versions. -// { -// let mut node = cluster_info.my_contact_info.write().unwrap(); -// node.shred_version = 42; -// } -// cluster_info.push_self(); -// cluster_info.flush_push_queue(); -// // Should now include both epoch slots. -// let slots = cluster_info.get_epoch_slots(&mut Cursor::default()); -// assert_eq!(slots.len(), 2); -// assert_eq!(slots[0].from, cluster_info.id()); -// assert_eq!(slots[1].from, node_pubkey); -// } - -// #[test] -// fn test_append_entrypoint_to_pulls() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let node_keypair = Arc::new(Keypair::new()); -// let cluster_info = ClusterInfo::new( -// ContactInfo::new_localhost(&node_keypair.pubkey(), timestamp()), -// node_keypair, -// SocketAddrSpace::Unspecified, -// ); -// let entrypoint_pubkey = solana_sdk::pubkey::new_rand(); -// let entrypoint = ContactInfo::new_localhost(&entrypoint_pubkey, timestamp()); -// cluster_info.set_entrypoint(entrypoint.clone()); -// let (pings, pulls) = cluster_info.new_pull_requests(&thread_pool, None, &HashMap::new()); -// assert!(pings.is_empty()); -// assert_eq!(pulls.len(), MIN_NUM_BLOOM_FILTERS); -// for (addr, msg) in pulls { -// assert_eq!(addr, entrypoint.gossip); -// match msg { -// Protocol::PullRequest(_, value) => { -// assert!(value.verify()); -// assert_eq!(value.pubkey(), cluster_info.id()) -// } -// _ => panic!("wrong protocol"), -// } -// } -// // now add this message back to the table and make sure after the next pull, the entrypoint is unset -// let entrypoint_crdsvalue = -// CrdsValue::new_unsigned(CrdsData::ContactInfo(entrypoint.clone())); -// let cluster_info = Arc::new(cluster_info); -// let timeouts = cluster_info.gossip.make_timeouts( -// cluster_info.id(), -// &HashMap::default(), // stakes, -// Duration::from_millis(cluster_info.gossip.pull.crds_timeout), -// ); -// ClusterInfo::handle_pull_response( -// &cluster_info, -// &entrypoint_pubkey, -// vec![entrypoint_crdsvalue], -// &timeouts, -// ); -// let (pings, pulls) = cluster_info.new_pull_requests(&thread_pool, None, &HashMap::new()); -// assert_eq!(pings.len(), 1); -// assert_eq!(pulls.len(), MIN_NUM_BLOOM_FILTERS); -// assert_eq!(*cluster_info.entrypoints.read().unwrap(), vec![entrypoint]); -// } - -// #[test] -// fn test_split_messages_small() { -// let value = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())); -// test_split_messages(value); -// } - -// #[test] -// fn test_split_messages_large() { -// let value = CrdsValue::new_unsigned(CrdsData::LowestSlot( -// 0, -// LowestSlot::new(Pubkey::default(), 0, 0), -// )); -// test_split_messages(value); -// } - -// #[test] -// fn test_split_gossip_messages() { -// const NUM_CRDS_VALUES: usize = 2048; -// let mut rng = rand::thread_rng(); -// let values: Vec<_> = repeat_with(|| CrdsValue::new_rand(&mut rng, None)) -// .take(NUM_CRDS_VALUES) -// .collect(); -// let splits: Vec<_> = -// ClusterInfo::split_gossip_messages(PUSH_MESSAGE_MAX_PAYLOAD_SIZE, values.clone()) -// .collect(); -// let self_pubkey = solana_sdk::pubkey::new_rand(); -// assert!(splits.len() * 3 < NUM_CRDS_VALUES); -// // Assert that all messages are included in the splits. -// assert_eq!(NUM_CRDS_VALUES, splits.iter().map(Vec::len).sum::()); -// splits -// .iter() -// .flat_map(|s| s.iter()) -// .zip(values) -// .for_each(|(a, b)| assert_eq!(*a, b)); -// let socket = SocketAddr::V4(SocketAddrV4::new( -// Ipv4Addr::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()), -// rng.gen(), -// )); -// let header_size = PACKET_DATA_SIZE - PUSH_MESSAGE_MAX_PAYLOAD_SIZE; -// for values in splits { -// // Assert that sum of parts equals the whole. -// let size: u64 = header_size as u64 -// + values -// .iter() -// .map(|v| serialized_size(v).unwrap()) -// .sum::(); -// let message = Protocol::PushMessage(self_pubkey, values); -// assert_eq!(serialized_size(&message).unwrap(), size); -// // Assert that the message fits into a packet. -// assert!(Packet::from_data(Some(&socket), message).is_ok()); -// } -// } - -// #[test] -// #[allow(clippy::needless_collect)] -// fn test_split_messages_packet_size() { -// // Test that if a value is smaller than payload size but too large to be wrapped in a vec -// // that it is still dropped -// let mut value = CrdsValue::new_unsigned(CrdsData::SnapshotHashes(SnapshotHashes { -// from: Pubkey::default(), -// hashes: vec![], -// wallclock: 0, -// })); - -// let mut i = 0; -// while value.size() < PUSH_MESSAGE_MAX_PAYLOAD_SIZE as u64 { -// value.data = CrdsData::SnapshotHashes(SnapshotHashes { -// from: Pubkey::default(), -// hashes: vec![(0, Hash::default()); i], -// wallclock: 0, -// }); -// i += 1; -// } -// let split: Vec<_> = -// ClusterInfo::split_gossip_messages(PUSH_MESSAGE_MAX_PAYLOAD_SIZE, vec![value]) -// .collect(); -// assert_eq!(split.len(), 0); -// } - -// fn test_split_messages(value: CrdsValue) { -// const NUM_VALUES: u64 = 30; -// let value_size = value.size(); -// let num_values_per_payload = (PUSH_MESSAGE_MAX_PAYLOAD_SIZE as u64 / value_size).max(1); - -// // Expected len is the ceiling of the division -// let expected_len = (NUM_VALUES + num_values_per_payload - 1) / num_values_per_payload; -// let msgs = vec![value; NUM_VALUES as usize]; - -// assert!( -// ClusterInfo::split_gossip_messages(PUSH_MESSAGE_MAX_PAYLOAD_SIZE, msgs).count() as u64 -// <= expected_len -// ); -// } - -// #[test] -// fn test_crds_filter_size() { -// //sanity test to ensure filter size never exceeds MTU size -// check_pull_request_size(CrdsFilter::new_rand(1000, 10)); -// check_pull_request_size(CrdsFilter::new_rand(1000, 1000)); -// check_pull_request_size(CrdsFilter::new_rand(100_000, 1000)); -// check_pull_request_size(CrdsFilter::new_rand(100_000, MAX_BLOOM_SIZE)); -// } - -// fn check_pull_request_size(filter: CrdsFilter) { -// let value = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())); -// let protocol = Protocol::PullRequest(filter, value); -// assert!(serialized_size(&protocol).unwrap() <= PACKET_DATA_SIZE as u64); -// } - -// #[test] -// fn test_tvu_peers_and_stakes() { -// let d = ContactInfo::new_localhost(&Pubkey::new(&[0; 32]), timestamp()); -// let cluster_info = ClusterInfo::new( -// d.clone(), -// Arc::new(Keypair::new()), -// SocketAddrSpace::Unspecified, -// ); -// let mut stakes = HashMap::new(); - -// // no stake -// let id = Pubkey::new(&[1u8; 32]); -// let contact_info = ContactInfo::new_localhost(&id, timestamp()); -// cluster_info.insert_info(contact_info); - -// // normal -// let id2 = Pubkey::new(&[2u8; 32]); -// let mut contact_info = ContactInfo::new_localhost(&id2, timestamp()); -// cluster_info.insert_info(contact_info.clone()); -// stakes.insert(id2, 10); - -// // duplicate -// contact_info.wallclock = timestamp() + 1; -// cluster_info.insert_info(contact_info); - -// // no tvu -// let id3 = Pubkey::new(&[3u8; 32]); -// let mut contact_info = ContactInfo::new_localhost(&id3, timestamp()); -// contact_info.tvu = "0.0.0.0:0".parse().unwrap(); -// cluster_info.insert_info(contact_info); -// stakes.insert(id3, 10); - -// // normal but with different shred version -// let id4 = Pubkey::new(&[4u8; 32]); -// let mut contact_info = ContactInfo::new_localhost(&id4, timestamp()); -// contact_info.shred_version = 1; -// assert_ne!(contact_info.shred_version, d.shred_version); -// cluster_info.insert_info(contact_info); -// stakes.insert(id4, 10); -// } - -// #[test] -// fn test_pull_from_entrypoint_if_not_present() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let node_keypair = Arc::new(Keypair::new()); -// let cluster_info = ClusterInfo::new( -// ContactInfo::new_localhost(&node_keypair.pubkey(), timestamp()), -// node_keypair, -// SocketAddrSpace::Unspecified, -// ); -// let entrypoint_pubkey = solana_sdk::pubkey::new_rand(); -// let mut entrypoint = ContactInfo::new_localhost(&entrypoint_pubkey, timestamp()); -// entrypoint.gossip = socketaddr!("127.0.0.2:1234"); -// cluster_info.set_entrypoint(entrypoint.clone()); - -// let mut stakes = HashMap::new(); - -// let other_node_pubkey = solana_sdk::pubkey::new_rand(); -// let other_node = ContactInfo::new_localhost(&other_node_pubkey, timestamp()); -// assert_ne!(other_node.gossip, entrypoint.gossip); -// cluster_info.ping_cache.lock().unwrap().mock_pong( -// other_node.id, -// other_node.gossip, -// Instant::now(), -// ); -// cluster_info.insert_info(other_node.clone()); -// stakes.insert(other_node_pubkey, 10); - -// // Pull request 1: `other_node` is present but `entrypoint` was just added (so it has a -// // fresh timestamp). There should only be one pull request to `other_node` -// let (pings, pulls) = cluster_info.new_pull_requests(&thread_pool, None, &stakes); -// assert!(pings.is_empty()); -// assert_eq!(pulls.len(), MIN_NUM_BLOOM_FILTERS); -// assert!(pulls.into_iter().all(|(addr, _)| addr == other_node.gossip)); - -// // Pull request 2: pretend it's been a while since we've pulled from `entrypoint`. There should -// // now be two pull requests -// cluster_info.entrypoints.write().unwrap()[0].wallclock = 0; -// let (pings, pulls) = cluster_info.new_pull_requests(&thread_pool, None, &stakes); -// assert!(pings.is_empty()); -// assert_eq!(pulls.len(), 2 * MIN_NUM_BLOOM_FILTERS); -// for node in [&other_node, &entrypoint] { -// assert_eq!( -// pulls -// .iter() -// .filter(|(addr, _)| *addr == node.gossip) -// .count(), -// MIN_NUM_BLOOM_FILTERS -// ); -// } -// // Pull request 3: `other_node` is present and `entrypoint` was just pulled from. There should -// // only be one pull request to `other_node` -// let (pings, pulls) = cluster_info.new_pull_requests(&thread_pool, None, &stakes); -// assert!(pings.is_empty()); -// assert_eq!(pulls.len(), MIN_NUM_BLOOM_FILTERS); -// assert!(pulls.into_iter().all(|(addr, _)| addr == other_node.gossip)); -// } - -// #[test] -// fn test_repair_peers() { -// let node_keypair = Arc::new(Keypair::new()); -// let cluster_info = ClusterInfo::new( -// ContactInfo::new_localhost(&node_keypair.pubkey(), timestamp()), -// node_keypair, -// SocketAddrSpace::Unspecified, -// ); -// for i in 0..10 { -// // make these invalid for the upcoming repair request -// let peer_lowest = if i >= 5 { 10 } else { 0 }; -// let other_node_pubkey = solana_sdk::pubkey::new_rand(); -// let other_node = ContactInfo::new_localhost(&other_node_pubkey, timestamp()); -// cluster_info.insert_info(other_node.clone()); -// let value = CrdsValue::new_unsigned(CrdsData::LowestSlot( -// 0, -// LowestSlot::new(other_node_pubkey, peer_lowest, timestamp()), -// )); -// let mut gossip_crds = cluster_info.gossip.crds.write().unwrap(); -// let _ = gossip_crds.insert(value, timestamp(), GossipRoute::LocalMessage); -// } -// // only half the visible peers should be eligible to serve this repair -// assert_eq!(cluster_info.repair_peers(5).len(), 5); -// } - -// #[test] -// fn test_max_bloom_size() { -// // check that the constant fits into the dynamic size -// assert!(MAX_BLOOM_SIZE <= max_bloom_size()); -// } - -// #[test] -// fn test_protocol_sanitize() { -// let pd = PruneData { -// wallclock: MAX_WALLCLOCK, -// ..PruneData::default() -// }; -// let msg = Protocol::PruneMessage(Pubkey::default(), pd); -// assert_eq!(msg.sanitize(), Err(SanitizeError::ValueOutOfBounds)); -// } - -// #[test] -// fn test_protocol_prune_message_sanitize() { -// let keypair = Keypair::new(); -// let mut prune_data = PruneData { -// pubkey: keypair.pubkey(), -// prunes: vec![], -// signature: Signature::default(), -// destination: Pubkey::new_unique(), -// wallclock: timestamp(), -// }; -// prune_data.sign(&keypair); -// let prune_message = Protocol::PruneMessage(keypair.pubkey(), prune_data.clone()); -// assert_eq!(prune_message.sanitize(), Ok(())); -// let prune_message = Protocol::PruneMessage(Pubkey::new_unique(), prune_data); -// assert_eq!(prune_message.sanitize(), Err(SanitizeError::InvalidValue)); -// } - -// // computes the maximum size for pull request blooms -// fn max_bloom_size() -> usize { -// let filter_size = serialized_size(&CrdsFilter::default()) -// .expect("unable to serialize default filter") as usize; -// let protocol = Protocol::PullRequest( -// CrdsFilter::default(), -// CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())), -// ); -// let protocol_size = -// serialized_size(&protocol).expect("unable to serialize gossip protocol") as usize; -// PACKET_DATA_SIZE - (protocol_size - filter_size) -// } - -// #[test] -// #[allow(clippy::same_item_push)] -// fn test_push_epoch_slots_large() { -// let node_keypair = Arc::new(Keypair::new()); -// let cluster_info = ClusterInfo::new( -// ContactInfo::new_localhost(&node_keypair.pubkey(), timestamp()), -// node_keypair, -// SocketAddrSpace::Unspecified, -// ); -// let mut range: Vec = vec![]; -// //random should be hard to compress -// for _ in 0..32000 { -// let last = *range.last().unwrap_or(&0); -// range.push(last + rand::thread_rng().gen_range(1, 32)); -// } -// cluster_info.push_epoch_slots(&range[..16000]); -// cluster_info.push_epoch_slots(&range[16000..]); -// let slots = cluster_info.get_epoch_slots(&mut Cursor::default()); -// let slots: Vec<_> = slots.iter().flat_map(|x| x.to_slots(0)).collect(); -// assert_eq!(slots, range); -// } - -// #[test] -// fn test_vote_size() { -// let slots = vec![1; 32]; -// let vote = Vote::new(slots, Hash::default()); -// let keypair = Arc::new(Keypair::new()); - -// // Create the biggest possible vote transaction -// let vote_ix = vote_instruction::vote_switch( -// &keypair.pubkey(), -// &keypair.pubkey(), -// vote, -// Hash::default(), -// ); -// let mut vote_tx = Transaction::new_with_payer(&[vote_ix], Some(&keypair.pubkey())); - -// vote_tx.partial_sign(&[keypair.as_ref()], Hash::default()); -// vote_tx.partial_sign(&[keypair.as_ref()], Hash::default()); - -// let vote = CrdsVote::new( -// keypair.pubkey(), -// vote_tx, -// 0, // wallclock -// ) -// .unwrap(); -// let vote = CrdsValue::new_signed(CrdsData::Vote(1, vote), &Keypair::new()); -// assert!(bincode::serialized_size(&vote).unwrap() <= PUSH_MESSAGE_MAX_PAYLOAD_SIZE as u64); -// } - -// #[test] -// fn test_process_entrypoint_adopt_shred_version() { -// let node_keypair = Arc::new(Keypair::new()); -// let cluster_info = Arc::new(ClusterInfo::new( -// ContactInfo::new_localhost(&node_keypair.pubkey(), timestamp()), -// node_keypair, -// SocketAddrSpace::Unspecified, -// )); -// assert_eq!(cluster_info.my_shred_version(), 0); - -// // Simulating starting up with two entrypoints, no known id, only a gossip -// // address -// let entrypoint1_gossip_addr = socketaddr!("127.0.0.2:1234"); -// let mut entrypoint1 = ContactInfo::new_localhost(&Pubkey::default(), timestamp()); -// entrypoint1.gossip = entrypoint1_gossip_addr; -// assert_eq!(entrypoint1.shred_version, 0); - -// let entrypoint2_gossip_addr = socketaddr!("127.0.0.2:5678"); -// let mut entrypoint2 = ContactInfo::new_localhost(&Pubkey::default(), timestamp()); -// entrypoint2.gossip = entrypoint2_gossip_addr; -// assert_eq!(entrypoint2.shred_version, 0); -// cluster_info.set_entrypoints(vec![entrypoint1, entrypoint2]); - -// // Simulate getting entrypoint ContactInfo from gossip with an entrypoint1 shred version of -// // 0 -// let mut gossiped_entrypoint1_info = -// ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), timestamp()); -// gossiped_entrypoint1_info.gossip = entrypoint1_gossip_addr; -// gossiped_entrypoint1_info.shred_version = 0; -// cluster_info.insert_info(gossiped_entrypoint1_info.clone()); -// assert!(!cluster_info -// .entrypoints -// .read() -// .unwrap() -// .iter() -// .any(|entrypoint| *entrypoint == gossiped_entrypoint1_info)); - -// // Adopt the entrypoint's gossiped contact info and verify -// let entrypoints_processed = ClusterInfo::process_entrypoints(&cluster_info); -// assert_eq!(cluster_info.entrypoints.read().unwrap().len(), 2); -// assert!(cluster_info -// .entrypoints -// .read() -// .unwrap() -// .iter() -// .any(|entrypoint| *entrypoint == gossiped_entrypoint1_info)); - -// assert!(!entrypoints_processed); // <--- entrypoint processing incomplete because shred adoption still pending -// assert_eq!(cluster_info.my_shred_version(), 0); // <-- shred version still 0 - -// // Simulate getting entrypoint ContactInfo from gossip with an entrypoint2 shred version of -// // !0 -// let mut gossiped_entrypoint2_info = -// ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), timestamp()); -// gossiped_entrypoint2_info.gossip = entrypoint2_gossip_addr; -// gossiped_entrypoint2_info.shred_version = 1; -// cluster_info.insert_info(gossiped_entrypoint2_info.clone()); -// assert!(!cluster_info -// .entrypoints -// .read() -// .unwrap() -// .iter() -// .any(|entrypoint| *entrypoint == gossiped_entrypoint2_info)); - -// // Adopt the entrypoint's gossiped contact info and verify -// error!("Adopt the entrypoint's gossiped contact info and verify"); -// let entrypoints_processed = ClusterInfo::process_entrypoints(&cluster_info); -// assert_eq!(cluster_info.entrypoints.read().unwrap().len(), 2); -// assert!(cluster_info -// .entrypoints -// .read() -// .unwrap() -// .iter() -// .any(|entrypoint| *entrypoint == gossiped_entrypoint2_info)); - -// assert!(entrypoints_processed); -// assert_eq!(cluster_info.my_shred_version(), 1); // <-- shred version now adopted from entrypoint2 -// } - -// #[test] -// fn test_process_entrypoint_without_adopt_shred_version() { -// let node_keypair = Arc::new(Keypair::new()); -// let cluster_info = Arc::new(ClusterInfo::new( -// { -// let mut contact_info = -// ContactInfo::new_localhost(&node_keypair.pubkey(), timestamp()); -// contact_info.shred_version = 2; -// contact_info -// }, -// node_keypair, -// SocketAddrSpace::Unspecified, -// )); -// assert_eq!(cluster_info.my_shred_version(), 2); - -// // Simulating starting up with default entrypoint, no known id, only a gossip -// // address -// let entrypoint_gossip_addr = socketaddr!("127.0.0.2:1234"); -// let mut entrypoint = ContactInfo::new_localhost(&Pubkey::default(), timestamp()); -// entrypoint.gossip = entrypoint_gossip_addr; -// assert_eq!(entrypoint.shred_version, 0); -// cluster_info.set_entrypoint(entrypoint); - -// // Simulate getting entrypoint ContactInfo from gossip -// let mut gossiped_entrypoint_info = -// ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), timestamp()); -// gossiped_entrypoint_info.gossip = entrypoint_gossip_addr; -// gossiped_entrypoint_info.shred_version = 1; -// cluster_info.insert_info(gossiped_entrypoint_info.clone()); - -// // Adopt the entrypoint's gossiped contact info and verify -// let entrypoints_processed = ClusterInfo::process_entrypoints(&cluster_info); -// assert_eq!(cluster_info.entrypoints.read().unwrap().len(), 1); -// assert_eq!( -// cluster_info.entrypoints.read().unwrap()[0], -// gossiped_entrypoint_info -// ); -// assert!(entrypoints_processed); -// assert_eq!(cluster_info.my_shred_version(), 2); // <--- No change to shred version -// } - -// #[test] -// fn test_compute_retransmit_peers_small() { -// const FANOUT: usize = 3; -// let index = vec![ -// 14, 15, 28, // 1st layer -// // 2nd layer -// 29, 4, 5, // 1st neighborhood -// 9, 16, 7, // 2nd neighborhood -// 26, 23, 2, // 3rd neighborhood -// // 3rd layer -// 31, 3, 17, // 1st neighborhood -// 20, 25, 0, // 2nd neighborhood -// 13, 30, 18, // 3rd neighborhood -// 19, 21, 22, // 4th neighborhood -// 6, 8, 11, // 5th neighborhood -// 27, 1, 10, // 6th neighborhood -// 12, 24, 34, // 7th neighborhood -// 33, 32, // 8th neighborhood -// ]; -// // 1st layer -// assert_eq!( -// compute_retransmit_peers(FANOUT, 0, &index), -// (vec![14, 15, 28], vec![29, 9, 26]) -// ); -// assert_eq!( -// compute_retransmit_peers(FANOUT, 1, &index), -// (vec![14, 15, 28], vec![4, 16, 23]) -// ); -// assert_eq!( -// compute_retransmit_peers(FANOUT, 2, &index), -// (vec![14, 15, 28], vec![5, 7, 2]) -// ); -// // 2nd layer, 1st neighborhood -// assert_eq!( -// compute_retransmit_peers(FANOUT, 3, &index), -// (vec![29, 4, 5], vec![31, 20, 13]) -// ); -// assert_eq!( -// compute_retransmit_peers(FANOUT, 4, &index), -// (vec![29, 4, 5], vec![3, 25, 30]) -// ); -// assert_eq!( -// compute_retransmit_peers(FANOUT, 5, &index), -// (vec![29, 4, 5], vec![17, 0, 18]) -// ); -// // 2nd layer, 2nd neighborhood -// assert_eq!( -// compute_retransmit_peers(FANOUT, 6, &index), -// (vec![9, 16, 7], vec![19, 6, 27]) -// ); -// assert_eq!( -// compute_retransmit_peers(FANOUT, 7, &index), -// (vec![9, 16, 7], vec![21, 8, 1]) -// ); -// assert_eq!( -// compute_retransmit_peers(FANOUT, 8, &index), -// (vec![9, 16, 7], vec![22, 11, 10]) -// ); -// // 2nd layer, 3rd neighborhood -// assert_eq!( -// compute_retransmit_peers(FANOUT, 9, &index), -// (vec![26, 23, 2], vec![12, 33]) -// ); -// assert_eq!( -// compute_retransmit_peers(FANOUT, 10, &index), -// (vec![26, 23, 2], vec![24, 32]) -// ); -// assert_eq!( -// compute_retransmit_peers(FANOUT, 11, &index), -// (vec![26, 23, 2], vec![34]) -// ); -// // 3rd layer -// let num_nodes = index.len(); -// for k in (12..num_nodes).step_by(3) { -// let end = num_nodes.min(k + 3); -// let neighbors = index[k..end].to_vec(); -// for i in k..end { -// assert_eq!( -// compute_retransmit_peers(FANOUT, i, &index), -// (neighbors.clone(), vec![]) -// ); -// } -// } -// } - -// #[test] -// fn test_compute_retransmit_peers_with_fanout_five() { -// const FANOUT: usize = 5; -// const NUM_NODES: usize = 2048; -// const SEED: [u8; 32] = [0x55; 32]; -// let mut rng = ChaChaRng::from_seed(SEED); -// let mut index: Vec<_> = (0..NUM_NODES).collect(); -// index.shuffle(&mut rng); -// let (neighbors, children) = compute_retransmit_peers(FANOUT, 17, &index); -// assert_eq!(neighbors, vec![1410, 1293, 1810, 552, 512]); -// assert_eq!(children, vec![511, 1989, 283, 1606, 1154]); -// } - -// #[test] -// fn test_compute_retransmit_peers_large() { -// const FANOUT: usize = 7; -// const NUM_NODES: usize = 512; -// let mut rng = rand::thread_rng(); -// let mut index: Vec<_> = (0..NUM_NODES).collect(); -// index.shuffle(&mut rng); -// let pos: HashMap = index -// .iter() -// .enumerate() -// .map(|(i, node)| (*node, i)) -// .collect(); -// let mut seen = vec![0; NUM_NODES]; -// for i in 0..NUM_NODES { -// let node = index[i]; -// let (neighbors, children) = compute_retransmit_peers(FANOUT, i, &index); -// assert!(neighbors.len() <= FANOUT); -// assert!(children.len() <= FANOUT); -// // If x is neighbor of y then y is also neighbor of x. -// for other in &neighbors { -// let j = pos[other]; -// let (other_neighbors, _) = compute_retransmit_peers(FANOUT, j, &index); -// assert!(other_neighbors.contains(&node)); -// } -// for i in children { -// seen[i] += 1; -// } -// } -// // Except for the first layer, each node -// // is child of exactly one other node. -// let (seed, _) = compute_retransmit_peers(FANOUT, 0, &index); -// for (i, k) in seen.into_iter().enumerate() { -// if seed.contains(&i) { -// assert_eq!(k, 0); -// } else { -// assert_eq!(k, 1); -// } -// } -// } - -// #[test] -// #[ignore] // TODO: debug why this is flaky on buildkite! -// fn test_pull_request_time_pruning() { -// let node = Node::new_localhost(); -// let cluster_info = Arc::new(ClusterInfo::new( -// node.info, -// Arc::new(Keypair::new()), -// SocketAddrSpace::Unspecified, -// )); -// let entrypoint_pubkey = solana_sdk::pubkey::new_rand(); -// let entrypoint = ContactInfo::new_localhost(&entrypoint_pubkey, timestamp()); -// cluster_info.set_entrypoint(entrypoint); - -// let mut rng = rand::thread_rng(); -// let shred_version = cluster_info.my_shred_version(); -// let mut peers: Vec = vec![]; - -// const NO_ENTRIES: usize = CRDS_UNIQUE_PUBKEY_CAPACITY + 128; -// let data: Vec<_> = repeat_with(|| { -// let keypair = Keypair::new(); -// peers.push(keypair.pubkey()); -// let mut rand_ci = ContactInfo::new_rand(&mut rng, Some(keypair.pubkey())); -// rand_ci.shred_version = shred_version; -// rand_ci.wallclock = timestamp(); -// CrdsValue::new_signed(CrdsData::ContactInfo(rand_ci), &keypair) -// }) -// .take(NO_ENTRIES) -// .collect(); -// let mut timeouts = HashMap::new(); -// timeouts.insert(Pubkey::default(), CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS * 4); -// assert_eq!( -// (0, 0, NO_ENTRIES), -// cluster_info.handle_pull_response(&entrypoint_pubkey, data, &timeouts) -// ); - -// let now = timestamp(); -// for peer in peers { -// cluster_info -// .gossip -// .mark_pull_request_creation_time(peer, now); -// } -// assert_eq!( -// cluster_info.gossip.pull.pull_request_time().len(), -// CRDS_UNIQUE_PUBKEY_CAPACITY -// ); -// } - -// #[test] -// fn test_get_epoch_millis_no_bank() { -// let epoch_duration = get_epoch_duration(/*bank_forks:*/ None, &GossipStats::default()); -// assert_eq!( -// epoch_duration.as_millis() as u64, -// DEFAULT_SLOTS_PER_EPOCH * DEFAULT_MS_PER_SLOT // 48 hours -// ); -// } -// } diff --git a/gossip/src/cluster_info_metrics.rs b/gossip/src/cluster_info_metrics.rs deleted file mode 100644 index 7026ec4..0000000 --- a/gossip/src/cluster_info_metrics.rs +++ /dev/null @@ -1,720 +0,0 @@ -use { - crate::crds_gossip::CrdsGossip, - itertools::Itertools, - solana_measure::measure::Measure, - solana_sdk::{clock::Slot, pubkey::Pubkey}, - std::{ - cmp::Reverse, - collections::HashMap, - ops::{Deref, DerefMut}, - sync::atomic::{AtomicU64, Ordering}, - time::Instant, - }, -}; - -#[derive(Default)] -pub(crate) struct Counter(AtomicU64); - -impl Counter { - pub(crate) fn add_measure(&self, x: &mut Measure) { - x.stop(); - self.0.fetch_add(x.as_us(), Ordering::Relaxed); - } - pub(crate) fn add_relaxed(&self, x: u64) { - self.0.fetch_add(x, Ordering::Relaxed); - } - fn clear(&self) -> u64 { - self.0.swap(0, Ordering::Relaxed) - } -} - -pub(crate) struct TimedGuard<'a, T> { - guard: T, - timer: Measure, - counter: &'a Counter, -} - -pub(crate) struct ScopedTimer<'a> { - clock: Instant, - metric: &'a AtomicU64, -} - -impl<'a> From<&'a Counter> for ScopedTimer<'a> { - // Output should be assigned to a *named* variable, otherwise it is - // immediately dropped. - #[must_use] - fn from(counter: &'a Counter) -> Self { - Self { - clock: Instant::now(), - metric: &counter.0, - } - } -} - -impl Drop for ScopedTimer<'_> { - fn drop(&mut self) { - let micros = self.clock.elapsed().as_micros(); - self.metric.fetch_add(micros as u64, Ordering::Relaxed); - } -} - -impl<'a, T> TimedGuard<'a, T> { - pub(crate) fn new(guard: T, label: &'static str, counter: &'a Counter) -> Self { - Self { - guard, - timer: Measure::start(label), - counter, - } - } -} - -impl<'a, T> Deref for TimedGuard<'a, T> { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.guard - } -} - -impl<'a, T> DerefMut for TimedGuard<'a, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.guard - } -} - -impl<'a, T> Drop for TimedGuard<'a, T> { - fn drop(&mut self) { - self.counter.add_measure(&mut self.timer); - } -} - -#[derive(Default)] -pub struct GossipStats { - pub(crate) all_tvu_peers: Counter, - pub(crate) bad_prune_destination: Counter, - pub(crate) entrypoint2: Counter, - pub(crate) entrypoint: Counter, - pub(crate) epoch_slots_filled: Counter, - pub(crate) epoch_slots_lookup: Counter, - pub(crate) filter_crds_values_dropped_requests: Counter, - pub(crate) filter_crds_values_dropped_values: Counter, - pub(crate) filter_pull_response: Counter, - pub(crate) generate_pull_responses: Counter, - pub(crate) get_accounts_hash: Counter, - pub(crate) get_epoch_duration_no_working_bank: Counter, - pub(crate) get_votes: Counter, - pub(crate) get_votes_count: Counter, - pub(crate) gossip_listen_loop_iterations_since_last_report: Counter, - pub(crate) gossip_listen_loop_time: Counter, - pub(crate) gossip_packets_dropped_count: Counter, - pub(crate) gossip_ping_msg_verify_fail: Counter, - pub(crate) gossip_pong_msg_verify_fail: Counter, - pub(crate) gossip_prune_msg_verify_fail: Counter, - pub(crate) gossip_pull_request_dropped_requests: Counter, - pub(crate) gossip_pull_request_no_budget: Counter, - pub(crate) gossip_pull_request_sent_requests: Counter, - pub(crate) gossip_pull_request_verify_fail: Counter, - pub(crate) gossip_pull_response_verify_fail: Counter, - pub(crate) gossip_push_msg_verify_fail: Counter, - pub(crate) gossip_transmit_loop_iterations_since_last_report: Counter, - pub(crate) gossip_transmit_loop_time: Counter, - pub(crate) handle_batch_ping_messages_time: Counter, - pub(crate) handle_batch_pong_messages_time: Counter, - pub(crate) handle_batch_prune_messages_time: Counter, - pub(crate) handle_batch_pull_requests_time: Counter, - pub(crate) handle_batch_pull_responses_time: Counter, - pub(crate) handle_batch_push_messages_time: Counter, - pub(crate) mark_pull_request: Counter, - pub(crate) new_pull_requests: Counter, - pub(crate) new_pull_requests_count: Counter, - pub(crate) new_pull_requests_pings_count: Counter, - pub(crate) new_push_requests2: Counter, - pub(crate) new_push_requests: Counter, - pub(crate) new_push_requests_num: Counter, - pub(crate) packets_received_count: Counter, - pub(crate) packets_received_ping_messages_count: Counter, - pub(crate) packets_received_pong_messages_count: Counter, - pub(crate) packets_received_prune_messages_count: Counter, - pub(crate) packets_received_pull_requests_count: Counter, - pub(crate) packets_received_pull_responses_count: Counter, - pub(crate) packets_received_push_messages_count: Counter, - pub(crate) packets_received_unknown_count: Counter, - pub(crate) packets_received_verified_count: Counter, - pub(crate) packets_sent_gossip_requests_count: Counter, - pub(crate) packets_sent_prune_messages_count: Counter, - pub(crate) packets_sent_pull_requests_count: Counter, - pub(crate) packets_sent_pull_responses_count: Counter, - pub(crate) packets_sent_push_messages_count: Counter, - pub(crate) process_gossip_packets_iterations_since_last_report: Counter, - pub(crate) process_gossip_packets_time: Counter, - pub(crate) process_prune: Counter, - pub(crate) process_pull_requests: Counter, - pub(crate) process_pull_response: Counter, - pub(crate) process_pull_response_count: Counter, - pub(crate) process_pull_response_fail_insert: Counter, - pub(crate) process_pull_response_fail_timeout: Counter, - pub(crate) process_pull_response_len: Counter, - pub(crate) process_pull_response_success: Counter, - pub(crate) process_pull_response_timeout: Counter, - pub(crate) process_push_message: Counter, - pub(crate) prune_message_count: Counter, - pub(crate) prune_message_len: Counter, - pub(crate) prune_message_timeout: Counter, - pub(crate) prune_received_cache: Counter, - pub(crate) pull_from_entrypoint_count: Counter, - pub(crate) pull_request_ping_pong_check_failed_count: Counter, - pub(crate) pull_requests_count: Counter, - pub(crate) purge: Counter, - pub(crate) purge_count: Counter, - pub(crate) push_fanout_num_entries: Counter, - pub(crate) push_fanout_num_nodes: Counter, - pub(crate) push_message_count: Counter, - pub(crate) push_message_pushes: Counter, - pub(crate) push_message_value_count: Counter, - pub(crate) push_response_count: Counter, - pub(crate) push_vote_read: Counter, - pub(crate) repair_peers: Counter, - pub(crate) require_stake_for_gossip_unknown_stakes: Counter, - pub(crate) skip_pull_response_shred_version: Counter, - pub(crate) skip_pull_shred_version: Counter, - pub(crate) skip_push_message_shred_version: Counter, - pub(crate) trim_crds_table: Counter, - pub(crate) trim_crds_table_failed: Counter, - pub(crate) trim_crds_table_purged_values_count: Counter, - pub(crate) tvu_peers: Counter, - pub(crate) verify_gossip_packets_time: Counter, - pub(crate) window_request_loopback: Counter, -} - -pub(crate) fn submit_gossip_stats( - stats: &GossipStats, - gossip: &CrdsGossip, - stakes: &HashMap, -) { - let (crds_stats, table_size, num_nodes, num_pubkeys, purged_values_size, failed_inserts_size) = { - let gossip_crds = gossip.crds.read().unwrap(); - ( - gossip_crds.take_stats(), - gossip_crds.len(), - gossip_crds.num_nodes(), - gossip_crds.num_pubkeys(), - gossip_crds.num_purged(), - gossip.pull.failed_inserts_size(), - ) - }; - let num_nodes_staked = stakes.values().filter(|stake| **stake > 0).count(); - datapoint_info!( - "cluster_info_stats", - ("entrypoint", stats.entrypoint.clear(), i64), - ("entrypoint2", stats.entrypoint2.clear(), i64), - ("push_vote_read", stats.push_vote_read.clear(), i64), - ("get_votes", stats.get_votes.clear(), i64), - ("get_votes_count", stats.get_votes_count.clear(), i64), - ("get_accounts_hash", stats.get_accounts_hash.clear(), i64), - ("all_tvu_peers", stats.all_tvu_peers.clear(), i64), - ("tvu_peers", stats.tvu_peers.clear(), i64), - ( - "new_push_requests_num", - stats.new_push_requests_num.clear(), - i64 - ), - ("table_size", table_size as i64, i64), - ("purged_values_size", purged_values_size as i64, i64), - ("failed_inserts_size", failed_inserts_size as i64, i64), - ("num_nodes", num_nodes as i64, i64), - ("num_nodes_staked", num_nodes_staked as i64, i64), - ("num_pubkeys", num_pubkeys, i64), - ); - datapoint_info!( - "cluster_info_stats2", - ( - "gossip_packets_dropped_count", - stats.gossip_packets_dropped_count.clear(), - i64 - ), - ("repair_peers", stats.repair_peers.clear(), i64), - ("new_push_requests", stats.new_push_requests.clear(), i64), - ("new_push_requests2", stats.new_push_requests2.clear(), i64), - ("purge", stats.purge.clear(), i64), - ("purge_count", stats.purge_count.clear(), i64), - ( - "process_gossip_packets_time", - stats.process_gossip_packets_time.clear(), - i64 - ), - ( - "verify_gossip_packets_time", - stats.verify_gossip_packets_time.clear(), - i64 - ), - ( - "handle_batch_ping_messages_time", - stats.handle_batch_ping_messages_time.clear(), - i64 - ), - ( - "handle_batch_pong_messages_time", - stats.handle_batch_pong_messages_time.clear(), - i64 - ), - ( - "handle_batch_prune_messages_time", - stats.handle_batch_prune_messages_time.clear(), - i64 - ), - ( - "handle_batch_pull_requests_time", - stats.handle_batch_pull_requests_time.clear(), - i64 - ), - ( - "handle_batch_pull_responses_time", - stats.handle_batch_pull_responses_time.clear(), - i64 - ), - ( - "handle_batch_push_messages_time", - stats.handle_batch_push_messages_time.clear(), - i64 - ), - ( - "process_pull_resp", - stats.process_pull_response.clear(), - i64 - ), - ("filter_pull_resp", stats.filter_pull_response.clear(), i64), - ( - "filter_crds_values_dropped_requests", - stats.filter_crds_values_dropped_requests.clear(), - i64 - ), - ( - "filter_crds_values_dropped_values", - stats.filter_crds_values_dropped_values.clear(), - i64 - ), - ( - "process_pull_resp_count", - stats.process_pull_response_count.clear(), - i64 - ), - ( - "pull_response_fail_insert", - stats.process_pull_response_fail_insert.clear(), - i64 - ), - ( - "pull_response_fail_timeout", - stats.process_pull_response_fail_timeout.clear(), - i64 - ), - ( - "pull_response_success", - stats.process_pull_response_success.clear(), - i64 - ), - ( - "process_pull_resp_timeout", - stats.process_pull_response_timeout.clear(), - i64 - ), - ( - "push_response_count", - stats.push_response_count.clear(), - i64 - ), - ); - datapoint_info!( - "cluster_info_stats3", - ( - "process_pull_resp_len", - stats.process_pull_response_len.clear(), - i64 - ), - ( - "process_pull_requests", - stats.process_pull_requests.clear(), - i64 - ), - ( - "pull_request_ping_pong_check_failed_count", - stats.pull_request_ping_pong_check_failed_count.clear(), - i64 - ), - ( - "new_pull_requests_pings_count", - stats.new_pull_requests_pings_count.clear(), - i64 - ), - ( - "generate_pull_responses", - stats.generate_pull_responses.clear(), - i64 - ), - ("process_prune", stats.process_prune.clear(), i64), - ( - "prune_message_timeout", - stats.prune_message_timeout.clear(), - i64 - ), - ( - "bad_prune_destination", - stats.bad_prune_destination.clear(), - i64 - ), - ( - "process_push_message", - stats.process_push_message.clear(), - i64 - ), - ( - "prune_received_cache", - stats.prune_received_cache.clear(), - i64 - ), - ("epoch_slots_lookup", stats.epoch_slots_lookup.clear(), i64), - ("new_pull_requests", stats.new_pull_requests.clear(), i64), - ("mark_pull_request", stats.mark_pull_request.clear(), i64), - ( - "gossip_pull_request_no_budget", - stats.gossip_pull_request_no_budget.clear(), - i64 - ), - ( - "gossip_pull_request_sent_requests", - stats.gossip_pull_request_sent_requests.clear(), - i64 - ), - ( - "gossip_pull_request_dropped_requests", - stats.gossip_pull_request_dropped_requests.clear(), - i64 - ), - ( - "gossip_transmit_loop_time", - stats.gossip_transmit_loop_time.clear(), - i64 - ), - ( - "gossip_transmit_loop_iterations_since_last_report", - stats - .gossip_transmit_loop_iterations_since_last_report - .clear(), - i64 - ), - ( - "gossip_listen_loop_time", - stats.gossip_listen_loop_time.clear(), - i64 - ), - ( - "gossip_listen_loop_iterations_since_last_report", - stats - .gossip_listen_loop_iterations_since_last_report - .clear(), - i64 - ), - ( - "process_gossip_packets_iterations_since_last_report", - stats - .process_gossip_packets_iterations_since_last_report - .clear(), - i64 - ), - ); - datapoint_info!( - "cluster_info_stats4", - ( - "skip_push_message_shred_version", - stats.skip_push_message_shred_version.clear(), - i64 - ), - ( - "skip_pull_response_shred_version", - stats.skip_pull_response_shred_version.clear(), - i64 - ), - ( - "skip_pull_shred_version", - stats.skip_pull_shred_version.clear(), - i64 - ), - ("push_message_count", stats.push_message_count.clear(), i64), - ( - "push_fanout_num_entries", - stats.push_fanout_num_entries.clear(), - i64 - ), - ( - "push_fanout_num_nodes", - stats.push_fanout_num_nodes.clear(), - i64 - ), - ( - "push_message_pushes", - stats.push_message_pushes.clear(), - i64 - ), - ( - "push_message_value_count", - stats.push_message_value_count.clear(), - i64 - ), - ( - "new_pull_requests_count", - stats.new_pull_requests_count.clear(), - i64 - ), - ( - "pull_from_entrypoint_count", - stats.pull_from_entrypoint_count.clear(), - i64 - ), - ( - "prune_message_count", - stats.prune_message_count.clear(), - i64 - ), - ("prune_message_len", stats.prune_message_len.clear(), i64), - ("epoch_slots_filled", stats.epoch_slots_filled.clear(), i64), - ( - "window_request_loopback", - stats.window_request_loopback.clear(), - i64 - ), - ( - "get_epoch_duration_no_working_bank", - stats.get_epoch_duration_no_working_bank.clear(), - i64 - ), - ); - datapoint_info!( - "cluster_info_stats5", - ( - "pull_requests_count", - stats.pull_requests_count.clear(), - i64 - ), - ( - "packets_received_count", - stats.packets_received_count.clear(), - i64 - ), - ( - "packets_received_ping_messages_count", - stats.packets_received_ping_messages_count.clear(), - i64 - ), - ( - "packets_received_pong_messages_count", - stats.packets_received_pong_messages_count.clear(), - i64 - ), - ( - "packets_received_prune_messages_count", - stats.packets_received_prune_messages_count.clear(), - i64 - ), - ( - "packets_received_pull_requests_count", - stats.packets_received_pull_requests_count.clear(), - i64 - ), - ( - "packets_received_pull_responses_count", - stats.packets_received_pull_responses_count.clear(), - i64 - ), - ( - "packets_received_push_messages_count", - stats.packets_received_push_messages_count.clear(), - i64 - ), - ( - "packets_received_unknown_count", - stats.packets_received_unknown_count.clear(), - i64 - ), - ( - "packets_received_verified_count", - stats.packets_received_verified_count.clear(), - i64 - ), - ( - "packets_sent_gossip_requests_count", - stats.packets_sent_gossip_requests_count.clear(), - i64 - ), - ( - "packets_sent_prune_messages_count", - stats.packets_sent_prune_messages_count.clear(), - i64 - ), - ( - "packets_sent_pull_requests_count", - stats.packets_sent_pull_requests_count.clear(), - i64 - ), - ( - "packets_sent_pull_responses_count", - stats.packets_sent_pull_responses_count.clear(), - i64 - ), - ( - "packets_sent_push_messages_count", - stats.packets_sent_push_messages_count.clear(), - i64 - ), - ( - "require_stake_for_gossip_unknown_stakes", - stats.require_stake_for_gossip_unknown_stakes.clear(), - i64 - ), - ("trim_crds_table", stats.trim_crds_table.clear(), i64), - ( - "trim_crds_table_failed", - stats.trim_crds_table_failed.clear(), - i64 - ), - ( - "trim_crds_table_purged_values_count", - stats.trim_crds_table_purged_values_count.clear(), - i64 - ), - ( - "gossip_pull_request_verify_fail", - stats.gossip_pull_request_verify_fail.clear(), - i64 - ), - ( - "gossip_pull_response_verify_fail", - stats.gossip_pull_response_verify_fail.clear(), - i64 - ), - ( - "gossip_push_msg_verify_fail", - stats.gossip_push_msg_verify_fail.clear(), - i64 - ), - ( - "gossip_prune_msg_verify_fail", - stats.gossip_prune_msg_verify_fail.clear(), - i64 - ), - ( - "gossip_ping_msg_verify_fail", - stats.gossip_ping_msg_verify_fail.clear(), - i64 - ), - ( - "gossip_pong_msg_verify_fail", - stats.gossip_pong_msg_verify_fail.clear(), - i64 - ), - ); - datapoint_info!( - "cluster_info_crds_stats", - ("ContactInfo-push", crds_stats.push.counts[0], i64), - ("ContactInfo-pull", crds_stats.pull.counts[0], i64), - ("Vote-push", crds_stats.push.counts[1], i64), - ("Vote-pull", crds_stats.pull.counts[1], i64), - ("LowestSlot-push", crds_stats.push.counts[2], i64), - ("LowestSlot-pull", crds_stats.pull.counts[2], i64), - ("SnapshotHashes-push", crds_stats.push.counts[3], i64), - ("SnapshotHashes-pull", crds_stats.pull.counts[3], i64), - ("AccountsHashes-push", crds_stats.push.counts[4], i64), - ("AccountsHashes-pull", crds_stats.pull.counts[4], i64), - ("EpochSlots-push", crds_stats.push.counts[5], i64), - ("EpochSlots-pull", crds_stats.pull.counts[5], i64), - ("LegacyVersion-push", crds_stats.push.counts[6], i64), - ("LegacyVersion-pull", crds_stats.pull.counts[6], i64), - ("Version-push", crds_stats.push.counts[7], i64), - ("Version-pull", crds_stats.pull.counts[7], i64), - ("NodeInstance-push", crds_stats.push.counts[8], i64), - ("NodeInstance-pull", crds_stats.pull.counts[8], i64), - ("DuplicateShred-push", crds_stats.push.counts[9], i64), - ("DuplicateShred-pull", crds_stats.pull.counts[9], i64), - ( - "IncrementalSnapshotHashes-push", - crds_stats.push.counts[10], - i64 - ), - ( - "IncrementalSnapshotHashes-pull", - crds_stats.pull.counts[10], - i64 - ), - ( - "all-push", - crds_stats.push.counts.iter().sum::(), - i64 - ), - ( - "all-pull", - crds_stats.pull.counts.iter().sum::(), - i64 - ), - ); - datapoint_info!( - "cluster_info_crds_stats_fails", - ("ContactInfo-push", crds_stats.push.fails[0], i64), - ("ContactInfo-pull", crds_stats.pull.fails[0], i64), - ("Vote-push", crds_stats.push.fails[1], i64), - ("Vote-pull", crds_stats.pull.fails[1], i64), - ("LowestSlot-push", crds_stats.push.fails[2], i64), - ("LowestSlot-pull", crds_stats.pull.fails[2], i64), - ("SnapshotHashes-push", crds_stats.push.fails[3], i64), - ("SnapshotHashes-pull", crds_stats.pull.fails[3], i64), - ("AccountsHashes-push", crds_stats.push.fails[4], i64), - ("AccountsHashes-pull", crds_stats.pull.fails[4], i64), - ("EpochSlots-push", crds_stats.push.fails[5], i64), - ("EpochSlots-pull", crds_stats.pull.fails[5], i64), - ("LegacyVersion-push", crds_stats.push.fails[6], i64), - ("LegacyVersion-pull", crds_stats.pull.fails[6], i64), - ("Version-push", crds_stats.push.fails[7], i64), - ("Version-pull", crds_stats.pull.fails[7], i64), - ("NodeInstance-push", crds_stats.push.fails[8], i64), - ("NodeInstance-pull", crds_stats.pull.fails[8], i64), - ("DuplicateShred-push", crds_stats.push.fails[9], i64), - ("DuplicateShred-pull", crds_stats.pull.fails[9], i64), - ( - "IncrementalSnapshotHashes-push", - crds_stats.push.fails[10], - i64 - ), - ( - "IncrementalSnapshotHashes-pull", - crds_stats.pull.fails[10], - i64 - ), - ("all-push", crds_stats.push.fails.iter().sum::(), i64), - ("all-pull", crds_stats.pull.fails.iter().sum::(), i64), - ); - if !log::log_enabled!(log::Level::Trace) { - return; - } - submit_vote_stats("cluster_info_crds_stats_votes_pull", &crds_stats.pull.votes); - submit_vote_stats("cluster_info_crds_stats_votes_push", &crds_stats.push.votes); - let votes: HashMap = crds_stats - .pull - .votes - .into_iter() - .chain(crds_stats.push.votes.into_iter()) - .into_grouping_map() - .aggregate(|acc, _slot, num_votes| Some(acc.unwrap_or_default() + num_votes)); - submit_vote_stats("cluster_info_crds_stats_votes", &votes); -} - -fn submit_vote_stats<'a, I>(name: &'static str, votes: I) -where - I: IntoIterator, -{ - // Submit vote stats only for the top most voted slots. - const NUM_SLOTS: usize = 10; - let mut votes: Vec<_> = votes.into_iter().map(|(k, v)| (*k, *v)).collect(); - if votes.len() > NUM_SLOTS { - votes.select_nth_unstable_by_key(NUM_SLOTS, |(_, num)| Reverse(*num)); - } - for (slot, num_votes) in votes.into_iter().take(NUM_SLOTS) { - datapoint_trace!(name, ("slot", slot, i64), ("num_votes", num_votes, i64)); - } -} diff --git a/gossip/src/contact_info.rs b/gossip/src/contact_info.rs deleted file mode 100644 index 083f4cd..0000000 --- a/gossip/src/contact_info.rs +++ /dev/null @@ -1,359 +0,0 @@ -use { - crate::crds_value::MAX_WALLCLOCK, - solana_sdk::{ - pubkey::Pubkey, - rpc_port, - sanitize::{Sanitize, SanitizeError}, - signature::{Keypair, Signer}, - timing::timestamp, - }, - solana_streamer::socket::SocketAddrSpace, - std::net::{IpAddr, SocketAddr}, -}; - -/// Structure representing a node on the network -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)] -pub struct ContactInfo { - pub id: Pubkey, - /// gossip address - pub gossip: SocketAddr, - /// address to connect to for replication - pub tvu: SocketAddr, - /// address to forward shreds to - pub tvu_forwards: SocketAddr, - /// address to send repair responses to - pub repair: SocketAddr, - /// transactions address - pub tpu: SocketAddr, - /// address to forward unprocessed transactions to - pub tpu_forwards: SocketAddr, - /// address to which to send bank state requests - pub tpu_vote: SocketAddr, - /// address to which to send JSON-RPC requests - pub rpc: SocketAddr, - /// websocket for JSON-RPC push notifications - pub rpc_pubsub: SocketAddr, - /// address to send repair requests to - pub serve_repair: SocketAddr, - /// latest wallclock picked - pub wallclock: u64, - /// node shred version - pub shred_version: u16, -} - -impl Sanitize for ContactInfo { - fn sanitize(&self) -> std::result::Result<(), SanitizeError> { - if self.wallclock >= MAX_WALLCLOCK { - return Err(SanitizeError::ValueOutOfBounds); - } - Ok(()) - } -} - -#[macro_export] -macro_rules! socketaddr { - ($ip:expr, $port:expr) => { - std::net::SocketAddr::from((std::net::Ipv4Addr::from($ip), $port)) - }; - ($str:expr) => {{ - $str.parse::().unwrap() - }}; -} -#[macro_export] -macro_rules! socketaddr_any { - () => { - socketaddr!(0, 0) - }; -} - -impl Default for ContactInfo { - fn default() -> Self { - ContactInfo { - id: Pubkey::default(), - gossip: socketaddr_any!(), - tvu: socketaddr_any!(), - tvu_forwards: socketaddr_any!(), - repair: socketaddr_any!(), - tpu: socketaddr_any!(), - tpu_forwards: socketaddr_any!(), - tpu_vote: socketaddr_any!(), - rpc: socketaddr_any!(), - rpc_pubsub: socketaddr_any!(), - serve_repair: socketaddr_any!(), - wallclock: 0, - shred_version: 0, - } - } -} - -impl ContactInfo { - pub fn new_localhost(id: &Pubkey, now: u64) -> Self { - Self { - id: *id, - gossip: socketaddr!("127.0.0.1:1234"), - tvu: socketaddr!("127.0.0.1:1235"), - tvu_forwards: socketaddr!("127.0.0.1:1236"), - repair: socketaddr!("127.0.0.1:1237"), - tpu: socketaddr!("127.0.0.1:1238"), - tpu_forwards: socketaddr!("127.0.0.1:1239"), - tpu_vote: socketaddr!("127.0.0.1:1240"), - rpc: socketaddr!("127.0.0.1:1241"), - rpc_pubsub: socketaddr!("127.0.0.1:1242"), - serve_repair: socketaddr!("127.0.0.1:1243"), - wallclock: now, - shred_version: 0, - } - } - - /// New random ContactInfo for tests and simulations. - pub fn new_rand(rng: &mut R, pubkey: Option) -> Self { - let delay = 10 * 60 * 1000; // 10 minutes - let now = timestamp() - delay + rng.gen_range(0, 2 * delay); - let pubkey = pubkey.unwrap_or_else(solana_sdk::pubkey::new_rand); - ContactInfo::new_localhost(&pubkey, now) - } - - #[cfg(test)] - /// ContactInfo with multicast addresses for adversarial testing. - pub fn new_multicast() -> Self { - let addr = socketaddr!("224.0.1.255:1000"); - assert!(addr.ip().is_multicast()); - Self { - id: solana_sdk::pubkey::new_rand(), - gossip: addr, - tvu: addr, - tvu_forwards: addr, - repair: addr, - tpu: addr, - tpu_forwards: addr, - tpu_vote: addr, - rpc: addr, - rpc_pubsub: addr, - serve_repair: addr, - wallclock: 0, - shred_version: 0, - } - } - - // Used in tests - pub fn new_with_pubkey_socketaddr(pubkey: &Pubkey, bind_addr: &SocketAddr) -> Self { - fn next_port(addr: &SocketAddr, nxt: u16) -> SocketAddr { - let mut nxt_addr = *addr; - nxt_addr.set_port(addr.port() + nxt); - nxt_addr - } - - let tpu = *bind_addr; - let gossip = next_port(bind_addr, 1); - let tvu = next_port(bind_addr, 2); - let tpu_forwards = next_port(bind_addr, 3); - let tvu_forwards = next_port(bind_addr, 4); - let repair = next_port(bind_addr, 5); - let rpc = SocketAddr::new(bind_addr.ip(), rpc_port::DEFAULT_RPC_PORT); - let rpc_pubsub = SocketAddr::new(bind_addr.ip(), rpc_port::DEFAULT_RPC_PUBSUB_PORT); - let serve_repair = next_port(bind_addr, 6); - let tpu_vote = next_port(bind_addr, 7); - Self { - id: *pubkey, - gossip, - tvu, - tvu_forwards, - repair, - tpu, - tpu_forwards, - tpu_vote, - rpc, - rpc_pubsub, - serve_repair, - wallclock: timestamp(), - shred_version: 0, - } - } - - // Used in tests - pub fn new_with_socketaddr(bind_addr: &SocketAddr) -> Self { - let keypair = Keypair::new(); - Self::new_with_pubkey_socketaddr(&keypair.pubkey(), bind_addr) - } - - // Construct a ContactInfo that's only usable for gossip - pub fn new_gossip_entry_point(gossip_addr: &SocketAddr) -> Self { - Self { - id: Pubkey::default(), - gossip: *gossip_addr, - wallclock: timestamp(), - ..ContactInfo::default() - } - } - - fn is_valid_ip(addr: IpAddr) -> bool { - !(addr.is_unspecified() || addr.is_multicast()) - // || (addr.is_loopback() && !cfg_test)) - // TODO: boot loopback in production networks - } - - /// port must not be 0 - /// ip must be specified and not multicast - /// loopback ip is only allowed in tests - // Keeping this for now not to break tvu-peers and turbine shuffle order of - // nodes when arranging nodes on retransmit tree. Private IP addresses in - // turbine are filtered out just before sending packets. - pub(crate) fn is_valid_tvu_address(addr: &SocketAddr) -> bool { - (addr.port() != 0) && Self::is_valid_ip(addr.ip()) - } - - // TODO: Replace this entirely with streamer SocketAddrSpace. - pub fn is_valid_address(addr: &SocketAddr, socket_addr_space: &SocketAddrSpace) -> bool { - Self::is_valid_tvu_address(addr) && socket_addr_space.check(addr) - } - - pub fn client_facing_addr(&self) -> (SocketAddr, SocketAddr) { - (self.rpc, self.tpu) - } - - pub fn valid_client_facing_addr( - &self, - socket_addr_space: &SocketAddrSpace, - ) -> Option<(SocketAddr, SocketAddr)> { - if ContactInfo::is_valid_address(&self.rpc, socket_addr_space) - && ContactInfo::is_valid_address(&self.tpu, socket_addr_space) - { - Some((self.rpc, self.tpu)) - } else { - None - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_is_valid_address() { - let bad_address_port = socketaddr!("127.0.0.1:0"); - assert!(!ContactInfo::is_valid_address( - &bad_address_port, - &SocketAddrSpace::Unspecified - )); - let bad_address_unspecified = socketaddr!(0, 1234); - assert!(!ContactInfo::is_valid_address( - &bad_address_unspecified, - &SocketAddrSpace::Unspecified - )); - let bad_address_multicast = socketaddr!([224, 254, 0, 0], 1234); - assert!(!ContactInfo::is_valid_address( - &bad_address_multicast, - &SocketAddrSpace::Unspecified - )); - let loopback = socketaddr!("127.0.0.1:1234"); - assert!(ContactInfo::is_valid_address( - &loopback, - &SocketAddrSpace::Unspecified - )); - // assert!(!ContactInfo::is_valid_ip_internal(loopback.ip(), false)); - } - - #[test] - fn test_default() { - let ci = ContactInfo::default(); - assert!(ci.gossip.ip().is_unspecified()); - assert!(ci.tvu.ip().is_unspecified()); - assert!(ci.tpu_forwards.ip().is_unspecified()); - assert!(ci.rpc.ip().is_unspecified()); - assert!(ci.rpc_pubsub.ip().is_unspecified()); - assert!(ci.tpu.ip().is_unspecified()); - assert!(ci.tpu_vote.ip().is_unspecified()); - assert!(ci.serve_repair.ip().is_unspecified()); - } - #[test] - fn test_multicast() { - let ci = ContactInfo::new_multicast(); - assert!(ci.gossip.ip().is_multicast()); - assert!(ci.tvu.ip().is_multicast()); - assert!(ci.tpu_forwards.ip().is_multicast()); - assert!(ci.rpc.ip().is_multicast()); - assert!(ci.rpc_pubsub.ip().is_multicast()); - assert!(ci.tpu.ip().is_multicast()); - assert!(ci.tpu_vote.ip().is_multicast()); - assert!(ci.serve_repair.ip().is_multicast()); - } - #[test] - fn test_entry_point() { - let addr = socketaddr!("127.0.0.1:10"); - let ci = ContactInfo::new_gossip_entry_point(&addr); - assert_eq!(ci.gossip, addr); - assert!(ci.tvu.ip().is_unspecified()); - assert!(ci.tpu_forwards.ip().is_unspecified()); - assert!(ci.rpc.ip().is_unspecified()); - assert!(ci.rpc_pubsub.ip().is_unspecified()); - assert!(ci.tpu.ip().is_unspecified()); - assert!(ci.tpu_vote.ip().is_unspecified()); - assert!(ci.serve_repair.ip().is_unspecified()); - } - #[test] - fn test_socketaddr() { - let addr = socketaddr!("127.0.0.1:10"); - let ci = ContactInfo::new_with_socketaddr(&addr); - assert_eq!(ci.tpu, addr); - assert_eq!(ci.tpu_vote.port(), 17); - assert_eq!(ci.gossip.port(), 11); - assert_eq!(ci.tvu.port(), 12); - assert_eq!(ci.tpu_forwards.port(), 13); - assert_eq!(ci.rpc.port(), rpc_port::DEFAULT_RPC_PORT); - assert_eq!(ci.rpc_pubsub.port(), rpc_port::DEFAULT_RPC_PUBSUB_PORT); - assert_eq!(ci.serve_repair.port(), 16); - } - - #[test] - fn replayed_data_new_with_socketaddr_with_pubkey() { - let keypair = Keypair::new(); - let d1 = ContactInfo::new_with_pubkey_socketaddr( - &keypair.pubkey(), - &socketaddr!("127.0.0.1:1234"), - ); - assert_eq!(d1.id, keypair.pubkey()); - assert_eq!(d1.gossip, socketaddr!("127.0.0.1:1235")); - assert_eq!(d1.tvu, socketaddr!("127.0.0.1:1236")); - assert_eq!(d1.tpu_forwards, socketaddr!("127.0.0.1:1237")); - assert_eq!(d1.tpu, socketaddr!("127.0.0.1:1234")); - assert_eq!( - d1.rpc, - socketaddr!(format!("127.0.0.1:{}", rpc_port::DEFAULT_RPC_PORT)) - ); - assert_eq!( - d1.rpc_pubsub, - socketaddr!(format!("127.0.0.1:{}", rpc_port::DEFAULT_RPC_PUBSUB_PORT)) - ); - assert_eq!(d1.tvu_forwards, socketaddr!("127.0.0.1:1238")); - assert_eq!(d1.repair, socketaddr!("127.0.0.1:1239")); - assert_eq!(d1.serve_repair, socketaddr!("127.0.0.1:1240")); - assert_eq!(d1.tpu_vote, socketaddr!("127.0.0.1:1241")); - } - - #[test] - fn test_valid_client_facing() { - let mut ci = ContactInfo::default(); - assert_eq!( - ci.valid_client_facing_addr(&SocketAddrSpace::Unspecified), - None - ); - ci.tpu = socketaddr!("127.0.0.1:123"); - assert_eq!( - ci.valid_client_facing_addr(&SocketAddrSpace::Unspecified), - None - ); - ci.rpc = socketaddr!("127.0.0.1:234"); - assert!(ci - .valid_client_facing_addr(&SocketAddrSpace::Unspecified) - .is_some()); - } - - #[test] - fn test_sanitize() { - let mut ci = ContactInfo::default(); - assert_eq!(ci.sanitize(), Ok(())); - ci.wallclock = MAX_WALLCLOCK; - assert_eq!(ci.sanitize(), Err(SanitizeError::ValueOutOfBounds)); - } -} diff --git a/gossip/src/crds.rs b/gossip/src/crds.rs deleted file mode 100644 index cb96ec9..0000000 --- a/gossip/src/crds.rs +++ /dev/null @@ -1,1465 +0,0 @@ -//! This module implements Cluster Replicated Data Store for -//! asynchronous updates in a distributed network. -//! -//! Data is stored in the CrdsValue type, each type has a specific -//! CrdsValueLabel. Labels are semantically grouped into a single record -//! that is identified by a Pubkey. -//! * 1 Pubkey maps many CrdsValueLabels -//! * 1 CrdsValueLabel maps to 1 CrdsValue -//! The Label, the record Pubkey, and all the record labels can be derived -//! from a single CrdsValue. -//! -//! The actual data is stored in a single map of -//! `CrdsValueLabel(Pubkey) -> CrdsValue` This allows for partial record -//! updates to be propagated through the network. -//! -//! This means that full `Record` updates are not atomic. -//! -//! Additional labels can be added by appending them to the CrdsValueLabel, -//! CrdsValue enums. -//! -//! Merge strategy is implemented in: -//! fn overrides(value: &CrdsValue, other: &VersionedCrdsValue) -> bool -//! -//! A value is updated to a new version if the labels match, and the value -//! wallclock is later, or the value hash is greater. - -use { - crate::{ - contact_info::ContactInfo, - crds_entry::CrdsEntry, - crds_shards::CrdsShards, - crds_value::{CrdsData, CrdsValue, CrdsValueLabel}, - }, - bincode::serialize, - indexmap::{ - map::{rayon::ParValues, Entry, IndexMap}, - set::IndexSet, - }, - lru::LruCache, - matches::debug_assert_matches, - rayon::{prelude::*, ThreadPool}, - solana_sdk::{ - clock::Slot, - hash::{hash, Hash}, - pubkey::Pubkey, - }, - std::{ - cmp::Ordering, - collections::{hash_map, BTreeMap, HashMap, VecDeque}, - ops::{Bound, Index, IndexMut}, - sync::Mutex, - }, -}; - -const CRDS_SHARDS_BITS: u32 = 12; -// Number of vote slots to track in an lru-cache for metrics. -const VOTE_SLOTS_METRICS_CAP: usize = 100; - -pub struct Crds { - /// Stores the map of labels and values - table: IndexMap, - cursor: Cursor, // Next insert ordinal location. - shards: CrdsShards, - nodes: IndexSet, // Indices of nodes' ContactInfo. - // Indices of Votes keyed by insert order. - // votes: BTreeMap, - // Indices of EpochSlots keyed by insert order. - epoch_slots: BTreeMap, - // Indices of DuplicateShred keyed by insert order. - // duplicate_shreds: BTreeMap, - // Indices of all crds values associated with a node. - records: HashMap>, - // Indices of all entries keyed by insert order. - entries: BTreeMap, - // Hash of recently purged values. - purged: VecDeque<(Hash, u64 /*timestamp*/)>, - // Mapping from nodes' pubkeys to their respective shred-version. - shred_versions: HashMap, - stats: Mutex, -} - -#[derive(PartialEq, Eq, Debug)] -pub enum CrdsError { - DuplicatePush(/*num dups:*/ u8), - InsertFailed, - UnknownStakes, -} - -#[derive(Clone, Copy)] -pub enum GossipRoute { - LocalMessage, - PullRequest, - PullResponse, - PushMessage, -} - -type CrdsCountsArray = [usize; 11]; - -pub(crate) struct CrdsDataStats { - pub(crate) counts: CrdsCountsArray, - pub(crate) fails: CrdsCountsArray, - pub(crate) votes: LruCache, -} - -#[derive(Default)] -pub(crate) struct CrdsStats { - pub(crate) pull: CrdsDataStats, - pub(crate) push: CrdsDataStats, -} - -/// This structure stores some local metadata associated with the CrdsValue -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct VersionedCrdsValue { - /// Ordinal index indicating insert order. - ordinal: u64, - pub value: CrdsValue, - /// local time when updated - pub(crate) local_timestamp: u64, - /// value hash - pub(crate) value_hash: Hash, - /// Number of times duplicates of this value are recevied from gossip push. - num_push_dups: u8, -} - -#[derive(Clone, Copy, Default)] -pub struct Cursor(u64); - -impl Cursor { - fn ordinal(&self) -> u64 { - self.0 - } - - // Updates the cursor position given the ordinal index of value consumed. - #[inline] - fn consume(&mut self, ordinal: u64) { - self.0 = self.0.max(ordinal + 1); - } -} - -impl VersionedCrdsValue { - fn new(value: CrdsValue, cursor: Cursor, local_timestamp: u64) -> Self { - let value_hash = hash(&serialize(&value).unwrap()); - VersionedCrdsValue { - ordinal: cursor.ordinal(), - value, - local_timestamp, - value_hash, - num_push_dups: 0u8, - } - } -} - -impl Default for Crds { - fn default() -> Self { - Crds { - table: IndexMap::default(), - cursor: Cursor::default(), - shards: CrdsShards::new(CRDS_SHARDS_BITS), - nodes: IndexSet::default(), - // votes: BTreeMap::default(), - epoch_slots: BTreeMap::default(), - // duplicate_shreds: BTreeMap::default(), - records: HashMap::default(), - entries: BTreeMap::default(), - purged: VecDeque::default(), - shred_versions: HashMap::default(), - stats: Mutex::::default(), - } - } -} - -// Returns true if the first value updates the 2nd one. -// Both values should have the same key/label. -fn overrides(value: &CrdsValue, other: &VersionedCrdsValue) -> bool { - assert_eq!(value.label(), other.value.label(), "labels mismatch!"); - // Node instances are special cased so that if there are two running - // instances of the same node, the more recent start is propagated through - // gossip regardless of wallclocks. - if let CrdsData::NodeInstance(value) = &value.data { - if let Some(out) = value.overrides(&other.value) { - return out; - } - } - match value.wallclock().cmp(&other.value.wallclock()) { - Ordering::Less => false, - Ordering::Greater => true, - // Ties should be broken in a deterministic way across the cluster. - // For backward compatibility this is done by comparing hash of - // serialized values. - Ordering::Equal => { - let value_hash = hash(&serialize(&value).unwrap()); - other.value_hash < value_hash - } - } -} - -impl Crds { - /// Returns true if the given value updates an existing one in the table. - /// The value is outdated and fails to insert, if it already exists in the - /// table with a more recent wallclock. - pub(crate) fn upserts(&self, value: &CrdsValue) -> bool { - match self.table.get(&value.label()) { - Some(other) => overrides(value, other), - None => true, - } - } - - pub fn insert( - &mut self, - value: CrdsValue, - now: u64, - route: GossipRoute, - ) -> Result<(), CrdsError> { - let label = value.label(); - let pubkey = value.pubkey(); - let value = VersionedCrdsValue::new(value, self.cursor, now); - match self.table.entry(label) { - Entry::Vacant(entry) => { - self.stats.lock().unwrap().record_insert(&value, route); - let entry_index = entry.index(); - self.shards.insert(entry_index, &value); - match &value.value.data { - CrdsData::ContactInfo(node) => { - self.nodes.insert(entry_index); - self.shred_versions.insert(pubkey, node.shred_version); - } - // CrdsData::Vote(_, _) => { - // self.votes.insert(value.ordinal, entry_index); - // } - CrdsData::EpochSlots(_, _) => { - self.epoch_slots.insert(value.ordinal, entry_index); - } - // CrdsData::DuplicateShred(_, _) => { - // self.duplicate_shreds.insert(value.ordinal, entry_index); - // } - _ => (), - }; - self.entries.insert(value.ordinal, entry_index); - self.records.entry(pubkey).or_default().insert(entry_index); - self.cursor.consume(value.ordinal); - entry.insert(value); - Ok(()) - } - Entry::Occupied(mut entry) if overrides(&value.value, entry.get()) => { - self.stats.lock().unwrap().record_insert(&value, route); - let entry_index = entry.index(); - self.shards.remove(entry_index, entry.get()); - self.shards.insert(entry_index, &value); - match &value.value.data { - CrdsData::ContactInfo(node) => { - self.shred_versions.insert(pubkey, node.shred_version); - // self.nodes does not need to be updated since the - // entry at this index was and stays contact-info. - debug_assert_matches!(entry.get().value.data, CrdsData::ContactInfo(_)); - } - // CrdsData::Vote(_, _) => { - // self.votes.remove(&entry.get().ordinal); - // self.votes.insert(value.ordinal, entry_index); - // } - CrdsData::EpochSlots(_, _) => { - self.epoch_slots.remove(&entry.get().ordinal); - self.epoch_slots.insert(value.ordinal, entry_index); - } - // CrdsData::DuplicateShred(_, _) => { - // self.duplicate_shreds.remove(&entry.get().ordinal); - // self.duplicate_shreds.insert(value.ordinal, entry_index); - // } - _ => (), - } - self.entries.remove(&entry.get().ordinal); - self.entries.insert(value.ordinal, entry_index); - // As long as the pubkey does not change, self.records - // does not need to be updated. - debug_assert_eq!(entry.get().value.pubkey(), pubkey); - self.cursor.consume(value.ordinal); - self.purged.push_back((entry.get().value_hash, now)); - entry.insert(value); - Ok(()) - } - Entry::Occupied(mut entry) => { - self.stats.lock().unwrap().record_fail(&value, route); - trace!( - "INSERT FAILED data: {} new.wallclock: {}", - value.value.label(), - value.value.wallclock(), - ); - // Identify if the message is outdated (as opposed to - // duplicate) by comparing value hashes. - if entry.get().value_hash != value.value_hash { - self.purged.push_back((value.value_hash, now)); - Err(CrdsError::InsertFailed) - } else if matches!(route, GossipRoute::PushMessage) { - let entry = entry.get_mut(); - entry.num_push_dups = entry.num_push_dups.saturating_add(1); - Err(CrdsError::DuplicatePush(entry.num_push_dups)) - } else { - Err(CrdsError::InsertFailed) - } - } - } - } - - pub fn get<'a, 'b, V>(&'a self, key: V::Key) -> Option - where - V: CrdsEntry<'a, 'b>, - { - V::get_entry(&self.table, key) - } - - pub(crate) fn get_shred_version(&self, pubkey: &Pubkey) -> Option { - self.shred_versions.get(pubkey).copied() - } - - /// Returns all entries which are ContactInfo. - pub(crate) fn get_nodes(&self) -> impl Iterator { - self.nodes.iter().map(move |i| self.table.index(*i)) - } - - /// Returns ContactInfo of all known nodes. - pub(crate) fn get_nodes_contact_info(&self) -> impl Iterator { - self.get_nodes().map(|v| match &v.value.data { - CrdsData::ContactInfo(info) => info, - _ => panic!("this should not happen!"), - }) - } - - /// Returns all vote entries inserted since the given cursor. - /// Updates the cursor as the votes are consumed. - // pub(crate) fn get_votes<'a>( - // &'a self, - // cursor: &'a mut Cursor, - // ) -> impl Iterator { - // let range = (Bound::Included(cursor.ordinal()), Bound::Unbounded); - // self.votes.range(range).map(move |(ordinal, index)| { - // cursor.consume(*ordinal); - // self.table.index(*index) - // }) - // } - - /// Returns epoch-slots inserted since the given cursor. - /// Updates the cursor as the values are consumed. - pub(crate) fn get_epoch_slots<'a>( - &'a self, - cursor: &'a mut Cursor, - ) -> impl Iterator { - let range = (Bound::Included(cursor.ordinal()), Bound::Unbounded); - self.epoch_slots.range(range).map(move |(ordinal, index)| { - cursor.consume(*ordinal); - self.table.index(*index) - }) - } - - /// Returns duplicate-shreds inserted since the given cursor. - /// Updates the cursor as the values are consumed. - // pub(crate) fn get_duplicate_shreds<'a>( - // &'a self, - // cursor: &'a mut Cursor, - // ) -> impl Iterator { - // let range = (Bound::Included(cursor.ordinal()), Bound::Unbounded); - // self.duplicate_shreds - // .range(range) - // .map(move |(ordinal, index)| { - // cursor.consume(*ordinal); - // self.table.index(*index) - // }) - // } - - /// Returns all entries inserted since the given cursor. - pub(crate) fn get_entries<'a>( - &'a self, - cursor: &'a mut Cursor, - ) -> impl Iterator { - let range = (Bound::Included(cursor.ordinal()), Bound::Unbounded); - self.entries.range(range).map(move |(ordinal, index)| { - cursor.consume(*ordinal); - self.table.index(*index) - }) - } - - /// Returns all records associated with a pubkey. - pub(crate) fn get_records(&self, pubkey: &Pubkey) -> impl Iterator { - self.records - .get(pubkey) - .into_iter() - .flat_map(|records| records.into_iter()) - .map(move |i| self.table.index(*i)) - } - - /// Returns number of known contact-infos (network size). - pub(crate) fn num_nodes(&self) -> usize { - self.nodes.len() - } - - /// Returns number of unique pubkeys. - pub(crate) fn num_pubkeys(&self) -> usize { - self.records.len() - } - - pub fn len(&self) -> usize { - self.table.len() - } - - pub fn is_empty(&self) -> bool { - self.table.is_empty() - } - - #[cfg(test)] - pub(crate) fn values(&self) -> impl Iterator { - self.table.values() - } - - pub(crate) fn par_values(&self) -> ParValues<'_, CrdsValueLabel, VersionedCrdsValue> { - self.table.par_values() - } - - pub(crate) fn num_purged(&self) -> usize { - self.purged.len() - } - - pub(crate) fn purged(&self) -> impl IndexedParallelIterator + '_ { - self.purged.par_iter().map(|(hash, _)| *hash) - } - - /// Drops purged value hashes with timestamp less than the given one. - pub(crate) fn trim_purged(&mut self, timestamp: u64) { - let count = self - .purged - .iter() - .take_while(|(_, ts)| *ts < timestamp) - .count(); - self.purged.drain(..count); - } - - /// Returns all crds values which the first 'mask_bits' - /// of their hash value is equal to 'mask'. - pub(crate) fn filter_bitmask( - &self, - mask: u64, - mask_bits: u32, - ) -> impl Iterator { - self.shards - .find(mask, mask_bits) - .map(move |i| self.table.index(i)) - } - - /// Update the timestamp's of all the labels that are associated with Pubkey - pub(crate) fn update_record_timestamp(&mut self, pubkey: &Pubkey, now: u64) { - // It suffices to only overwrite the origin's timestamp since that is - // used when purging old values. If the origin does not exist in the - // table, fallback to exhaustive update on all associated records. - let origin = CrdsValueLabel::ContactInfo(*pubkey); - if let Some(origin) = self.table.get_mut(&origin) { - if origin.local_timestamp < now { - origin.local_timestamp = now; - } - } else if let Some(indices) = self.records.get(pubkey) { - for index in indices { - let entry = self.table.index_mut(*index); - if entry.local_timestamp < now { - entry.local_timestamp = now; - } - } - } - } - - /// Find all the keys that are older or equal to the timeout. - /// * timeouts - Pubkey specific timeouts with Pubkey::default() as the default timeout. - pub fn find_old_labels( - &self, - thread_pool: &ThreadPool, - now: u64, - timeouts: &HashMap, - ) -> Vec { - let default_timeout = *timeouts - .get(&Pubkey::default()) - .expect("must have default timeout"); - // Given an index of all crd values associated with a pubkey, - // returns crds labels of old values to be evicted. - let evict = |pubkey, index: &IndexSet| { - let timeout = timeouts.get(pubkey).copied().unwrap_or(default_timeout); - // If the origin's contact-info hasn't expired yet then preserve - // all associated values. - let origin = CrdsValueLabel::ContactInfo(*pubkey); - if let Some(origin) = self.table.get(&origin) { - if now < origin.local_timestamp.saturating_add(timeout) { - return vec![]; - } - } - // Otherwise check each value's timestamp individually. - index - .into_iter() - .filter_map(|ix| { - let (label, value) = self.table.get_index(*ix).unwrap(); - if value.local_timestamp.saturating_add(timeout) <= now { - Some(label.clone()) - } else { - None - } - }) - .collect::>() - }; - thread_pool.install(|| { - self.records - .par_iter() - .flat_map(|(pubkey, index)| evict(pubkey, index)) - .collect() - }) - } - - pub fn remove(&mut self, key: &CrdsValueLabel, now: u64) { - let (index, _ /*label*/, value) = match self.table.swap_remove_full(key) { - Some(entry) => entry, - None => return, - }; - self.purged.push_back((value.value_hash, now)); - self.shards.remove(index, &value); - match value.value.data { - CrdsData::ContactInfo(_) => { - self.nodes.swap_remove(&index); - } - // CrdsData::Vote(_, _) => { - // self.votes.remove(&value.ordinal); - // } - CrdsData::EpochSlots(_, _) => { - self.epoch_slots.remove(&value.ordinal); - } - // CrdsData::DuplicateShred(_, _) => { - // self.duplicate_shreds.remove(&value.ordinal); - // } - _ => (), - } - self.entries.remove(&value.ordinal); - // Remove the index from records associated with the value's pubkey. - let pubkey = value.value.pubkey(); - let mut records_entry = match self.records.entry(pubkey) { - hash_map::Entry::Vacant(_) => panic!("this should not happen!"), - hash_map::Entry::Occupied(entry) => entry, - }; - records_entry.get_mut().swap_remove(&index); - if records_entry.get().is_empty() { - records_entry.remove(); - self.shred_versions.remove(&pubkey); - } - // If index == self.table.len(), then the removed entry was the last - // entry in the table, in which case no other keys were modified. - // Otherwise, the previously last element in the table is now moved to - // the 'index' position; and so shards and nodes need to be updated - // accordingly. - let size = self.table.len(); - if index < size { - let value = self.table.index(index); - self.shards.remove(size, value); - self.shards.insert(index, value); - match value.value.data { - CrdsData::ContactInfo(_) => { - self.nodes.swap_remove(&size); - self.nodes.insert(index); - } - // CrdsData::Vote(_, _) => { - // self.votes.insert(value.ordinal, index); - // } - CrdsData::EpochSlots(_, _) => { - self.epoch_slots.insert(value.ordinal, index); - } - // CrdsData::DuplicateShred(_, _) => { - // self.duplicate_shreds.insert(value.ordinal, index); - // } - _ => (), - }; - self.entries.insert(value.ordinal, index); - let pubkey = value.value.pubkey(); - let records = self.records.get_mut(&pubkey).unwrap(); - records.swap_remove(&size); - records.insert(index); - } - } - - /// Returns true if the number of unique pubkeys in the table exceeds the - /// given capacity (plus some margin). - /// Allows skipping unnecessary calls to trim without obtaining a write - /// lock on gossip. - pub(crate) fn should_trim(&self, cap: usize) -> bool { - // Allow 10% overshoot so that the computation cost is amortized down. - 10 * self.records.len() > 11 * cap - } - - /// Trims the table by dropping all values associated with the pubkeys with - /// the lowest stake, so that the number of unique pubkeys are bounded. - pub(crate) fn trim( - &mut self, - cap: usize, // Capacity hint for number of unique pubkeys. - // Set of pubkeys to never drop. - // e.g. known validators, self pubkey, ... - keep: &[Pubkey], - stakes: &HashMap, - now: u64, - ) -> Result { - if self.should_trim(cap) { - let size = self.records.len().saturating_sub(cap); - self.drop(size, keep, stakes, now) - } else { - Ok(0) - } - } - - // Drops 'size' many pubkeys with the lowest stake. - fn drop( - &mut self, - size: usize, - keep: &[Pubkey], - stakes: &HashMap, - now: u64, - ) -> Result { - if stakes.values().all(|&stake| stake == 0) { - return Err(CrdsError::UnknownStakes); - } - let mut keys: Vec<_> = self - .records - .keys() - .map(|k| (stakes.get(k).copied().unwrap_or_default(), *k)) - .collect(); - if size < keys.len() { - keys.select_nth_unstable(size); - } - let keys: Vec<_> = keys - .into_iter() - .take(size) - .map(|(_, k)| k) - .filter(|k| !keep.contains(k)) - .flat_map(|k| &self.records[&k]) - .map(|k| self.table.get_index(*k).unwrap().0.clone()) - .collect(); - for key in &keys { - self.remove(key, now); - } - Ok(keys.len()) - } - - pub(crate) fn take_stats(&self) -> CrdsStats { - std::mem::take(&mut self.stats.lock().unwrap()) - } - - // Only for tests and simulations. - pub(crate) fn mock_clone(&self) -> Self { - Self { - table: self.table.clone(), - cursor: self.cursor, - shards: self.shards.clone(), - nodes: self.nodes.clone(), - // votes: self.votes.clone(), - epoch_slots: self.epoch_slots.clone(), - // duplicate_shreds: self.duplicate_shreds.clone(), - records: self.records.clone(), - entries: self.entries.clone(), - purged: self.purged.clone(), - shred_versions: self.shred_versions.clone(), - stats: Mutex::::default(), - } - } -} - -impl Default for CrdsDataStats { - fn default() -> Self { - Self { - counts: CrdsCountsArray::default(), - fails: CrdsCountsArray::default(), - votes: LruCache::new(VOTE_SLOTS_METRICS_CAP), - } - } -} - -impl CrdsDataStats { - fn record_insert(&mut self, entry: &VersionedCrdsValue) { - self.counts[Self::ordinal(entry)] += 1; - // if let CrdsData::Vote(_, vote) = &entry.value.data { - // if let Some(slot) = vote.slot() { - // let num_nodes = self.votes.get(&slot).copied().unwrap_or_default(); - // self.votes.put(slot, num_nodes + 1); - // } - // } - } - - fn record_fail(&mut self, entry: &VersionedCrdsValue) { - self.fails[Self::ordinal(entry)] += 1; - } - - fn ordinal(entry: &VersionedCrdsValue) -> usize { - match &entry.value.data { - CrdsData::ContactInfo(_) => 0, - // CrdsData::Vote(_, _) => 1, - // CrdsData::LowestSlot(_, _) => 2, - // CrdsData::SnapshotHashes(_) => 3, - // CrdsData::AccountsHashes(_) => 4, - CrdsData::EpochSlots(_, _) => 5, - // CrdsData::LegacyVersion(_) => 6, - CrdsData::Version(_) => 7, - CrdsData::NodeInstance(_) => 8, - // CrdsData::DuplicateShred(_, _) => 9, - // CrdsData::IncrementalSnapshotHashes(_) => 10, - } - } -} - -impl CrdsStats { - fn record_insert(&mut self, entry: &VersionedCrdsValue, route: GossipRoute) { - match route { - GossipRoute::LocalMessage => (), - GossipRoute::PullRequest => (), - GossipRoute::PushMessage => self.push.record_insert(entry), - GossipRoute::PullResponse => self.pull.record_insert(entry), - } - } - - fn record_fail(&mut self, entry: &VersionedCrdsValue, route: GossipRoute) { - match route { - GossipRoute::LocalMessage => (), - GossipRoute::PullRequest => (), - GossipRoute::PushMessage => self.push.record_fail(entry), - GossipRoute::PullResponse => self.pull.record_fail(entry), - } - } -} - -// #[cfg(test)] -// mod tests { -// use { -// super::*, -// crate::{ -// contact_info::ContactInfo, -// crds_value::{new_rand_timestamp, NodeInstance, SnapshotHashes}, -// }, -// rand::{thread_rng, Rng, SeedableRng}, -// rand_chacha::ChaChaRng, -// rayon::ThreadPoolBuilder, -// solana_sdk::{ -// signature::{Keypair, Signer}, -// timing::timestamp, -// }, -// std::{collections::HashSet, iter::repeat_with}, -// }; - -// #[test] -// fn test_insert() { -// let mut crds = Crds::default(); -// let val = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())); -// assert_eq!( -// crds.insert(val.clone(), 0, GossipRoute::LocalMessage), -// Ok(()) -// ); -// assert_eq!(crds.table.len(), 1); -// assert!(crds.table.contains_key(&val.label())); -// assert_eq!(crds.table[&val.label()].local_timestamp, 0); -// } -// #[test] -// fn test_update_old() { -// let mut crds = Crds::default(); -// let val = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())); -// assert_eq!( -// crds.insert(val.clone(), 0, GossipRoute::LocalMessage), -// Ok(()) -// ); -// assert_eq!( -// crds.insert(val.clone(), 1, GossipRoute::LocalMessage), -// Err(CrdsError::InsertFailed) -// ); -// assert!(crds.purged.is_empty()); -// assert_eq!(crds.table[&val.label()].local_timestamp, 0); -// } -// #[test] -// fn test_update_new() { -// let mut crds = Crds::default(); -// let original = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &Pubkey::default(), -// 0, -// ))); -// let value_hash = hash(&serialize(&original).unwrap()); -// assert_matches!(crds.insert(original, 0, GossipRoute::LocalMessage), Ok(())); -// let val = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &Pubkey::default(), -// 1, -// ))); -// assert_eq!( -// crds.insert(val.clone(), 1, GossipRoute::LocalMessage), -// Ok(()) -// ); -// assert_eq!(*crds.purged.back().unwrap(), (value_hash, 1)); -// assert_eq!(crds.table[&val.label()].local_timestamp, 1); -// } -// #[test] -// fn test_update_timestamp() { -// let mut crds = Crds::default(); -// let val = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &Pubkey::default(), -// 0, -// ))); -// assert_eq!( -// crds.insert(val.clone(), 0, GossipRoute::LocalMessage), -// Ok(()) -// ); -// assert_eq!(crds.table[&val.label()].ordinal, 0); - -// let val2 = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())); -// let value_hash = hash(&serialize(&val2).unwrap()); -// assert_eq!(val2.label().pubkey(), val.label().pubkey()); -// assert_eq!( -// crds.insert(val2.clone(), 0, GossipRoute::LocalMessage), -// Ok(()) -// ); - -// crds.update_record_timestamp(&val.label().pubkey(), 2); -// assert_eq!(crds.table[&val.label()].local_timestamp, 2); -// assert_eq!(crds.table[&val.label()].ordinal, 1); -// assert_eq!(crds.table[&val2.label()].local_timestamp, 2); -// assert_eq!(crds.table[&val2.label()].ordinal, 1); - -// crds.update_record_timestamp(&val.label().pubkey(), 1); -// assert_eq!(crds.table[&val.label()].local_timestamp, 2); -// assert_eq!(crds.table[&val.label()].ordinal, 1); - -// let mut ci = ContactInfo::default(); -// ci.wallclock += 1; -// let val3 = CrdsValue::new_unsigned(CrdsData::ContactInfo(ci)); -// assert_eq!(crds.insert(val3, 3, GossipRoute::LocalMessage), Ok(())); -// assert_eq!(*crds.purged.back().unwrap(), (value_hash, 3)); -// assert_eq!(crds.table[&val2.label()].local_timestamp, 3); -// assert_eq!(crds.table[&val2.label()].ordinal, 2); -// } - -// #[test] -// fn test_upsert_node_instance() { -// const SEED: [u8; 32] = [0x42; 32]; -// let mut rng = ChaChaRng::from_seed(SEED); -// fn make_crds_value(node: NodeInstance) -> CrdsValue { -// CrdsValue::new_unsigned(CrdsData::NodeInstance(node)) -// } -// let now = 1_620_838_767_000; -// let mut crds = Crds::default(); -// let pubkey = Pubkey::new_unique(); -// let node = NodeInstance::new(&mut rng, pubkey, now); -// let node = make_crds_value(node); -// assert_eq!(crds.insert(node, now, GossipRoute::LocalMessage), Ok(())); -// // A node-instance with a different key should insert fine even with -// // older timestamps. -// let other = NodeInstance::new(&mut rng, Pubkey::new_unique(), now - 1); -// let other = make_crds_value(other); -// assert_eq!(crds.insert(other, now, GossipRoute::LocalMessage), Ok(())); -// // A node-instance with older timestamp should fail to insert, even if -// // the wallclock is more recent. -// let other = NodeInstance::new(&mut rng, pubkey, now - 1); -// let other = other.with_wallclock(now + 1); -// let other = make_crds_value(other); -// let value_hash = hash(&serialize(&other).unwrap()); -// assert_eq!( -// crds.insert(other, now, GossipRoute::LocalMessage), -// Err(CrdsError::InsertFailed) -// ); -// assert_eq!(*crds.purged.back().unwrap(), (value_hash, now)); -// // A node instance with the same timestamp should insert only if the -// // random token is larger. -// let mut num_overrides = 0; -// for _ in 0..100 { -// let other = NodeInstance::new(&mut rng, pubkey, now); -// let other = make_crds_value(other); -// let value_hash = hash(&serialize(&other).unwrap()); -// match crds.insert(other, now, GossipRoute::LocalMessage) { -// Ok(()) => num_overrides += 1, -// Err(CrdsError::InsertFailed) => { -// assert_eq!(*crds.purged.back().unwrap(), (value_hash, now)) -// } -// _ => panic!(), -// } -// } -// assert_eq!(num_overrides, 5); -// // A node instance with larger timestamp should insert regardless of -// // its token value. -// for k in 1..10 { -// let other = NodeInstance::new(&mut rng, pubkey, now + k); -// let other = other.with_wallclock(now - 1); -// let other = make_crds_value(other); -// match crds.insert(other, now, GossipRoute::LocalMessage) { -// Ok(()) => (), -// _ => panic!(), -// } -// } -// } - -// #[test] -// fn test_find_old_records_default() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let mut crds = Crds::default(); -// let val = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())); -// assert_eq!( -// crds.insert(val.clone(), 1, GossipRoute::LocalMessage), -// Ok(()) -// ); -// let mut set = HashMap::new(); -// set.insert(Pubkey::default(), 0); -// assert!(crds.find_old_labels(&thread_pool, 0, &set).is_empty()); -// set.insert(Pubkey::default(), 1); -// assert_eq!( -// crds.find_old_labels(&thread_pool, 2, &set), -// vec![val.label()] -// ); -// set.insert(Pubkey::default(), 2); -// assert_eq!( -// crds.find_old_labels(&thread_pool, 4, &set), -// vec![val.label()] -// ); -// } -// #[test] -// fn test_find_old_records_with_override() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let mut rng = thread_rng(); -// let mut crds = Crds::default(); -// let mut timeouts = HashMap::new(); -// let val = CrdsValue::new_rand(&mut rng, None); -// timeouts.insert(Pubkey::default(), 3); -// assert_eq!( -// crds.insert(val.clone(), 0, GossipRoute::LocalMessage), -// Ok(()) -// ); -// assert!(crds.find_old_labels(&thread_pool, 2, &timeouts).is_empty()); -// timeouts.insert(val.pubkey(), 1); -// assert_eq!( -// crds.find_old_labels(&thread_pool, 2, &timeouts), -// vec![val.label()] -// ); -// timeouts.insert(val.pubkey(), u64::MAX); -// assert!(crds.find_old_labels(&thread_pool, 2, &timeouts).is_empty()); -// timeouts.insert(Pubkey::default(), 1); -// assert!(crds.find_old_labels(&thread_pool, 2, &timeouts).is_empty()); -// timeouts.remove(&val.pubkey()); -// assert_eq!( -// crds.find_old_labels(&thread_pool, 2, &timeouts), -// vec![val.label()] -// ); -// } - -// #[test] -// fn test_remove_default() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let mut crds = Crds::default(); -// let val = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())); -// assert_matches!( -// crds.insert(val.clone(), 1, GossipRoute::LocalMessage), -// Ok(_) -// ); -// let mut set = HashMap::new(); -// set.insert(Pubkey::default(), 1); -// assert_eq!( -// crds.find_old_labels(&thread_pool, 2, &set), -// vec![val.label()] -// ); -// crds.remove(&val.label(), /*now=*/ 0); -// assert!(crds.find_old_labels(&thread_pool, 2, &set).is_empty()); -// } -// #[test] -// fn test_find_old_records_staked() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let mut crds = Crds::default(); -// let val = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())); -// assert_eq!( -// crds.insert(val.clone(), 1, GossipRoute::LocalMessage), -// Ok(()) -// ); -// let mut set = HashMap::new(); -// //now < timestamp -// set.insert(Pubkey::default(), 0); -// set.insert(val.pubkey(), 0); -// assert!(crds.find_old_labels(&thread_pool, 0, &set).is_empty()); - -// //pubkey shouldn't expire since its timeout is MAX -// set.insert(val.pubkey(), std::u64::MAX); -// assert!(crds.find_old_labels(&thread_pool, 2, &set).is_empty()); - -// //default has max timeout, but pubkey should still expire -// set.insert(Pubkey::default(), std::u64::MAX); -// set.insert(val.pubkey(), 1); -// assert_eq!( -// crds.find_old_labels(&thread_pool, 2, &set), -// vec![val.label()] -// ); - -// set.insert(val.pubkey(), 2); -// assert!(crds.find_old_labels(&thread_pool, 2, &set).is_empty()); -// assert_eq!( -// crds.find_old_labels(&thread_pool, 3, &set), -// vec![val.label()] -// ); -// } - -// #[test] -// fn test_crds_shards() { -// fn check_crds_shards(crds: &Crds) { -// crds.shards -// .check(&crds.table.values().cloned().collect::>()); -// } - -// let mut crds = Crds::default(); -// let keypairs: Vec<_> = std::iter::repeat_with(Keypair::new).take(256).collect(); -// let mut rng = thread_rng(); -// let mut num_inserts = 0; -// for _ in 0..4096 { -// let keypair = &keypairs[rng.gen_range(0, keypairs.len())]; -// let value = CrdsValue::new_rand(&mut rng, Some(keypair)); -// let local_timestamp = new_rand_timestamp(&mut rng); -// if let Ok(()) = crds.insert(value, local_timestamp, GossipRoute::LocalMessage) { -// num_inserts += 1; -// check_crds_shards(&crds); -// } -// } -// assert_eq!(num_inserts, crds.cursor.0 as usize); -// assert!(num_inserts > 700); -// assert!(crds.num_purged() > 500); -// assert_eq!(crds.num_purged() + crds.table.len(), 4096); -// assert!(crds.table.len() > 200); -// assert!(num_inserts > crds.table.len()); -// check_crds_shards(&crds); -// // Remove values one by one and assert that shards stay valid. -// while !crds.table.is_empty() { -// let index = rng.gen_range(0, crds.table.len()); -// let key = crds.table.get_index(index).unwrap().0.clone(); -// crds.remove(&key, /*now=*/ 0); -// check_crds_shards(&crds); -// } -// } - -// fn check_crds_value_indices( -// rng: &mut R, -// crds: &Crds, -// ) -> ( -// usize, // number of nodes -// usize, // number of votes -// usize, // number of epoch slots -// ) { -// let size = crds.table.len(); -// let since = if size == 0 || rng.gen() { -// rng.gen_range(0, crds.cursor.0 + 1) -// } else { -// crds.table[rng.gen_range(0, size)].ordinal -// }; -// let num_epoch_slots = crds -// .table -// .values() -// .filter(|v| v.ordinal >= since) -// .filter(|v| matches!(v.value.data, CrdsData::EpochSlots(_, _))) -// .count(); -// let mut cursor = Cursor(since); -// assert_eq!(num_epoch_slots, crds.get_epoch_slots(&mut cursor).count()); -// assert_eq!( -// cursor.0, -// crds.epoch_slots -// .iter() -// .last() -// .map(|(k, _)| k + 1) -// .unwrap_or_default() -// .max(since) -// ); -// for value in crds.get_epoch_slots(&mut Cursor(since)) { -// assert!(value.ordinal >= since); -// match value.value.data { -// CrdsData::EpochSlots(_, _) => (), -// _ => panic!("not an epoch-slot!"), -// } -// } -// let num_votes = crds -// .table -// .values() -// .filter(|v| v.ordinal >= since) -// .filter(|v| matches!(v.value.data, CrdsData::Vote(_, _))) -// .count(); -// let mut cursor = Cursor(since); -// assert_eq!(num_votes, crds.get_votes(&mut cursor).count()); -// assert_eq!( -// cursor.0, -// crds.table -// .values() -// .filter(|v| matches!(v.value.data, CrdsData::Vote(_, _))) -// .map(|v| v.ordinal) -// .max() -// .map(|k| k + 1) -// .unwrap_or_default() -// .max(since) -// ); -// for value in crds.get_votes(&mut Cursor(since)) { -// assert!(value.ordinal >= since); -// match value.value.data { -// CrdsData::Vote(_, _) => (), -// _ => panic!("not a vote!"), -// } -// } -// let num_entries = crds -// .table -// .values() -// .filter(|value| value.ordinal >= since) -// .count(); -// let mut cursor = Cursor(since); -// assert_eq!(num_entries, crds.get_entries(&mut cursor).count()); -// assert_eq!( -// cursor.0, -// crds.entries -// .iter() -// .last() -// .map(|(k, _)| k + 1) -// .unwrap_or_default() -// .max(since) -// ); -// for value in crds.get_entries(&mut Cursor(since)) { -// assert!(value.ordinal >= since); -// } -// let num_nodes = crds -// .table -// .values() -// .filter(|v| matches!(v.value.data, CrdsData::ContactInfo(_))) -// .count(); -// let num_votes = crds -// .table -// .values() -// .filter(|v| matches!(v.value.data, CrdsData::Vote(_, _))) -// .count(); -// let num_epoch_slots = crds -// .table -// .values() -// .filter(|v| matches!(v.value.data, CrdsData::EpochSlots(_, _))) -// .count(); -// assert_eq!( -// crds.table.len(), -// crds.get_entries(&mut Cursor::default()).count() -// ); -// assert_eq!(num_nodes, crds.get_nodes_contact_info().count()); -// assert_eq!(num_votes, crds.get_votes(&mut Cursor::default()).count()); -// assert_eq!( -// num_epoch_slots, -// crds.get_epoch_slots(&mut Cursor::default()).count() -// ); -// for vote in crds.get_votes(&mut Cursor::default()) { -// match vote.value.data { -// CrdsData::Vote(_, _) => (), -// _ => panic!("not a vote!"), -// } -// } -// for epoch_slots in crds.get_epoch_slots(&mut Cursor::default()) { -// match epoch_slots.value.data { -// CrdsData::EpochSlots(_, _) => (), -// _ => panic!("not an epoch-slot!"), -// } -// } -// (num_nodes, num_votes, num_epoch_slots) -// } - -// #[test] -// fn test_crds_value_indices() { -// let mut rng = thread_rng(); -// let keypairs: Vec<_> = repeat_with(Keypair::new).take(128).collect(); -// let mut crds = Crds::default(); -// let mut num_inserts = 0; -// for k in 0..4096 { -// let keypair = &keypairs[rng.gen_range(0, keypairs.len())]; -// let value = CrdsValue::new_rand(&mut rng, Some(keypair)); -// let local_timestamp = new_rand_timestamp(&mut rng); -// if let Ok(()) = crds.insert(value, local_timestamp, GossipRoute::LocalMessage) { -// num_inserts += 1; -// } -// if k % 16 == 0 { -// check_crds_value_indices(&mut rng, &crds); -// } -// } -// assert_eq!(num_inserts, crds.cursor.0 as usize); -// assert!(num_inserts > 700); -// assert!(crds.num_purged() > 500); -// assert!(crds.table.len() > 200); -// assert_eq!(crds.num_purged() + crds.table.len(), 4096); -// assert!(num_inserts > crds.table.len()); -// let (num_nodes, num_votes, num_epoch_slots) = check_crds_value_indices(&mut rng, &crds); -// assert!(num_nodes * 3 < crds.table.len()); -// assert!(num_nodes > 100, "num nodes: {num_nodes}"); -// assert!(num_votes > 100, "num votes: {num_votes}"); -// assert!(num_epoch_slots > 100, "num epoch slots: {num_epoch_slots}"); -// // Remove values one by one and assert that nodes indices stay valid. -// while !crds.table.is_empty() { -// let index = rng.gen_range(0, crds.table.len()); -// let key = crds.table.get_index(index).unwrap().0.clone(); -// crds.remove(&key, /*now=*/ 0); -// if crds.table.len() % 16 == 0 { -// check_crds_value_indices(&mut rng, &crds); -// } -// } -// } - -// #[test] -// fn test_crds_records() { -// fn check_crds_records(crds: &Crds) { -// assert_eq!( -// crds.table.len(), -// crds.records.values().map(IndexSet::len).sum::() -// ); -// for (pubkey, indices) in &crds.records { -// for index in indices { -// let value = crds.table.index(*index); -// assert_eq!(*pubkey, value.value.pubkey()); -// } -// } -// } -// let mut rng = thread_rng(); -// let keypairs: Vec<_> = repeat_with(Keypair::new).take(128).collect(); -// let mut crds = Crds::default(); -// for k in 0..4096 { -// let keypair = &keypairs[rng.gen_range(0, keypairs.len())]; -// let value = CrdsValue::new_rand(&mut rng, Some(keypair)); -// let local_timestamp = new_rand_timestamp(&mut rng); -// let _ = crds.insert(value, local_timestamp, GossipRoute::LocalMessage); -// if k % 64 == 0 { -// check_crds_records(&crds); -// } -// } -// assert!(crds.records.len() > 96); -// assert!(crds.records.len() <= keypairs.len()); -// // Remove values one by one and assert that records stay valid. -// while !crds.table.is_empty() { -// let index = rng.gen_range(0, crds.table.len()); -// let key = crds.table.get_index(index).unwrap().0.clone(); -// crds.remove(&key, /*now=*/ 0); -// if crds.table.len() % 64 == 0 { -// check_crds_records(&crds); -// } -// } -// assert!(crds.records.is_empty()); -// } - -// #[test] -// fn test_get_shred_version() { -// let mut rng = rand::thread_rng(); -// let pubkey = Pubkey::new_unique(); -// let mut crds = Crds::default(); -// assert_eq!(crds.get_shred_version(&pubkey), None); -// // Initial insertion of a node with shred version: -// let mut node = ContactInfo::new_rand(&mut rng, Some(pubkey)); -// let wallclock = node.wallclock; -// node.shred_version = 42; -// let node = CrdsData::ContactInfo(node); -// let node = CrdsValue::new_unsigned(node); -// assert_eq!( -// crds.insert(node, timestamp(), GossipRoute::LocalMessage), -// Ok(()) -// ); -// assert_eq!(crds.get_shred_version(&pubkey), Some(42)); -// // An outdated value should not update shred-version: -// let mut node = ContactInfo::new_rand(&mut rng, Some(pubkey)); -// node.wallclock = wallclock - 1; // outdated. -// node.shred_version = 8; -// let node = CrdsData::ContactInfo(node); -// let node = CrdsValue::new_unsigned(node); -// assert_eq!( -// crds.insert(node, timestamp(), GossipRoute::LocalMessage), -// Err(CrdsError::InsertFailed) -// ); -// assert_eq!(crds.get_shred_version(&pubkey), Some(42)); -// // Update shred version: -// let mut node = ContactInfo::new_rand(&mut rng, Some(pubkey)); -// node.wallclock = wallclock + 1; // so that it overrides the prev one. -// node.shred_version = 8; -// let node = CrdsData::ContactInfo(node); -// let node = CrdsValue::new_unsigned(node); -// assert_eq!( -// crds.insert(node, timestamp(), GossipRoute::LocalMessage), -// Ok(()) -// ); -// assert_eq!(crds.get_shred_version(&pubkey), Some(8)); -// // Add other crds values with the same pubkey. -// let val = SnapshotHashes::new_rand(&mut rng, Some(pubkey)); -// let val = CrdsData::SnapshotHashes(val); -// let val = CrdsValue::new_unsigned(val); -// assert_eq!( -// crds.insert(val, timestamp(), GossipRoute::LocalMessage), -// Ok(()) -// ); -// assert_eq!(crds.get_shred_version(&pubkey), Some(8)); -// // Remove contact-info. Shred version should stay there since there -// // are still values associated with the pubkey. -// crds.remove(&CrdsValueLabel::ContactInfo(pubkey), timestamp()); -// assert_eq!(crds.get::<&ContactInfo>(pubkey), None); -// assert_eq!(crds.get_shred_version(&pubkey), Some(8)); -// // Remove the remaining entry with the same pubkey. -// crds.remove(&CrdsValueLabel::SnapshotHashes(pubkey), timestamp()); -// assert_eq!(crds.get_records(&pubkey).count(), 0); -// assert_eq!(crds.get_shred_version(&pubkey), None); -// } - -// #[test] -// #[allow(clippy::needless_collect)] -// fn test_drop() { -// fn num_unique_pubkeys<'a, I>(values: I) -> usize -// where -// I: IntoIterator, -// { -// values -// .into_iter() -// .map(|v| v.value.pubkey()) -// .collect::>() -// .len() -// } -// let mut rng = thread_rng(); -// let keypairs: Vec<_> = repeat_with(Keypair::new).take(64).collect(); -// let stakes = keypairs -// .iter() -// .map(|k| (k.pubkey(), rng.gen_range(0, 1000))) -// .collect(); -// let mut crds = Crds::default(); -// for _ in 0..2048 { -// let keypair = &keypairs[rng.gen_range(0, keypairs.len())]; -// let value = CrdsValue::new_rand(&mut rng, Some(keypair)); -// let local_timestamp = new_rand_timestamp(&mut rng); -// let _ = crds.insert(value, local_timestamp, GossipRoute::LocalMessage); -// } -// let num_values = crds.table.len(); -// let num_pubkeys = num_unique_pubkeys(crds.table.values()); -// assert!(!crds.should_trim(num_pubkeys)); -// assert!(crds.should_trim(num_pubkeys * 5 / 6)); -// let values: Vec<_> = crds.table.values().cloned().collect(); -// crds.drop(16, &[], &stakes, /*now=*/ 0).unwrap(); -// let purged: Vec<_> = { -// let purged: HashSet<_> = crds.purged.iter().map(|(hash, _)| hash).copied().collect(); -// values -// .into_iter() -// .filter(|v| purged.contains(&v.value_hash)) -// .collect() -// }; -// assert_eq!(purged.len() + crds.table.len(), num_values); -// assert_eq!(num_unique_pubkeys(&purged), 16); -// assert_eq!(num_unique_pubkeys(crds.table.values()), num_pubkeys - 16); -// let attach_stake = |v: &VersionedCrdsValue| { -// let pk = v.value.pubkey(); -// (stakes[&pk], pk) -// }; -// assert!( -// purged.iter().map(attach_stake).max().unwrap() -// < crds.table.values().map(attach_stake).min().unwrap() -// ); -// let purged = purged -// .into_iter() -// .map(|v| v.value.pubkey()) -// .collect::>(); -// for (k, v) in crds.table { -// assert!(!purged.contains(&k.pubkey())); -// assert!(!purged.contains(&v.value.pubkey())); -// } -// } - -// #[test] -// fn test_remove_staked() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let mut crds = Crds::default(); -// let val = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())); -// assert_matches!( -// crds.insert(val.clone(), 1, GossipRoute::LocalMessage), -// Ok(_) -// ); -// let mut set = HashMap::new(); - -// //default has max timeout, but pubkey should still expire -// set.insert(Pubkey::default(), std::u64::MAX); -// set.insert(val.pubkey(), 1); -// assert_eq!( -// crds.find_old_labels(&thread_pool, 2, &set), -// vec![val.label()] -// ); -// crds.remove(&val.label(), /*now=*/ 0); -// assert!(crds.find_old_labels(&thread_pool, 2, &set).is_empty()); -// } - -// #[test] -// #[allow(clippy::neg_cmp_op_on_partial_ord)] -// fn test_equal() { -// let val = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())); -// let v1 = VersionedCrdsValue::new(val.clone(), Cursor::default(), 1); -// let v2 = VersionedCrdsValue::new(val, Cursor::default(), 1); -// assert_eq!(v1, v2); -// assert!(!(v1 != v2)); -// assert!(!overrides(&v1.value, &v2)); -// assert!(!overrides(&v2.value, &v1)); -// } -// #[test] -// #[allow(clippy::neg_cmp_op_on_partial_ord)] -// fn test_hash_order() { -// let v1 = VersionedCrdsValue::new( -// CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &Pubkey::default(), -// 0, -// ))), -// Cursor::default(), -// 1, // local_timestamp -// ); -// let v2 = VersionedCrdsValue::new( -// { -// let mut contact_info = ContactInfo::new_localhost(&Pubkey::default(), 0); -// contact_info.rpc = socketaddr!("0.0.0.0:0"); -// CrdsValue::new_unsigned(CrdsData::ContactInfo(contact_info)) -// }, -// Cursor::default(), -// 1, // local_timestamp -// ); - -// assert_eq!(v1.value.label(), v2.value.label()); -// assert_eq!(v1.value.wallclock(), v2.value.wallclock()); -// assert_ne!(v1.value_hash, v2.value_hash); -// assert!(v1 != v2); -// assert!(!(v1 == v2)); -// if v1.value_hash > v2.value_hash { -// assert!(overrides(&v1.value, &v2)); -// assert!(!overrides(&v2.value, &v1)); -// } else { -// assert!(overrides(&v2.value, &v1)); -// assert!(!overrides(&v1.value, &v2)); -// } -// } -// #[test] -// #[allow(clippy::neg_cmp_op_on_partial_ord)] -// fn test_wallclock_order() { -// let v1 = VersionedCrdsValue::new( -// CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &Pubkey::default(), -// 1, -// ))), -// Cursor::default(), -// 1, // local_timestamp -// ); -// let v2 = VersionedCrdsValue::new( -// CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &Pubkey::default(), -// 0, -// ))), -// Cursor::default(), -// 1, // local_timestamp -// ); -// assert_eq!(v1.value.label(), v2.value.label()); -// assert!(overrides(&v1.value, &v2)); -// assert!(!overrides(&v2.value, &v1)); -// assert!(v1 != v2); -// assert!(!(v1 == v2)); -// } -// #[test] -// #[should_panic(expected = "labels mismatch!")] -// #[allow(clippy::neg_cmp_op_on_partial_ord)] -// fn test_label_order() { -// let v1 = VersionedCrdsValue::new( -// CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &solana_sdk::pubkey::new_rand(), -// 0, -// ))), -// Cursor::default(), -// 1, // local_timestamp -// ); -// let v2 = VersionedCrdsValue::new( -// CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &solana_sdk::pubkey::new_rand(), -// 0, -// ))), -// Cursor::default(), -// 1, // local_timestamp -// ); -// assert_ne!(v1, v2); -// assert!(!(v1 == v2)); -// assert!(!overrides(&v2.value, &v1)); -// } -// } diff --git a/gossip/src/crds_entry.rs b/gossip/src/crds_entry.rs deleted file mode 100644 index 9e875b0..0000000 --- a/gossip/src/crds_entry.rs +++ /dev/null @@ -1,137 +0,0 @@ -use { - crate::{ - contact_info::ContactInfo, - crds::VersionedCrdsValue, - crds_value::{ - CrdsData, CrdsValue, CrdsValueLabel, IncrementalSnapshotHashes, LegacyVersion, - LowestSlot, SnapshotHashes, Version, - }, - }, - indexmap::IndexMap, - solana_sdk::pubkey::Pubkey, -}; - -type CrdsTable = IndexMap; - -/// Represents types which can be looked up from crds table given a key. e.g. -/// CrdsValueLabel -> VersionedCrdsValue, CrdsValue, CrdsData -/// Pubkey -> ContactInfo, LowestSlot, SnapshotHashes, ... -pub trait CrdsEntry<'a, 'b>: Sized { - type Key; // Lookup key. - fn get_entry(table: &'a CrdsTable, key: Self::Key) -> Option; -} - -macro_rules! impl_crds_entry ( - // Lookup by CrdsValueLabel. - ($name:ident, |$entry:ident| $body:expr) => ( - impl<'a, 'b> CrdsEntry<'a, 'b> for &'a $name { - type Key = &'b CrdsValueLabel; - fn get_entry(table:&'a CrdsTable, key: Self::Key) -> Option { - let $entry = table.get(key); - $body - } - } - ); - // Lookup by Pubkey. - ($name:ident, $pat:pat, $expr:expr) => ( - impl<'a, 'b> CrdsEntry<'a, 'b> for &'a $name { - type Key = Pubkey; - fn get_entry(table:&'a CrdsTable, key: Self::Key) -> Option { - let key = CrdsValueLabel::$name(key); - match &table.get(&key)?.value.data { - $pat => Some($expr), - _ => None, - } - } - } - ); -); - -// Lookup by CrdsValueLabel. -impl_crds_entry!(CrdsData, |entry| Some(&entry?.value.data)); -impl_crds_entry!(CrdsValue, |entry| Some(&entry?.value)); -impl_crds_entry!(VersionedCrdsValue, |entry| entry); - -// Lookup by Pubkey. -impl_crds_entry!(ContactInfo, CrdsData::ContactInfo(node), node); -// impl_crds_entry!(LegacyVersion, CrdsData::LegacyVersion(version), version); -// impl_crds_entry!(LowestSlot, CrdsData::LowestSlot(_, slot), slot); -impl_crds_entry!(Version, CrdsData::Version(version), version); -// impl_crds_entry!( -// IncrementalSnapshotHashes, -// CrdsData::IncrementalSnapshotHashes(incremental_snapshot_hashes), -// incremental_snapshot_hashes -// ); - -// impl<'a, 'b> CrdsEntry<'a, 'b> for &'a SnapshotHashes { -// type Key = Pubkey; -// fn get_entry(table: &'a CrdsTable, key: Self::Key) -> Option { -// let key = CrdsValueLabel::SnapshotHashes(key); -// match &table.get(&key)?.value.data { -// CrdsData::SnapshotHashes(snapshot_hash) => Some(snapshot_hash), -// _ => None, -// } -// } -// } - -#[cfg(test)] -mod tests { - use { - super::*, - crate::{ - crds::{Crds, GossipRoute}, - crds_value::new_rand_timestamp, - }, - rand::seq::SliceRandom, - solana_sdk::signature::Keypair, - std::collections::HashMap, - }; - - #[test] - fn test_get_crds_entry() { - let mut rng = rand::thread_rng(); - let mut crds = Crds::default(); - let keypairs: Vec<_> = std::iter::repeat_with(Keypair::new).take(32).collect(); - let mut entries = HashMap::new(); - for _ in 0..256 { - let keypair = keypairs.choose(&mut rng).unwrap(); - let value = CrdsValue::new_rand(&mut rng, Some(keypair)); - let key = value.label(); - if let Ok(()) = crds.insert( - value.clone(), - new_rand_timestamp(&mut rng), - GossipRoute::LocalMessage, - ) { - entries.insert(key, value); - } - } - assert!(crds.len() > 64); - assert_eq!(crds.len(), entries.len()); - for entry in entries.values() { - let key = entry.label(); - assert_eq!(crds.get::<&CrdsValue>(&key), Some(entry)); - assert_eq!(crds.get::<&CrdsData>(&key), Some(&entry.data)); - assert_eq!(crds.get::<&VersionedCrdsValue>(&key).unwrap().value, *entry); - let key = entry.pubkey(); - match &entry.data { - CrdsData::ContactInfo(node) => { - assert_eq!(crds.get::<&ContactInfo>(key), Some(node)) - } - // CrdsData::LowestSlot(_, slot) => { - // assert_eq!(crds.get::<&LowestSlot>(key), Some(slot)) - // } - CrdsData::Version(version) => assert_eq!(crds.get::<&Version>(key), Some(version)), - // CrdsData::LegacyVersion(version) => { - // assert_eq!(crds.get::<&LegacyVersion>(key), Some(version)) - // } - // CrdsData::SnapshotHashes(hash) => { - // assert_eq!(crds.get::<&SnapshotHashes>(key), Some(hash)) - // } - // CrdsData::IncrementalSnapshotHashes(hash) => { - // assert_eq!(crds.get::<&IncrementalSnapshotHashes>(key), Some(hash)) - // } - _ => (), - } - } - } -} diff --git a/gossip/src/crds_gossip.rs b/gossip/src/crds_gossip.rs deleted file mode 100644 index b16bef8..0000000 --- a/gossip/src/crds_gossip.rs +++ /dev/null @@ -1,429 +0,0 @@ -//! Crds Gossip. -//! -//! This module ties together Crds and the push and pull gossip overlays. The interface is -//! designed to run with a simulator or over a UDP network connection with messages up to a -//! packet::PACKET_DATA_SIZE size. - -use { - crate::{ - cluster_info::Ping, - cluster_info_metrics::GossipStats, - contact_info::ContactInfo, - crds::{Crds, GossipRoute}, - crds_gossip_error::CrdsGossipError, - crds_gossip_pull::{CrdsFilter, CrdsGossipPull, ProcessPullStats}, - crds_gossip_push::{CrdsGossipPush, CRDS_GOSSIP_NUM_ACTIVE}, - crds_value::{CrdsData, CrdsValue}, - duplicate_shred::{self, DuplicateShredIndex, LeaderScheduleFn, MAX_DUPLICATE_SHREDS}, - ping_pong::PingCache, - }, - rayon::ThreadPool, - solana_ledger::shred::Shred, - solana_sdk::{ - hash::Hash, - pubkey::Pubkey, - signature::{Keypair, Signer}, - timing::timestamp, - }, - solana_streamer::socket::SocketAddrSpace, - std::{ - collections::{HashMap, HashSet}, - net::SocketAddr, - sync::{Mutex, RwLock}, - time::Duration, - }, -}; - -#[derive(Default)] -pub struct CrdsGossip { - pub crds: RwLock, - pub push: CrdsGossipPush, - pub pull: CrdsGossipPull, -} - -impl CrdsGossip { - /// Process a push message to the network. - /// - /// Returns unique origins' pubkeys of upserted values. - pub fn process_push_message( - &self, - messages: Vec<(/*from:*/ Pubkey, Vec)>, - now: u64, - ) -> HashSet { - self.push.process_push_message(&self.crds, messages, now) - } - - /// Remove redundant paths in the network. - pub fn prune_received_cache( - &self, - self_pubkey: &Pubkey, - origins: I, // Unique pubkeys of crds values' owners. - stakes: &HashMap, - ) -> HashMap> - where - I: IntoIterator, - { - self.push.prune_received_cache(self_pubkey, origins, stakes) - } - - pub fn new_push_messages( - &self, - pending_push_messages: Vec, - now: u64, - ) -> ( - HashMap>, - usize, // number of values - usize, // number of push messages - ) { - { - let mut crds = self.crds.write().unwrap(); - for entry in pending_push_messages { - let _ = crds.insert(entry, now, GossipRoute::LocalMessage); - } - } - self.push.new_push_messages(&self.crds, now) - } - - // pub(crate) fn push_duplicate_shred( - // &self, - // keypair: &Keypair, - // shred: &Shred, - // other_payload: &[u8], - // leader_schedule: Option, - // // Maximum serialized size of each DuplicateShred chunk payload. - // max_payload_size: usize, - // ) -> Result<(), duplicate_shred::Error> { - // let pubkey = keypair.pubkey(); - // // Skip if there are already records of duplicate shreds for this slot. - // let shred_slot = shred.slot(); - // let mut crds = self.crds.write().unwrap(); - // if crds - // .get_records(&pubkey) - // .any(|value| match &value.value.data { - // CrdsData::DuplicateShred(_, value) => value.slot == shred_slot, - // _ => false, - // }) - // { - // return Ok(()); - // } - // let chunks = duplicate_shred::from_shred( - // shred.clone(), - // pubkey, - // Vec::from(other_payload), - // leader_schedule, - // timestamp(), - // max_payload_size, - // )?; - // // Find the index of oldest duplicate shred. - // let mut num_dup_shreds = 0; - // let offset = crds - // .get_records(&pubkey) - // .filter_map(|value| match &value.value.data { - // CrdsData::DuplicateShred(ix, value) => { - // num_dup_shreds += 1; - // Some((value.wallclock, *ix)) - // } - // _ => None, - // }) - // .min() // Override the oldest records. - // .map(|(_ /*wallclock*/, ix)| ix) - // .unwrap_or(0); - // let offset = if num_dup_shreds < MAX_DUPLICATE_SHREDS { - // num_dup_shreds - // } else { - // offset - // }; - // let entries = chunks.enumerate().map(|(k, chunk)| { - // let index = (offset + k as DuplicateShredIndex) % MAX_DUPLICATE_SHREDS; - // let data = CrdsData::DuplicateShred(index, chunk); - // CrdsValue::new_signed(data, keypair) - // }); - // let now = timestamp(); - // for entry in entries { - // if let Err(err) = crds.insert(entry, now, GossipRoute::LocalMessage) { - // error!("push_duplicate_shred faild: {:?}", err); - // } - // } - // Ok(()) - // } - - /// Add the `from` to the peer's filter of nodes. - pub fn process_prune_msg( - &self, - self_pubkey: &Pubkey, - peer: &Pubkey, - destination: &Pubkey, - origin: &[Pubkey], - wallclock: u64, - now: u64, - ) -> Result<(), CrdsGossipError> { - if now > wallclock.saturating_add(self.push.prune_timeout) { - Err(CrdsGossipError::PruneMessageTimeout) - } else if self_pubkey == destination { - self.push.process_prune_msg(self_pubkey, peer, origin); - Ok(()) - } else { - Err(CrdsGossipError::BadPruneDestination) - } - } - - /// Refresh the push active set. - pub fn refresh_push_active_set( - &self, - self_keypair: &Keypair, - self_shred_version: u16, - stakes: &HashMap, - gossip_validators: Option<&HashSet>, - ping_cache: &Mutex, - pings: &mut Vec<(SocketAddr, Ping)>, - socket_addr_space: &SocketAddrSpace, - ) { - let network_size = self.crds.read().unwrap().num_nodes(); - self.push.refresh_push_active_set( - &self.crds, - stakes, - gossip_validators, - self_keypair, - self_shred_version, - network_size, - CRDS_GOSSIP_NUM_ACTIVE, - ping_cache, - pings, - socket_addr_space, - ) - } - - /// Generate a random request. - #[allow(clippy::too_many_arguments)] - pub fn new_pull_request( - &self, - thread_pool: &ThreadPool, - self_keypair: &Keypair, - self_shred_version: u16, - now: u64, - gossip_validators: Option<&HashSet>, - stakes: &HashMap, - bloom_size: usize, - ping_cache: &Mutex, - pings: &mut Vec<(SocketAddr, Ping)>, - socket_addr_space: &SocketAddrSpace, - ) -> Result>, CrdsGossipError> { - self.pull.new_pull_request( - thread_pool, - &self.crds, - self_keypair, - self_shred_version, - now, - gossip_validators, - stakes, - bloom_size, - ping_cache, - pings, - socket_addr_space, - ) - } - - /// Time when a request to `from` was initiated. - /// - /// This is used for weighted random selection during `new_pull_request` - /// It's important to use the local nodes request creation time as the weight - /// instead of the response received time otherwise failed nodes will increase their weight. - pub fn mark_pull_request_creation_time(&self, from: Pubkey, now: u64) { - self.pull.mark_pull_request_creation_time(from, now) - } - /// Process a pull request and create a response. - pub fn process_pull_requests(&self, callers: I, now: u64) - where - I: IntoIterator, - { - CrdsGossipPull::process_pull_requests(&self.crds, callers, now); - } - - pub fn generate_pull_responses( - &self, - thread_pool: &ThreadPool, - filters: &[(CrdsValue, CrdsFilter)], - output_size_limit: usize, // Limit number of crds values returned. - now: u64, - stats: &GossipStats, - ) -> Vec> { - CrdsGossipPull::generate_pull_responses( - thread_pool, - &self.crds, - filters, - output_size_limit, - now, - stats, - ) - } - - pub fn filter_pull_responses( - &self, - timeouts: &HashMap, - response: Vec, - now: u64, - process_pull_stats: &mut ProcessPullStats, - ) -> ( - Vec, // valid responses. - Vec, // responses with expired timestamps. - Vec, // hash of outdated values. - ) { - self.pull - .filter_pull_responses(&self.crds, timeouts, response, now, process_pull_stats) - } - - /// Process a pull response. - pub fn process_pull_responses( - &self, - from: &Pubkey, - responses: Vec, - responses_expired_timeout: Vec, - failed_inserts: Vec, - now: u64, - process_pull_stats: &mut ProcessPullStats, - ) { - self.pull.process_pull_responses( - &self.crds, - from, - responses, - responses_expired_timeout, - failed_inserts, - now, - process_pull_stats, - ); - } - - pub fn make_timeouts( - &self, - self_pubkey: Pubkey, - stakes: &HashMap, - epoch_duration: Duration, - ) -> HashMap { - self.pull.make_timeouts(self_pubkey, stakes, epoch_duration) - } - - pub fn purge( - &self, - self_pubkey: &Pubkey, - thread_pool: &ThreadPool, - now: u64, - timeouts: &HashMap, - ) -> usize { - let mut rv = 0; - if now > self.pull.crds_timeout { - //sanity check - assert_eq!(timeouts[self_pubkey], std::u64::MAX); - assert!(timeouts.contains_key(&Pubkey::default())); - rv = CrdsGossipPull::purge_active(thread_pool, &self.crds, now, timeouts); - } - self.crds - .write() - .unwrap() - .trim_purged(now.saturating_sub(5 * self.pull.crds_timeout)); - self.pull.purge_failed_inserts(now); - rv - } - - // Only for tests and simulations. - pub(crate) fn mock_clone(&self) -> Self { - let crds = self.crds.read().unwrap().mock_clone(); - Self { - crds: RwLock::new(crds), - push: self.push.mock_clone(), - pull: self.pull.mock_clone(), - } - } -} - -/// Computes a normalized (log of actual stake) stake. -pub fn get_stake(id: &Pubkey, stakes: &HashMap) -> f32 { - // cap the max balance to u32 max (it should be plenty) - let bal = f64::from(u32::max_value()).min(*stakes.get(id).unwrap_or(&0) as f64); - 1_f32.max((bal as f32).ln()) -} - -/// Computes bounded weight given some max, a time since last selected, and a stake value. -/// -/// The minimum stake is 1 and not 0 to allow 'time since last' picked to factor in. -pub fn get_weight(max_weight: f32, time_since_last_selected: u32, stake: f32) -> f32 { - let mut weight = time_since_last_selected as f32 * stake; - if weight.is_infinite() { - weight = max_weight; - } - 1.0_f32.max(weight.min(max_weight)) -} - -#[cfg(test)] -mod test { - use { - super::*, - crate::{contact_info::ContactInfo, crds_value::CrdsData}, - solana_sdk::{hash::hash, timing::timestamp}, - }; - - #[test] - fn test_prune_errors() { - let crds_gossip = CrdsGossip::default(); - let keypair = Keypair::new(); - let id = keypair.pubkey(); - let ci = ContactInfo::new_localhost(&Pubkey::new(&[1; 32]), 0); - let prune_pubkey = Pubkey::new(&[2; 32]); - crds_gossip - .crds - .write() - .unwrap() - .insert( - CrdsValue::new_unsigned(CrdsData::ContactInfo(ci.clone())), - 0, - GossipRoute::LocalMessage, - ) - .unwrap(); - let ping_cache = PingCache::new( - Duration::from_secs(20 * 60), // ttl - Duration::from_secs(20 * 60) / 64, // rate_limit_delay - 128, // capacity - ); - let ping_cache = Mutex::new(ping_cache); - crds_gossip.refresh_push_active_set( - &keypair, - 0, // shred version - &HashMap::new(), // stakes - None, // gossip validators - &ping_cache, - &mut Vec::new(), // pings - &SocketAddrSpace::Unspecified, - ); - let now = timestamp(); - //incorrect dest - let mut res = crds_gossip.process_prune_msg( - &id, - &ci.id, - &Pubkey::new(hash(&[1; 32]).as_ref()), - &[prune_pubkey], - now, - now, - ); - assert_eq!(res.err(), Some(CrdsGossipError::BadPruneDestination)); - //correct dest - res = crds_gossip.process_prune_msg( - &id, // self_pubkey - &ci.id, // peer - &id, // destination - &[prune_pubkey], // origins - now, - now, - ); - res.unwrap(); - //test timeout - let timeout = now + crds_gossip.push.prune_timeout * 2; - res = crds_gossip.process_prune_msg( - &id, // self_pubkey - &ci.id, // peer - &id, // destination - &[prune_pubkey], // origins - now, - timeout, - ); - assert_eq!(res.err(), Some(CrdsGossipError::PruneMessageTimeout)); - } -} diff --git a/gossip/src/crds_gossip_error.rs b/gossip/src/crds_gossip_error.rs deleted file mode 100644 index d6820bf..0000000 --- a/gossip/src/crds_gossip_error.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[derive(PartialEq, Eq, Debug)] -pub enum CrdsGossipError { - NoPeers, - PushMessageTimeout, - PushMessageOldVersion, - BadPruneDestination, - PruneMessageTimeout, -} diff --git a/gossip/src/crds_gossip_pull.rs b/gossip/src/crds_gossip_pull.rs deleted file mode 100644 index 53e0a7b..0000000 --- a/gossip/src/crds_gossip_pull.rs +++ /dev/null @@ -1,1713 +0,0 @@ -//! Crds Gossip Pull overlay. -//! -//! This module implements the anti-entropy protocol for the network. -//! -//! The basic strategy is as follows: -//! -//! 1. Construct a bloom filter of the local data set -//! 2. Randomly ask a node on the network for data that is not contained in the bloom filter. -//! -//! Bloom filters have a false positive rate. Each requests uses a different bloom filter -//! with random hash functions. So each subsequent request will have a different distribution -//! of false positives. - -use { - crate::{ - cluster_info::{Ping, CRDS_UNIQUE_PUBKEY_CAPACITY}, - cluster_info_metrics::GossipStats, - contact_info::ContactInfo, - crds::{Crds, GossipRoute, VersionedCrdsValue}, - crds_gossip::{get_stake, get_weight}, - crds_gossip_error::CrdsGossipError, - crds_value::CrdsValue, - ping_pong::PingCache, - }, - itertools::Itertools, - lru::LruCache, - rand::{ - distributions::{Distribution, WeightedIndex}, - Rng, - }, - rayon::{prelude::*, ThreadPool}, - solana_bloom::bloom::{AtomicBloom, Bloom}, - solana_sdk::{ - hash::{hash, Hash}, - pubkey::Pubkey, - signature::{Keypair, Signer}, - }, - solana_streamer::socket::SocketAddrSpace, - std::{ - collections::{HashMap, HashSet, VecDeque}, - convert::TryInto, - iter::{repeat, repeat_with}, - net::SocketAddr, - sync::{ - atomic::{AtomicI64, AtomicUsize, Ordering}, - Mutex, RwLock, - }, - time::{Duration, Instant}, - }, -}; - -pub const CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS: u64 = 15000; -// The maximum age of a value received over pull responses -pub const CRDS_GOSSIP_PULL_MSG_TIMEOUT_MS: u64 = 60000; -// Retention period of hashes of received outdated values. -const FAILED_INSERTS_RETENTION_MS: u64 = 20_000; -// Do not pull from peers which have not been updated for this long. -const PULL_ACTIVE_TIMEOUT_MS: u64 = 60_000; -pub const FALSE_RATE: f64 = 0.1f64; -pub const KEYS: f64 = 8f64; - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct CrdsFilter { - pub filter: Bloom, - mask: u64, - mask_bits: u32, -} - -impl Default for CrdsFilter { - fn default() -> Self { - CrdsFilter { - filter: Bloom::default(), - mask: !0u64, - mask_bits: 0u32, - } - } -} - -impl solana_sdk::sanitize::Sanitize for CrdsFilter { - fn sanitize(&self) -> std::result::Result<(), solana_sdk::sanitize::SanitizeError> { - self.filter.sanitize()?; - Ok(()) - } -} - -impl CrdsFilter { - #[cfg(test)] - pub(crate) fn new_rand(num_items: usize, max_bytes: usize) -> Self { - let max_bits = (max_bytes * 8) as f64; - let max_items = Self::max_items(max_bits, FALSE_RATE, KEYS); - let mask_bits = Self::mask_bits(num_items as f64, max_items); - let filter = Bloom::random(max_items as usize, FALSE_RATE, max_bits as usize); - let seed: u64 = rand::thread_rng().gen_range(0, 2u64.pow(mask_bits)); - let mask = Self::compute_mask(seed, mask_bits); - CrdsFilter { - filter, - mask, - mask_bits, - } - } - - fn compute_mask(seed: u64, mask_bits: u32) -> u64 { - assert!(seed <= 2u64.pow(mask_bits)); - let seed: u64 = seed.checked_shl(64 - mask_bits).unwrap_or(0x0); - seed | (!0u64).checked_shr(mask_bits).unwrap_or(!0x0) - } - fn max_items(max_bits: f64, false_rate: f64, num_keys: f64) -> f64 { - let m = max_bits; - let p = false_rate; - let k = num_keys; - (m / (-k / (1f64 - (p.ln() / k).exp()).ln())).ceil() - } - fn mask_bits(num_items: f64, max_items: f64) -> u32 { - // for small ratios this can result in a negative number, ensure it returns 0 instead - ((num_items / max_items).log2().ceil()).max(0.0) as u32 - } - pub fn hash_as_u64(item: &Hash) -> u64 { - let buf = item.as_ref()[..8].try_into().unwrap(); - u64::from_le_bytes(buf) - } - fn test_mask(&self, item: &Hash) -> bool { - // only consider the highest mask_bits bits from the hash and set the rest to 1. - let ones = (!0u64).checked_shr(self.mask_bits).unwrap_or(!0u64); - let bits = Self::hash_as_u64(item) | ones; - bits == self.mask - } - #[cfg(test)] - fn add(&mut self, item: &Hash) { - if self.test_mask(item) { - self.filter.add(item); - } - } - #[cfg(test)] - fn contains(&self, item: &Hash) -> bool { - if !self.test_mask(item) { - return true; - } - self.filter.contains(item) - } - fn filter_contains(&self, item: &Hash) -> bool { - self.filter.contains(item) - } -} - -/// A vector of crds filters that together hold a complete set of Hashes. -struct CrdsFilterSet { - filters: Vec>, - mask_bits: u32, -} - -impl CrdsFilterSet { - fn new(num_items: usize, max_bytes: usize) -> Self { - let max_bits = (max_bytes * 8) as f64; - let max_items = CrdsFilter::max_items(max_bits, FALSE_RATE, KEYS); - let mask_bits = CrdsFilter::mask_bits(num_items as f64, max_items); - let filters = - repeat_with(|| Bloom::random(max_items as usize, FALSE_RATE, max_bits as usize).into()) - .take(1 << mask_bits) - .collect(); - Self { filters, mask_bits } - } - - fn add(&self, hash_value: Hash) { - let index = CrdsFilter::hash_as_u64(&hash_value) - .checked_shr(64 - self.mask_bits) - .unwrap_or(0); - self.filters[index as usize].add(&hash_value); - } -} - -impl From for Vec { - fn from(cfs: CrdsFilterSet) -> Self { - let mask_bits = cfs.mask_bits; - cfs.filters - .into_iter() - .enumerate() - .map(|(seed, filter)| CrdsFilter { - filter: filter.into(), - mask: CrdsFilter::compute_mask(seed as u64, mask_bits), - mask_bits, - }) - .collect() - } -} - -#[derive(Default)] -pub struct ProcessPullStats { - pub success: usize, - pub failed_insert: usize, - pub failed_timeout: usize, - pub timeout_count: usize, -} - -pub struct CrdsGossipPull { - /// Timestamp of last request - pull_request_time: RwLock>, - // Hash value and record time (ms) of the pull responses which failed to be - // inserted in crds table; Preserved to stop the sender to send back the - // same outdated payload again by adding them to the filter for the next - // pull request. - failed_inserts: RwLock>, - pub crds_timeout: u64, - msg_timeout: u64, - pub num_pulls: AtomicUsize, -} - -impl Default for CrdsGossipPull { - fn default() -> Self { - Self { - pull_request_time: RwLock::new(LruCache::new(CRDS_UNIQUE_PUBKEY_CAPACITY)), - failed_inserts: RwLock::default(), - crds_timeout: CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS, - msg_timeout: CRDS_GOSSIP_PULL_MSG_TIMEOUT_MS, - num_pulls: AtomicUsize::default(), - } - } -} -impl CrdsGossipPull { - /// Generate a random request - #[allow(clippy::too_many_arguments)] - pub(crate) fn new_pull_request( - &self, - thread_pool: &ThreadPool, - crds: &RwLock, - self_keypair: &Keypair, - self_shred_version: u16, - now: u64, - gossip_validators: Option<&HashSet>, - stakes: &HashMap, - bloom_size: usize, - ping_cache: &Mutex, - pings: &mut Vec<(SocketAddr, Ping)>, - socket_addr_space: &SocketAddrSpace, - ) -> Result>, CrdsGossipError> { - // Gossip peers and respective sampling weights. - let peers = self.pull_options( - crds, - &self_keypair.pubkey(), - self_shred_version, - now, - gossip_validators, - stakes, - socket_addr_space, - ); - // Check for nodes which have responded to ping messages. - let mut rng = rand::thread_rng(); - let (weights, peers): (Vec<_>, Vec<_>) = { - let mut ping_cache = ping_cache.lock().unwrap(); - let mut pingf = move || Ping::new_rand(&mut rng, self_keypair).ok(); - let now = Instant::now(); - peers - .into_iter() - .filter_map(|(weight, peer)| { - let node = (peer.id, peer.gossip); - let (check, ping) = ping_cache.check(now, node, &mut pingf); - if let Some(ping) = ping { - pings.push((peer.gossip, ping)); - } - check.then_some((weight, peer)) - }) - .unzip() - }; - if peers.is_empty() { - return Err(CrdsGossipError::NoPeers); - } - // Associate each pull-request filter with a randomly selected peer. - let filters = self.build_crds_filters(thread_pool, crds, bloom_size); - let dist = WeightedIndex::new(&weights).unwrap(); - let peers = repeat_with(|| peers[dist.sample(&mut rng)].clone()); - Ok(peers.zip(filters).into_group_map()) - } - - fn pull_options( - &self, - crds: &RwLock, - self_id: &Pubkey, - self_shred_version: u16, - now: u64, - gossip_validators: Option<&HashSet>, - stakes: &HashMap, - socket_addr_space: &SocketAddrSpace, - ) -> Vec<(/*weight:*/ u64, ContactInfo)> { - let mut rng = rand::thread_rng(); - let active_cutoff = now.saturating_sub(PULL_ACTIVE_TIMEOUT_MS); - let pull_request_time = self.pull_request_time.read().unwrap(); - // crds should be locked last after self.pull_request_time. - let crds = crds.read().unwrap(); - crds.get_nodes() - .filter_map(|value| { - let info = value.value.contact_info().unwrap(); - // Stop pulling from nodes which have not been active recently. - if value.local_timestamp < active_cutoff { - // In order to mitigate eclipse attack, for staked nodes - // continue retrying periodically. - let stake = stakes.get(&info.id).unwrap_or(&0); - if *stake == 0 || !rng.gen_ratio(1, 16) { - return None; - } - } - Some(info) - }) - .filter(|v| { - v.id != *self_id - && ContactInfo::is_valid_address(&v.gossip, socket_addr_space) - && (self_shred_version == 0 || self_shred_version == v.shred_version) - && gossip_validators - .map_or(true, |gossip_validators| gossip_validators.contains(&v.id)) - }) - .map(|item| { - let max_weight = f32::from(u16::max_value()) - 1.0; - let req_time: u64 = pull_request_time - .peek(&item.id) - .copied() - .unwrap_or_default(); - let since = (now.saturating_sub(req_time).min(3600 * 1000) / 1024) as u32; - let stake = get_stake(&item.id, stakes); - let weight = get_weight(max_weight, since, stake); - // Weights are bounded by max_weight defined above. - // So this type-cast should be safe. - ((weight * 100.0) as u64, item.clone()) - }) - .collect() - } - - /// Time when a request to `from` was initiated. - /// - /// This is used for weighted random selection during `new_pull_request` - /// It's important to use the local nodes request creation time as the weight - /// instead of the response received time otherwise failed nodes will increase their weight. - pub(crate) fn mark_pull_request_creation_time(&self, from: Pubkey, now: u64) { - self.pull_request_time.write().unwrap().put(from, now); - } - - /// Process a pull request - pub(crate) fn process_pull_requests(crds: &RwLock, callers: I, now: u64) - where - I: IntoIterator, - { - let mut crds = crds.write().unwrap(); - for caller in callers { - let key = caller.pubkey(); - let _ = crds.insert(caller, now, GossipRoute::PullRequest); - crds.update_record_timestamp(&key, now); - } - } - - /// Create gossip responses to pull requests - pub(crate) fn generate_pull_responses( - thread_pool: &ThreadPool, - crds: &RwLock, - requests: &[(CrdsValue, CrdsFilter)], - output_size_limit: usize, // Limit number of crds values returned. - now: u64, - stats: &GossipStats, - ) -> Vec> { - Self::filter_crds_values(thread_pool, crds, requests, output_size_limit, now, stats) - } - - // Checks if responses should be inserted and - // returns those responses converted to VersionedCrdsValue - // Separated in three vecs as: - // .0 => responses that update the owner timestamp - // .1 => responses that do not update the owner timestamp - // .2 => hash value of outdated values which will fail to insert. - pub(crate) fn filter_pull_responses( - &self, - crds: &RwLock, - timeouts: &HashMap, - responses: Vec, - now: u64, - stats: &mut ProcessPullStats, - ) -> (Vec, Vec, Vec) { - let mut active_values = vec![]; - let mut expired_values = vec![]; - let default_timeout = timeouts - .get(&Pubkey::default()) - .copied() - .unwrap_or(self.msg_timeout); - let crds = crds.read().unwrap(); - let upsert = |response: CrdsValue| { - let owner = response.label().pubkey(); - // Check if the crds value is older than the msg_timeout - let timeout = timeouts.get(&owner).copied().unwrap_or(default_timeout); - // Before discarding this value, check if a ContactInfo for the - // owner exists in the table. If it doesn't, that implies that this - // value can be discarded - if !crds.upserts(&response) { - Some(response) - } else if now <= response.wallclock().saturating_add(timeout) { - active_values.push(response); - None - } else if crds.get::<&ContactInfo>(owner).is_some() { - // Silently insert this old value without bumping record - // timestamps - expired_values.push(response); - None - } else { - stats.timeout_count += 1; - stats.failed_timeout += 1; - Some(response) - } - }; - let failed_inserts = responses - .into_iter() - .filter_map(upsert) - .map(|resp| hash(&bincode::serialize(&resp).unwrap())) - .collect(); - (active_values, expired_values, failed_inserts) - } - - /// Process a vec of pull responses - pub(crate) fn process_pull_responses( - &self, - crds: &RwLock, - from: &Pubkey, - responses: Vec, - responses_expired_timeout: Vec, - failed_inserts: Vec, - now: u64, - stats: &mut ProcessPullStats, - ) { - let mut owners = HashSet::new(); - let mut crds = crds.write().unwrap(); - for response in responses_expired_timeout { - let _ = crds.insert(response, now, GossipRoute::PullResponse); - } - let mut num_inserts = 0; - for response in responses { - let owner = response.pubkey(); - if let Ok(()) = crds.insert(response, now, GossipRoute::PullResponse) { - num_inserts += 1; - owners.insert(owner); - } - } - stats.success += num_inserts; - self.num_pulls.fetch_add(num_inserts, Ordering::Relaxed); - owners.insert(*from); - for owner in owners { - crds.update_record_timestamp(&owner, now); - } - drop(crds); - stats.failed_insert += failed_inserts.len(); - self.purge_failed_inserts(now); - let failed_inserts = failed_inserts.into_iter().zip(repeat(now)); - self.failed_inserts.write().unwrap().extend(failed_inserts); - } - - pub(crate) fn purge_failed_inserts(&self, now: u64) { - if FAILED_INSERTS_RETENTION_MS < now { - let cutoff = now - FAILED_INSERTS_RETENTION_MS; - let mut failed_inserts = self.failed_inserts.write().unwrap(); - let outdated = failed_inserts - .iter() - .take_while(|(_, ts)| *ts < cutoff) - .count(); - failed_inserts.drain(..outdated); - } - } - - pub(crate) fn failed_inserts_size(&self) -> usize { - self.failed_inserts.read().unwrap().len() - } - - // build a set of filters of the current crds table - // num_filters - used to increase the likelihood of a value in crds being added to some filter - pub fn build_crds_filters( - &self, - thread_pool: &ThreadPool, - crds: &RwLock, - bloom_size: usize, - ) -> Vec { - const PAR_MIN_LENGTH: usize = 512; - #[cfg(debug_assertions)] - const MIN_NUM_BLOOM_ITEMS: usize = 512; - #[cfg(not(debug_assertions))] - const MIN_NUM_BLOOM_ITEMS: usize = 65_536; - let failed_inserts = self.failed_inserts.read().unwrap(); - // crds should be locked last after self.failed_inserts. - let crds = crds.read().unwrap(); - let num_items = crds.len() + crds.num_purged() + failed_inserts.len(); - let num_items = MIN_NUM_BLOOM_ITEMS.max(num_items); - let filters = CrdsFilterSet::new(num_items, bloom_size); - thread_pool.install(|| { - crds.par_values() - .with_min_len(PAR_MIN_LENGTH) - .map(|v| v.value_hash) - .chain(crds.purged().with_min_len(PAR_MIN_LENGTH)) - .chain( - failed_inserts - .par_iter() - .with_min_len(PAR_MIN_LENGTH) - .map(|(v, _)| *v), - ) - .for_each(|v| filters.add(v)); - }); - drop(crds); - drop(failed_inserts); - filters.into() - } - - /// Filter values that fail the bloom filter up to `max_bytes`. - fn filter_crds_values( - thread_pool: &ThreadPool, - crds: &RwLock, - filters: &[(CrdsValue, CrdsFilter)], - output_size_limit: usize, // Limit number of crds values returned. - now: u64, - stats: &GossipStats, - ) -> Vec> { - let msg_timeout = CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS; - let jitter = rand::thread_rng().gen_range(0, msg_timeout / 4); - //skip filters from callers that are too old - let caller_wallclock_window = - now.saturating_sub(msg_timeout)..now.saturating_add(msg_timeout); - let dropped_requests = AtomicUsize::default(); - let total_skipped = AtomicUsize::default(); - let output_size_limit = output_size_limit.try_into().unwrap_or(i64::MAX); - let output_size_limit = AtomicI64::new(output_size_limit); - let crds = crds.read().unwrap(); - let apply_filter = |caller: &CrdsValue, filter: &CrdsFilter| { - if output_size_limit.load(Ordering::Relaxed) <= 0 { - return Vec::default(); - } - let caller_wallclock = caller.wallclock(); - if !caller_wallclock_window.contains(&caller_wallclock) { - dropped_requests.fetch_add(1, Ordering::Relaxed); - return Vec::default(); - } - let caller_wallclock = caller_wallclock.checked_add(jitter).unwrap_or(0); - let pred = |entry: &&VersionedCrdsValue| { - debug_assert!(filter.test_mask(&entry.value_hash)); - // Skip values that are too new. - if entry.value.wallclock() > caller_wallclock { - total_skipped.fetch_add(1, Ordering::Relaxed); - false - } else { - !filter.filter_contains(&entry.value_hash) - } - }; - let out: Vec<_> = crds - .filter_bitmask(filter.mask, filter.mask_bits) - .filter(pred) - .map(|entry| entry.value.clone()) - .take(output_size_limit.load(Ordering::Relaxed).max(0) as usize) - .collect(); - output_size_limit.fetch_sub(out.len() as i64, Ordering::Relaxed); - out - }; - let ret: Vec<_> = thread_pool.install(|| { - filters - .par_iter() - .map(|(caller, filter)| apply_filter(caller, filter)) - .collect() - }); - stats - .filter_crds_values_dropped_requests - .add_relaxed(dropped_requests.into_inner() as u64); - stats - .filter_crds_values_dropped_values - .add_relaxed(total_skipped.into_inner() as u64); - ret - } - - pub(crate) fn make_timeouts( - &self, - self_pubkey: Pubkey, - stakes: &HashMap, - epoch_duration: Duration, - ) -> HashMap { - let extended_timeout = self.crds_timeout.max(epoch_duration.as_millis() as u64); - let default_timeout = if stakes.values().all(|stake| *stake == 0) { - extended_timeout - } else { - self.crds_timeout - }; - stakes - .iter() - .filter(|(_, stake)| **stake > 0) - .map(|(pubkey, _)| (*pubkey, extended_timeout)) - .chain(vec![ - (Pubkey::default(), default_timeout), - (self_pubkey, u64::MAX), - ]) - .collect() - } - - /// Purge values from the crds that are older then `active_timeout` - pub(crate) fn purge_active( - thread_pool: &ThreadPool, - crds: &RwLock, - now: u64, - timeouts: &HashMap, - ) -> usize { - let mut crds = crds.write().unwrap(); - let labels = crds.find_old_labels(thread_pool, now, timeouts); - for label in &labels { - crds.remove(label, now); - } - labels.len() - } - - /// For legacy tests - #[cfg(test)] - fn process_pull_response( - &self, - crds: &RwLock, - from: &Pubkey, - timeouts: &HashMap, - response: Vec, - now: u64, - ) -> (usize, usize, usize) { - let mut stats = ProcessPullStats::default(); - let (versioned, versioned_expired_timeout, failed_inserts) = - self.filter_pull_responses(crds, timeouts, response, now, &mut stats); - self.process_pull_responses( - crds, - from, - versioned, - versioned_expired_timeout, - failed_inserts, - now, - &mut stats, - ); - ( - stats.failed_timeout + stats.failed_insert, - stats.timeout_count, - stats.success, - ) - } - - // Only for tests and simulations. - pub(crate) fn mock_clone(&self) -> Self { - let pull_request_time = { - let pull_request_time = self.pull_request_time.read().unwrap(); - let mut clone = LruCache::new(pull_request_time.cap()); - for (k, v) in pull_request_time.iter().rev() { - clone.put(*k, *v); - } - clone - }; - let failed_inserts = self.failed_inserts.read().unwrap().clone(); - Self { - pull_request_time: RwLock::new(pull_request_time), - failed_inserts: RwLock::new(failed_inserts), - num_pulls: AtomicUsize::new(self.num_pulls.load(Ordering::Relaxed)), - ..*self - } - } - - #[cfg(test)] - pub(crate) fn pull_request_time(&self) -> std::sync::RwLockReadGuard> { - self.pull_request_time.read().unwrap() - } -} - -// #[cfg(test)] -// pub(crate) mod tests { -// use { -// super::*, -// crate::{ -// cluster_info::MAX_BLOOM_SIZE, -// contact_info::ContactInfo, -// crds_value::{CrdsData, Vote}, -// }, -// itertools::Itertools, -// rand::{seq::SliceRandom, thread_rng, SeedableRng}, -// rand_chacha::ChaChaRng, -// rayon::ThreadPoolBuilder, -// solana_perf::test_tx::new_test_vote_tx, -// solana_sdk::{ -// hash::{hash, HASH_BYTES}, -// packet::PACKET_DATA_SIZE, -// timing::timestamp, -// }, -// }; - -// #[cfg(debug_assertions)] -// pub(crate) const MIN_NUM_BLOOM_FILTERS: usize = 1; -// #[cfg(not(debug_assertions))] -// pub(crate) const MIN_NUM_BLOOM_FILTERS: usize = 64; - -// #[test] -// fn test_hash_as_u64() { -// let arr: Vec = (0..HASH_BYTES).map(|i| i as u8 + 1).collect(); -// let hash = Hash::new(&arr); -// assert_eq!(CrdsFilter::hash_as_u64(&hash), 0x807060504030201); -// } - -// #[test] -// fn test_hash_as_u64_random() { -// fn hash_as_u64_bitops(hash: &Hash) -> u64 { -// let mut out = 0; -// for (i, val) in hash.as_ref().iter().enumerate().take(8) { -// out |= (u64::from(*val)) << (i * 8) as u64; -// } -// out -// } -// let mut rng = thread_rng(); -// for _ in 0..100 { -// let hash = solana_sdk::hash::new_rand(&mut rng); -// assert_eq!(CrdsFilter::hash_as_u64(&hash), hash_as_u64_bitops(&hash)); -// } -// } - -// #[test] -// fn test_crds_filter_default() { -// let filter = CrdsFilter::default(); -// let mask = CrdsFilter::compute_mask(0, filter.mask_bits); -// assert_eq!(filter.mask, mask); -// let mut rng = thread_rng(); -// for _ in 0..10 { -// let hash = solana_sdk::hash::new_rand(&mut rng); -// assert!(filter.test_mask(&hash)); -// } -// } - -// #[test] -// fn test_new_pull_with_stakes() { -// let mut crds = Crds::default(); -// let mut stakes = HashMap::new(); -// let node = CrdsGossipPull::default(); -// let me = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &solana_sdk::pubkey::new_rand(), -// 0, -// ))); -// crds.insert(me.clone(), 0, GossipRoute::LocalMessage) -// .unwrap(); -// for i in 1..=30 { -// let entry = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &solana_sdk::pubkey::new_rand(), -// 0, -// ))); -// let id = entry.label().pubkey(); -// crds.insert(entry.clone(), 0, GossipRoute::LocalMessage) -// .unwrap(); -// stakes.insert(id, i * 100); -// } -// let now = 1024; -// let crds = RwLock::new(crds); -// let mut options = node.pull_options( -// &crds, -// &me.label().pubkey(), -// 0, -// now, -// None, -// &stakes, -// &SocketAddrSpace::Unspecified, -// ); -// assert!(!options.is_empty()); -// options.sort_by(|(weight_l, _), (weight_r, _)| weight_r.partial_cmp(weight_l).unwrap()); -// // check that the highest stake holder is also the heaviest weighted. -// assert_eq!(stakes[&options[0].1.id], 3000_u64); -// } - -// #[test] -// fn test_no_pulls_from_different_shred_versions() { -// let mut crds = Crds::default(); -// let stakes = HashMap::new(); -// let node = CrdsGossipPull::default(); - -// let gossip = socketaddr!("127.0.0.1:1234"); - -// let me = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { -// id: solana_sdk::pubkey::new_rand(), -// shred_version: 123, -// gossip, -// ..ContactInfo::default() -// })); -// let spy = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { -// id: solana_sdk::pubkey::new_rand(), -// shred_version: 0, -// gossip, -// ..ContactInfo::default() -// })); -// let node_123 = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { -// id: solana_sdk::pubkey::new_rand(), -// shred_version: 123, -// gossip, -// ..ContactInfo::default() -// })); -// let node_456 = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { -// id: solana_sdk::pubkey::new_rand(), -// shred_version: 456, -// gossip, -// ..ContactInfo::default() -// })); - -// crds.insert(me.clone(), 0, GossipRoute::LocalMessage) -// .unwrap(); -// crds.insert(spy.clone(), 0, GossipRoute::LocalMessage) -// .unwrap(); -// crds.insert(node_123.clone(), 0, GossipRoute::LocalMessage) -// .unwrap(); -// crds.insert(node_456.clone(), 0, GossipRoute::LocalMessage) -// .unwrap(); -// let crds = RwLock::new(crds); - -// // shred version 123 should ignore nodes with versions 0 and 456 -// let options = node -// .pull_options( -// &crds, -// &me.label().pubkey(), -// 123, -// 0, -// None, -// &stakes, -// &SocketAddrSpace::Unspecified, -// ) -// .iter() -// .map(|(_, peer)| peer.id) -// .collect::>(); -// assert_eq!(options.len(), 1); -// assert!(!options.contains(&spy.pubkey())); -// assert!(options.contains(&node_123.pubkey())); - -// // spy nodes will see all -// let options = node -// .pull_options( -// &crds, -// &spy.label().pubkey(), -// 0, -// 0, -// None, -// &stakes, -// &SocketAddrSpace::Unspecified, -// ) -// .iter() -// .map(|(_, peer)| peer.id) -// .collect::>(); -// assert_eq!(options.len(), 3); -// assert!(options.contains(&me.pubkey())); -// assert!(options.contains(&node_123.pubkey())); -// assert!(options.contains(&node_456.pubkey())); -// } - -// #[test] -// fn test_pulls_only_from_allowed() { -// let mut crds = Crds::default(); -// let stakes = HashMap::new(); -// let node = CrdsGossipPull::default(); -// let gossip = socketaddr!("127.0.0.1:1234"); - -// let me = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { -// id: solana_sdk::pubkey::new_rand(), -// gossip, -// ..ContactInfo::default() -// })); -// let node_123 = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { -// id: solana_sdk::pubkey::new_rand(), -// gossip, -// ..ContactInfo::default() -// })); - -// crds.insert(me.clone(), 0, GossipRoute::LocalMessage) -// .unwrap(); -// crds.insert(node_123.clone(), 0, GossipRoute::LocalMessage) -// .unwrap(); -// let crds = RwLock::new(crds); - -// // Empty gossip_validators -- will pull from nobody -// let mut gossip_validators = HashSet::new(); -// let options = node.pull_options( -// &crds, -// &me.label().pubkey(), -// 0, -// 0, -// Some(&gossip_validators), -// &stakes, -// &SocketAddrSpace::Unspecified, -// ); -// assert!(options.is_empty()); - -// // Unknown pubkey in gossip_validators -- will pull from nobody -// gossip_validators.insert(solana_sdk::pubkey::new_rand()); -// let options = node.pull_options( -// &crds, -// &me.label().pubkey(), -// 0, -// 0, -// Some(&gossip_validators), -// &stakes, -// &SocketAddrSpace::Unspecified, -// ); -// assert!(options.is_empty()); - -// // node_123 pubkey in gossip_validators -- will pull from it -// gossip_validators.insert(node_123.pubkey()); -// let options = node.pull_options( -// &crds, -// &me.label().pubkey(), -// 0, -// 0, -// Some(&gossip_validators), -// &stakes, -// &SocketAddrSpace::Unspecified, -// ); -// assert_eq!(options.len(), 1); -// assert_eq!(options[0].1.id, node_123.pubkey()); -// } - -// #[test] -// fn test_crds_filter_set_add() { -// let mut rng = thread_rng(); -// let crds_filter_set = -// CrdsFilterSet::new(/*num_items=*/ 9672788, /*max_bytes=*/ 8196); -// let hash_values: Vec<_> = repeat_with(|| solana_sdk::hash::new_rand(&mut rng)) -// .take(1024) -// .collect(); -// for hash_value in &hash_values { -// crds_filter_set.add(*hash_value); -// } -// let filters: Vec = crds_filter_set.into(); -// assert_eq!(filters.len(), 1024); -// for hash_value in hash_values { -// let mut num_hits = 0; -// let mut false_positives = 0; -// for filter in &filters { -// if filter.test_mask(&hash_value) { -// num_hits += 1; -// assert!(filter.contains(&hash_value)); -// assert!(filter.filter.contains(&hash_value)); -// } else if filter.filter.contains(&hash_value) { -// false_positives += 1; -// } -// } -// assert_eq!(num_hits, 1); -// assert!(false_positives < 5); -// } -// } - -// #[test] -// fn test_crds_filter_set_new() { -// // Validates invariances required by CrdsFilterSet::get in the -// // vector of filters generated by CrdsFilterSet::new. -// let filters: Vec = -// CrdsFilterSet::new(/*num_items=*/ 55345017, /*max_bytes=*/ 4098).into(); -// assert_eq!(filters.len(), 16384); -// let mask_bits = filters[0].mask_bits; -// let right_shift = 64 - mask_bits; -// let ones = !0u64 >> mask_bits; -// for (i, filter) in filters.iter().enumerate() { -// // Check that all mask_bits are equal. -// assert_eq!(mask_bits, filter.mask_bits); -// assert_eq!(i as u64, filter.mask >> right_shift); -// assert_eq!(ones, ones & filter.mask); -// } -// } - -// #[test] -// fn test_build_crds_filter() { -// const SEED: [u8; 32] = [0x55; 32]; -// let mut rng = ChaChaRng::from_seed(SEED); -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let crds_gossip_pull = CrdsGossipPull::default(); -// let mut crds = Crds::default(); -// let keypairs: Vec<_> = repeat_with(|| Keypair::generate(&mut rng)) -// .take(10_000) -// .collect(); -// let mut num_inserts = 0; -// for _ in 0..40_000 { -// let keypair = keypairs.choose(&mut rng).unwrap(); -// let value = CrdsValue::new_rand(&mut rng, Some(keypair)); -// if crds -// .insert(value, rng.gen(), GossipRoute::LocalMessage) -// .is_ok() -// { -// num_inserts += 1; -// } -// } -// let crds = RwLock::new(crds); -// assert!(num_inserts > 30_000, "num inserts: {num_inserts}"); -// let filters = crds_gossip_pull.build_crds_filters(&thread_pool, &crds, MAX_BLOOM_SIZE); -// assert_eq!(filters.len(), MIN_NUM_BLOOM_FILTERS.max(32)); -// let crds = crds.read().unwrap(); -// let purged: Vec<_> = thread_pool.install(|| crds.purged().collect()); -// let hash_values: Vec<_> = crds.values().map(|v| v.value_hash).chain(purged).collect(); -// // CrdsValue::new_rand may generate exact same value twice in which -// // case its hash-value is not added to purged values. -// assert!( -// hash_values.len() >= 40_000 - 5, -// "hash_values.len(): {}", -// hash_values.len() -// ); -// let mut false_positives = 0; -// for hash_value in hash_values { -// let mut num_hits = 0; -// for filter in &filters { -// if filter.test_mask(&hash_value) { -// num_hits += 1; -// assert!(filter.contains(&hash_value)); -// assert!(filter.filter.contains(&hash_value)); -// } else if filter.filter.contains(&hash_value) { -// false_positives += 1; -// } -// } -// assert_eq!(num_hits, 1); -// } -// assert!(false_positives < 150_000, "fp: {false_positives}"); -// } - -// #[test] -// fn test_new_pull_request() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let crds = RwLock::::default(); -// let node_keypair = Keypair::new(); -// let entry = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &node_keypair.pubkey(), -// 0, -// ))); -// let node = CrdsGossipPull::default(); -// let mut pings = Vec::new(); -// let ping_cache = Mutex::new(PingCache::new( -// Duration::from_secs(20 * 60), // ttl -// Duration::from_secs(20 * 60) / 64, // rate_limit_delay -// 128, // capacity -// )); -// assert_eq!( -// node.new_pull_request( -// &thread_pool, -// &crds, -// &node_keypair, -// 0, -// 0, -// None, -// &HashMap::new(), -// PACKET_DATA_SIZE, -// &ping_cache, -// &mut pings, -// &SocketAddrSpace::Unspecified, -// ), -// Err(CrdsGossipError::NoPeers) -// ); - -// crds.write() -// .unwrap() -// .insert(entry, 0, GossipRoute::LocalMessage) -// .unwrap(); -// assert_eq!( -// node.new_pull_request( -// &thread_pool, -// &crds, -// &node_keypair, -// 0, -// 0, -// None, -// &HashMap::new(), -// PACKET_DATA_SIZE, -// &ping_cache, -// &mut pings, -// &SocketAddrSpace::Unspecified, -// ), -// Err(CrdsGossipError::NoPeers) -// ); -// let now = 1625029781069; -// let new = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), now); -// ping_cache -// .lock() -// .unwrap() -// .mock_pong(new.id, new.gossip, Instant::now()); -// let new = CrdsValue::new_unsigned(CrdsData::ContactInfo(new)); -// crds.write() -// .unwrap() -// .insert(new.clone(), now, GossipRoute::LocalMessage) -// .unwrap(); -// let req = node.new_pull_request( -// &thread_pool, -// &crds, -// &node_keypair, -// 0, -// now, -// None, -// &HashMap::new(), -// PACKET_DATA_SIZE, -// &ping_cache, -// &mut pings, -// &SocketAddrSpace::Unspecified, -// ); -// let peers: Vec<_> = req.unwrap().into_keys().collect(); -// assert_eq!(peers, vec![new.contact_info().unwrap().clone()]); - -// node.mark_pull_request_creation_time(new.contact_info().unwrap().id, now); -// let offline = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), now); -// let offline = CrdsValue::new_unsigned(CrdsData::ContactInfo(offline)); -// crds.write() -// .unwrap() -// .insert(offline, now, GossipRoute::LocalMessage) -// .unwrap(); -// let req = node.new_pull_request( -// &thread_pool, -// &crds, -// &node_keypair, -// 0, -// now, -// None, -// &HashMap::new(), -// PACKET_DATA_SIZE, -// &ping_cache, -// &mut pings, -// &SocketAddrSpace::Unspecified, -// ); -// // Even though the offline node should have higher weight, we shouldn't request from it -// // until we receive a ping. -// let peers: Vec<_> = req.unwrap().into_keys().collect(); -// assert_eq!(peers, vec![new.contact_info().unwrap().clone()]); -// } - -// #[test] -// fn test_new_mark_creation_time() { -// let now: u64 = 1_605_127_770_789; -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let mut ping_cache = PingCache::new( -// Duration::from_secs(20 * 60), // ttl -// Duration::from_secs(20 * 60) / 64, // rate_limit_delay -// 128, // capacity -// ); -// let mut crds = Crds::default(); -// let node_keypair = Keypair::new(); -// let entry = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &node_keypair.pubkey(), -// 0, -// ))); -// let node = CrdsGossipPull::default(); -// crds.insert(entry, now, GossipRoute::LocalMessage).unwrap(); -// let old = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); -// ping_cache.mock_pong(old.id, old.gossip, Instant::now()); -// let old = CrdsValue::new_unsigned(CrdsData::ContactInfo(old)); -// crds.insert(old.clone(), now, GossipRoute::LocalMessage) -// .unwrap(); -// let new = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); -// ping_cache.mock_pong(new.id, new.gossip, Instant::now()); -// let new = CrdsValue::new_unsigned(CrdsData::ContactInfo(new)); -// crds.insert(new.clone(), now, GossipRoute::LocalMessage) -// .unwrap(); -// let crds = RwLock::new(crds); - -// // set request creation time to now. -// let now = now + 50_000; -// node.mark_pull_request_creation_time(new.label().pubkey(), now); - -// // odds of getting the other request should be close to 1. -// let now = now + 1_000; -// let mut pings = Vec::new(); -// let ping_cache = Mutex::new(ping_cache); -// let old = old.contact_info().unwrap(); -// let count = repeat_with(|| { -// let requests = node -// .new_pull_request( -// &thread_pool, -// &crds, -// &node_keypair, -// 0, // self_shred_version -// now, -// None, // gossip_validators -// &HashMap::new(), // stakes -// PACKET_DATA_SIZE, // bloom_size -// &ping_cache, -// &mut pings, -// &SocketAddrSpace::Unspecified, -// ) -// .unwrap(); -// requests.into_keys() -// }) -// .flatten() -// .take(100) -// .filter(|peer| peer != old) -// .count(); -// assert!(count < 2, "count of peer != old: {count}"); -// } - -// #[test] -// fn test_pull_request_time() { -// const NUM_REPS: usize = 2 * CRDS_UNIQUE_PUBKEY_CAPACITY; -// let mut rng = rand::thread_rng(); -// let pubkeys: Vec<_> = repeat_with(Pubkey::new_unique).take(NUM_REPS).collect(); -// let node = CrdsGossipPull::default(); -// let mut requests = HashMap::new(); -// let now = timestamp(); -// for k in 0..NUM_REPS { -// let pubkey = pubkeys[rng.gen_range(0, pubkeys.len())]; -// let now = now + k as u64; -// node.mark_pull_request_creation_time(pubkey, now); -// *requests.entry(pubkey).or_default() = now; -// } -// let pull_request_time = node.pull_request_time.read().unwrap(); -// assert!(pull_request_time.len() <= CRDS_UNIQUE_PUBKEY_CAPACITY); -// // Assert that timestamps match most recent request. -// for (pk, ts) in pull_request_time.iter() { -// assert_eq!(*ts, requests[pk]); -// } -// // Assert that most recent pull timestamps are maintained. -// let max_ts = requests -// .iter() -// .filter(|(pk, _)| !pull_request_time.contains(*pk)) -// .map(|(_, ts)| *ts) -// .max() -// .unwrap(); -// let min_ts = requests -// .iter() -// .filter(|(pk, _)| pull_request_time.contains(*pk)) -// .map(|(_, ts)| *ts) -// .min() -// .unwrap(); -// assert!(max_ts <= min_ts); -// } - -// #[test] -// fn test_generate_pull_responses() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let node_keypair = Keypair::new(); -// let mut node_crds = Crds::default(); -// let mut ping_cache = PingCache::new( -// Duration::from_secs(20 * 60), // ttl -// Duration::from_secs(20 * 60) / 64, // rate_limit_delay -// 128, // capacity -// ); -// let entry = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &node_keypair.pubkey(), -// 0, -// ))); -// let caller = entry.clone(); -// let node = CrdsGossipPull::default(); -// node_crds -// .insert(entry, 0, GossipRoute::LocalMessage) -// .unwrap(); -// let new = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); -// ping_cache.mock_pong(new.id, new.gossip, Instant::now()); -// let new = CrdsValue::new_unsigned(CrdsData::ContactInfo(new)); -// node_crds.insert(new, 0, GossipRoute::LocalMessage).unwrap(); -// let node_crds = RwLock::new(node_crds); -// let mut pings = Vec::new(); -// let req = node.new_pull_request( -// &thread_pool, -// &node_crds, -// &node_keypair, -// 0, -// 0, -// None, -// &HashMap::new(), -// PACKET_DATA_SIZE, -// &Mutex::new(ping_cache), -// &mut pings, -// &SocketAddrSpace::Unspecified, -// ); - -// let dest_crds = RwLock::::default(); -// let filters = req.unwrap().into_values().flatten(); -// let mut filters: Vec<_> = filters.into_iter().map(|f| (caller.clone(), f)).collect(); -// let rsp = CrdsGossipPull::generate_pull_responses( -// &thread_pool, -// &dest_crds, -// &filters, -// usize::MAX, // output_size_limit -// 0, // now -// &GossipStats::default(), -// ); - -// assert_eq!(rsp[0].len(), 0); - -// let new = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &solana_sdk::pubkey::new_rand(), -// CRDS_GOSSIP_PULL_MSG_TIMEOUT_MS, -// ))); -// dest_crds -// .write() -// .unwrap() -// .insert( -// new, -// CRDS_GOSSIP_PULL_MSG_TIMEOUT_MS, -// GossipRoute::LocalMessage, -// ) -// .unwrap(); - -// //should skip new value since caller is to old -// let rsp = CrdsGossipPull::generate_pull_responses( -// &thread_pool, -// &dest_crds, -// &filters, -// usize::MAX, // output_size_limit -// CRDS_GOSSIP_PULL_MSG_TIMEOUT_MS, // now -// &GossipStats::default(), -// ); -// assert_eq!(rsp[0].len(), 0); -// assert_eq!(filters.len(), MIN_NUM_BLOOM_FILTERS); -// filters.extend({ -// // Should return new value since caller is new. -// let now = CRDS_GOSSIP_PULL_MSG_TIMEOUT_MS + 1; -// let caller = ContactInfo::new_localhost(&Pubkey::new_unique(), now); -// let caller = CrdsValue::new_unsigned(CrdsData::ContactInfo(caller)); -// filters -// .iter() -// .map(|(_, filter)| (caller.clone(), filter.clone())) -// .collect::>() -// }); -// let rsp = CrdsGossipPull::generate_pull_responses( -// &thread_pool, -// &dest_crds, -// &filters, -// usize::MAX, // output_size_limit -// CRDS_GOSSIP_PULL_MSG_TIMEOUT_MS, -// &GossipStats::default(), -// ); -// assert_eq!(rsp.len(), 2 * MIN_NUM_BLOOM_FILTERS); -// // There should be only one non-empty response in the 2nd half. -// // Orders are also preserved. -// assert!(rsp.iter().take(MIN_NUM_BLOOM_FILTERS).all(|r| r.is_empty())); -// assert_eq!(rsp.iter().filter(|r| r.is_empty()).count(), rsp.len() - 1); -// assert_eq!(rsp.iter().find(|r| r.len() == 1).unwrap().len(), 1); -// } - -// #[test] -// fn test_process_pull_request() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let node_keypair = Keypair::new(); -// let mut node_crds = Crds::default(); -// let entry = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &node_keypair.pubkey(), -// 0, -// ))); -// let caller = entry.clone(); -// let node = CrdsGossipPull::default(); -// node_crds -// .insert(entry, 0, GossipRoute::LocalMessage) -// .unwrap(); -// let mut ping_cache = PingCache::new( -// Duration::from_secs(20 * 60), // ttl -// Duration::from_secs(20 * 60) / 64, // rate_limit_delay -// 128, // capacity -// ); -// let new = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); -// ping_cache.mock_pong(new.id, new.gossip, Instant::now()); -// let new = CrdsValue::new_unsigned(CrdsData::ContactInfo(new)); -// node_crds.insert(new, 0, GossipRoute::LocalMessage).unwrap(); -// let node_crds = RwLock::new(node_crds); -// let mut pings = Vec::new(); -// let req = node.new_pull_request( -// &thread_pool, -// &node_crds, -// &node_keypair, -// 0, -// 0, -// None, -// &HashMap::new(), -// PACKET_DATA_SIZE, -// &Mutex::new(ping_cache), -// &mut pings, -// &SocketAddrSpace::Unspecified, -// ); - -// let dest_crds = RwLock::::default(); -// let filters = req.unwrap().into_values().flatten(); -// let filters: Vec<_> = filters.into_iter().map(|f| (caller.clone(), f)).collect(); -// let rsp = CrdsGossipPull::generate_pull_responses( -// &thread_pool, -// &dest_crds, -// &filters, -// usize::MAX, // output_size_limit -// 0, // now -// &GossipStats::default(), -// ); -// let callers = filters.into_iter().map(|(caller, _)| caller); -// CrdsGossipPull::process_pull_requests(&dest_crds, callers, 1); -// let dest_crds = dest_crds.read().unwrap(); -// assert!(rsp.iter().all(|rsp| rsp.is_empty())); -// assert!(dest_crds.get::<&CrdsValue>(&caller.label()).is_some()); -// assert_eq!(1, { -// let entry: &VersionedCrdsValue = dest_crds.get(&caller.label()).unwrap(); -// entry.local_timestamp -// }); -// } -// #[test] -// fn test_process_pull_request_response() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let node_keypair = Keypair::new(); -// let mut node_crds = Crds::default(); -// let entry = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &node_keypair.pubkey(), -// 1, -// ))); -// let caller = entry.clone(); -// let node_pubkey = entry.label().pubkey(); -// let node = CrdsGossipPull::default(); -// node_crds -// .insert(entry, 0, GossipRoute::LocalMessage) -// .unwrap(); -// let mut ping_cache = PingCache::new( -// Duration::from_secs(20 * 60), // ttl -// Duration::from_secs(20 * 60) / 64, // rate_limit_delay -// 128, // capacity -// ); -// let new = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 1); -// ping_cache.mock_pong(new.id, new.gossip, Instant::now()); -// let new = CrdsValue::new_unsigned(CrdsData::ContactInfo(new)); -// node_crds.insert(new, 0, GossipRoute::LocalMessage).unwrap(); - -// let mut dest_crds = Crds::default(); -// let new_id = solana_sdk::pubkey::new_rand(); -// let new = ContactInfo::new_localhost(&new_id, 1); -// ping_cache.mock_pong(new.id, new.gossip, Instant::now()); -// let new = CrdsValue::new_unsigned(CrdsData::ContactInfo(new)); -// dest_crds -// .insert(new.clone(), 0, GossipRoute::LocalMessage) -// .unwrap(); -// let dest_crds = RwLock::new(dest_crds); - -// // node contains a key from the dest node, but at an older local timestamp -// let same_key = ContactInfo::new_localhost(&new_id, 0); -// ping_cache.mock_pong(same_key.id, same_key.gossip, Instant::now()); -// let same_key = CrdsValue::new_unsigned(CrdsData::ContactInfo(same_key)); -// assert_eq!(same_key.label(), new.label()); -// assert!(same_key.wallclock() < new.wallclock()); -// node_crds -// .insert(same_key.clone(), 0, GossipRoute::LocalMessage) -// .unwrap(); -// assert_eq!(0, { -// let entry: &VersionedCrdsValue = node_crds.get(&same_key.label()).unwrap(); -// entry.local_timestamp -// }); -// let node_crds = RwLock::new(node_crds); -// let mut done = false; -// let mut pings = Vec::new(); -// let ping_cache = Mutex::new(ping_cache); -// for _ in 0..30 { -// // there is a chance of a false positive with bloom filters -// let req = node.new_pull_request( -// &thread_pool, -// &node_crds, -// &node_keypair, -// 0, -// 0, -// None, -// &HashMap::new(), -// PACKET_DATA_SIZE, -// &ping_cache, -// &mut pings, -// &SocketAddrSpace::Unspecified, -// ); -// let filters = req.unwrap().into_values().flatten(); -// let filters: Vec<_> = filters.into_iter().map(|f| (caller.clone(), f)).collect(); -// let rsp = CrdsGossipPull::generate_pull_responses( -// &thread_pool, -// &dest_crds, -// &filters, -// usize::MAX, // output_size_limit -// 0, // now -// &GossipStats::default(), -// ); -// CrdsGossipPull::process_pull_requests( -// &dest_crds, -// filters.into_iter().map(|(caller, _)| caller), -// 0, -// ); -// // if there is a false positive this is empty -// // prob should be around 0.1 per iteration -// if rsp.is_empty() { -// continue; -// } - -// if rsp.is_empty() { -// continue; -// } -// assert_eq!(rsp.len(), MIN_NUM_BLOOM_FILTERS); -// let failed = node -// .process_pull_response( -// &node_crds, -// &node_pubkey, -// &node.make_timeouts(node_pubkey, &HashMap::new(), Duration::default()), -// rsp.into_iter().flatten().collect(), -// 1, -// ) -// .0; -// assert_eq!(failed, 0); -// assert_eq!(1, { -// let node_crds = node_crds.read().unwrap(); -// let entry: &VersionedCrdsValue = node_crds.get(&new.label()).unwrap(); -// entry.local_timestamp -// }); -// // verify that the whole record was updated for dest since this is a response from dest -// assert_eq!(1, { -// let node_crds = node_crds.read().unwrap(); -// let entry: &VersionedCrdsValue = node_crds.get(&same_key.label()).unwrap(); -// entry.local_timestamp -// }); -// done = true; -// break; -// } -// assert!(done); -// } -// #[test] -// fn test_gossip_purge() { -// let thread_pool = ThreadPoolBuilder::new().build().unwrap(); -// let mut node_crds = Crds::default(); -// let entry = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &solana_sdk::pubkey::new_rand(), -// 0, -// ))); -// let node_label = entry.label(); -// let node_pubkey = node_label.pubkey(); -// let node = CrdsGossipPull::default(); -// node_crds -// .insert(entry, 0, GossipRoute::LocalMessage) -// .unwrap(); -// let old = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &solana_sdk::pubkey::new_rand(), -// 0, -// ))); -// node_crds -// .insert(old.clone(), 0, GossipRoute::LocalMessage) -// .unwrap(); -// let value_hash = { -// let entry: &VersionedCrdsValue = node_crds.get(&old.label()).unwrap(); -// entry.value_hash -// }; -// //verify self is valid -// assert_eq!( -// node_crds.get::<&CrdsValue>(&node_label).unwrap().label(), -// node_label -// ); -// // purge -// let node_crds = RwLock::new(node_crds); -// let timeouts = node.make_timeouts(node_pubkey, &HashMap::new(), Duration::default()); -// CrdsGossipPull::purge_active(&thread_pool, &node_crds, node.crds_timeout, &timeouts); - -// //verify self is still valid after purge -// assert_eq!(node_label, { -// let node_crds = node_crds.read().unwrap(); -// node_crds.get::<&CrdsValue>(&node_label).unwrap().label() -// }); -// assert_eq!( -// node_crds.read().unwrap().get::<&CrdsValue>(&old.label()), -// None -// ); -// assert_eq!(node_crds.read().unwrap().num_purged(), 1); -// for _ in 0..30 { -// // there is a chance of a false positive with bloom filters -// // assert that purged value is still in the set -// // chance of 30 consecutive false positives is 0.1^30 -// let filters = node.build_crds_filters(&thread_pool, &node_crds, PACKET_DATA_SIZE); -// assert!(filters.iter().any(|filter| filter.contains(&value_hash))); -// } - -// // purge the value -// let mut node_crds = node_crds.write().unwrap(); -// node_crds.trim_purged(node.crds_timeout + 1); -// assert_eq!(node_crds.num_purged(), 0); -// } -// #[test] -// #[allow(clippy::float_cmp)] -// fn test_crds_filter_mask() { -// let filter = CrdsFilter::new_rand(1, 128); -// assert_eq!(filter.mask, !0x0); -// assert_eq!(CrdsFilter::max_items(80f64, 0.01, 8f64), 9f64); -// //1000/9 = 111, so 7 bits are needed to mask it -// assert_eq!(CrdsFilter::mask_bits(1000f64, 9f64), 7u32); -// let filter = CrdsFilter::new_rand(1000, 10); -// assert_eq!(filter.mask & 0x00_ffff_ffff, 0x00_ffff_ffff); -// } -// #[test] -// fn test_crds_filter_add_no_mask() { -// let mut filter = CrdsFilter::new_rand(1, 128); -// let h: Hash = hash(Hash::default().as_ref()); -// assert!(!filter.contains(&h)); -// filter.add(&h); -// assert!(filter.contains(&h)); -// let h: Hash = hash(h.as_ref()); -// assert!(!filter.contains(&h)); -// } -// #[test] -// fn test_crds_filter_add_mask() { -// let mut filter = CrdsFilter::new_rand(1000, 10); -// let mut h: Hash = Hash::default(); -// while !filter.test_mask(&h) { -// h = hash(h.as_ref()); -// } -// assert!(filter.test_mask(&h)); -// //if the mask succeeds, we want the guaranteed negative -// assert!(!filter.contains(&h)); -// filter.add(&h); -// assert!(filter.contains(&h)); -// } -// #[test] -// fn test_crds_filter_complete_set_add_mask() { -// let mut filters: Vec = CrdsFilterSet::new(1000, 10).into(); -// assert!(filters.iter().all(|f| f.mask_bits > 0)); -// let mut h: Hash = Hash::default(); -// // rev to make the hash::default() miss on the first few test_masks -// while !filters.iter().rev().any(|f| f.test_mask(&h)) { -// h = hash(h.as_ref()); -// } -// let filter = filters.iter_mut().find(|f| f.test_mask(&h)).unwrap(); -// assert!(filter.test_mask(&h)); -// //if the mask succeeds, we want the guaranteed negative -// assert!(!filter.contains(&h)); -// filter.add(&h); -// assert!(filter.contains(&h)); -// } -// #[test] -// fn test_crds_filter_contains_mask() { -// let filter = CrdsFilter::new_rand(1000, 10); -// assert!(filter.mask_bits > 0); -// let mut h: Hash = Hash::default(); -// while filter.test_mask(&h) { -// h = hash(h.as_ref()); -// } -// assert!(!filter.test_mask(&h)); -// //if the mask fails, the hash is contained in the set, and can be treated as a false -// //positive -// assert!(filter.contains(&h)); -// } -// #[test] -// fn test_mask() { -// for i in 0..16 { -// run_test_mask(i); -// } -// } -// fn run_test_mask(mask_bits: u32) { -// assert_eq!( -// (0..2u64.pow(mask_bits)) -// .map(|seed| CrdsFilter::compute_mask(seed, mask_bits)) -// .dedup() -// .count(), -// 2u64.pow(mask_bits) as usize -// ) -// } - -// #[test] -// fn test_process_pull_response() { -// let mut rng = rand::thread_rng(); -// let node_crds = RwLock::::default(); -// let node = CrdsGossipPull::default(); - -// let peer_pubkey = solana_sdk::pubkey::new_rand(); -// let peer_entry = CrdsValue::new_unsigned(CrdsData::ContactInfo( -// ContactInfo::new_localhost(&peer_pubkey, 0), -// )); -// let mut timeouts = HashMap::new(); -// timeouts.insert(Pubkey::default(), node.crds_timeout); -// timeouts.insert(peer_pubkey, node.msg_timeout + 1); -// // inserting a fresh value should be fine. -// assert_eq!( -// node.process_pull_response( -// &node_crds, -// &peer_pubkey, -// &timeouts, -// vec![peer_entry.clone()], -// 1, -// ) -// .0, -// 0 -// ); - -// let node_crds = RwLock::::default(); -// let unstaked_peer_entry = CrdsValue::new_unsigned(CrdsData::ContactInfo( -// ContactInfo::new_localhost(&peer_pubkey, 0), -// )); -// // check that old contact infos fail if they are too old, regardless of "timeouts" -// assert_eq!( -// node.process_pull_response( -// &node_crds, -// &peer_pubkey, -// &timeouts, -// vec![peer_entry.clone(), unstaked_peer_entry], -// node.msg_timeout + 100, -// ) -// .0, -// 4 -// ); - -// let node_crds = RwLock::::default(); -// // check that old contact infos can still land as long as they have a "timeouts" entry -// assert_eq!( -// node.process_pull_response( -// &node_crds, -// &peer_pubkey, -// &timeouts, -// vec![peer_entry], -// node.msg_timeout + 1, -// ) -// .0, -// 0 -// ); - -// // construct something that's not a contact info -// let peer_vote = Vote::new(peer_pubkey, new_test_vote_tx(&mut rng), 0).unwrap(); -// let peer_vote = CrdsValue::new_unsigned(CrdsData::Vote(0, peer_vote)); -// // check that older CrdsValues (non-ContactInfos) infos pass even if are too old, -// // but a recent contact info (inserted above) exists -// assert_eq!( -// node.process_pull_response( -// &node_crds, -// &peer_pubkey, -// &timeouts, -// vec![peer_vote.clone()], -// node.msg_timeout + 1, -// ) -// .0, -// 0 -// ); - -// let node_crds = RwLock::::default(); -// // without a contact info, inserting an old value should fail -// assert_eq!( -// node.process_pull_response( -// &node_crds, -// &peer_pubkey, -// &timeouts, -// vec![peer_vote], -// node.msg_timeout + 2, -// ) -// .0, -// 2 -// ); -// } -// } diff --git a/gossip/src/crds_gossip_push.rs b/gossip/src/crds_gossip_push.rs deleted file mode 100644 index d984893..0000000 --- a/gossip/src/crds_gossip_push.rs +++ /dev/null @@ -1,1020 +0,0 @@ -//! Crds Gossip Push overlay. -//! -//! This module is used to propagate recently created CrdsValues across the network -//! Eager push strategy is based on [Plumtree]. -//! -//! [Plumtree]: http://asc.di.fct.unl.pt/~jleitao/pdf/srds07-leitao.pdf -//! -//! Main differences are: -//! -//! 1. There is no `max hop`. Messages are signed with a local wallclock. If they are outside of -//! the local nodes wallclock window they are dropped silently. -//! 2. The prune set is stored in a Bloom filter. - -use { - crate::{ - cluster_info::{Ping, CRDS_UNIQUE_PUBKEY_CAPACITY}, - contact_info::ContactInfo, - crds::{Crds, CrdsError, Cursor, GossipRoute}, - crds_gossip::{get_stake, get_weight}, - crds_value::CrdsValue, - ping_pong::PingCache, - received_cache::ReceivedCache, - weighted_shuffle::WeightedShuffle, - }, - bincode::serialized_size, - indexmap::map::IndexMap, - itertools::Itertools, - lru::LruCache, - rand::{seq::SliceRandom, Rng}, - solana_bloom::bloom::{AtomicBloom, Bloom}, - solana_sdk::{ - packet::PACKET_DATA_SIZE, - pubkey::Pubkey, - signature::{Keypair, Signer}, - timing::timestamp, - }, - solana_streamer::socket::SocketAddrSpace, - std::{ - cmp, - collections::{HashMap, HashSet}, - iter::repeat, - net::SocketAddr, - ops::{DerefMut, RangeBounds}, - sync::{ - atomic::{AtomicUsize, Ordering}, - Mutex, RwLock, - }, - time::Instant, - }, -}; - -pub(crate) const CRDS_GOSSIP_NUM_ACTIVE: usize = 30; -const CRDS_GOSSIP_PUSH_FANOUT: usize = 6; -// With a fanout of 6, a 1000 node cluster should only take ~4 hops to converge. -// However since pushes are stake weighed, some trailing nodes -// might need more time to receive values. 30 seconds should be plenty. -pub const CRDS_GOSSIP_PUSH_MSG_TIMEOUT_MS: u64 = 30000; -const CRDS_GOSSIP_PRUNE_MSG_TIMEOUT_MS: u64 = 500; -const CRDS_GOSSIP_PRUNE_STAKE_THRESHOLD_PCT: f64 = 0.15; -const CRDS_GOSSIP_PRUNE_MIN_INGRESS_NODES: usize = 3; -// Do not push to peers which have not been updated for this long. -const PUSH_ACTIVE_TIMEOUT_MS: u64 = 60_000; - -pub struct CrdsGossipPush { - /// Max bytes per message - max_bytes: usize, - /// Active set of validators for push - active_set: RwLock>>, - /// Cursor into the crds table for values to push. - crds_cursor: Mutex, - /// Cache that tracks which validators a message was received from - /// This cache represents a lagging view of which validators - /// currently have this node in their `active_set` - received_cache: Mutex, - last_pushed_to: RwLock>, - num_active: usize, - push_fanout: usize, - pub(crate) msg_timeout: u64, - pub prune_timeout: u64, - pub num_total: AtomicUsize, - pub num_old: AtomicUsize, - pub num_pushes: AtomicUsize, -} - -impl Default for CrdsGossipPush { - fn default() -> Self { - Self { - // Allow upto 64 Crds Values per PUSH - max_bytes: PACKET_DATA_SIZE * 64, - active_set: RwLock::default(), - crds_cursor: Mutex::default(), - received_cache: Mutex::new(ReceivedCache::new(2 * CRDS_UNIQUE_PUBKEY_CAPACITY)), - last_pushed_to: RwLock::new(LruCache::new(CRDS_UNIQUE_PUBKEY_CAPACITY)), - num_active: CRDS_GOSSIP_NUM_ACTIVE, - push_fanout: CRDS_GOSSIP_PUSH_FANOUT, - msg_timeout: CRDS_GOSSIP_PUSH_MSG_TIMEOUT_MS, - prune_timeout: CRDS_GOSSIP_PRUNE_MSG_TIMEOUT_MS, - num_total: AtomicUsize::default(), - num_old: AtomicUsize::default(), - num_pushes: AtomicUsize::default(), - } - } -} -impl CrdsGossipPush { - pub fn num_pending(&self, crds: &RwLock) -> usize { - let mut cursor: Cursor = *self.crds_cursor.lock().unwrap(); - crds.read().unwrap().get_entries(&mut cursor).count() - } - - pub(crate) fn prune_received_cache( - &self, - self_pubkey: &Pubkey, - origins: I, // Unique pubkeys of crds values' owners. - stakes: &HashMap, - ) -> HashMap> - where - I: IntoIterator, - { - let mut received_cache = self.received_cache.lock().unwrap(); - origins - .into_iter() - .flat_map(|origin| { - received_cache - .prune( - self_pubkey, - origin, - CRDS_GOSSIP_PRUNE_STAKE_THRESHOLD_PCT, - CRDS_GOSSIP_PRUNE_MIN_INGRESS_NODES, - stakes, - ) - .zip(repeat(origin)) - }) - .into_group_map() - } - - fn wallclock_window(&self, now: u64) -> impl RangeBounds { - now.saturating_sub(self.msg_timeout)..=now.saturating_add(self.msg_timeout) - } - - /// Process a push message to the network. - /// - /// Returns origins' pubkeys of upserted values. - pub(crate) fn process_push_message( - &self, - crds: &RwLock, - messages: Vec<(/*from:*/ Pubkey, Vec)>, - now: u64, - ) -> HashSet { - let mut received_cache = self.received_cache.lock().unwrap(); - let mut crds = crds.write().unwrap(); - let wallclock_window = self.wallclock_window(now); - let mut origins = HashSet::with_capacity(messages.len()); - for (from, values) in messages { - self.num_total.fetch_add(values.len(), Ordering::Relaxed); - for value in values { - if !wallclock_window.contains(&value.wallclock()) { - continue; - } - let origin = value.pubkey(); - match crds.insert(value, now, GossipRoute::PushMessage) { - Ok(()) => { - received_cache.record(origin, from, /*num_dups:*/ 0); - origins.insert(origin); - } - Err(CrdsError::DuplicatePush(num_dups)) => { - received_cache.record(origin, from, usize::from(num_dups)); - self.num_old.fetch_add(1, Ordering::Relaxed); - } - Err(_) => { - self.num_old.fetch_add(1, Ordering::Relaxed); - } - } - } - } - origins - } - - /// New push message to broadcast to peers. - /// - /// Returns a list of Pubkeys for the selected peers and a list of values to send to all the - /// peers. - /// The list of push messages is created such that all the randomly selected peers have not - /// pruned the source addresses. - pub(crate) fn new_push_messages( - &self, - crds: &RwLock, - now: u64, - ) -> ( - HashMap>, - usize, // number of values - usize, // number of push messages - ) { - let active_set = self.active_set.read().unwrap(); - let active_set_len = active_set.len(); - let push_fanout = self.push_fanout.min(active_set_len); - if push_fanout == 0 { - return (HashMap::default(), 0, 0); - } - let mut num_pushes = 0; - let mut num_values = 0; - let mut total_bytes: usize = 0; - let mut push_messages: HashMap> = HashMap::new(); - let wallclock_window = self.wallclock_window(now); - let mut crds_cursor = self.crds_cursor.lock().unwrap(); - // crds should be locked last after self.{active_set,crds_cursor}. - let crds = crds.read().unwrap(); - let entries = crds - .get_entries(crds_cursor.deref_mut()) - .map(|entry| &entry.value) - .filter(|value| wallclock_window.contains(&value.wallclock())); - for value in entries { - let serialized_size = serialized_size(&value).unwrap(); - total_bytes = total_bytes.saturating_add(serialized_size as usize); - if total_bytes > self.max_bytes { - break; - } - num_values += 1; - let origin = value.pubkey(); - // Use a consistent index for the same origin so the active set - // learns the MST for that origin. - let offset = origin.as_ref()[0] as usize; - for i in offset..offset + push_fanout { - let index = i % active_set_len; - let (peer, filter) = active_set.get_index(index).unwrap(); - if !filter.contains(&origin) || value.should_force_push(peer) { - trace!("new_push_messages insert {} {:?}", *peer, value); - push_messages.entry(*peer).or_default().push(value.clone()); - num_pushes += 1; - } - } - } - drop(crds); - drop(crds_cursor); - drop(active_set); - self.num_pushes.fetch_add(num_pushes, Ordering::Relaxed); - trace!("new_push_messages {} {}", num_values, active_set_len); - let mut last_pushed_to = self.last_pushed_to.write().unwrap(); - for target_pubkey in push_messages.keys().copied() { - last_pushed_to.put(target_pubkey, now); - } - (push_messages, num_values, num_pushes) - } - - /// Add the `from` to the peer's filter of nodes. - pub(crate) fn process_prune_msg( - &self, - self_pubkey: &Pubkey, - peer: &Pubkey, - origins: &[Pubkey], - ) { - if let Some(filter) = self.active_set.read().unwrap().get(peer) { - for origin in origins { - if origin != self_pubkey { - filter.add(origin); - } - } - } - } - - fn compute_need(num_active: usize, active_set_len: usize, ratio: usize) -> usize { - let num = active_set_len / ratio; - cmp::min(num_active, (num_active - active_set_len) + num) - } - - /// Refresh the push active set. - /// - /// # Arguments - /// - /// * ratio - active_set.len()/ratio is the number of actives to rotate - #[allow(clippy::too_many_arguments)] - pub(crate) fn refresh_push_active_set( - &self, - crds: &RwLock, - stakes: &HashMap, - gossip_validators: Option<&HashSet>, - self_keypair: &Keypair, - self_shred_version: u16, - network_size: usize, - ratio: usize, - ping_cache: &Mutex, - pings: &mut Vec<(SocketAddr, Ping)>, - socket_addr_space: &SocketAddrSpace, - ) { - const BLOOM_FALSE_RATE: f64 = 0.1; - const BLOOM_MAX_BITS: usize = 1024 * 8 * 4; - #[cfg(debug_assertions)] - const MIN_NUM_BLOOM_ITEMS: usize = 512; - #[cfg(not(debug_assertions))] - const MIN_NUM_BLOOM_ITEMS: usize = CRDS_UNIQUE_PUBKEY_CAPACITY; - let mut rng = rand::thread_rng(); - let mut new_items = HashMap::new(); - // Gossip peers and respective sampling weights. - let peers = self.push_options( - crds, - &self_keypair.pubkey(), - self_shred_version, - stakes, - gossip_validators, - socket_addr_space, - ); - // Check for nodes which have responded to ping messages. - let (weights, peers): (Vec<_>, Vec<_>) = { - let mut ping_cache = ping_cache.lock().unwrap(); - let mut pingf = move || Ping::new_rand(&mut rng, self_keypair).ok(); - let now = Instant::now(); - peers - .into_iter() - .filter_map(|(weight, peer)| { - let node = (peer.id, peer.gossip); - let (check, ping) = ping_cache.check(now, node, &mut pingf); - if let Some(ping) = ping { - pings.push((peer.gossip, ping)); - } - check.then_some((weight, peer.id)) - }) - .unzip() - }; - if peers.is_empty() { - return; - } - let num_bloom_items = MIN_NUM_BLOOM_ITEMS.max(network_size); - let shuffle = WeightedShuffle::new("push-options", &weights).shuffle(&mut rng); - let mut active_set = self.active_set.write().unwrap(); - let need = Self::compute_need(self.num_active, active_set.len(), ratio); - for peer in shuffle.map(|i| peers[i]) { - if new_items.len() >= need { - break; - } - if active_set.contains_key(&peer) || new_items.contains_key(&peer) { - continue; - } - let bloom = AtomicBloom::from(Bloom::random( - num_bloom_items, - BLOOM_FALSE_RATE, - BLOOM_MAX_BITS, - )); - bloom.add(&peer); - new_items.insert(peer, bloom); - } - let mut keys: Vec = active_set.keys().cloned().collect(); - keys.shuffle(&mut rng); - let num = keys.len() / ratio; - for k in &keys[..num] { - active_set.swap_remove(k); - } - for (k, v) in new_items { - active_set.insert(k, v); - } - } - - fn push_options( - &self, - crds: &RwLock, - self_id: &Pubkey, - self_shred_version: u16, - stakes: &HashMap, - gossip_validators: Option<&HashSet>, - socket_addr_space: &SocketAddrSpace, - ) -> Vec<(/*weight:*/ u64, /*node:*/ ContactInfo)> { - let now = timestamp(); - let mut rng = rand::thread_rng(); - let max_weight = u16::MAX as f32 - 1.0; - let active_cutoff = now.saturating_sub(PUSH_ACTIVE_TIMEOUT_MS); - let last_pushed_to = self.last_pushed_to.read().unwrap(); - // crds should be locked last after self.last_pushed_to. - let crds = crds.read().unwrap(); - crds.get_nodes() - .filter_map(|value| { - let info = value.value.contact_info().unwrap(); - // Stop pushing to nodes which have not been active recently. - if value.local_timestamp < active_cutoff { - // In order to mitigate eclipse attack, for staked nodes - // continue retrying periodically. - let stake = stakes.get(&info.id).unwrap_or(&0); - if *stake == 0 || !rng.gen_ratio(1, 16) { - return None; - } - } - Some(info) - }) - .filter(|info| { - info.id != *self_id - && ContactInfo::is_valid_address(&info.gossip, socket_addr_space) - && self_shred_version == info.shred_version - && gossip_validators.map_or(true, |gossip_validators| { - gossip_validators.contains(&info.id) - }) - }) - .map(|info| { - let last_pushed_to = last_pushed_to.peek(&info.id).copied().unwrap_or_default(); - let since = (now.saturating_sub(last_pushed_to).min(3600 * 1000) / 1024) as u32; - let stake = get_stake(&info.id, stakes); - let weight = get_weight(max_weight, since, stake); - // Weights are bounded by max_weight defined above. - // So this type-cast should be safe. - ((weight * 100.0) as u64, info.clone()) - }) - .collect() - } - - // Only for tests and simulations. - pub(crate) fn mock_clone(&self) -> Self { - let active_set = { - let active_set = self.active_set.read().unwrap(); - active_set - .iter() - .map(|(k, v)| (*k, v.mock_clone())) - .collect() - }; - let last_pushed_to = { - let last_pushed_to = self.last_pushed_to.read().unwrap(); - let mut clone = LruCache::new(last_pushed_to.cap()); - for (k, v) in last_pushed_to.iter().rev() { - clone.put(*k, *v); - } - clone - }; - let received_cache = self.received_cache.lock().unwrap().mock_clone(); - let crds_cursor = *self.crds_cursor.lock().unwrap(); - Self { - active_set: RwLock::new(active_set), - received_cache: Mutex::new(received_cache), - last_pushed_to: RwLock::new(last_pushed_to), - crds_cursor: Mutex::new(crds_cursor), - num_total: AtomicUsize::new(self.num_total.load(Ordering::Relaxed)), - num_old: AtomicUsize::new(self.num_old.load(Ordering::Relaxed)), - num_pushes: AtomicUsize::new(self.num_pushes.load(Ordering::Relaxed)), - ..*self - } - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::{contact_info::ContactInfo, crds_value::CrdsData}, - std::time::Duration, - }; - - fn new_ping_cache() -> PingCache { - PingCache::new( - Duration::from_secs(20 * 60), // ttl - Duration::from_secs(20 * 60) / 64, // rate_limit_delay - 128, // capacity - ) - } - - #[test] - fn test_process_push_one() { - let crds = RwLock::::default(); - let push = CrdsGossipPush::default(); - let value = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( - &solana_sdk::pubkey::new_rand(), - 0, - ))); - let label = value.label(); - // push a new message - assert_eq!( - push.process_push_message(&crds, vec![(Pubkey::default(), vec![value.clone()])], 0), - [label.pubkey()].into_iter().collect(), - ); - assert_eq!(crds.read().unwrap().get::<&CrdsValue>(&label), Some(&value)); - - // push it again - assert!(push - .process_push_message(&crds, vec![(Pubkey::default(), vec![value])], 0) - .is_empty()); - } - #[test] - fn test_process_push_old_version() { - let crds = RwLock::::default(); - let push = CrdsGossipPush::default(); - let mut ci = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); - ci.wallclock = 1; - let value = CrdsValue::new_unsigned(CrdsData::ContactInfo(ci.clone())); - - // push a new message - assert_eq!( - push.process_push_message(&crds, vec![(Pubkey::default(), vec![value])], 0), - [ci.id].into_iter().collect() - ); - - // push an old version - ci.wallclock = 0; - let value = CrdsValue::new_unsigned(CrdsData::ContactInfo(ci)); - assert!(push - .process_push_message(&crds, vec![(Pubkey::default(), vec![value])], 0) - .is_empty()); - } - #[test] - fn test_process_push_timeout() { - let crds = RwLock::::default(); - let push = CrdsGossipPush::default(); - let timeout = push.msg_timeout; - let mut ci = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); - - // push a version to far in the future - ci.wallclock = timeout + 1; - let value = CrdsValue::new_unsigned(CrdsData::ContactInfo(ci.clone())); - assert!(push - .process_push_message(&crds, vec![(Pubkey::default(), vec![value])], 0) - .is_empty()); - - // push a version to far in the past - ci.wallclock = 0; - let value = CrdsValue::new_unsigned(CrdsData::ContactInfo(ci)); - assert!(push - .process_push_message(&crds, vec![(Pubkey::default(), vec![value])], timeout + 1) - .is_empty()); - } - #[test] - fn test_process_push_update() { - let crds = RwLock::::default(); - let push = CrdsGossipPush::default(); - let mut ci = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); - let origin = ci.id; - ci.wallclock = 0; - let value_old = CrdsValue::new_unsigned(CrdsData::ContactInfo(ci.clone())); - - // push a new message - assert_eq!( - push.process_push_message(&crds, vec![(Pubkey::default(), vec![value_old])], 0), - [origin].into_iter().collect() - ); - - // push an old version - ci.wallclock = 1; - let value = CrdsValue::new_unsigned(CrdsData::ContactInfo(ci)); - assert_eq!( - push.process_push_message(&crds, vec![(Pubkey::default(), vec![value])], 0), - [origin].into_iter().collect() - ); - } - #[test] - fn test_compute_need() { - assert_eq!(CrdsGossipPush::compute_need(30, 0, 10), 30); - assert_eq!(CrdsGossipPush::compute_need(30, 1, 10), 29); - assert_eq!(CrdsGossipPush::compute_need(30, 30, 10), 3); - assert_eq!(CrdsGossipPush::compute_need(30, 29, 10), 3); - } - #[test] - fn test_refresh_active_set() { - solana_logger::setup(); - let now = timestamp(); - let mut crds = Crds::default(); - let push = CrdsGossipPush::default(); - let mut ping_cache = new_ping_cache(); - let value1 = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); - ping_cache.mock_pong(value1.id, value1.gossip, Instant::now()); - let value1 = CrdsValue::new_unsigned(CrdsData::ContactInfo(value1)); - - assert_eq!( - crds.insert(value1.clone(), now, GossipRoute::LocalMessage), - Ok(()) - ); - let keypair = Keypair::new(); - let crds = RwLock::new(crds); - let ping_cache = Mutex::new(ping_cache); - push.refresh_push_active_set( - &crds, - &HashMap::new(), // stakes - None, // gossip_validators - &keypair, - 0, // self_shred_version - 1, // network_sizer - 1, // ratio - &ping_cache, - &mut Vec::new(), // pings - &SocketAddrSpace::Unspecified, - ); - - let active_set = push.active_set.read().unwrap(); - assert!(active_set.get(&value1.label().pubkey()).is_some()); - let value2 = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); - ping_cache - .lock() - .unwrap() - .mock_pong(value2.id, value2.gossip, Instant::now()); - let value2 = CrdsValue::new_unsigned(CrdsData::ContactInfo(value2)); - assert!(active_set.get(&value2.label().pubkey()).is_none()); - drop(active_set); - assert_eq!( - crds.write() - .unwrap() - .insert(value2.clone(), now, GossipRoute::LocalMessage), - Ok(()) - ); - for _ in 0..30 { - push.refresh_push_active_set( - &crds, - &HashMap::new(), // stakes - None, // gossip_validators - &keypair, - 0, // self_shred_version - 1, // network_size - 1, // ratio - &ping_cache, - &mut Vec::new(), // pings - &SocketAddrSpace::Unspecified, - ); - let active_set = push.active_set.read().unwrap(); - if active_set.get(&value2.label().pubkey()).is_some() { - break; - } - } - { - let active_set = push.active_set.read().unwrap(); - assert!(active_set.get(&value2.label().pubkey()).is_some()); - } - for _ in 0..push.num_active { - let value2 = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); - ping_cache - .lock() - .unwrap() - .mock_pong(value2.id, value2.gossip, Instant::now()); - let value2 = CrdsValue::new_unsigned(CrdsData::ContactInfo(value2)); - assert_eq!( - crds.write() - .unwrap() - .insert(value2.clone(), now, GossipRoute::LocalMessage), - Ok(()) - ); - } - - push.refresh_push_active_set( - &crds, - &HashMap::new(), // stakes - None, // gossip_validators - &keypair, - 0, // self_shred_version - 1, // network_size - 1, // ratio - &ping_cache, - &mut Vec::new(), // pings - &SocketAddrSpace::Unspecified, - ); - assert_eq!(push.active_set.read().unwrap().len(), push.num_active); - } - #[test] - fn test_active_set_refresh_with_bank() { - solana_logger::setup(); - let time = timestamp() - 1024; //make sure there's at least a 1 second delay - let mut crds = Crds::default(); - let push = CrdsGossipPush::default(); - let mut stakes = HashMap::new(); - for i in 1..=100 { - let peer = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( - &solana_sdk::pubkey::new_rand(), - time, - ))); - let id = peer.label().pubkey(); - crds.insert(peer.clone(), time, GossipRoute::LocalMessage) - .unwrap(); - stakes.insert(id, i * 100); - push.last_pushed_to.write().unwrap().put(id, time); - } - let crds = RwLock::new(crds); - let mut options = push.push_options( - &crds, - &Pubkey::default(), - 0, - &stakes, - None, - &SocketAddrSpace::Unspecified, - ); - assert!(!options.is_empty()); - options.sort_by(|(weight_l, _), (weight_r, _)| weight_r.partial_cmp(weight_l).unwrap()); - // check that the highest stake holder is also the heaviest weighted. - assert_eq!(stakes[&options[0].1.id], 10_000_u64); - } - - #[test] - fn test_no_pushes_to_from_different_shred_versions() { - let now = timestamp(); - let mut crds = Crds::default(); - let stakes = HashMap::new(); - let node = CrdsGossipPush::default(); - - let gossip = socketaddr!("127.0.0.1:1234"); - - let me = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { - id: solana_sdk::pubkey::new_rand(), - shred_version: 123, - gossip, - ..ContactInfo::default() - })); - let spy = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { - id: solana_sdk::pubkey::new_rand(), - shred_version: 0, - gossip, - ..ContactInfo::default() - })); - let node_123 = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { - id: solana_sdk::pubkey::new_rand(), - shred_version: 123, - gossip, - ..ContactInfo::default() - })); - let node_456 = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { - id: solana_sdk::pubkey::new_rand(), - shred_version: 456, - gossip, - ..ContactInfo::default() - })); - - crds.insert(me.clone(), now, GossipRoute::LocalMessage) - .unwrap(); - crds.insert(spy.clone(), now, GossipRoute::LocalMessage) - .unwrap(); - crds.insert(node_123.clone(), now, GossipRoute::LocalMessage) - .unwrap(); - crds.insert(node_456, now, GossipRoute::LocalMessage) - .unwrap(); - let crds = RwLock::new(crds); - - // shred version 123 should ignore nodes with versions 0 and 456 - let options = node - .push_options( - &crds, - &me.label().pubkey(), - 123, - &stakes, - None, - &SocketAddrSpace::Unspecified, - ) - .iter() - .map(|(_, node)| node.id) - .collect::>(); - assert_eq!(options.len(), 1); - assert!(!options.contains(&spy.pubkey())); - assert!(options.contains(&node_123.pubkey())); - - // spy nodes should not push to people on different shred versions - let options = node.push_options( - &crds, - &spy.label().pubkey(), - 0, - &stakes, - None, - &SocketAddrSpace::Unspecified, - ); - assert!(options.is_empty()); - } - - #[test] - fn test_pushes_only_to_allowed() { - let now = timestamp(); - let mut crds = Crds::default(); - let stakes = HashMap::new(); - let node = CrdsGossipPush::default(); - let gossip = socketaddr!("127.0.0.1:1234"); - - let me = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { - id: solana_sdk::pubkey::new_rand(), - gossip, - ..ContactInfo::default() - })); - let node_123 = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo { - id: solana_sdk::pubkey::new_rand(), - gossip, - ..ContactInfo::default() - })); - - crds.insert(me.clone(), 0, GossipRoute::LocalMessage) - .unwrap(); - crds.insert(node_123.clone(), now, GossipRoute::LocalMessage) - .unwrap(); - let crds = RwLock::new(crds); - - // Unknown pubkey in gossip_validators -- will push to nobody - let mut gossip_validators = HashSet::new(); - let options = node.push_options( - &crds, - &me.label().pubkey(), - 0, - &stakes, - Some(&gossip_validators), - &SocketAddrSpace::Unspecified, - ); - - assert!(options.is_empty()); - - // Unknown pubkey in gossip_validators -- will push to nobody - gossip_validators.insert(solana_sdk::pubkey::new_rand()); - let options = node.push_options( - &crds, - &me.label().pubkey(), - 0, - &stakes, - Some(&gossip_validators), - &SocketAddrSpace::Unspecified, - ); - assert!(options.is_empty()); - - // node_123 pubkey in gossip_validators -- will push to it - gossip_validators.insert(node_123.pubkey()); - let options = node.push_options( - &crds, - &me.label().pubkey(), - 0, - &stakes, - Some(&gossip_validators), - &SocketAddrSpace::Unspecified, - ); - - assert_eq!(options.len(), 1); - assert_eq!(options[0].1.id, node_123.pubkey()); - } - - #[test] - fn test_new_push_messages() { - let now = timestamp(); - let mut crds = Crds::default(); - let push = CrdsGossipPush::default(); - let mut ping_cache = new_ping_cache(); - let peer = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); - ping_cache.mock_pong(peer.id, peer.gossip, Instant::now()); - let peer = CrdsValue::new_unsigned(CrdsData::ContactInfo(peer)); - assert_eq!( - crds.insert(peer.clone(), now, GossipRoute::LocalMessage), - Ok(()) - ); - let crds = RwLock::new(crds); - let ping_cache = Mutex::new(ping_cache); - push.refresh_push_active_set( - &crds, - &HashMap::new(), // stakes - None, // gossip_validtors - &Keypair::new(), - 0, // self_shred_version - 1, // network_size - 1, // ratio - &ping_cache, - &mut Vec::new(), // pings - &SocketAddrSpace::Unspecified, - ); - - let new_msg = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( - &solana_sdk::pubkey::new_rand(), - 0, - ))); - let mut expected = HashMap::new(); - expected.insert(peer.label().pubkey(), vec![new_msg.clone()]); - let origin = new_msg.pubkey(); - assert_eq!( - push.process_push_message(&crds, vec![(Pubkey::default(), vec![new_msg])], 0), - [origin].into_iter().collect() - ); - assert_eq!(push.active_set.read().unwrap().len(), 1); - assert_eq!(push.new_push_messages(&crds, 0).0, expected); - } - #[test] - fn test_personalized_push_messages() { - let now = timestamp(); - let mut rng = rand::thread_rng(); - let mut crds = Crds::default(); - let push = CrdsGossipPush::default(); - let mut ping_cache = new_ping_cache(); - let peers: Vec<_> = vec![0, 0, now] - .into_iter() - .map(|wallclock| { - let mut peer = ContactInfo::new_rand(&mut rng, /*pubkey=*/ None); - peer.wallclock = wallclock; - ping_cache.mock_pong(peer.id, peer.gossip, Instant::now()); - CrdsValue::new_unsigned(CrdsData::ContactInfo(peer)) - }) - .collect(); - let origin: Vec<_> = peers.iter().map(|node| node.pubkey()).collect(); - assert_eq!( - crds.insert(peers[0].clone(), now, GossipRoute::LocalMessage), - Ok(()) - ); - assert_eq!( - crds.insert(peers[1].clone(), now, GossipRoute::LocalMessage), - Ok(()) - ); - let crds = RwLock::new(crds); - assert_eq!( - push.process_push_message( - &crds, - vec![(Pubkey::default(), vec![peers[2].clone()])], - now - ), - [origin[2]].into_iter().collect() - ); - let ping_cache = Mutex::new(ping_cache); - push.refresh_push_active_set( - &crds, - &HashMap::new(), // stakes - None, // gossip_validators - &Keypair::new(), - 0, // self_shred_version - 1, // network_size - 1, // ratio - &ping_cache, - &mut Vec::new(), - &SocketAddrSpace::Unspecified, - ); - - // push 3's contact info to 1 and 2 and 3 - let expected: HashMap<_, _> = vec![ - (peers[0].pubkey(), vec![peers[2].clone()]), - (peers[1].pubkey(), vec![peers[2].clone()]), - ] - .into_iter() - .collect(); - assert_eq!(push.active_set.read().unwrap().len(), 3); - assert_eq!(push.new_push_messages(&crds, now).0, expected); - } - #[test] - fn test_process_prune() { - let mut crds = Crds::default(); - let self_id = solana_sdk::pubkey::new_rand(); - let push = CrdsGossipPush::default(); - let peer = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( - &solana_sdk::pubkey::new_rand(), - 0, - ))); - assert_eq!( - crds.insert(peer.clone(), 0, GossipRoute::LocalMessage), - Ok(()) - ); - let crds = RwLock::new(crds); - let ping_cache = Mutex::new(new_ping_cache()); - push.refresh_push_active_set( - &crds, - &HashMap::new(), // stakes - None, // gossip_validators - &Keypair::new(), - 0, // self_shred_version - 1, // network_size - 1, // ratio - &ping_cache, - &mut Vec::new(), // pings - &SocketAddrSpace::Unspecified, - ); - - let new_msg = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( - &solana_sdk::pubkey::new_rand(), - 0, - ))); - let expected = HashMap::new(); - let origin = new_msg.pubkey(); - assert_eq!( - push.process_push_message(&crds, vec![(Pubkey::default(), vec![new_msg.clone()])], 0), - [origin].into_iter().collect() - ); - push.process_prune_msg( - &self_id, - &peer.label().pubkey(), - &[new_msg.label().pubkey()], - ); - assert_eq!(push.new_push_messages(&crds, 0).0, expected); - } - #[test] - fn test_purge_old_pending_push_messages() { - let mut crds = Crds::default(); - let push = CrdsGossipPush::default(); - let peer = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( - &solana_sdk::pubkey::new_rand(), - 0, - ))); - assert_eq!(crds.insert(peer, 0, GossipRoute::LocalMessage), Ok(())); - let crds = RwLock::new(crds); - let ping_cache = Mutex::new(new_ping_cache()); - push.refresh_push_active_set( - &crds, - &HashMap::new(), // stakes - None, // gossip_validators - &Keypair::new(), - 0, // self_shred_version - 1, // network_size - 1, // ratio - &ping_cache, - &mut Vec::new(), // pings - &SocketAddrSpace::Unspecified, - ); - - let mut ci = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); - ci.wallclock = 1; - let new_msg = CrdsValue::new_unsigned(CrdsData::ContactInfo(ci)); - let expected = HashMap::new(); - let origin = new_msg.pubkey(); - assert_eq!( - push.process_push_message(&crds, vec![(Pubkey::default(), vec![new_msg])], 1), - [origin].into_iter().collect() - ); - assert_eq!(push.new_push_messages(&crds, 0).0, expected); - } - - #[test] - fn test_purge_old_received_cache() { - let crds = RwLock::::default(); - let push = CrdsGossipPush::default(); - let mut ci = ContactInfo::new_localhost(&solana_sdk::pubkey::new_rand(), 0); - ci.wallclock = 0; - let value = CrdsValue::new_unsigned(CrdsData::ContactInfo(ci)); - let label = value.label(); - // push a new message - assert_eq!( - push.process_push_message(&crds, vec![(Pubkey::default(), vec![value.clone()])], 0), - [label.pubkey()].into_iter().collect() - ); - assert_eq!( - crds.write().unwrap().get::<&CrdsValue>(&label), - Some(&value) - ); - - // push it again - assert!(push - .process_push_message(&crds, vec![(Pubkey::default(), vec![value.clone()])], 0) - .is_empty()); - - // push it again - assert!(push - .process_push_message(&crds, vec![(Pubkey::default(), vec![value])], 0) - .is_empty()); - } -} diff --git a/gossip/src/crds_shards.rs b/gossip/src/crds_shards.rs deleted file mode 100644 index 3bf7b12..0000000 --- a/gossip/src/crds_shards.rs +++ /dev/null @@ -1,239 +0,0 @@ -use { - crate::{crds::VersionedCrdsValue, crds_gossip_pull::CrdsFilter}, - indexmap::map::IndexMap, - std::{ - cmp::Ordering, - ops::{Index, IndexMut}, - }, -}; - -#[derive(Clone)] -pub struct CrdsShards { - // shards[k] includes crds values which the first shard_bits of their hash - // value is equal to k. Each shard is a mapping from crds values indices to - // their hash value. - shards: Vec>, - shard_bits: u32, -} - -impl CrdsShards { - pub fn new(shard_bits: u32) -> Self { - CrdsShards { - shards: vec![IndexMap::new(); 1 << shard_bits], - shard_bits, - } - } - - pub fn insert(&mut self, index: usize, value: &VersionedCrdsValue) -> bool { - let hash = CrdsFilter::hash_as_u64(&value.value_hash); - self.shard_mut(hash).insert(index, hash).is_none() - } - - pub fn remove(&mut self, index: usize, value: &VersionedCrdsValue) -> bool { - let hash = CrdsFilter::hash_as_u64(&value.value_hash); - self.shard_mut(hash).swap_remove(&index).is_some() - } - - /// Returns indices of all crds values which the first 'mask_bits' of their - /// hash value is equal to 'mask'. - pub fn find(&self, mask: u64, mask_bits: u32) -> impl Iterator + '_ { - let ones = (!0u64).checked_shr(mask_bits).unwrap_or(0); - let mask = mask | ones; - match self.shard_bits.cmp(&mask_bits) { - Ordering::Less => { - let pred = move |(&index, hash)| { - if hash | ones == mask { - Some(index) - } else { - None - } - }; - Iter::Less(self.shard(mask).iter().filter_map(pred)) - } - Ordering::Equal => Iter::Equal(self.shard(mask).keys().cloned()), - Ordering::Greater => { - let count = 1 << (self.shard_bits - mask_bits); - let end = self.shard_index(mask) + 1; - Iter::Greater( - self.shards[end - count..end] - .iter() - .flat_map(IndexMap::keys) - .cloned(), - ) - } - } - } - - #[inline] - fn shard_index(&self, hash: u64) -> usize { - hash.checked_shr(64 - self.shard_bits).unwrap_or(0) as usize - } - - #[inline] - fn shard(&self, hash: u64) -> &IndexMap { - let shard_index = self.shard_index(hash); - self.shards.index(shard_index) - } - - #[inline] - fn shard_mut(&mut self, hash: u64) -> &mut IndexMap { - let shard_index = self.shard_index(hash); - self.shards.index_mut(shard_index) - } - - // Checks invariants in the shards tables against the crds table. - #[cfg(test)] - pub fn check(&self, crds: &[VersionedCrdsValue]) { - let mut indices: Vec<_> = self - .shards - .iter() - .flat_map(IndexMap::keys) - .cloned() - .collect(); - indices.sort_unstable(); - assert_eq!(indices, (0..crds.len()).collect::>()); - for (shard_index, shard) in self.shards.iter().enumerate() { - for (&index, &hash) in shard { - assert_eq!(hash, CrdsFilter::hash_as_u64(&crds[index].value_hash)); - assert_eq!( - shard_index as u64, - hash.checked_shr(64 - self.shard_bits).unwrap_or(0) - ); - } - } - } -} - -// Wrapper for 3 types of iterators we get when comparing shard_bits and -// mask_bits in find method. This is to avoid Box> -// which involves dynamic dispatch and is relatively slow. -enum Iter { - Less(R), - Equal(S), - Greater(T), -} - -impl Iterator for Iter -where - R: Iterator, - S: Iterator, - T: Iterator, -{ - type Item = usize; - - fn next(&mut self) -> Option { - match self { - Self::Greater(iter) => iter.next(), - Self::Less(iter) => iter.next(), - Self::Equal(iter) => iter.next(), - } - } -} - -#[cfg(test)] -mod test { - use { - super::*, - crate::{ - crds::{Crds, GossipRoute}, - crds_value::CrdsValue, - }, - rand::{thread_rng, Rng}, - solana_sdk::timing::timestamp, - std::{collections::HashSet, iter::repeat_with, ops::Index}, - }; - - fn new_test_crds_value(rng: &mut R) -> VersionedCrdsValue { - let value = CrdsValue::new_rand(rng, None); - let label = value.label(); - let mut crds = Crds::default(); - crds.insert(value, timestamp(), GossipRoute::LocalMessage) - .unwrap(); - crds.get::<&VersionedCrdsValue>(&label).cloned().unwrap() - } - - // Returns true if the first mask_bits most significant bits of hash is the - // same as the given bit mask. - fn check_mask(value: &VersionedCrdsValue, mask: u64, mask_bits: u32) -> bool { - let hash = CrdsFilter::hash_as_u64(&value.value_hash); - let ones = (!0u64).checked_shr(mask_bits).unwrap_or(0u64); - (hash | ones) == (mask | ones) - } - - // Manual filtering by scanning all the values. - fn filter_crds_values( - values: &[VersionedCrdsValue], - mask: u64, - mask_bits: u32, - ) -> HashSet { - values - .iter() - .enumerate() - .filter_map(|(index, value)| { - if check_mask(value, mask, mask_bits) { - Some(index) - } else { - None - } - }) - .collect() - } - - #[test] - fn test_crds_shards_round_trip() { - let mut rng = thread_rng(); - // Generate some random hash and crds value labels. - let mut values: Vec<_> = repeat_with(|| new_test_crds_value(&mut rng)) - .take(4096) - .collect(); - // Insert everything into the crds shards. - let mut shards = CrdsShards::new(5); - for (index, value) in values.iter().enumerate() { - assert!(shards.insert(index, value)); - } - shards.check(&values); - // Remove some of the values. - for _ in 0..512 { - let index = rng.gen_range(0, values.len()); - let value = values.swap_remove(index); - assert!(shards.remove(index, &value)); - if index < values.len() { - let value = values.index(index); - assert!(shards.remove(values.len(), value)); - assert!(shards.insert(index, value)); - } - shards.check(&values); - } - // Random masks. - for _ in 0..10 { - let mask = rng.gen(); - for mask_bits in 0..12 { - let mut set = filter_crds_values(&values, mask, mask_bits); - for index in shards.find(mask, mask_bits) { - assert!(set.remove(&index)); - } - assert!(set.is_empty()); - } - } - // Existing hash values. - for (index, value) in values.iter().enumerate() { - let mask = CrdsFilter::hash_as_u64(&value.value_hash); - let hits: Vec<_> = shards.find(mask, 64).collect(); - assert_eq!(hits, vec![index]); - } - // Remove everything. - while !values.is_empty() { - let index = rng.gen_range(0, values.len()); - let value = values.swap_remove(index); - assert!(shards.remove(index, &value)); - if index < values.len() { - let value = values.index(index); - assert!(shards.remove(values.len(), value)); - assert!(shards.insert(index, value)); - } - if index % 5 == 0 { - shards.check(&values); - } - } - } -} diff --git a/gossip/src/crds_value.rs b/gossip/src/crds_value.rs deleted file mode 100644 index 7125457..0000000 --- a/gossip/src/crds_value.rs +++ /dev/null @@ -1,1060 +0,0 @@ -use { - crate::{ - cluster_info::MAX_SNAPSHOT_HASHES, - contact_info::ContactInfo, - deprecated, - duplicate_shred::{DuplicateShred, DuplicateShredIndex, MAX_DUPLICATE_SHREDS}, - epoch_slots::EpochSlots, - }, - bincode::{serialize, serialized_size}, - rand::{CryptoRng, Rng}, - serde::de::{Deserialize, Deserializer}, - solana_runtime::vote_parser, - solana_sdk::{ - clock::Slot, - hash::Hash, - pubkey::{self, Pubkey}, - sanitize::{Sanitize, SanitizeError}, - signature::{Keypair, Signable, Signature, Signer}, - timing::timestamp, - transaction::Transaction, - }, - std::{ - borrow::{Borrow, Cow}, - cmp::Ordering, - collections::{hash_map::Entry, BTreeSet, HashMap}, - fmt, - }, -}; - -pub const MAX_WALLCLOCK: u64 = 1_000_000_000_000_000; -pub const MAX_SLOT: u64 = 1_000_000_000_000_000; - -pub type VoteIndex = u8; -// TODO: Remove this in favor of vote_state::MAX_LOCKOUT_HISTORY once -// the fleet is updated to the new ClusterInfo::push_vote code. -pub const MAX_VOTES: VoteIndex = 32; - -pub type EpochSlotsIndex = u8; -pub const MAX_EPOCH_SLOTS: EpochSlotsIndex = 255; - -/// CrdsValue that is replicated across the cluster -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct CrdsValue { - pub signature: Signature, - pub data: CrdsData, -} - -impl Sanitize for CrdsValue { - fn sanitize(&self) -> Result<(), SanitizeError> { - self.signature.sanitize()?; - self.data.sanitize() - } -} - -impl Signable for CrdsValue { - fn pubkey(&self) -> Pubkey { - self.pubkey() - } - - fn signable_data(&self) -> Cow<[u8]> { - Cow::Owned(serialize(&self.data).expect("failed to serialize CrdsData")) - } - - fn get_signature(&self) -> Signature { - self.signature - } - - fn set_signature(&mut self, signature: Signature) { - self.signature = signature - } - - fn verify(&self) -> bool { - self.get_signature() - .verify(self.pubkey().as_ref(), self.signable_data().borrow()) - } -} - -/// CrdsData that defines the different types of items CrdsValues can hold -/// * Merge Strategy - Latest wallclock is picked -/// * LowestSlot index is deprecated -#[allow(clippy::large_enum_variant)] -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub enum CrdsData { - ContactInfo(ContactInfo), - // Vote(VoteIndex, Vote), - // LowestSlot(/*DEPRECATED:*/ u8, LowestSlot), - // SnapshotHashes(SnapshotHashes), - // AccountsHashes(SnapshotHashes), - EpochSlots(EpochSlotsIndex, EpochSlots), - // LegacyVersion(LegacyVersion), - Version(Version), - NodeInstance(NodeInstance), - // DuplicateShred(DuplicateShredIndex, DuplicateShred), - // IncrementalSnapshotHashes(IncrementalSnapshotHashes), -} - -impl Sanitize for CrdsData { - fn sanitize(&self) -> Result<(), SanitizeError> { - match self { - CrdsData::ContactInfo(val) => val.sanitize(), - // CrdsData::Vote(ix, val) => { - // if *ix >= MAX_VOTES { - // return Err(SanitizeError::ValueOutOfBounds); - // } - // val.sanitize() - // } - // CrdsData::LowestSlot(ix, val) => { - // if *ix as usize >= 1 { - // return Err(SanitizeError::ValueOutOfBounds); - // } - // val.sanitize() - // } - // CrdsData::SnapshotHashes(val) => val.sanitize(), - // CrdsData::AccountsHashes(val) => val.sanitize(), - CrdsData::EpochSlots(ix, val) => { - if *ix as usize >= MAX_EPOCH_SLOTS as usize { - return Err(SanitizeError::ValueOutOfBounds); - } - val.sanitize() - } - // CrdsData::LegacyVersion(version) => version.sanitize(), - CrdsData::Version(version) => version.sanitize(), - CrdsData::NodeInstance(node) => node.sanitize(), - // CrdsData::DuplicateShred(ix, shred) => { - // if *ix >= MAX_DUPLICATE_SHREDS { - // Err(SanitizeError::ValueOutOfBounds) - // } else { - // shred.sanitize() - // } - // } - // CrdsData::IncrementalSnapshotHashes(val) => val.sanitize(), - } - } -} - -/// Random timestamp for tests and benchmarks. -pub(crate) fn new_rand_timestamp(rng: &mut R) -> u64 { - const DELAY: u64 = 10 * 60 * 1000; // 10 minutes - timestamp() - DELAY + rng.gen_range(0, 2 * DELAY) -} - -impl CrdsData { - /// New random CrdsData for tests and benchmarks. - fn new_rand(rng: &mut R, pubkey: Option) -> CrdsData { - let kind = rng.gen_range(0, 7); - // TODO: Implement other kinds of CrdsData here. - // TODO: Assign ranges to each arm proportional to their frequency in - // the mainnet crds table. - match kind { - 0 => CrdsData::ContactInfo(ContactInfo::new_rand(rng, pubkey)), - // 1 => CrdsData::LowestSlot(rng.gen(), LowestSlot::new_rand(rng, pubkey)), - // 2 => CrdsData::SnapshotHashes(SnapshotHashes::new_rand(rng, pubkey)), - // 3 => CrdsData::AccountsHashes(SnapshotHashes::new_rand(rng, pubkey)), - // 4 => CrdsData::Version(Version::new_rand(rng, pubkey)), - // 5 => CrdsData::Vote(rng.gen_range(0, MAX_VOTES), Vote::new_rand(rng, pubkey)), - _ => CrdsData::EpochSlots( - rng.gen_range(0, MAX_EPOCH_SLOTS), - EpochSlots::new_rand(rng, pubkey), - ), - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct SnapshotHashes { - pub from: Pubkey, - pub hashes: Vec<(Slot, Hash)>, - pub wallclock: u64, -} - -impl Sanitize for SnapshotHashes { - fn sanitize(&self) -> Result<(), SanitizeError> { - sanitize_wallclock(self.wallclock)?; - for (slot, _) in &self.hashes { - if *slot >= MAX_SLOT { - return Err(SanitizeError::ValueOutOfBounds); - } - } - self.from.sanitize() - } -} - -impl SnapshotHashes { - pub fn new(from: Pubkey, hashes: Vec<(Slot, Hash)>) -> Self { - Self { - from, - hashes, - wallclock: timestamp(), - } - } - - /// New random SnapshotHashes for tests and benchmarks. - pub(crate) fn new_rand(rng: &mut R, pubkey: Option) -> Self { - let num_hashes = rng.gen_range(0, MAX_SNAPSHOT_HASHES) + 1; - let hashes = std::iter::repeat_with(|| { - let slot = 47825632 + rng.gen_range(0, 512); - let hash = solana_sdk::hash::new_rand(rng); - (slot, hash) - }) - .take(num_hashes) - .collect(); - Self { - from: pubkey.unwrap_or_else(pubkey::new_rand), - hashes, - wallclock: new_rand_timestamp(rng), - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct IncrementalSnapshotHashes { - pub from: Pubkey, - pub base: (Slot, Hash), - pub hashes: Vec<(Slot, Hash)>, - pub wallclock: u64, -} - -impl Sanitize for IncrementalSnapshotHashes { - fn sanitize(&self) -> Result<(), SanitizeError> { - sanitize_wallclock(self.wallclock)?; - if self.base.0 >= MAX_SLOT { - return Err(SanitizeError::ValueOutOfBounds); - } - for (slot, _) in &self.hashes { - if *slot >= MAX_SLOT { - return Err(SanitizeError::ValueOutOfBounds); - } - if self.base.0 >= *slot { - return Err(SanitizeError::InvalidValue); - } - } - self.from.sanitize() - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct LowestSlot { - pub from: Pubkey, - root: Slot, //deprecated - pub lowest: Slot, - slots: BTreeSet, //deprecated - stash: Vec, //deprecated - pub wallclock: u64, -} - -impl LowestSlot { - pub fn new(from: Pubkey, lowest: Slot, wallclock: u64) -> Self { - Self { - from, - root: 0, - lowest, - slots: BTreeSet::new(), - stash: vec![], - wallclock, - } - } - - /// New random LowestSlot for tests and benchmarks. - fn new_rand(rng: &mut R, pubkey: Option) -> Self { - Self { - from: pubkey.unwrap_or_else(pubkey::new_rand), - root: rng.gen(), - lowest: rng.gen(), - slots: BTreeSet::default(), - stash: Vec::default(), - wallclock: new_rand_timestamp(rng), - } - } -} - -impl Sanitize for LowestSlot { - fn sanitize(&self) -> Result<(), SanitizeError> { - sanitize_wallclock(self.wallclock)?; - if self.lowest >= MAX_SLOT { - return Err(SanitizeError::ValueOutOfBounds); - } - if self.root != 0 { - return Err(SanitizeError::InvalidValue); - } - if !self.slots.is_empty() { - return Err(SanitizeError::InvalidValue); - } - if !self.stash.is_empty() { - return Err(SanitizeError::InvalidValue); - } - self.from.sanitize() - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct Vote { - pub(crate) from: Pubkey, - transaction: Transaction, - pub(crate) wallclock: u64, - #[serde(skip_serializing)] - slot: Option, -} - -impl Sanitize for Vote { - fn sanitize(&self) -> Result<(), SanitizeError> { - sanitize_wallclock(self.wallclock)?; - self.from.sanitize()?; - self.transaction.sanitize() - } -} - -impl Vote { - // Returns None if cannot parse transaction into a vote. - pub fn new(from: Pubkey, transaction: Transaction, wallclock: u64) -> Option { - vote_parser::parse_vote_transaction(&transaction).map(|(_, vote, ..)| Self { - from, - transaction, - wallclock, - slot: vote.last_voted_slot(), - }) - } - - /// New random Vote for tests and benchmarks. - fn new_rand(rng: &mut R, pubkey: Option) -> Self { - Self { - from: pubkey.unwrap_or_else(pubkey::new_rand), - transaction: Transaction::default(), - wallclock: new_rand_timestamp(rng), - slot: None, - } - } - - pub(crate) fn transaction(&self) -> &Transaction { - &self.transaction - } - - pub(crate) fn slot(&self) -> Option { - self.slot - } -} - -impl<'de> Deserialize<'de> for Vote { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - struct Vote { - from: Pubkey, - transaction: Transaction, - wallclock: u64, - } - let vote = Vote::deserialize(deserializer)?; - vote.transaction - .sanitize() - .map_err(serde::de::Error::custom)?; - Self::new(vote.from, vote.transaction, vote.wallclock) - .ok_or_else(|| serde::de::Error::custom("invalid vote tx")) - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct LegacyVersion { - pub from: Pubkey, - pub wallclock: u64, - pub version: solana_version::LegacyVersion, -} - -impl Sanitize for LegacyVersion { - fn sanitize(&self) -> Result<(), SanitizeError> { - sanitize_wallclock(self.wallclock)?; - self.from.sanitize()?; - self.version.sanitize() - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct Version { - pub from: Pubkey, - pub wallclock: u64, - pub version: solana_version::Version, -} - -impl Sanitize for Version { - fn sanitize(&self) -> Result<(), SanitizeError> { - sanitize_wallclock(self.wallclock)?; - self.from.sanitize()?; - self.version.sanitize() - } -} - -impl Version { - pub fn new(from: Pubkey) -> Self { - Self { - from, - wallclock: timestamp(), - version: solana_version::Version::default(), - } - } - - /// New random Version for tests and benchmarks. - fn new_rand(rng: &mut R, pubkey: Option) -> Self { - Self { - from: pubkey.unwrap_or_else(pubkey::new_rand), - wallclock: new_rand_timestamp(rng), - version: solana_version::Version { - major: rng.gen(), - minor: rng.gen(), - patch: rng.gen(), - commit: Some(rng.gen()), - feature_set: rng.gen(), - }, - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct NodeInstance { - from: Pubkey, - wallclock: u64, - timestamp: u64, // Timestamp when the instance was created. - token: u64, // Randomly generated value at node instantiation. -} - -impl NodeInstance { - pub fn new(rng: &mut R, from: Pubkey, now: u64) -> Self - where - R: Rng + CryptoRng, - { - Self { - from, - wallclock: now, - timestamp: now, - token: rng.gen(), - } - } - - // Clones the value with an updated wallclock. - pub(crate) fn with_wallclock(&self, wallclock: u64) -> Self { - Self { wallclock, ..*self } - } - - // Returns true if the crds-value is a duplicate instance - // of this node, with a more recent timestamp. - pub(crate) fn check_duplicate(&self, other: &CrdsValue) -> bool { - match &other.data { - CrdsData::NodeInstance(other) => { - self.token != other.token - && self.timestamp <= other.timestamp - && self.from == other.from - } - _ => false, - } - } - - // Returns None if tokens are the same or other is not a node-instance from - // the same owner. Otherwise returns true if self has more recent timestamp - // than other, and so overrides it. - pub(crate) fn overrides(&self, other: &CrdsValue) -> Option { - let other = match &other.data { - CrdsData::NodeInstance(other) => other, - _ => return None, - }; - if self.token == other.token || self.from != other.from { - return None; - } - match self.timestamp.cmp(&other.timestamp) { - Ordering::Less => Some(false), - Ordering::Greater => Some(true), - // Ties should be broken in a deterministic way across the cluster, - // so that nodes propagate the same value through gossip. - Ordering::Equal => Some(other.token < self.token), - } - } -} - -impl Sanitize for NodeInstance { - fn sanitize(&self) -> Result<(), SanitizeError> { - sanitize_wallclock(self.wallclock)?; - self.from.sanitize() - } -} - -/// Type of the replicated value -/// These are labels for values in a record that is associated with `Pubkey` -#[derive(PartialEq, Hash, Eq, Clone, Debug)] -pub enum CrdsValueLabel { - ContactInfo(Pubkey), - // Vote(VoteIndex, Pubkey), - // LowestSlot(Pubkey), - // SnapshotHashes(Pubkey), - EpochSlots(EpochSlotsIndex, Pubkey), - // AccountsHashes(Pubkey), - // LegacyVersion(Pubkey), - Version(Pubkey), - NodeInstance(Pubkey), - // DuplicateShred(DuplicateShredIndex, Pubkey), - // IncrementalSnapshotHashes(Pubkey), -} - -impl fmt::Display for CrdsValueLabel { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - CrdsValueLabel::ContactInfo(_) => write!(f, "ContactInfo({})", self.pubkey()), - // CrdsValueLabel::Vote(ix, _) => write!(f, "Vote({}, {})", ix, self.pubkey()), - // CrdsValueLabel::LowestSlot(_) => write!(f, "LowestSlot({})", self.pubkey()), - // CrdsValueLabel::SnapshotHashes(_) => write!(f, "SnapshotHashes({})", self.pubkey()), - CrdsValueLabel::EpochSlots(ix, _) => write!(f, "EpochSlots({}, {})", ix, self.pubkey()), - // CrdsValueLabel::AccountsHashes(_) => write!(f, "AccountsHashes({})", self.pubkey()), - // CrdsValueLabel::LegacyVersion(_) => write!(f, "LegacyVersion({})", self.pubkey()), - CrdsValueLabel::Version(_) => write!(f, "Version({})", self.pubkey()), - CrdsValueLabel::NodeInstance(pk) => write!(f, "NodeInstance({pk})"), - // CrdsValueLabel::DuplicateShred(ix, pk) => write!(f, "DuplicateShred({ix}, {pk})"), - // CrdsValueLabel::IncrementalSnapshotHashes(_) => { - // write!(f, "IncrementalSnapshotHashes({})", self.pubkey()) - // } - } - } -} - -impl CrdsValueLabel { - pub fn pubkey(&self) -> Pubkey { - match self { - CrdsValueLabel::ContactInfo(p) => *p, - // CrdsValueLabel::Vote(_, p) => *p, - // CrdsValueLabel::LowestSlot(p) => *p, - // CrdsValueLabel::SnapshotHashes(p) => *p, - CrdsValueLabel::EpochSlots(_, p) => *p, - // CrdsValueLabel::AccountsHashes(p) => *p, - // CrdsValueLabel::LegacyVersion(p) => *p, - CrdsValueLabel::Version(p) => *p, - CrdsValueLabel::NodeInstance(p) => *p, - // CrdsValueLabel::DuplicateShred(_, p) => *p, - // CrdsValueLabel::IncrementalSnapshotHashes(p) => *p, - } - } -} - -impl CrdsValue { - pub fn new_unsigned(data: CrdsData) -> Self { - Self { - signature: Signature::default(), - data, - } - } - - pub fn new_signed(data: CrdsData, keypair: &Keypair) -> Self { - let mut value = Self::new_unsigned(data); - value.sign(keypair); - value - } - - /// New random CrdsValue for tests and benchmarks. - pub fn new_rand(rng: &mut R, keypair: Option<&Keypair>) -> CrdsValue { - match keypair { - None => { - let keypair = Keypair::new(); - let data = CrdsData::new_rand(rng, Some(keypair.pubkey())); - Self::new_signed(data, &keypair) - } - Some(keypair) => { - let data = CrdsData::new_rand(rng, Some(keypair.pubkey())); - Self::new_signed(data, keypair) - } - } - } - - /// Totally unsecure unverifiable wallclock of the node that generated this message - /// Latest wallclock is always picked. - /// This is used to time out push messages. - pub fn wallclock(&self) -> u64 { - match &self.data { - CrdsData::ContactInfo(contact_info) => contact_info.wallclock, - // CrdsData::Vote(_, vote) => vote.wallclock, - // CrdsData::LowestSlot(_, obj) => obj.wallclock, - // CrdsData::SnapshotHashes(hash) => hash.wallclock, - // CrdsData::AccountsHashes(hash) => hash.wallclock, - CrdsData::EpochSlots(_, p) => p.wallclock, - // CrdsData::LegacyVersion(version) => version.wallclock, - CrdsData::Version(version) => version.wallclock, - CrdsData::NodeInstance(node) => node.wallclock, - // CrdsData::DuplicateShred(_, shred) => shred.wallclock, - // CrdsData::IncrementalSnapshotHashes(hash) => hash.wallclock, - } - } - pub fn pubkey(&self) -> Pubkey { - match &self.data { - CrdsData::ContactInfo(contact_info) => contact_info.id, - // CrdsData::Vote(_, vote) => vote.from, - // CrdsData::LowestSlot(_, slots) => slots.from, - // CrdsData::SnapshotHashes(hash) => hash.from, - // CrdsData::AccountsHashes(hash) => hash.from, - CrdsData::EpochSlots(_, p) => p.from, - // CrdsData::LegacyVersion(version) => version.from, - CrdsData::Version(version) => version.from, - CrdsData::NodeInstance(node) => node.from, - // CrdsData::DuplicateShred(_, shred) => shred.from, - // CrdsData::IncrementalSnapshotHashes(hash) => hash.from, - } - } - pub fn label(&self) -> CrdsValueLabel { - match &self.data { - CrdsData::ContactInfo(_) => CrdsValueLabel::ContactInfo(self.pubkey()), - // CrdsData::Vote(ix, _) => CrdsValueLabel::Vote(*ix, self.pubkey()), - // CrdsData::LowestSlot(_, _) => CrdsValueLabel::LowestSlot(self.pubkey()), - // CrdsData::SnapshotHashes(_) => CrdsValueLabel::SnapshotHashes(self.pubkey()), - // CrdsData::AccountsHashes(_) => CrdsValueLabel::AccountsHashes(self.pubkey()), - CrdsData::EpochSlots(ix, _) => CrdsValueLabel::EpochSlots(*ix, self.pubkey()), - // CrdsData::LegacyVersion(_) => CrdsValueLabel::LegacyVersion(self.pubkey()), - CrdsData::Version(_) => CrdsValueLabel::Version(self.pubkey()), - CrdsData::NodeInstance(node) => CrdsValueLabel::NodeInstance(node.from), - // CrdsData::DuplicateShred(ix, shred) => CrdsValueLabel::DuplicateShred(*ix, shred.from), - // CrdsData::IncrementalSnapshotHashes(_) => { - // CrdsValueLabel::IncrementalSnapshotHashes(self.pubkey()) - // } - } - } - pub fn contact_info(&self) -> Option<&ContactInfo> { - match &self.data { - CrdsData::ContactInfo(contact_info) => Some(contact_info), - _ => None, - } - } - - // pub(crate) fn accounts_hash(&self) -> Option<&SnapshotHashes> { - // match &self.data { - // CrdsData::AccountsHashes(slots) => Some(slots), - // _ => None, - // } - // } - - pub(crate) fn epoch_slots(&self) -> Option<&EpochSlots> { - match &self.data { - CrdsData::EpochSlots(_, slots) => Some(slots), - _ => None, - } - } - - /// Returns the size (in bytes) of a CrdsValue - pub fn size(&self) -> u64 { - serialized_size(&self).expect("unable to serialize contact info") - } - - /// Returns true if, regardless of prunes, this crds-value - /// should be pushed to the receiving node. - pub(crate) fn should_force_push(&self, peer: &Pubkey) -> bool { - match &self.data { - CrdsData::NodeInstance(node) => node.from == *peer, - _ => false, - } - } -} - -/// Filters out an iterator of crds values, returning -/// the unique ones with the most recent wallclock. -pub(crate) fn filter_current<'a, I>(values: I) -> impl Iterator -where - I: IntoIterator, -{ - let mut out = HashMap::new(); - for value in values { - match out.entry(value.label()) { - Entry::Vacant(entry) => { - entry.insert((value, value.wallclock())); - } - Entry::Occupied(mut entry) => { - let value_wallclock = value.wallclock(); - let (_, entry_wallclock) = entry.get(); - if *entry_wallclock < value_wallclock { - entry.insert((value, value_wallclock)); - } - } - } - } - out.into_iter().map(|(_, (v, _))| v) -} - -pub(crate) fn sanitize_wallclock(wallclock: u64) -> Result<(), SanitizeError> { - if wallclock >= MAX_WALLCLOCK { - Err(SanitizeError::ValueOutOfBounds) - } else { - Ok(()) - } -} - -// #[cfg(test)] -// mod test { -// use { -// super::*, -// crate::contact_info::ContactInfo, -// bincode::{deserialize, Options}, -// rand::SeedableRng, -// rand_chacha::ChaChaRng, -// solana_perf::test_tx::new_test_vote_tx, -// solana_sdk::{ -// signature::{Keypair, Signer}, -// timing::timestamp, -// }, -// solana_vote_program::{vote_instruction, vote_state}, -// std::{cmp::Ordering, iter::repeat_with}, -// }; - -// #[test] -// fn test_keys_and_values() { -// let mut rng = rand::thread_rng(); -// let v = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default())); -// assert_eq!(v.wallclock(), 0); -// let key = v.contact_info().unwrap().id; -// assert_eq!(v.label(), CrdsValueLabel::ContactInfo(key)); - -// let v = Vote::new(Pubkey::default(), new_test_vote_tx(&mut rng), 0).unwrap(); -// let v = CrdsValue::new_unsigned(CrdsData::Vote(0, v)); -// assert_eq!(v.wallclock(), 0); -// let key = match &v.data { -// CrdsData::Vote(_, vote) => vote.from, -// _ => panic!(), -// }; -// assert_eq!(v.label(), CrdsValueLabel::Vote(0, key)); - -// let v = CrdsValue::new_unsigned(CrdsData::LowestSlot( -// 0, -// LowestSlot::new(Pubkey::default(), 0, 0), -// )); -// assert_eq!(v.wallclock(), 0); -// let key = match &v.data { -// CrdsData::LowestSlot(_, data) => data.from, -// _ => panic!(), -// }; -// assert_eq!(v.label(), CrdsValueLabel::LowestSlot(key)); -// } - -// #[test] -// fn test_lowest_slot_sanitize() { -// let ls = LowestSlot::new(Pubkey::default(), 0, 0); -// let v = CrdsValue::new_unsigned(CrdsData::LowestSlot(0, ls.clone())); -// assert_eq!(v.sanitize(), Ok(())); - -// let mut o = ls.clone(); -// o.root = 1; -// let v = CrdsValue::new_unsigned(CrdsData::LowestSlot(0, o)); -// assert_eq!(v.sanitize(), Err(SanitizeError::InvalidValue)); - -// let o = ls.clone(); -// let v = CrdsValue::new_unsigned(CrdsData::LowestSlot(1, o)); -// assert_eq!(v.sanitize(), Err(SanitizeError::ValueOutOfBounds)); - -// let mut o = ls.clone(); -// o.slots.insert(1); -// let v = CrdsValue::new_unsigned(CrdsData::LowestSlot(0, o)); -// assert_eq!(v.sanitize(), Err(SanitizeError::InvalidValue)); - -// let mut o = ls; -// o.stash.push(deprecated::EpochIncompleteSlots::default()); -// let v = CrdsValue::new_unsigned(CrdsData::LowestSlot(0, o)); -// assert_eq!(v.sanitize(), Err(SanitizeError::InvalidValue)); -// } - -// #[test] -// fn test_signature() { -// let mut rng = rand::thread_rng(); -// let keypair = Keypair::new(); -// let wrong_keypair = Keypair::new(); -// let mut v = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost( -// &keypair.pubkey(), -// timestamp(), -// ))); -// verify_signatures(&mut v, &keypair, &wrong_keypair); -// let v = Vote::new(keypair.pubkey(), new_test_vote_tx(&mut rng), timestamp()).unwrap(); -// let mut v = CrdsValue::new_unsigned(CrdsData::Vote(0, v)); -// verify_signatures(&mut v, &keypair, &wrong_keypair); -// v = CrdsValue::new_unsigned(CrdsData::LowestSlot( -// 0, -// LowestSlot::new(keypair.pubkey(), 0, timestamp()), -// )); -// verify_signatures(&mut v, &keypair, &wrong_keypair); -// } - -// #[test] -// fn test_max_vote_index() { -// let mut rng = rand::thread_rng(); -// let keypair = Keypair::new(); -// let vote = Vote::new(keypair.pubkey(), new_test_vote_tx(&mut rng), timestamp()).unwrap(); -// let vote = CrdsValue::new_signed(CrdsData::Vote(MAX_VOTES, vote), &keypair); -// assert!(vote.sanitize().is_err()); -// } - -// #[test] -// fn test_vote_round_trip() { -// let mut rng = rand::thread_rng(); -// let vote = vote_state::Vote::new( -// vec![1, 3, 7], // slots -// solana_sdk::hash::new_rand(&mut rng), -// ); -// let ix = vote_instruction::vote( -// &Pubkey::new_unique(), // vote_pubkey -// &Pubkey::new_unique(), // authorized_voter_pubkey -// vote, -// ); -// let tx = Transaction::new_with_payer( -// &[ix], // instructions -// Some(&Pubkey::new_unique()), // payer -// ); -// let vote = Vote::new( -// Pubkey::new_unique(), // from -// tx, -// rng.gen(), // wallclock -// ) -// .unwrap(); -// assert_eq!(vote.slot, Some(7)); -// let bytes = bincode::serialize(&vote).unwrap(); -// let other = bincode::deserialize(&bytes[..]).unwrap(); -// assert_eq!(vote, other); -// assert_eq!(other.slot, Some(7)); -// let bytes = bincode::options().serialize(&vote).unwrap(); -// let other = bincode::options().deserialize(&bytes[..]).unwrap(); -// assert_eq!(vote, other); -// assert_eq!(other.slot, Some(7)); -// } - -// #[test] -// fn test_max_epoch_slots_index() { -// let keypair = Keypair::new(); -// let item = CrdsValue::new_signed( -// CrdsData::EpochSlots( -// MAX_EPOCH_SLOTS, -// EpochSlots::new(keypair.pubkey(), timestamp()), -// ), -// &keypair, -// ); -// assert_eq!(item.sanitize(), Err(SanitizeError::ValueOutOfBounds)); -// } - -// fn serialize_deserialize_value(value: &mut CrdsValue, keypair: &Keypair) { -// let num_tries = 10; -// value.sign(keypair); -// let original_signature = value.get_signature(); -// for _ in 0..num_tries { -// let serialized_value = serialize(value).unwrap(); -// let deserialized_value: CrdsValue = deserialize(&serialized_value).unwrap(); - -// // Signatures shouldn't change -// let deserialized_signature = deserialized_value.get_signature(); -// assert_eq!(original_signature, deserialized_signature); - -// // After deserializing, check that the signature is still the same -// assert!(deserialized_value.verify()); -// } -// } - -// fn verify_signatures( -// value: &mut CrdsValue, -// correct_keypair: &Keypair, -// wrong_keypair: &Keypair, -// ) { -// assert!(!value.verify()); -// value.sign(correct_keypair); -// assert!(value.verify()); -// value.sign(wrong_keypair); -// assert!(!value.verify()); -// serialize_deserialize_value(value, correct_keypair); -// } - -// #[test] -// fn test_filter_current() { -// let seed = [48u8; 32]; -// let mut rng = ChaChaRng::from_seed(seed); -// let keys: Vec<_> = repeat_with(Keypair::new).take(16).collect(); -// let values: Vec<_> = repeat_with(|| { -// let index = rng.gen_range(0, keys.len()); -// CrdsValue::new_rand(&mut rng, Some(&keys[index])) -// }) -// .take(2048) -// .collect(); -// let mut currents = HashMap::new(); -// for value in filter_current(&values) { -// // Assert that filtered values have unique labels. -// assert!(currents.insert(value.label(), value).is_none()); -// } -// // Assert that currents are the most recent version of each value. -// let mut count = 0; -// for value in &values { -// let current_value = currents.get(&value.label()).unwrap(); -// match value.wallclock().cmp(¤t_value.wallclock()) { -// Ordering::Less => (), -// Ordering::Equal => { -// // There is a chance that two randomly generated -// // crds-values have the same label and wallclock. -// if value == *current_value { -// count += 1; -// } -// } -// Ordering::Greater => panic!("this should not happen!"), -// } -// } -// assert_eq!(count, currents.len()); -// // Currently CrdsData::new_rand is only implemented for 5 different -// // kinds and excludes EpochSlots, and so the unique labels cannot be -// // more than (5 + MAX_VOTES) times number of keys. -// assert!(currents.len() <= keys.len() * (5 + MAX_VOTES as usize)); -// } - -// #[test] -// fn test_node_instance_crds_lable() { -// fn make_crds_value(node: NodeInstance) -> CrdsValue { -// CrdsValue::new_unsigned(CrdsData::NodeInstance(node)) -// } -// let mut rng = rand::thread_rng(); -// let now = timestamp(); -// let pubkey = Pubkey::new_unique(); -// let node = NodeInstance::new(&mut rng, pubkey, now); -// assert_eq!( -// make_crds_value(node.clone()).label(), -// make_crds_value(node.with_wallclock(now + 8)).label() -// ); -// let other = NodeInstance { -// from: Pubkey::new_unique(), -// ..node -// }; -// assert_ne!( -// make_crds_value(node.clone()).label(), -// make_crds_value(other).label() -// ); -// let other = NodeInstance { -// wallclock: now + 8, -// ..node -// }; -// assert_eq!( -// make_crds_value(node.clone()).label(), -// make_crds_value(other).label() -// ); -// let other = NodeInstance { -// timestamp: now + 8, -// ..node -// }; -// assert_eq!( -// make_crds_value(node.clone()).label(), -// make_crds_value(other).label() -// ); -// let other = NodeInstance { -// token: rng.gen(), -// ..node -// }; -// assert_eq!( -// make_crds_value(node).label(), -// make_crds_value(other).label() -// ); -// } - -// #[test] -// fn test_check_duplicate_instance() { -// fn make_crds_value(node: NodeInstance) -> CrdsValue { -// CrdsValue::new_unsigned(CrdsData::NodeInstance(node)) -// } -// let now = timestamp(); -// let mut rng = rand::thread_rng(); -// let pubkey = Pubkey::new_unique(); -// let node = NodeInstance::new(&mut rng, pubkey, now); -// let node_crds = make_crds_value(node.clone()); -// // Same token is not a duplicate. -// let other = NodeInstance { -// from: pubkey, -// wallclock: now + 1, -// timestamp: now + 1, -// token: node.token, -// }; -// let other_crds = make_crds_value(other.clone()); -// assert!(!node.check_duplicate(&other_crds)); -// assert!(!other.check_duplicate(&node_crds)); -// assert_eq!(node.overrides(&other_crds), None); -// assert_eq!(other.overrides(&node_crds), None); -// // Older timestamp is not a duplicate. -// let other = NodeInstance { -// from: pubkey, -// wallclock: now + 1, -// timestamp: now - 1, -// token: rng.gen(), -// }; -// let other_crds = make_crds_value(other.clone()); -// assert!(!node.check_duplicate(&other_crds)); -// assert!(other.check_duplicate(&node_crds)); -// assert_eq!(node.overrides(&other_crds), Some(true)); -// assert_eq!(other.overrides(&node_crds), Some(false)); -// // Updated wallclock is not a duplicate. -// let other = node.with_wallclock(now + 8); -// assert_eq!( -// other, -// NodeInstance { -// from: pubkey, -// wallclock: now + 8, -// timestamp: now, -// token: node.token, -// } -// ); -// let other_crds = make_crds_value(other.clone()); -// assert!(!node.check_duplicate(&other_crds)); -// assert!(!other.check_duplicate(&node_crds)); -// assert_eq!(node.overrides(&other_crds), None); -// assert_eq!(other.overrides(&node_crds), None); -// // Duplicate instance; tied timestamp. -// for _ in 0..10 { -// let other = NodeInstance { -// from: pubkey, -// wallclock: 0, -// timestamp: now, -// token: rng.gen(), -// }; -// let other_crds = make_crds_value(other.clone()); -// assert!(node.check_duplicate(&other_crds)); -// assert!(other.check_duplicate(&node_crds)); -// assert_eq!(node.overrides(&other_crds), Some(other.token < node.token)); -// assert_eq!(other.overrides(&node_crds), Some(node.token < other.token)); -// } -// // Duplicate instance; more recent timestamp. -// for _ in 0..10 { -// let other = NodeInstance { -// from: pubkey, -// wallclock: 0, -// timestamp: now + 1, -// token: rng.gen(), -// }; -// let other_crds = make_crds_value(other.clone()); -// assert!(node.check_duplicate(&other_crds)); -// assert!(!other.check_duplicate(&node_crds)); -// assert_eq!(node.overrides(&other_crds), Some(false)); -// assert_eq!(other.overrides(&node_crds), Some(true)); -// } -// // Different pubkey is not a duplicate. -// let other = NodeInstance { -// from: Pubkey::new_unique(), -// wallclock: now + 1, -// timestamp: now + 1, -// token: rng.gen(), -// }; -// let other_crds = make_crds_value(other.clone()); -// assert!(!node.check_duplicate(&other_crds)); -// assert!(!other.check_duplicate(&node_crds)); -// assert_eq!(node.overrides(&other_crds), None); -// assert_eq!(other.overrides(&node_crds), None); -// // Differnt crds value is not a duplicate. -// let other = ContactInfo::new_rand(&mut rng, Some(pubkey)); -// let other = CrdsValue::new_unsigned(CrdsData::ContactInfo(other)); -// assert!(!node.check_duplicate(&other)); -// assert_eq!(node.overrides(&other), None); -// } - -// #[test] -// fn test_should_force_push() { -// let mut rng = rand::thread_rng(); -// let pubkey = Pubkey::new_unique(); -// assert!( -// !CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_rand( -// &mut rng, -// Some(pubkey), -// ))) -// .should_force_push(&pubkey) -// ); -// let node = CrdsValue::new_unsigned(CrdsData::NodeInstance(NodeInstance::new( -// &mut rng, -// pubkey, -// timestamp(), -// ))); -// assert!(node.should_force_push(&pubkey)); -// assert!(!node.should_force_push(&Pubkey::new_unique())); -// } -// } diff --git a/gossip/src/deprecated.rs b/gossip/src/deprecated.rs deleted file mode 100644 index 8997db4..0000000 --- a/gossip/src/deprecated.rs +++ /dev/null @@ -1,21 +0,0 @@ -use solana_sdk::clock::Slot; - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -enum CompressionType { - Uncompressed, - GZip, - BZip2, -} - -impl Default for CompressionType { - fn default() -> Self { - Self::Uncompressed - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)] -pub(crate) struct EpochIncompleteSlots { - first: Slot, - compression: CompressionType, - compressed_list: Vec, -} diff --git a/gossip/src/duplicate_shred.rs b/gossip/src/duplicate_shred.rs deleted file mode 100644 index 4cd85c0..0000000 --- a/gossip/src/duplicate_shred.rs +++ /dev/null @@ -1,383 +0,0 @@ -use { - crate::crds_value::sanitize_wallclock, - itertools::Itertools, - solana_ledger::{ - blockstore_meta::DuplicateSlotProof, - shred::{self, Shred, ShredType}, - }, - solana_sdk::{ - clock::Slot, - pubkey::Pubkey, - sanitize::{Sanitize, SanitizeError}, - }, - std::{ - collections::{hash_map::Entry, HashMap}, - convert::TryFrom, - num::TryFromIntError, - }, - thiserror::Error, -}; - -const DUPLICATE_SHRED_HEADER_SIZE: usize = 63; - -pub(crate) type DuplicateShredIndex = u16; -pub(crate) const MAX_DUPLICATE_SHREDS: DuplicateShredIndex = 512; - -/// Function returning leader at a given slot. -pub trait LeaderScheduleFn: FnOnce(Slot) -> Option {} -impl LeaderScheduleFn for F where F: FnOnce(Slot) -> Option {} - -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct DuplicateShred { - pub(crate) from: Pubkey, - pub(crate) wallclock: u64, - pub(crate) slot: Slot, - shred_index: u32, - shred_type: ShredType, - // Serialized DuplicateSlotProof split into chunks. - num_chunks: u8, - chunk_index: u8, - #[serde(with = "serde_bytes")] - chunk: Vec, -} - -#[derive(Debug, Error)] -pub enum Error { - #[error("data chunk mismatch")] - DataChunkMismatch, - #[error("invalid chunk index")] - InvalidChunkIndex, - #[error("invalid duplicate shreds")] - InvalidDuplicateShreds, - #[error("invalid duplicate slot proof")] - InvalidDuplicateSlotProof, - #[error("invalid signature")] - InvalidSignature, - #[error("invalid size limit")] - InvalidSizeLimit, - #[error(transparent)] - InvalidShred(#[from] shred::Error), - #[error("number of chunks mismatch")] - NumChunksMismatch, - #[error("missing data chunk")] - MissingDataChunk, - #[error("(de)serialization error")] - SerializationError(#[from] bincode::Error), - #[error("shred index mismatch")] - ShredIndexMismatch, - #[error("shred type mismatch")] - ShredTypeMismatch, - #[error("slot mismatch")] - SlotMismatch, - #[error("type conversion error")] - TryFromIntError(#[from] TryFromIntError), - #[error("unknown slot leader")] - UnknownSlotLeader, -} - -// Asserts that the two shreds can indicate duplicate proof for -// the same triplet of (slot, shred-index, and shred-type_), and -// that they have valid signatures from the slot leader. -fn check_shreds( - leader_schedule: Option, - shred1: &Shred, - shred2: &Shred, -) -> Result<(), Error> { - if shred1.slot() != shred2.slot() { - Err(Error::SlotMismatch) - } else if shred1.index() != shred2.index() { - // TODO: Should also allow two coding shreds with different indices but - // same fec-set-index and mismatching erasure-config. - Err(Error::ShredIndexMismatch) - } else if shred1.shred_type() != shred2.shred_type() { - Err(Error::ShredTypeMismatch) - } else if shred1.payload() == shred2.payload() { - Err(Error::InvalidDuplicateShreds) - } else { - if let Some(leader_schedule) = leader_schedule { - let slot_leader = leader_schedule(shred1.slot()).ok_or(Error::UnknownSlotLeader)?; - if !shred1.verify(&slot_leader) || !shred2.verify(&slot_leader) { - return Err(Error::InvalidSignature); - } - } - Ok(()) - } -} - -/// Splits a DuplicateSlotProof into DuplicateShred -/// chunks with a size limit on each chunk. -pub fn from_duplicate_slot_proof( - proof: &DuplicateSlotProof, - self_pubkey: Pubkey, // Pubkey of my node broadcasting crds value. - leader_schedule: Option, - wallclock: u64, - max_size: usize, // Maximum serialized size of each DuplicateShred. -) -> Result, Error> { - if proof.shred1 == proof.shred2 { - return Err(Error::InvalidDuplicateSlotProof); - } - let shred1 = Shred::new_from_serialized_shred(proof.shred1.clone())?; - let shred2 = Shred::new_from_serialized_shred(proof.shred2.clone())?; - check_shreds(leader_schedule, &shred1, &shred2)?; - let (slot, shred_index, shred_type) = (shred1.slot(), shred1.index(), shred1.shred_type()); - let data = bincode::serialize(proof)?; - let chunk_size = if DUPLICATE_SHRED_HEADER_SIZE < max_size { - max_size - DUPLICATE_SHRED_HEADER_SIZE - } else { - return Err(Error::InvalidSizeLimit); - }; - let chunks: Vec<_> = data.chunks(chunk_size).map(Vec::from).collect(); - let num_chunks = u8::try_from(chunks.len())?; - let chunks = chunks - .into_iter() - .enumerate() - .map(move |(i, chunk)| DuplicateShred { - from: self_pubkey, - wallclock, - slot, - shred_index, - shred_type, - num_chunks, - chunk_index: i as u8, - chunk, - }); - Ok(chunks) -} - -pub(crate) fn from_shred( - shred: Shred, - self_pubkey: Pubkey, // Pubkey of my node broadcasting crds value. - other_payload: Vec, - leader_schedule: Option, - wallclock: u64, - max_size: usize, // Maximum serialized size of each DuplicateShred. -) -> Result, Error> { - if shred.payload() == &other_payload { - return Err(Error::InvalidDuplicateShreds); - } - let other_shred = Shred::new_from_serialized_shred(other_payload.clone())?; - check_shreds(leader_schedule, &shred, &other_shred)?; - let (slot, shred_index, shred_type) = (shred.slot(), shred.index(), shred.shred_type()); - let proof = DuplicateSlotProof { - shred1: shred.into_payload(), - shred2: other_payload, - }; - let data = bincode::serialize(&proof)?; - let chunk_size = if DUPLICATE_SHRED_HEADER_SIZE < max_size { - max_size - DUPLICATE_SHRED_HEADER_SIZE - } else { - return Err(Error::InvalidSizeLimit); - }; - let chunks: Vec<_> = data.chunks(chunk_size).map(Vec::from).collect(); - let num_chunks = u8::try_from(chunks.len())?; - let chunks = chunks - .into_iter() - .enumerate() - .map(move |(i, chunk)| DuplicateShred { - from: self_pubkey, - wallclock, - slot, - shred_index, - shred_type, - num_chunks, - chunk_index: i as u8, - chunk, - }); - Ok(chunks) -} - -// Returns a predicate checking if a duplicate-shred chunk matches -// (slot, shred_index, shred_type) and has valid chunk_index. -fn check_chunk( - slot: Slot, - shred_index: u32, - shred_type: ShredType, - num_chunks: u8, -) -> impl Fn(&DuplicateShred) -> Result<(), Error> { - move |dup| { - if dup.slot != slot { - Err(Error::SlotMismatch) - } else if dup.shred_index != shred_index { - Err(Error::ShredIndexMismatch) - } else if dup.shred_type != shred_type { - Err(Error::ShredTypeMismatch) - } else if dup.num_chunks != num_chunks { - Err(Error::NumChunksMismatch) - } else if dup.chunk_index >= num_chunks { - Err(Error::InvalidChunkIndex) - } else { - Ok(()) - } - } -} - -/// Reconstructs the duplicate shreds from chunks of DuplicateShred. -pub fn into_shreds( - chunks: impl IntoIterator, - leader: impl LeaderScheduleFn, -) -> Result<(Shred, Shred), Error> { - let mut chunks = chunks.into_iter(); - let DuplicateShred { - slot, - shred_index, - shred_type, - num_chunks, - chunk_index, - chunk, - .. - } = chunks.next().ok_or(Error::InvalidDuplicateShreds)?; - let slot_leader = leader(slot).ok_or(Error::UnknownSlotLeader)?; - let check_chunk = check_chunk(slot, shred_index, shred_type, num_chunks); - let mut data = HashMap::new(); - data.insert(chunk_index, chunk); - for chunk in chunks { - check_chunk(&chunk)?; - match data.entry(chunk.chunk_index) { - Entry::Vacant(entry) => { - entry.insert(chunk.chunk); - } - Entry::Occupied(entry) => { - if *entry.get() != chunk.chunk { - return Err(Error::DataChunkMismatch); - } - } - } - } - if data.len() != num_chunks as usize { - return Err(Error::MissingDataChunk); - } - let data = (0..num_chunks).map(|k| data.remove(&k).unwrap()).concat(); - let proof: DuplicateSlotProof = bincode::deserialize(&data)?; - if proof.shred1 == proof.shred2 { - return Err(Error::InvalidDuplicateSlotProof); - } - let shred1 = Shred::new_from_serialized_shred(proof.shred1)?; - let shred2 = Shred::new_from_serialized_shred(proof.shred2)?; - if shred1.slot() != slot || shred2.slot() != slot { - Err(Error::SlotMismatch) - } else if shred1.index() != shred_index || shred2.index() != shred_index { - Err(Error::ShredIndexMismatch) - } else if shred1.shred_type() != shred_type || shred2.shred_type() != shred_type { - Err(Error::ShredTypeMismatch) - } else if shred1.payload() == shred2.payload() { - Err(Error::InvalidDuplicateShreds) - } else if !shred1.verify(&slot_leader) || !shred2.verify(&slot_leader) { - Err(Error::InvalidSignature) - } else { - Ok((shred1, shred2)) - } -} - -impl Sanitize for DuplicateShred { - fn sanitize(&self) -> Result<(), SanitizeError> { - sanitize_wallclock(self.wallclock)?; - if self.chunk_index >= self.num_chunks { - return Err(SanitizeError::IndexOutOfBounds); - } - self.from.sanitize() - } -} - -#[cfg(test)] -pub(crate) mod tests { - use { - super::*, - rand::Rng, - solana_entry::entry::Entry, - solana_ledger::shred::{ProcessShredsStats, ReedSolomonCache, Shredder}, - solana_sdk::{ - hash, - signature::{Keypair, Signer}, - system_transaction, - }, - std::sync::Arc, - }; - - #[test] - fn test_duplicate_shred_header_size() { - let dup = DuplicateShred { - from: Pubkey::new_unique(), - wallclock: u64::MAX, - slot: Slot::MAX, - shred_index: u32::MAX, - shred_type: ShredType::Data, - num_chunks: u8::MAX, - chunk_index: u8::MAX, - chunk: Vec::default(), - }; - assert_eq!( - bincode::serialize(&dup).unwrap().len(), - DUPLICATE_SHRED_HEADER_SIZE - ); - assert_eq!( - bincode::serialized_size(&dup).unwrap(), - DUPLICATE_SHRED_HEADER_SIZE as u64 - ); - } - - pub fn new_rand_shred( - rng: &mut R, - next_shred_index: u32, - shredder: &Shredder, - keypair: &Keypair, - ) -> Shred { - let entries: Vec<_> = std::iter::repeat_with(|| { - let tx = system_transaction::transfer( - &Keypair::new(), // from - &Pubkey::new_unique(), // to - rng.gen(), // lamports - hash::new_rand(rng), // recent blockhash - ); - Entry::new( - &hash::new_rand(rng), // prev_hash - 1, // num_hashes, - vec![tx], // transactions - ) - }) - .take(5) - .collect(); - let (mut data_shreds, _coding_shreds) = shredder.entries_to_shreds( - keypair, - &entries, - true, // is_last_in_slot - next_shred_index, - next_shred_index, // next_code_index - true, // merkle_variant - &ReedSolomonCache::default(), - &mut ProcessShredsStats::default(), - ); - data_shreds.swap_remove(0) - } - - #[test] - fn test_duplicate_shred_round_trip() { - let mut rng = rand::thread_rng(); - let leader = Arc::new(Keypair::new()); - let (slot, parent_slot, reference_tick, version) = (53084024, 53084023, 0, 0); - let shredder = Shredder::new(slot, parent_slot, reference_tick, version).unwrap(); - let next_shred_index = rng.gen_range(0, 32_000); - let shred1 = new_rand_shred(&mut rng, next_shred_index, &shredder, &leader); - let shred2 = new_rand_shred(&mut rng, next_shred_index, &shredder, &leader); - let leader_schedule = |s| { - if s == slot { - Some(leader.pubkey()) - } else { - None - } - }; - let chunks: Vec<_> = from_shred( - shred1.clone(), - Pubkey::new_unique(), // self_pubkey - shred2.payload().clone(), - Some(leader_schedule), - rng.gen(), // wallclock - 512, // max_size - ) - .unwrap() - .collect(); - assert!(chunks.len() > 4); - let (shred3, shred4) = into_shreds(chunks, leader_schedule).unwrap(); - assert_eq!(shred1, shred3); - assert_eq!(shred2, shred4); - } -} diff --git a/gossip/src/epoch_slots.rs b/gossip/src/epoch_slots.rs deleted file mode 100644 index 919c51a..0000000 --- a/gossip/src/epoch_slots.rs +++ /dev/null @@ -1,554 +0,0 @@ -use { - crate::{ - cluster_info::MAX_CRDS_OBJECT_SIZE, - crds_value::{self, MAX_SLOT, MAX_WALLCLOCK}, - }, - bincode::serialized_size, - bv::BitVec, - flate2::{Compress, Compression, Decompress, FlushCompress, FlushDecompress}, - solana_sdk::{ - clock::Slot, - pubkey::Pubkey, - sanitize::{Sanitize, SanitizeError}, - }, -}; - -const MAX_SLOTS_PER_ENTRY: usize = 2048 * 8; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct Uncompressed { - pub first_slot: Slot, - pub num: usize, - pub slots: BitVec, -} - -impl Sanitize for Uncompressed { - fn sanitize(&self) -> std::result::Result<(), SanitizeError> { - if self.first_slot >= MAX_SLOT { - return Err(SanitizeError::ValueOutOfBounds); - } - if self.num >= MAX_SLOTS_PER_ENTRY { - return Err(SanitizeError::ValueOutOfBounds); - } - if self.slots.len() % 8 != 0 { - // Uncompressed::new() ensures the length is always a multiple of 8 - return Err(SanitizeError::ValueOutOfBounds); - } - if self.slots.len() != self.slots.capacity() { - // A BitVec with a length that's a multiple of 8 will always have len() equal to - // capacity(), assuming no bit manipulation - return Err(SanitizeError::ValueOutOfBounds); - } - Ok(()) - } -} - -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)] -pub struct Flate2 { - pub first_slot: Slot, - pub num: usize, - pub compressed: Vec, -} - -impl Sanitize for Flate2 { - fn sanitize(&self) -> std::result::Result<(), SanitizeError> { - if self.first_slot >= MAX_SLOT { - return Err(SanitizeError::ValueOutOfBounds); - } - if self.num >= MAX_SLOTS_PER_ENTRY { - return Err(SanitizeError::ValueOutOfBounds); - } - Ok(()) - } -} - -#[derive(Debug, PartialEq, Eq)] -pub enum Error { - CompressError, - DecompressError, -} - -pub type Result = std::result::Result; - -impl std::convert::From for Error { - fn from(_e: flate2::CompressError) -> Error { - Error::CompressError - } -} -impl std::convert::From for Error { - fn from(_e: flate2::DecompressError) -> Error { - Error::DecompressError - } -} - -impl Flate2 { - fn deflate(mut unc: Uncompressed) -> Result { - let mut compressed = Vec::with_capacity(unc.slots.block_capacity()); - let mut compressor = Compress::new(Compression::best(), false); - let first_slot = unc.first_slot; - let num = unc.num; - unc.slots.shrink_to_fit(); - let bits = unc.slots.into_boxed_slice(); - compressor.compress_vec(&bits, &mut compressed, FlushCompress::Finish)?; - let rv = Self { - first_slot, - num, - compressed, - }; - let _ = rv.inflate()?; - Ok(rv) - } - pub fn inflate(&self) -> Result { - //add some head room for the decompressor which might spill more bits - let mut uncompressed = Vec::with_capacity(32 + (self.num + 4) / 8); - let mut decompress = Decompress::new(false); - decompress.decompress_vec(&self.compressed, &mut uncompressed, FlushDecompress::Finish)?; - Ok(Uncompressed { - first_slot: self.first_slot, - num: self.num, - slots: BitVec::from_bits(&uncompressed), - }) - } -} - -impl Uncompressed { - pub fn new(max_size: usize) -> Self { - Self { - num: 0, - first_slot: 0, - slots: BitVec::new_fill(false, 8 * max_size as u64), - } - } - pub fn to_slots(&self, min_slot: Slot) -> Vec { - let mut rv = vec![]; - let start = if min_slot < self.first_slot { - 0 - } else { - (min_slot - self.first_slot) as usize - }; - for i in start..self.num { - if i >= self.slots.len() as usize { - break; - } - if self.slots.get(i as u64) { - rv.push(self.first_slot + i as Slot); - } - } - rv - } - pub fn add(&mut self, slots: &[Slot]) -> usize { - for (i, s) in slots.iter().enumerate() { - if self.num == 0 { - self.first_slot = *s; - } - if self.num >= MAX_SLOTS_PER_ENTRY { - return i; - } - if *s < self.first_slot { - return i; - } - if *s - self.first_slot >= self.slots.len() { - return i; - } - self.slots.set(*s - self.first_slot, true); - self.num = std::cmp::max(self.num, 1 + (*s - self.first_slot) as usize); - } - slots.len() - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub enum CompressedSlots { - Flate2(Flate2), - Uncompressed(Uncompressed), -} - -impl Sanitize for CompressedSlots { - fn sanitize(&self) -> std::result::Result<(), SanitizeError> { - match self { - CompressedSlots::Uncompressed(a) => a.sanitize(), - CompressedSlots::Flate2(b) => b.sanitize(), - } - } -} - -impl Default for CompressedSlots { - fn default() -> Self { - CompressedSlots::new(0) - } -} - -impl CompressedSlots { - fn new(max_size: usize) -> Self { - CompressedSlots::Uncompressed(Uncompressed::new(max_size)) - } - - pub fn first_slot(&self) -> Slot { - match self { - CompressedSlots::Uncompressed(a) => a.first_slot, - CompressedSlots::Flate2(b) => b.first_slot, - } - } - - pub fn num_slots(&self) -> usize { - match self { - CompressedSlots::Uncompressed(a) => a.num, - CompressedSlots::Flate2(b) => b.num, - } - } - - pub fn add(&mut self, slots: &[Slot]) -> usize { - match self { - CompressedSlots::Uncompressed(vals) => vals.add(slots), - CompressedSlots::Flate2(_) => 0, - } - } - pub fn to_slots(&self, min_slot: Slot) -> Result> { - match self { - CompressedSlots::Uncompressed(vals) => Ok(vals.to_slots(min_slot)), - CompressedSlots::Flate2(vals) => { - let unc = vals.inflate()?; - Ok(unc.to_slots(min_slot)) - } - } - } - pub fn deflate(&mut self) -> Result<()> { - match self { - CompressedSlots::Uncompressed(vals) => { - let unc = vals.clone(); - let compressed = Flate2::deflate(unc)?; - *self = CompressedSlots::Flate2(compressed); - Ok(()) - } - CompressedSlots::Flate2(_) => Ok(()), - } - } -} - -#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq)] -pub struct EpochSlots { - pub from: Pubkey, - pub slots: Vec, - pub wallclock: u64, -} - -impl Sanitize for EpochSlots { - fn sanitize(&self) -> std::result::Result<(), SanitizeError> { - if self.wallclock >= MAX_WALLCLOCK { - return Err(SanitizeError::ValueOutOfBounds); - } - self.from.sanitize()?; - self.slots.sanitize() - } -} - -use std::fmt; -impl fmt::Debug for EpochSlots { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let num_slots: usize = self.slots.iter().map(|s| s.num_slots()).sum(); - let lowest_slot = self - .slots - .iter() - .map(|s| s.first_slot()) - .fold(0, std::cmp::min); - write!( - f, - "EpochSlots {{ from: {} num_slots: {} lowest_slot: {} wallclock: {} }}", - self.from, num_slots, lowest_slot, self.wallclock - ) - } -} - -impl EpochSlots { - pub fn new(from: Pubkey, now: u64) -> Self { - Self { - from, - wallclock: now, - slots: vec![], - } - } - pub fn fill(&mut self, slots: &[Slot], now: u64) -> usize { - let mut num = 0; - self.wallclock = std::cmp::max(now, self.wallclock + 1); - while num < slots.len() { - num += self.add(&slots[num..]); - if num < slots.len() { - if self.deflate().is_err() { - return num; - } - let space = self.max_compressed_slot_size(); - if space > 0 { - let cslot = CompressedSlots::new(space as usize); - self.slots.push(cslot); - } else { - return num; - } - } - } - num - } - pub fn add(&mut self, slots: &[Slot]) -> usize { - let mut num = 0; - for s in &mut self.slots { - num += s.add(&slots[num..]); - if num >= slots.len() { - break; - } - } - num - } - pub fn deflate(&mut self) -> Result<()> { - for s in self.slots.iter_mut() { - s.deflate()?; - } - Ok(()) - } - pub fn max_compressed_slot_size(&self) -> isize { - let len_header = serialized_size(self).unwrap(); - let len_slot = serialized_size(&CompressedSlots::default()).unwrap(); - MAX_CRDS_OBJECT_SIZE as isize - (len_header + len_slot) as isize - } - - pub fn first_slot(&self) -> Option { - self.slots.iter().map(|s| s.first_slot()).min() - } - - pub fn to_slots(&self, min_slot: Slot) -> Vec { - self.slots - .iter() - .filter(|s| min_slot < s.first_slot() + s.num_slots() as u64) - .filter_map(|s| s.to_slots(min_slot).ok()) - .flatten() - .collect() - } - - /// New random EpochSlots for tests and simulations. - pub(crate) fn new_rand(rng: &mut R, pubkey: Option) -> Self { - let now = crds_value::new_rand_timestamp(rng); - let pubkey = pubkey.unwrap_or_else(solana_sdk::pubkey::new_rand); - let mut epoch_slots = Self::new(pubkey, now); - let num_slots = rng.gen_range(0, 20); - let slots: Vec<_> = std::iter::repeat_with(|| 47825632 + rng.gen_range(0, 512)) - .take(num_slots) - .collect(); - epoch_slots.add(&slots); - epoch_slots - } -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_epoch_slots_max_size() { - let epoch_slots = EpochSlots::default(); - assert!(epoch_slots.max_compressed_slot_size() > 0); - } - - #[test] - fn test_epoch_slots_uncompressed_add_1() { - let mut slots = Uncompressed::new(1); - assert_eq!(slots.slots.capacity(), 8); - assert_eq!(slots.add(&[1]), 1); - assert_eq!(slots.to_slots(1), vec![1]); - assert!(slots.to_slots(2).is_empty()); - } - - #[test] - fn test_epoch_slots_to_slots_overflow() { - let mut slots = Uncompressed::new(1); - slots.num = 100; - assert!(slots.to_slots(0).is_empty()); - } - - #[test] - fn test_epoch_slots_uncompressed_add_2() { - let mut slots = Uncompressed::new(1); - assert_eq!(slots.add(&[1, 2]), 2); - assert_eq!(slots.to_slots(1), vec![1, 2]); - } - #[test] - fn test_epoch_slots_uncompressed_add_3a() { - let mut slots = Uncompressed::new(1); - assert_eq!(slots.add(&[1, 3, 2]), 3); - assert_eq!(slots.to_slots(1), vec![1, 2, 3]); - } - - #[test] - fn test_epoch_slots_uncompressed_add_3b() { - let mut slots = Uncompressed::new(1); - assert_eq!(slots.add(&[1, 10, 2]), 1); - assert_eq!(slots.to_slots(1), vec![1]); - } - - #[test] - fn test_epoch_slots_uncompressed_add_3c() { - let mut slots = Uncompressed::new(2); - assert_eq!(slots.add(&[1, 10, 2]), 3); - assert_eq!(slots.to_slots(1), vec![1, 2, 10]); - assert_eq!(slots.to_slots(2), vec![2, 10]); - assert_eq!(slots.to_slots(3), vec![10]); - assert!(slots.to_slots(11).is_empty()); - } - #[test] - fn test_epoch_slots_compressed() { - let mut slots = Uncompressed::new(100); - slots.add(&[1, 701, 2]); - assert_eq!(slots.num, 701); - let compressed = Flate2::deflate(slots).unwrap(); - assert_eq!(compressed.first_slot, 1); - assert_eq!(compressed.num, 701); - assert!(compressed.compressed.len() < 32); - let slots = compressed.inflate().unwrap(); - assert_eq!(slots.first_slot, 1); - assert_eq!(slots.num, 701); - assert_eq!(slots.to_slots(1), vec![1, 2, 701]); - } - - #[test] - fn test_epoch_slots_sanitize() { - let mut slots = Uncompressed::new(100); - slots.add(&[1, 701, 2]); - assert_eq!(slots.num, 701); - assert!(slots.sanitize().is_ok()); - - let mut o = slots.clone(); - o.first_slot = MAX_SLOT; - assert_eq!(o.sanitize(), Err(SanitizeError::ValueOutOfBounds)); - - let mut o = slots.clone(); - o.num = MAX_SLOTS_PER_ENTRY; - assert_eq!(o.sanitize(), Err(SanitizeError::ValueOutOfBounds)); - - let mut o = slots.clone(); - o.slots = BitVec::new_fill(false, 7); // Length not a multiple of 8 - assert_eq!(o.sanitize(), Err(SanitizeError::ValueOutOfBounds)); - - let mut o = slots.clone(); - o.slots = BitVec::with_capacity(8); // capacity() not equal to len() - assert_eq!(o.sanitize(), Err(SanitizeError::ValueOutOfBounds)); - - let compressed = Flate2::deflate(slots).unwrap(); - assert!(compressed.sanitize().is_ok()); - - let mut o = compressed.clone(); - o.first_slot = MAX_SLOT; - assert_eq!(o.sanitize(), Err(SanitizeError::ValueOutOfBounds)); - - let mut o = compressed; - o.num = MAX_SLOTS_PER_ENTRY; - assert_eq!(o.sanitize(), Err(SanitizeError::ValueOutOfBounds)); - - let mut slots = EpochSlots::default(); - let range: Vec = (0..5000).collect(); - assert_eq!(slots.fill(&range, 1), 5000); - assert_eq!(slots.wallclock, 1); - assert!(slots.sanitize().is_ok()); - - let mut o = slots; - o.wallclock = MAX_WALLCLOCK; - assert_eq!(o.sanitize(), Err(SanitizeError::ValueOutOfBounds)); - } - - #[test] - fn test_epoch_slots_fill_range() { - let range: Vec = (0..5000).collect(); - let mut slots = EpochSlots::default(); - assert_eq!(slots.fill(&range, 1), 5000); - assert_eq!(slots.wallclock, 1); - assert_eq!(slots.to_slots(0), range); - assert_eq!(slots.to_slots(4999), vec![4999]); - assert!(slots.to_slots(5000).is_empty()); - } - #[test] - fn test_epoch_slots_fill_sparce_range() { - let range: Vec = (0..5000).map(|x| x * 3).collect(); - let mut slots = EpochSlots::default(); - assert_eq!(slots.fill(&range, 2), 5000); - assert_eq!(slots.wallclock, 2); - assert_eq!(slots.slots.len(), 3); - assert_eq!(slots.slots[0].first_slot(), 0); - assert_ne!(slots.slots[0].num_slots(), 0); - let next = slots.slots[0].num_slots() as u64 + slots.slots[0].first_slot(); - assert!(slots.slots[1].first_slot() >= next); - assert_ne!(slots.slots[1].num_slots(), 0); - assert_ne!(slots.slots[2].num_slots(), 0); - assert_eq!(slots.to_slots(0), range); - assert_eq!(slots.to_slots(4999 * 3), vec![4999 * 3]); - } - - #[test] - fn test_epoch_slots_fill_large_sparce_range() { - let range: Vec = (0..5000).map(|x| x * 7).collect(); - let mut slots = EpochSlots::default(); - assert_eq!(slots.fill(&range, 2), 5000); - assert_eq!(slots.to_slots(0), range); - } - - #[test] - #[allow(clippy::same_item_push)] - fn test_epoch_slots_fill_uncompressed_random_range() { - use rand::Rng; - for _ in 0..10 { - let mut range: Vec = vec![]; - for _ in 0..5000 { - let last = *range.last().unwrap_or(&0); - range.push(last + rand::thread_rng().gen_range(1, 5)); - } - let sz = EpochSlots::default().max_compressed_slot_size(); - let mut slots = Uncompressed::new(sz as usize); - let sz = slots.add(&range); - let slots = slots.to_slots(0); - assert_eq!(slots.len(), sz); - assert_eq!(slots[..], range[..sz]); - } - } - - #[test] - #[allow(clippy::same_item_push)] - fn test_epoch_slots_fill_compressed_random_range() { - use rand::Rng; - for _ in 0..10 { - let mut range: Vec = vec![]; - for _ in 0..5000 { - let last = *range.last().unwrap_or(&0); - range.push(last + rand::thread_rng().gen_range(1, 5)); - } - let sz = EpochSlots::default().max_compressed_slot_size(); - let mut slots = Uncompressed::new(sz as usize); - let sz = slots.add(&range); - let mut slots = CompressedSlots::Uncompressed(slots); - slots.deflate().unwrap(); - let slots = slots.to_slots(0).unwrap(); - assert_eq!(slots.len(), sz); - assert_eq!(slots[..], range[..sz]); - } - } - - #[test] - #[allow(clippy::same_item_push)] - fn test_epoch_slots_fill_random_range() { - use rand::Rng; - for _ in 0..10 { - let mut range: Vec = vec![]; - for _ in 0..5000 { - let last = *range.last().unwrap_or(&0); - range.push(last + rand::thread_rng().gen_range(1, 5)); - } - let mut slots = EpochSlots::default(); - let sz = slots.fill(&range, 1); - let last = range[sz - 1]; - assert_eq!( - last, - slots.slots.last().unwrap().first_slot() - + slots.slots.last().unwrap().num_slots() as u64 - - 1 - ); - for s in &slots.slots { - assert!(s.to_slots(0).is_ok()); - } - let slots = slots.to_slots(0); - assert_eq!(slots[..], range[..slots.len()]); - assert_eq!(sz, slots.len()) - } - } -} diff --git a/gossip/src/gossip_error.rs b/gossip/src/gossip_error.rs deleted file mode 100644 index 87db5cc..0000000 --- a/gossip/src/gossip_error.rs +++ /dev/null @@ -1,28 +0,0 @@ -use { - crate::duplicate_shred, - crossbeam_channel::{RecvTimeoutError, SendError}, - std::io, - thiserror::Error, -}; - -#[derive(Error, Debug)] -pub enum GossipError { - #[error("duplicate node instance")] - DuplicateNodeInstance, - #[error(transparent)] - DuplicateShredError(#[from] duplicate_shred::Error), - #[error(transparent)] - Io(#[from] io::Error), - #[error(transparent)] - RecvTimeoutError(#[from] RecvTimeoutError), - #[error("send error")] - SendError, - #[error("serialization error")] - Serialize(#[from] Box), -} - -impl std::convert::From> for GossipError { - fn from(_e: SendError) -> GossipError { - GossipError::SendError - } -} diff --git a/gossip/src/gossip_service.rs b/gossip/src/gossip_service.rs deleted file mode 100644 index d487cf5..0000000 --- a/gossip/src/gossip_service.rs +++ /dev/null @@ -1,438 +0,0 @@ -//! The `gossip_service` module implements the network control plane. - -use { - crate::{cluster_info::ClusterInfo, contact_info::ContactInfo}, - crossbeam_channel::{unbounded, Sender}, - rand::{thread_rng, Rng}, - solana_client::{connection_cache::ConnectionCache, thin_client::ThinClient}, - solana_perf::recycler::Recycler, - solana_runtime::bank_forks::BankForks, - solana_sdk::{ - pubkey::Pubkey, - signature::{Keypair, Signer}, - }, - solana_streamer::{ - socket::SocketAddrSpace, - streamer::{self, StreamerReceiveStats}, - }, - std::{ - collections::HashSet, - net::{SocketAddr, TcpListener, UdpSocket}, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, RwLock, - }, - thread::{self, sleep, JoinHandle}, - time::{Duration, Instant}, - }, -}; - -pub struct GossipService { - thread_hdls: Vec>, -} - -impl GossipService { - pub fn new( - cluster_info: &Arc, - bank_forks: Option>>, - gossip_socket: UdpSocket, - gossip_validators: Option>, - should_check_duplicate_instance: bool, - stats_reporter_sender: Option>>, - exit: &Arc, - ) -> Self { - let (request_sender, request_receiver) = unbounded(); - let gossip_socket = Arc::new(gossip_socket); - trace!( - "GossipService: id: {}, listening on: {:?}", - &cluster_info.id(), - gossip_socket.local_addr().unwrap() - ); - let socket_addr_space = *cluster_info.socket_addr_space(); - let t_receiver = streamer::receiver( - gossip_socket.clone(), - exit.clone(), - request_sender, - Recycler::default(), - Arc::new(StreamerReceiveStats::new("gossip_receiver")), - 1, - false, - None, - ); - let (consume_sender, listen_receiver) = unbounded(); - let t_socket_consume = cluster_info.clone().start_socket_consume_thread( - request_receiver, - consume_sender, - exit.clone(), - ); - let (response_sender, response_receiver) = unbounded(); - let t_listen = cluster_info.clone().listen( - bank_forks.clone(), - listen_receiver, - response_sender.clone(), - should_check_duplicate_instance, - exit.clone(), - ); - let t_gossip = cluster_info.clone().gossip( - bank_forks, - response_sender, - gossip_validators, - exit.clone(), - ); - let t_responder = streamer::responder( - "Gossip", - gossip_socket, - response_receiver, - socket_addr_space, - stats_reporter_sender, - ); - let thread_hdls = vec![ - t_receiver, - t_responder, - t_socket_consume, - t_listen, - t_gossip, - ]; - Self { thread_hdls } - } - - pub fn join(self) -> thread::Result<()> { - for thread_hdl in self.thread_hdls { - thread_hdl.join()?; - } - Ok(()) - } -} - -/// Discover Validators in a cluster -pub fn discover_cluster( - entrypoint: &SocketAddr, - num_nodes: usize, - socket_addr_space: SocketAddrSpace, -) -> std::io::Result> { - const DISCOVER_CLUSTER_TIMEOUT: Duration = Duration::from_secs(120); - let (_all_peers, validators) = discover( - None, // keypair - Some(entrypoint), - Some(num_nodes), - DISCOVER_CLUSTER_TIMEOUT, - None, // find_node_by_pubkey - None, // find_node_by_gossip_addr - None, // my_gossip_addr - 0, // my_shred_version - socket_addr_space, - )?; - Ok(validators) -} - -pub fn discover( - keypair: Option, - entrypoint: Option<&SocketAddr>, - num_nodes: Option, // num_nodes only counts validators, excludes spy nodes - timeout: Duration, - find_node_by_pubkey: Option, - find_node_by_gossip_addr: Option<&SocketAddr>, - my_gossip_addr: Option<&SocketAddr>, - my_shred_version: u16, - socket_addr_space: SocketAddrSpace, -) -> std::io::Result<( - Vec, // all gossip peers - Vec, // tvu peers (validators) -)> { - let keypair = keypair.unwrap_or_else(Keypair::new); - let exit = Arc::new(AtomicBool::new(false)); - let (gossip_service, ip_echo, spy_ref) = make_gossip_node( - keypair, - entrypoint, - &exit, - my_gossip_addr, - my_shred_version, - true, // should_check_duplicate_instance, - socket_addr_space, - ); - - let id = spy_ref.id(); - info!("Entrypoint: {:?}", entrypoint); - info!("Node Id: {:?}", id); - if let Some(my_gossip_addr) = my_gossip_addr { - info!("Gossip Address: {:?}", my_gossip_addr); - } - let _ip_echo_server = ip_echo - .map(|tcp_listener| solana_net_utils::ip_echo_server(tcp_listener, Some(my_shred_version))); - let (met_criteria, elapsed, all_peers, tvu_peers) = spy( - spy_ref.clone(), - num_nodes, - timeout, - find_node_by_pubkey, - find_node_by_gossip_addr, - ); - - exit.store(true, Ordering::Relaxed); - gossip_service.join().unwrap(); - - if met_criteria { - info!( - "discover success in {}s...\n{}", - elapsed.as_secs(), - spy_ref.contact_info_trace() - ); - return Ok((all_peers, tvu_peers)); - } - - if !tvu_peers.is_empty() { - info!( - "discover failed to match criteria by timeout...\n{}", - spy_ref.contact_info_trace() - ); - return Ok((all_peers, tvu_peers)); - } - - info!("discover failed...\n{}", spy_ref.contact_info_trace()); - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Discover failed", - )) -} - -/// Creates a ThinClient by selecting a valid node at random -pub fn get_client( - nodes: &[ContactInfo], - socket_addr_space: &SocketAddrSpace, - connection_cache: Arc, -) -> ThinClient { - let nodes: Vec<_> = nodes - .iter() - .filter_map(|node| ContactInfo::valid_client_facing_addr(node, socket_addr_space)) - .collect(); - let select = thread_rng().gen_range(0, nodes.len()); - let (rpc, tpu) = nodes[select]; - ThinClient::new(rpc, tpu, connection_cache) -} - -pub fn get_multi_client( - nodes: &[ContactInfo], - socket_addr_space: &SocketAddrSpace, - connection_cache: Arc, -) -> (ThinClient, usize) { - let addrs: Vec<_> = nodes - .iter() - .filter_map(|node| ContactInfo::valid_client_facing_addr(node, socket_addr_space)) - .collect(); - let rpc_addrs: Vec<_> = addrs.iter().map(|addr| addr.0).collect(); - let tpu_addrs: Vec<_> = addrs.iter().map(|addr| addr.1).collect(); - - let num_nodes = tpu_addrs.len(); - ( - ThinClient::new_from_addrs(rpc_addrs, tpu_addrs, connection_cache), - num_nodes, - ) -} - -fn spy( - spy_ref: Arc, - num_nodes: Option, - timeout: Duration, - find_node_by_pubkey: Option, - find_node_by_gossip_addr: Option<&SocketAddr>, -) -> ( - bool, // if found the specified nodes - Duration, // elapsed time until found the nodes or timed-out - Vec, // all gossip peers - Vec, // tvu peers (validators) -) { - let now = Instant::now(); - let mut met_criteria = false; - let mut all_peers: Vec = Vec::new(); - let mut tvu_peers: Vec = Vec::new(); - let mut i = 1; - while !met_criteria && now.elapsed() < timeout { - all_peers = spy_ref - .all_peers() - .into_iter() - .map(|x| x.0) - .collect::>(); - tvu_peers = spy_ref.all_tvu_peers(); - - let found_node_by_pubkey = if let Some(pubkey) = find_node_by_pubkey { - all_peers.iter().any(|x| x.id == pubkey) - } else { - false - }; - - let found_node_by_gossip_addr = if let Some(gossip_addr) = find_node_by_gossip_addr { - all_peers.iter().any(|x| x.gossip == *gossip_addr) - } else { - false - }; - - if let Some(num) = num_nodes { - // Only consider validators and archives for `num_nodes` - let mut nodes: Vec<_> = tvu_peers.iter().collect(); - nodes.sort(); - nodes.dedup(); - - if nodes.len() >= num { - if found_node_by_pubkey || found_node_by_gossip_addr { - met_criteria = true; - } - - if find_node_by_pubkey.is_none() && find_node_by_gossip_addr.is_none() { - met_criteria = true; - } - } - } else if found_node_by_pubkey || found_node_by_gossip_addr { - met_criteria = true; - } - if i % 20 == 0 { - info!("discovering...\n{}", spy_ref.contact_info_trace()); - } - sleep(Duration::from_millis( - crate::cluster_info::GOSSIP_SLEEP_MILLIS, - )); - i += 1; - } - (met_criteria, now.elapsed(), all_peers, tvu_peers) -} - -/// Makes a spy or gossip node based on whether or not a gossip_addr was passed in -/// Pass in a gossip addr to fully participate in gossip instead of relying on just pulls -pub fn make_gossip_node( - keypair: Keypair, - entrypoint: Option<&SocketAddr>, - exit: &Arc, - gossip_addr: Option<&SocketAddr>, - shred_version: u16, - should_check_duplicate_instance: bool, - socket_addr_space: SocketAddrSpace, -) -> (GossipService, Option, Arc) { - let (node, gossip_socket, ip_echo) = if let Some(gossip_addr) = gossip_addr { - ClusterInfo::gossip_node(keypair.pubkey(), gossip_addr, shred_version) - } else { - ClusterInfo::spy_node(keypair.pubkey(), shred_version) - }; - let cluster_info = ClusterInfo::new(node, Arc::new(keypair), socket_addr_space); - if let Some(entrypoint) = entrypoint { - cluster_info.set_entrypoint(ContactInfo::new_gossip_entry_point(entrypoint)); - } - let cluster_info = Arc::new(cluster_info); - let gossip_service = GossipService::new( - &cluster_info, - None, - gossip_socket, - None, - should_check_duplicate_instance, - None, - exit, - ); - (gossip_service, ip_echo, cluster_info) -} - -#[cfg(test)] -mod tests { - use { - super::*, - crate::cluster_info::{ClusterInfo, Node}, - std::sync::{atomic::AtomicBool, Arc}, - }; - - #[test] - #[ignore] - // test that stage will exit when flag is set - fn test_exit() { - let exit = Arc::new(AtomicBool::new(false)); - let tn = Node::new_localhost(); - let cluster_info = ClusterInfo::new( - tn.info.clone(), - Arc::new(Keypair::new()), - SocketAddrSpace::Unspecified, - ); - let c = Arc::new(cluster_info); - let d = GossipService::new( - &c, - None, - tn.sockets.gossip, - None, - true, // should_check_duplicate_instance - None, - &exit, - ); - exit.store(true, Ordering::Relaxed); - d.join().unwrap(); - } - - #[test] - fn test_gossip_services_spy() { - const TIMEOUT: Duration = Duration::from_secs(5); - let keypair = Keypair::new(); - let peer0 = solana_sdk::pubkey::new_rand(); - let peer1 = solana_sdk::pubkey::new_rand(); - let contact_info = ContactInfo::new_localhost(&keypair.pubkey(), 0); - let peer0_info = ContactInfo::new_localhost(&peer0, 0); - let peer1_info = ContactInfo::new_localhost(&peer1, 0); - let cluster_info = ClusterInfo::new( - contact_info, - Arc::new(keypair), - SocketAddrSpace::Unspecified, - ); - cluster_info.insert_info(peer0_info.clone()); - cluster_info.insert_info(peer1_info); - - let spy_ref = Arc::new(cluster_info); - - let (met_criteria, elapsed, _, tvu_peers) = spy(spy_ref.clone(), None, TIMEOUT, None, None); - assert!(!met_criteria); - assert!((TIMEOUT..TIMEOUT + Duration::from_secs(1)).contains(&elapsed)); - assert_eq!(tvu_peers, spy_ref.tvu_peers()); - - // Find num_nodes - let (met_criteria, _, _, _) = spy(spy_ref.clone(), Some(1), TIMEOUT, None, None); - assert!(met_criteria); - let (met_criteria, _, _, _) = spy(spy_ref.clone(), Some(2), TIMEOUT, None, None); - assert!(met_criteria); - - // Find specific node by pubkey - let (met_criteria, _, _, _) = spy(spy_ref.clone(), None, TIMEOUT, Some(peer0), None); - assert!(met_criteria); - let (met_criteria, _, _, _) = spy( - spy_ref.clone(), - None, - TIMEOUT, - Some(solana_sdk::pubkey::new_rand()), - None, - ); - assert!(!met_criteria); - - // Find num_nodes *and* specific node by pubkey - let (met_criteria, _, _, _) = spy(spy_ref.clone(), Some(1), TIMEOUT, Some(peer0), None); - assert!(met_criteria); - let (met_criteria, _, _, _) = spy(spy_ref.clone(), Some(3), TIMEOUT, Some(peer0), None); - assert!(!met_criteria); - let (met_criteria, _, _, _) = spy( - spy_ref.clone(), - Some(1), - TIMEOUT, - Some(solana_sdk::pubkey::new_rand()), - None, - ); - assert!(!met_criteria); - - // Find specific node by gossip address - let (met_criteria, _, _, _) = spy( - spy_ref.clone(), - None, - TIMEOUT, - None, - Some(&peer0_info.gossip), - ); - assert!(met_criteria); - - let (met_criteria, _, _, _) = spy( - spy_ref, - None, - TIMEOUT, - None, - Some(&"1.1.1.1:1234".parse().unwrap()), - ); - assert!(!met_criteria); - } -} diff --git a/gossip/src/lib.rs b/gossip/src/lib.rs deleted file mode 100644 index a86b574..0000000 --- a/gossip/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -// #![cfg_attr(RUSTC_WITH_SPECIALIZATION, feature(min_specialization))] -#![allow(clippy::integer_arithmetic)] - -pub mod cluster_info; -pub mod cluster_info_metrics; -#[macro_use] -pub mod contact_info; -pub mod crds; -pub mod crds_entry; -pub mod crds_gossip; -pub mod crds_gossip_error; -pub mod crds_gossip_pull; -pub mod crds_gossip_push; -pub mod crds_shards; -pub mod crds_value; -mod deprecated; -pub mod duplicate_shred; -pub mod epoch_slots; -pub mod gossip_error; -pub mod gossip_service; -pub mod ping_pong; -mod received_cache; -pub mod weighted_shuffle; - -#[macro_use] -extern crate log; - -#[cfg(test)] -#[macro_use] -extern crate matches; - -#[macro_use] -extern crate serde_derive; - -#[macro_use] -extern crate solana_frozen_abi_macro; - -#[macro_use] -extern crate solana_metrics; diff --git a/gossip/src/main.rs b/gossip/src/main.rs deleted file mode 100644 index d1eb6a9..0000000 --- a/gossip/src/main.rs +++ /dev/null @@ -1,333 +0,0 @@ -//! A command-line executable for monitoring a cluster's gossip plane. - -use { - clap::{ - crate_description, crate_name, value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, - SubCommand, - }, - solana_clap_utils::{ - input_parsers::keypair_of, - input_validators::{is_keypair_or_ask_keyword, is_port, is_pubkey}, - }, - solana_sdk::pubkey::Pubkey, - solana_streamer::socket::SocketAddrSpace, - std::{ - error, - net::{IpAddr, Ipv4Addr, SocketAddr}, - process::exit, - time::Duration, - }, - tiny_gossip::{contact_info::ContactInfo, gossip_service::discover}, -}; - -fn parse_matches() -> ArgMatches<'static> { - let shred_version_arg = Arg::with_name("shred_version") - .long("shred-version") - .value_name("VERSION") - .takes_value(true) - .default_value("0") - .help("Filter gossip nodes by this shred version"); - - App::new(crate_name!()) - .about(crate_description!()) - .version(solana_version::version!()) - .setting(AppSettings::SubcommandRequiredElseHelp) - .arg( - Arg::with_name("allow_private_addr") - .long("allow-private-addr") - .takes_value(false) - .help("Allow contacting private ip addresses") - .hidden(true), - ) - .subcommand( - SubCommand::with_name("rpc-url") - .about("Get an RPC URL for the cluster") - .arg( - Arg::with_name("entrypoint") - .short("n") - .long("entrypoint") - .value_name("HOST:PORT") - .takes_value(true) - .required(true) - .validator(solana_net_utils::is_host_port) - .help("Rendezvous with the cluster at this entry point"), - ) - .arg( - Arg::with_name("all") - .long("all") - .takes_value(false) - .help("Return all RPC URLs"), - ) - .arg( - Arg::with_name("any") - .long("any") - .takes_value(false) - .conflicts_with("all") - .help("Return any RPC URL"), - ) - .arg( - Arg::with_name("timeout") - .long("timeout") - .value_name("SECONDS") - .takes_value(true) - .default_value("15") - .help("Timeout in seconds"), - ) - .arg(&shred_version_arg) - .setting(AppSettings::DisableVersion), - ) - .subcommand( - SubCommand::with_name("spy") - .about("Monitor the gossip entrypoint") - .setting(AppSettings::DisableVersion) - .arg( - Arg::with_name("entrypoint") - .short("n") - .long("entrypoint") - .value_name("HOST:PORT") - .takes_value(true) - .validator(solana_net_utils::is_host_port) - .help("Rendezvous with the cluster at this entrypoint"), - ) - .arg( - clap::Arg::with_name("gossip_port") - .long("gossip-port") - .value_name("PORT") - .takes_value(true) - .validator(is_port) - .help("Gossip port number for the node"), - ) - .arg( - clap::Arg::with_name("gossip_host") - .long("gossip-host") - .value_name("HOST") - .takes_value(true) - .validator(solana_net_utils::is_host) - .help("Gossip DNS name or IP address for the node to advertise in gossip \ - [default: ask --entrypoint, or 127.0.0.1 when --entrypoint is not provided]"), - ) - .arg( - Arg::with_name("identity") - .short("i") - .long("identity") - .value_name("PATH") - .takes_value(true) - .validator(is_keypair_or_ask_keyword) - .help("Identity keypair [default: ephemeral keypair]"), - ) - .arg( - Arg::with_name("num_nodes") - .short("N") - .long("num-nodes") - .value_name("NUM") - .takes_value(true) - .conflicts_with("num_nodes_exactly") - .help("Wait for at least NUM nodes to be visible"), - ) - .arg( - Arg::with_name("num_nodes_exactly") - .short("E") - .long("num-nodes-exactly") - .value_name("NUM") - .takes_value(true) - .help("Wait for exactly NUM nodes to be visible"), - ) - .arg( - Arg::with_name("node_pubkey") - .short("p") - .long("pubkey") - .value_name("PUBKEY") - .takes_value(true) - .validator(is_pubkey) - .help("Public key of a specific node to wait for"), - ) - .arg(&shred_version_arg) - .arg( - Arg::with_name("timeout") - .long("timeout") - .value_name("SECONDS") - .takes_value(true) - .help("Maximum time to wait in seconds [default: wait forever]"), - ), - ) - .get_matches() -} - -fn parse_gossip_host(matches: &ArgMatches, entrypoint_addr: Option) -> IpAddr { - matches - .value_of("gossip_host") - .map(|gossip_host| { - solana_net_utils::parse_host(gossip_host).unwrap_or_else(|e| { - eprintln!("failed to parse gossip-host: {e}"); - exit(1); - }) - }) - .unwrap_or_else(|| { - if let Some(entrypoint_addr) = entrypoint_addr { - solana_net_utils::get_public_ip_addr(&entrypoint_addr).unwrap_or_else(|err| { - eprintln!("Failed to contact cluster entrypoint {entrypoint_addr}: {err}"); - exit(1); - }) - } else { - IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)) - } - }) -} - -fn process_spy_results( - timeout: Option, - validators: Vec, - num_nodes: Option, - num_nodes_exactly: Option, - pubkey: Option, -) { - if timeout.is_some() { - if let Some(num) = num_nodes { - if validators.len() < num { - let add = if num_nodes_exactly.is_some() { - "" - } else { - " or more" - }; - eprintln!("Error: Insufficient validators discovered. Expecting {num}{add}",); - exit(1); - } - } - if let Some(node) = pubkey { - if !validators.iter().any(|x| x.id == node) { - eprintln!("Error: Could not find node {node:?}"); - exit(1); - } - } - } - if let Some(num_nodes_exactly) = num_nodes_exactly { - if validators.len() > num_nodes_exactly { - eprintln!("Error: Extra nodes discovered. Expecting exactly {num_nodes_exactly}"); - exit(1); - } - } -} - -fn process_spy(matches: &ArgMatches, socket_addr_space: SocketAddrSpace) -> std::io::Result<()> { - let num_nodes_exactly = matches - .value_of("num_nodes_exactly") - .map(|num| num.to_string().parse().unwrap()); - let num_nodes = matches - .value_of("num_nodes") - .map(|num| num.to_string().parse().unwrap()) - .or(num_nodes_exactly); - let timeout = matches - .value_of("timeout") - .map(|secs| secs.to_string().parse().unwrap()); - let pubkey = matches - .value_of("node_pubkey") - .map(|pubkey_str| pubkey_str.parse::().unwrap()); - let shred_version = value_t_or_exit!(matches, "shred_version", u16); - let identity_keypair = keypair_of(matches, "identity"); - - let entrypoint_addr = parse_entrypoint(matches); - - let gossip_host = parse_gossip_host(matches, entrypoint_addr); - - let gossip_addr = SocketAddr::new( - gossip_host, - value_t!(matches, "gossip_port", u16).unwrap_or_else(|_| { - solana_net_utils::find_available_port_in_range( - IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), - (0, 1), - ) - .expect("unable to find an available gossip port") - }), - ); - let discover_timeout = Duration::from_secs(timeout.unwrap_or(u64::MAX)); - let (_all_peers, validators) = discover( - identity_keypair, - entrypoint_addr.as_ref(), - num_nodes, - discover_timeout, - pubkey, // find_node_by_pubkey - None, // find_node_by_gossip_addr - Some(&gossip_addr), // my_gossip_addr - shred_version, - socket_addr_space, - )?; - - process_spy_results(timeout, validators, num_nodes, num_nodes_exactly, pubkey); - - Ok(()) -} - -fn parse_entrypoint(matches: &ArgMatches) -> Option { - matches.value_of("entrypoint").map(|entrypoint| { - solana_net_utils::parse_host_port(entrypoint).unwrap_or_else(|e| { - eprintln!("failed to parse entrypoint address: {e}"); - exit(1); - }) - }) -} - -fn process_rpc_url( - matches: &ArgMatches, - socket_addr_space: SocketAddrSpace, -) -> std::io::Result<()> { - let any = matches.is_present("any"); - let all = matches.is_present("all"); - let entrypoint_addr = parse_entrypoint(matches); - let timeout = value_t_or_exit!(matches, "timeout", u64); - let shred_version = value_t_or_exit!(matches, "shred_version", u16); - let (_all_peers, validators) = discover( - None, // keypair - entrypoint_addr.as_ref(), - Some(1), // num_nodes - Duration::from_secs(timeout), - None, // find_node_by_pubkey - entrypoint_addr.as_ref(), // find_node_by_gossip_addr - None, // my_gossip_addr - shred_version, - socket_addr_space, - )?; - - let rpc_addrs: Vec<_> = validators - .iter() - .filter_map(|contact_info| { - if (any || all || Some(contact_info.gossip) == entrypoint_addr) - && ContactInfo::is_valid_address(&contact_info.rpc, &socket_addr_space) - { - return Some(contact_info.rpc); - } - None - }) - .collect(); - - if rpc_addrs.is_empty() { - eprintln!("No RPC URL found"); - exit(1); - } - - for rpc_addr in rpc_addrs { - println!("http://{rpc_addr}"); - if any { - break; - } - } - - Ok(()) -} - -fn main() -> Result<(), Box> { - solana_logger::setup_with_default("solana=info"); - - let matches = parse_matches(); - let socket_addr_space = SocketAddrSpace::new(matches.is_present("allow_private_addr")); - match matches.subcommand() { - ("spy", Some(matches)) => { - process_spy(matches, socket_addr_space)?; - } - ("rpc-url", Some(matches)) => { - process_rpc_url(matches, socket_addr_space)?; - } - _ => unreachable!(), - } - - Ok(()) -} diff --git a/gossip/src/ping_pong.rs b/gossip/src/ping_pong.rs deleted file mode 100644 index 5b34378..0000000 --- a/gossip/src/ping_pong.rs +++ /dev/null @@ -1,432 +0,0 @@ -use { - bincode::{serialize, Error}, - lru::LruCache, - rand::{AsByteSliceMut, CryptoRng, Rng}, - serde::Serialize, - solana_sdk::{ - hash::{self, Hash}, - pubkey::Pubkey, - sanitize::{Sanitize, SanitizeError}, - signature::{Keypair, Signable, Signature, Signer}, - }, - std::{ - borrow::Cow, - net::SocketAddr, - time::{Duration, Instant}, - }, -}; - -const PING_PONG_HASH_PREFIX: &[u8] = "SOLANA_PING_PONG".as_bytes(); - -#[derive(Debug, Deserialize, Serialize)] -pub struct Ping { - from: Pubkey, - token: T, - signature: Signature, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct Pong { - from: Pubkey, - hash: Hash, // Hash of received ping token. - signature: Signature, -} - -/// Maintains records of remote nodes which have returned a valid response to a -/// ping message, and on-the-fly ping messages pending a pong response from the -/// remote node. -pub struct PingCache { - // Time-to-live of received pong messages. - ttl: Duration, - // Rate limit delay to generate pings for a given address - rate_limit_delay: Duration, - // Timestamp of last ping message sent to a remote node. - // Used to rate limit pings to remote nodes. - pings: LruCache<(Pubkey, SocketAddr), Instant>, - // Verified pong responses from remote nodes. - pongs: LruCache<(Pubkey, SocketAddr), Instant>, - // Hash of ping tokens sent out to remote nodes, - // pending a pong response back. - pending_cache: LruCache, -} - -impl Ping { - pub fn new(token: T, keypair: &Keypair) -> Result { - let signature = keypair.sign_message(&serialize(&token)?); - let ping = Ping { - from: keypair.pubkey(), - token, - signature, - }; - Ok(ping) - } -} - -impl Ping -where - T: Serialize + AsByteSliceMut + Default, -{ - pub fn new_rand(rng: &mut R, keypair: &Keypair) -> Result - where - R: Rng + CryptoRng, - { - let mut token = T::default(); - rng.fill(&mut token); - Ping::new(token, keypair) - } -} - -impl Sanitize for Ping { - fn sanitize(&self) -> Result<(), SanitizeError> { - self.from.sanitize()?; - // TODO Add self.token.sanitize()?; when rust's - // specialization feature becomes stable. - self.signature.sanitize() - } -} - -impl Signable for Ping { - fn pubkey(&self) -> Pubkey { - self.from - } - - fn signable_data(&self) -> Cow<[u8]> { - Cow::Owned(serialize(&self.token).unwrap()) - } - - fn get_signature(&self) -> Signature { - self.signature - } - - fn set_signature(&mut self, signature: Signature) { - self.signature = signature; - } -} - -impl Pong { - pub fn new(ping: &Ping, keypair: &Keypair) -> Result { - let token = serialize(&ping.token)?; - let hash = hash::hashv(&[PING_PONG_HASH_PREFIX, &token]); - let pong = Pong { - from: keypair.pubkey(), - hash, - signature: keypair.sign_message(hash.as_ref()), - }; - Ok(pong) - } - - pub fn from(&self) -> &Pubkey { - &self.from - } -} - -impl Sanitize for Pong { - fn sanitize(&self) -> Result<(), SanitizeError> { - self.from.sanitize()?; - self.hash.sanitize()?; - self.signature.sanitize() - } -} - -impl Signable for Pong { - fn pubkey(&self) -> Pubkey { - self.from - } - - fn signable_data(&self) -> Cow<[u8]> { - Cow::Owned(self.hash.as_ref().into()) - } - - fn get_signature(&self) -> Signature { - self.signature - } - - fn set_signature(&mut self, signature: Signature) { - self.signature = signature; - } -} - -impl PingCache { - pub fn new(ttl: Duration, rate_limit_delay: Duration, cap: usize) -> Self { - // Sanity check ttl/rate_limit_delay - assert!(rate_limit_delay <= ttl / 2); - Self { - ttl, - rate_limit_delay, - pings: LruCache::new(cap), - pongs: LruCache::new(cap), - pending_cache: LruCache::new(cap), - } - } - - /// Checks if the pong hash, pubkey and socket match a ping message sent - /// out previously. If so records current timestamp for the remote node and - /// returns true. - /// Note: Does not verify the signature. - pub fn add(&mut self, pong: &Pong, socket: SocketAddr, now: Instant) -> bool { - let node = (pong.pubkey(), socket); - match self.pending_cache.peek(&pong.hash) { - Some(value) if *value == node => { - self.pings.pop(&node); - self.pongs.put(node, now); - self.pending_cache.pop(&pong.hash); - true - } - _ => false, - } - } - - /// Checks if the remote node has been pinged recently. If not, calls the - /// given function to generates a new ping message, records current - /// timestamp and hash of ping token, and returns the ping message. - fn maybe_ping( - &mut self, - now: Instant, - node: (Pubkey, SocketAddr), - mut pingf: F, - ) -> Option> - where - T: Serialize, - F: FnMut() -> Option>, - { - match self.pings.peek(&node) { - // Rate limit consecutive pings sent to a remote node. - Some(t) if now.saturating_duration_since(*t) < self.rate_limit_delay => None, - _ => { - let ping = pingf()?; - let token = serialize(&ping.token).ok()?; - let hash = hash::hashv(&[PING_PONG_HASH_PREFIX, &token]); - self.pending_cache.put(hash, node); - self.pings.put(node, now); - Some(ping) - } - } - } - - /// Returns true if the remote node has responded to a ping message. - /// Removes expired pong messages. In order to extend verifications before - /// expiration, if the pong message is not too recent, and the node has not - /// been pinged recently, calls the given function to generates a new ping - /// message, records current timestamp and hash of ping token, and returns - /// the ping message. - /// Caller should verify if the socket address is valid. (e.g. by using - /// ContactInfo::is_valid_address). - pub fn check( - &mut self, - now: Instant, - node: (Pubkey, SocketAddr), - pingf: F, - ) -> (bool, Option>) - where - T: Serialize, - F: FnMut() -> Option>, - { - let (check, should_ping) = match self.pongs.get(&node) { - None => (false, true), - Some(t) => { - let age = now.saturating_duration_since(*t); - // Pop if the pong message has expired. - if age > self.ttl { - self.pongs.pop(&node); - } - // If the pong message is not too recent, generate a new ping - // message to extend remote node verification. - (true, age > self.ttl / 8) - } - }; - let ping = if should_ping { - self.maybe_ping(now, node, pingf) - } else { - None - }; - (check, ping) - } - - // Only for tests and simulations. - pub(crate) fn mock_clone(&self) -> Self { - let mut clone = Self { - ttl: self.ttl, - rate_limit_delay: self.rate_limit_delay, - pings: LruCache::new(self.pings.cap()), - pongs: LruCache::new(self.pongs.cap()), - pending_cache: LruCache::new(self.pending_cache.cap()), - }; - for (k, v) in self.pongs.iter().rev() { - clone.pings.put(*k, *v); - } - for (k, v) in self.pongs.iter().rev() { - clone.pongs.put(*k, *v); - } - for (k, v) in self.pending_cache.iter().rev() { - clone.pending_cache.put(*k, *v); - } - clone - } - - /// Only for tests and simulations. - pub fn mock_pong(&mut self, node: Pubkey, socket: SocketAddr, now: Instant) { - self.pongs.put((node, socket), now); - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - std::{ - collections::HashSet, - iter::repeat_with, - net::{Ipv4Addr, SocketAddrV4}, - }, - }; - - type Token = [u8; 32]; - - #[test] - fn test_ping_pong() { - let mut rng = rand::thread_rng(); - let keypair = Keypair::new(); - let ping = Ping::::new_rand(&mut rng, &keypair).unwrap(); - assert!(ping.verify()); - assert!(ping.sanitize().is_ok()); - - let pong = Pong::new(&ping, &keypair).unwrap(); - assert!(pong.verify()); - assert!(pong.sanitize().is_ok()); - assert_eq!( - hash::hashv(&[PING_PONG_HASH_PREFIX, &ping.token]), - pong.hash - ); - } - - #[test] - fn test_ping_cache() { - let now = Instant::now(); - let mut rng = rand::thread_rng(); - let ttl = Duration::from_millis(256); - let delay = ttl / 64; - let mut cache = PingCache::new(ttl, delay, /*cap=*/ 1000); - let this_node = Keypair::new(); - let keypairs: Vec<_> = repeat_with(Keypair::new).take(8).collect(); - let sockets: Vec<_> = repeat_with(|| { - SocketAddr::V4(SocketAddrV4::new( - Ipv4Addr::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()), - rng.gen(), - )) - }) - .take(8) - .collect(); - let remote_nodes: Vec<(&Keypair, SocketAddr)> = repeat_with(|| { - let keypair = &keypairs[rng.gen_range(0, keypairs.len())]; - let socket = sockets[rng.gen_range(0, sockets.len())]; - (keypair, socket) - }) - .take(128) - .collect(); - - // Initially all checks should fail. The first observation of each node - // should create a ping packet. - let mut seen_nodes = HashSet::<(Pubkey, SocketAddr)>::new(); - let pings: Vec>> = remote_nodes - .iter() - .map(|(keypair, socket)| { - let node = (keypair.pubkey(), *socket); - let pingf = || Ping::::new_rand(&mut rng, &this_node).ok(); - let (check, ping) = cache.check(now, node, pingf); - assert!(!check); - assert_eq!(seen_nodes.insert(node), ping.is_some()); - ping - }) - .collect(); - - let now = now + Duration::from_millis(1); - let panic_ping = || -> Option> { panic!("this should not happen!") }; - for ((keypair, socket), ping) in remote_nodes.iter().zip(&pings) { - match ping { - None => { - // Already have a recent ping packets for nodes, so no new - // ping packet will be generated. - let node = (keypair.pubkey(), *socket); - let (check, ping) = cache.check(now, node, panic_ping); - assert!(check); - assert!(ping.is_none()); - } - Some(ping) => { - let pong = Pong::new(ping, keypair).unwrap(); - assert!(cache.add(&pong, *socket, now)); - } - } - } - - let now = now + Duration::from_millis(1); - // All nodes now have a recent pong packet. - for (keypair, socket) in &remote_nodes { - let node = (keypair.pubkey(), *socket); - let (check, ping) = cache.check(now, node, panic_ping); - assert!(check); - assert!(ping.is_none()); - } - - let now = now + ttl / 8; - // All nodes still have a valid pong packet, but the cache will create - // a new ping packet to extend verification. - seen_nodes.clear(); - for (keypair, socket) in &remote_nodes { - let node = (keypair.pubkey(), *socket); - let pingf = || Ping::::new_rand(&mut rng, &this_node).ok(); - let (check, ping) = cache.check(now, node, pingf); - assert!(check); - assert_eq!(seen_nodes.insert(node), ping.is_some()); - } - - let now = now + Duration::from_millis(1); - // All nodes still have a valid pong packet, and a very recent ping - // packet pending response. So no new ping packet will be created. - for (keypair, socket) in &remote_nodes { - let node = (keypair.pubkey(), *socket); - let (check, ping) = cache.check(now, node, panic_ping); - assert!(check); - assert!(ping.is_none()); - } - - let now = now + ttl; - // Pong packets are still valid but expired. The first observation of - // each node will remove the pong packet from cache and create a new - // ping packet. - seen_nodes.clear(); - for (keypair, socket) in &remote_nodes { - let node = (keypair.pubkey(), *socket); - let pingf = || Ping::::new_rand(&mut rng, &this_node).ok(); - let (check, ping) = cache.check(now, node, pingf); - if seen_nodes.insert(node) { - assert!(check); - assert!(ping.is_some()); - } else { - assert!(!check); - assert!(ping.is_none()); - } - } - - let now = now + Duration::from_millis(1); - // No valid pong packet in the cache. A recent ping packet already - // created, so no new one will be created. - for (keypair, socket) in &remote_nodes { - let node = (keypair.pubkey(), *socket); - let (check, ping) = cache.check(now, node, panic_ping); - assert!(!check); - assert!(ping.is_none()); - } - - let now = now + ttl / 64; - // No valid pong packet in the cache. Another ping packet will be - // created for the first observation of each node. - seen_nodes.clear(); - for (keypair, socket) in &remote_nodes { - let node = (keypair.pubkey(), *socket); - let pingf = || Ping::::new_rand(&mut rng, &this_node).ok(); - let (check, ping) = cache.check(now, node, pingf); - assert!(!check); - assert_eq!(seen_nodes.insert(node), ping.is_some()); - } - } -} diff --git a/gossip/src/received_cache.rs b/gossip/src/received_cache.rs deleted file mode 100644 index a77a758..0000000 --- a/gossip/src/received_cache.rs +++ /dev/null @@ -1,191 +0,0 @@ -use { - itertools::Itertools, - lru::LruCache, - solana_sdk::pubkey::Pubkey, - std::{cmp::Reverse, collections::HashMap}, -}; - -// For each origin, tracks which nodes have sent messages from that origin and -// their respective score in terms of timeliness of delivered messages. -pub(crate) struct ReceivedCache(LruCache); - -#[derive(Clone, Default)] -struct ReceivedCacheEntry { - nodes: HashMap, - num_upserts: usize, -} - -impl ReceivedCache { - // Minimum number of upserts before a cache entry can be pruned. - const MIN_NUM_UPSERTS: usize = 20; - - pub(crate) fn new(capacity: usize) -> Self { - Self(LruCache::new(capacity)) - } - - pub(crate) fn record(&mut self, origin: Pubkey, node: Pubkey, num_dups: usize) { - match self.0.get_mut(&origin) { - Some(entry) => entry.record(node, num_dups), - None => { - let mut entry = ReceivedCacheEntry::default(); - entry.record(node, num_dups); - self.0.put(origin, entry); - } - } - } - - pub(crate) fn prune( - &mut self, - pubkey: &Pubkey, // This node. - origin: Pubkey, // CRDS value owner. - stake_threshold: f64, - min_ingress_nodes: usize, - stakes: &HashMap, - ) -> impl Iterator { - match self.0.peek_mut(&origin) { - None => None, - Some(entry) if entry.num_upserts < Self::MIN_NUM_UPSERTS => None, - Some(entry) => Some( - std::mem::take(entry) - .prune(pubkey, &origin, stake_threshold, min_ingress_nodes, stakes) - .filter(move |node| node != &origin), - ), - } - .into_iter() - .flatten() - } - - // Only for tests and simulations. - pub(crate) fn mock_clone(&self) -> Self { - let mut cache = LruCache::new(self.0.cap()); - for (&origin, entry) in self.0.iter().rev() { - cache.put(origin, entry.clone()); - } - Self(cache) - } -} - -impl ReceivedCacheEntry { - // Limit how big the cache can get if it is spammed - // with old messages with random pubkeys. - const CAPACITY: usize = 50; - // Threshold for the number of duplicates before which a message - // is counted as timely towards node's score. - const NUM_DUPS_THRESHOLD: usize = 2; - - fn record(&mut self, node: Pubkey, num_dups: usize) { - if num_dups == 0 { - self.num_upserts = self.num_upserts.saturating_add(1); - } - // If the message has been timely enough increment node's score. - if num_dups < Self::NUM_DUPS_THRESHOLD { - let score = self.nodes.entry(node).or_default(); - *score = score.saturating_add(1); - } else if self.nodes.len() < Self::CAPACITY { - // Ensure that node is inserted into the cache for later pruning. - let _ = self.nodes.entry(node).or_default(); - } - } - - fn prune( - self, - pubkey: &Pubkey, // This node. - origin: &Pubkey, // CRDS value owner. - stake_threshold: f64, - min_ingress_nodes: usize, - stakes: &HashMap, - ) -> impl Iterator { - debug_assert!((0.0..=1.0).contains(&stake_threshold)); - debug_assert!(self.num_upserts >= ReceivedCache::MIN_NUM_UPSERTS); - // Enforce a minimum aggregate ingress stake; see: - // https://github.com/solana-labs/solana/issues/3214 - let min_ingress_stake = { - let stake = stakes.get(pubkey).min(stakes.get(origin)); - (stake.copied().unwrap_or_default() as f64 * stake_threshold) as u64 - }; - self.nodes - .into_iter() - .map(|(node, score)| { - let stake = stakes.get(&node).copied().unwrap_or_default(); - (node, score, stake) - }) - .sorted_unstable_by_key(|&(_, score, stake)| Reverse((score, stake))) - .scan(0u64, |acc, (node, _score, stake)| { - let old = *acc; - *acc = acc.saturating_add(stake); - Some((node, old)) - }) - .skip(min_ingress_nodes) - .skip_while(move |&(_, stake)| stake < min_ingress_stake) - .map(|(node, _stake)| node) - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - std::{collections::HashSet, iter::repeat_with}, - }; - - #[test] - fn test_received_cache() { - let mut cache = ReceivedCache::new(/*capacity:*/ 100); - let pubkey = Pubkey::new_unique(); - let origin = Pubkey::new_unique(); - let records = vec![ - vec![3, 1, 7, 5], - vec![7, 6, 5, 2], - vec![2, 0, 0, 2], - vec![3, 5, 0, 6], - vec![6, 2, 6, 2], - ]; - let nodes: Vec<_> = repeat_with(Pubkey::new_unique) - .take(records.len()) - .collect(); - for (node, records) in nodes.iter().zip(records) { - for (num_dups, k) in records.into_iter().enumerate() { - for _ in 0..k { - cache.record(origin, *node, num_dups); - } - } - } - assert_eq!(cache.0.get(&origin).unwrap().num_upserts, 21); - let scores: HashMap = [ - (nodes[0], 4), - (nodes[1], 13), - (nodes[2], 2), - (nodes[3], 8), - (nodes[4], 8), - ] - .into_iter() - .collect(); - assert_eq!(cache.0.get(&origin).unwrap().nodes, scores); - let stakes = [ - (nodes[0], 6), - (nodes[1], 1), - (nodes[2], 5), - (nodes[3], 3), - (nodes[4], 7), - (pubkey, 9), - (origin, 9), - ] - .into_iter() - .collect(); - let prunes: HashSet = [nodes[0], nodes[2], nodes[3]].into_iter().collect(); - assert_eq!( - cache - .mock_clone() - .prune(&pubkey, origin, 0.5, 2, &stakes) - .collect::>(), - prunes - ); - let prunes: HashSet = [nodes[0], nodes[2]].into_iter().collect(); - assert_eq!( - cache - .prune(&pubkey, origin, 1.0, 0, &stakes) - .collect::>(), - prunes - ); - } -} diff --git a/gossip/src/weighted_shuffle.rs b/gossip/src/weighted_shuffle.rs deleted file mode 100644 index 8b2cf23..0000000 --- a/gossip/src/weighted_shuffle.rs +++ /dev/null @@ -1,360 +0,0 @@ -//! The `weighted_shuffle` module provides an iterator over shuffled weights. - -use { - num_traits::CheckedAdd, - rand::{ - distributions::uniform::{SampleUniform, UniformSampler}, - Rng, - }, - std::ops::{AddAssign, Sub, SubAssign}, -}; - -/// Implements an iterator where indices are shuffled according to their -/// weights: -/// - Returned indices are unique in the range [0, weights.len()). -/// - Higher weighted indices tend to appear earlier proportional to their -/// weight. -/// - Zero weighted indices are shuffled and appear only at the end, after -/// non-zero weighted indices. -#[derive(Clone)] -pub struct WeightedShuffle { - arr: Vec, // Underlying array implementing binary indexed tree. - sum: T, // Current sum of weights, excluding already selected indices. - zeros: Vec, // Indices of zero weighted entries. -} - -// The implementation uses binary indexed tree: -// https://en.wikipedia.org/wiki/Fenwick_tree -// to maintain cumulative sum of weights excluding already selected indices -// over self.arr. -impl WeightedShuffle -where - T: Copy + Default + PartialOrd + AddAssign + CheckedAdd, -{ - /// If weights are negative or overflow the total sum - /// they are treated as zero. - pub fn new(name: &'static str, weights: &[T]) -> Self { - let size = weights.len() + 1; - let zero = ::default(); - let mut arr = vec![zero; size]; - let mut sum = zero; - let mut zeros = Vec::default(); - let mut num_negative = 0; - let mut num_overflow = 0; - for (mut k, &weight) in (1usize..).zip(weights) { - #[allow(clippy::neg_cmp_op_on_partial_ord)] - // weight < zero does not work for NaNs. - if !(weight >= zero) { - zeros.push(k - 1); - num_negative += 1; - continue; - } - if weight == zero { - zeros.push(k - 1); - continue; - } - sum = match sum.checked_add(&weight) { - Some(val) => val, - None => { - zeros.push(k - 1); - num_overflow += 1; - continue; - } - }; - while k < size { - arr[k] += weight; - k += k & k.wrapping_neg(); - } - } - if num_negative > 0 { - datapoint_error!("weighted-shuffle-negative", (name, num_negative, i64)); - } - if num_overflow > 0 { - datapoint_error!("weighted-shuffle-overflow", (name, num_overflow, i64)); - } - Self { arr, sum, zeros } - } -} - -impl WeightedShuffle -where - T: Copy + Default + PartialOrd + AddAssign + SubAssign + Sub, -{ - // Returns cumulative sum of current weights upto index k (inclusive). - fn cumsum(&self, mut k: usize) -> T { - let mut out = ::default(); - while k != 0 { - out += self.arr[k]; - k ^= k & k.wrapping_neg(); - } - out - } - - // Removes given weight at index k. - fn remove(&mut self, mut k: usize, weight: T) { - self.sum -= weight; - let size = self.arr.len(); - while k < size { - self.arr[k] -= weight; - k += k & k.wrapping_neg(); - } - } - - // Returns smallest index such that self.cumsum(k) > val, - // along with its respective weight. - fn search(&self, val: T) -> (/*index:*/ usize, /*weight:*/ T) { - let zero = ::default(); - debug_assert!(val >= zero); - debug_assert!(val < self.sum); - let mut lo = (/*index:*/ 0, /*cumsum:*/ zero); - let mut hi = (self.arr.len() - 1, self.sum); - while lo.0 + 1 < hi.0 { - let k = lo.0 + (hi.0 - lo.0) / 2; - let sum = self.cumsum(k); - if sum <= val { - lo = (k, sum); - } else { - hi = (k, sum); - } - } - debug_assert!(lo.1 <= val); - debug_assert!(hi.1 > val); - (hi.0, hi.1 - lo.1) - } - - pub fn remove_index(&mut self, index: usize) { - let zero = ::default(); - let weight = self.cumsum(index + 1) - self.cumsum(index); - if weight != zero { - self.remove(index + 1, weight); - } else if let Some(index) = self.zeros.iter().position(|ix| *ix == index) { - self.zeros.remove(index); - } - } -} - -impl WeightedShuffle -where - T: Copy + Default + PartialOrd + AddAssign + SampleUniform + SubAssign + Sub, -{ - // Equivalent to weighted_shuffle.shuffle(&mut rng).next() - pub fn first(&self, rng: &mut R) -> Option { - let zero = ::default(); - if self.sum > zero { - let sample = ::Sampler::sample_single(zero, self.sum, rng); - let (index, _weight) = WeightedShuffle::search(self, sample); - return Some(index - 1); - } - if self.zeros.is_empty() { - return None; - } - let index = ::Sampler::sample_single(0usize, self.zeros.len(), rng); - self.zeros.get(index).copied() - } -} - -impl<'a, T: 'a> WeightedShuffle -where - T: Copy + Default + PartialOrd + AddAssign + SampleUniform + SubAssign + Sub, -{ - pub fn shuffle(mut self, rng: &'a mut R) -> impl Iterator + 'a { - std::iter::from_fn(move || { - let zero = ::default(); - if self.sum > zero { - let sample = ::Sampler::sample_single(zero, self.sum, rng); - let (index, weight) = WeightedShuffle::search(&self, sample); - self.remove(index, weight); - return Some(index - 1); - } - if self.zeros.is_empty() { - return None; - } - let index = - ::Sampler::sample_single(0usize, self.zeros.len(), rng); - Some(self.zeros.swap_remove(index)) - }) - } -} - -#[cfg(test)] -mod tests { - use { - super::*, - rand::SeedableRng, - rand_chacha::ChaChaRng, - std::{convert::TryInto, iter::repeat_with}, - }; - - fn weighted_shuffle_slow(rng: &mut R, mut weights: Vec) -> Vec - where - R: Rng, - { - let mut shuffle = Vec::with_capacity(weights.len()); - let mut high: u64 = weights.iter().sum(); - let mut zeros: Vec<_> = weights - .iter() - .enumerate() - .filter(|(_, w)| **w == 0) - .map(|(i, _)| i) - .collect(); - while high != 0 { - let sample = rng.gen_range(0, high); - let index = weights - .iter() - .scan(0, |acc, &w| { - *acc += w; - Some(*acc) - }) - .position(|acc| sample < acc) - .unwrap(); - shuffle.push(index); - high -= weights[index]; - weights[index] = 0; - } - while !zeros.is_empty() { - let index = ::Sampler::sample_single(0usize, zeros.len(), rng); - shuffle.push(zeros.swap_remove(index)); - } - shuffle - } - - // Asserts that empty weights will return empty shuffle. - #[test] - fn test_weighted_shuffle_empty_weights() { - let weights = Vec::::new(); - let mut rng = rand::thread_rng(); - let shuffle = WeightedShuffle::new("", &weights); - assert!(shuffle.clone().shuffle(&mut rng).next().is_none()); - assert!(shuffle.first(&mut rng).is_none()); - } - - // Asserts that zero weights will be shuffled. - #[test] - fn test_weighted_shuffle_zero_weights() { - let weights = vec![0u64; 5]; - let seed = [37u8; 32]; - let mut rng = ChaChaRng::from_seed(seed); - let shuffle = WeightedShuffle::new("", &weights); - assert_eq!( - shuffle.clone().shuffle(&mut rng).collect::>(), - [1, 4, 2, 3, 0] - ); - let mut rng = ChaChaRng::from_seed(seed); - assert_eq!(shuffle.first(&mut rng), Some(1)); - } - - // Asserts that each index is selected proportional to its weight. - #[test] - fn test_weighted_shuffle_sanity() { - let seed: Vec<_> = (1..).step_by(3).take(32).collect(); - let seed: [u8; 32] = seed.try_into().unwrap(); - let mut rng = ChaChaRng::from_seed(seed); - let weights = [1, 0, 1000, 0, 0, 10, 100, 0]; - let mut counts = [0; 8]; - for _ in 0..100000 { - let mut shuffle = WeightedShuffle::new("", &weights).shuffle(&mut rng); - counts[shuffle.next().unwrap()] += 1; - let _ = shuffle.count(); // consume the rest. - } - assert_eq!(counts, [95, 0, 90069, 0, 0, 908, 8928, 0]); - let mut counts = [0; 8]; - for _ in 0..100000 { - let mut shuffle = WeightedShuffle::new("", &weights); - shuffle.remove_index(5); - shuffle.remove_index(3); - shuffle.remove_index(1); - let mut shuffle = shuffle.shuffle(&mut rng); - counts[shuffle.next().unwrap()] += 1; - let _ = shuffle.count(); // consume the rest. - } - assert_eq!(counts, [97, 0, 90862, 0, 0, 0, 9041, 0]); - } - - #[test] - fn test_weighted_shuffle_negative_overflow() { - const SEED: [u8; 32] = [48u8; 32]; - let weights = [19i64, 23, 7, 0, 0, 23, 3, 0, 5, 0, 19, 29]; - let mut rng = ChaChaRng::from_seed(SEED); - let shuffle = WeightedShuffle::new("", &weights); - assert_eq!( - shuffle.shuffle(&mut rng).collect::>(), - [8, 1, 5, 10, 11, 0, 2, 6, 9, 4, 3, 7] - ); - // Negative weights and overflowing ones are treated as zero. - let weights = [19, 23, 7, -57, i64::MAX, 23, 3, i64::MAX, 5, -79, 19, 29]; - let mut rng = ChaChaRng::from_seed(SEED); - let shuffle = WeightedShuffle::new("", &weights); - assert_eq!( - shuffle.shuffle(&mut rng).collect::>(), - [8, 1, 5, 10, 11, 0, 2, 6, 9, 4, 3, 7] - ); - } - - #[test] - fn test_weighted_shuffle_hard_coded() { - let weights = [ - 78, 70, 38, 27, 21, 0, 82, 42, 21, 77, 77, 0, 17, 4, 50, 96, 0, 83, 33, 16, 72, - ]; - let seed = [48u8; 32]; - let mut rng = ChaChaRng::from_seed(seed); - let mut shuffle = WeightedShuffle::new("", &weights); - assert_eq!( - shuffle.clone().shuffle(&mut rng).collect::>(), - [2, 12, 18, 0, 14, 15, 17, 10, 1, 9, 7, 6, 13, 20, 4, 19, 3, 8, 11, 16, 5] - ); - let mut rng = ChaChaRng::from_seed(seed); - assert_eq!(shuffle.first(&mut rng), Some(2)); - let mut rng = ChaChaRng::from_seed(seed); - shuffle.remove_index(11); - shuffle.remove_index(3); - shuffle.remove_index(15); - shuffle.remove_index(0); - assert_eq!( - shuffle.clone().shuffle(&mut rng).collect::>(), - [4, 6, 1, 12, 19, 14, 17, 20, 2, 9, 10, 8, 7, 18, 13, 5, 16] - ); - let mut rng = ChaChaRng::from_seed(seed); - assert_eq!(shuffle.first(&mut rng), Some(4)); - let seed = [37u8; 32]; - let mut rng = ChaChaRng::from_seed(seed); - let mut shuffle = WeightedShuffle::new("", &weights); - assert_eq!( - shuffle.clone().shuffle(&mut rng).collect::>(), - [19, 3, 15, 14, 6, 10, 17, 18, 9, 2, 4, 1, 0, 7, 8, 20, 12, 13, 16, 5, 11] - ); - let mut rng = ChaChaRng::from_seed(seed); - assert_eq!(shuffle.first(&mut rng), Some(19)); - shuffle.remove_index(16); - shuffle.remove_index(8); - shuffle.remove_index(20); - shuffle.remove_index(5); - shuffle.remove_index(19); - shuffle.remove_index(4); - let mut rng = ChaChaRng::from_seed(seed); - assert_eq!( - shuffle.clone().shuffle(&mut rng).collect::>(), - [17, 2, 9, 14, 6, 10, 12, 1, 15, 13, 7, 0, 18, 3, 11] - ); - let mut rng = ChaChaRng::from_seed(seed); - assert_eq!(shuffle.first(&mut rng), Some(17)); - } - - #[test] - fn test_weighted_shuffle_match_slow() { - let mut rng = rand::thread_rng(); - let weights: Vec = repeat_with(|| rng.gen_range(0, 1000)).take(997).collect(); - for _ in 0..10 { - let mut seed = [0u8; 32]; - rng.fill(&mut seed[..]); - let mut rng = ChaChaRng::from_seed(seed); - let shuffle = WeightedShuffle::new("", &weights); - let shuffle: Vec<_> = shuffle.shuffle(&mut rng).collect(); - let mut rng = ChaChaRng::from_seed(seed); - let shuffle_slow = weighted_shuffle_slow(&mut rng, weights.clone()); - assert_eq!(shuffle, shuffle_slow); - let mut rng = ChaChaRng::from_seed(seed); - let shuffle = WeightedShuffle::new("", &weights); - assert_eq!(shuffle.first(&mut rng), Some(shuffle_slow[0])); - } - } -} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..7897a24 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.75.0" diff --git a/solana-spv-plugin b/solana-spv-plugin new file mode 160000 index 0000000..a11f500 --- /dev/null +++ b/solana-spv-plugin @@ -0,0 +1 @@ +Subproject commit a11f5004efae5030937571033a29d640b24fb79b diff --git a/tinydancer/Cargo.lock b/tinydancer/Cargo.lock deleted file mode 100644 index ad57866..0000000 --- a/tinydancer/Cargo.lock +++ /dev/null @@ -1,5370 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aead" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" -dependencies = [ - "generic-array", -] - -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher 0.3.0", - "cpufeatures", - "opaque-debug", -] - -[[package]] -name = "aes-gcm-siv" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc" -dependencies = [ - "aead", - "aes", - "cipher 0.3.0", - "ctr", - "polyval", - "subtle", - "zeroize", -] - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom 0.2.8", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" - -[[package]] -name = "arc-swap" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" - -[[package]] -name = "ark-bn254" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea691771ebbb28aea556c044e2e5c5227398d840cee0c34d4d20fa8eb2689e8c" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-ec" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea978406c4b1ca13c2db2373b05cc55429c3575b8b21f1b9ee859aa5b03dd42" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "num-traits", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" -dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", - "derivative", - "num-bigint", - "num-traits", - "paste", - "rustc_version 0.3.3", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" -dependencies = [ - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "ark-ff-macros" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" -dependencies = [ - "num-bigint", - "num-traits", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "ark-serialize" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" -dependencies = [ - "ark-std", - "digest 0.9.0", -] - -[[package]] -name = "ark-std" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" -dependencies = [ - "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "array-bytes" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ad284aeb45c13f2fb4f084de4a420ebf447423bdf9386c0540ce33cb3ef4b8c" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "ascii" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" - -[[package]] -name = "assert_matches" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" - -[[package]] -name = "async-compression" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" -dependencies = [ - "brotli", - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "async-stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" -dependencies = [ - "async-stream-impl", - "futures-core", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "async-trait" -version = "0.1.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "autotools" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8138adefca3e5d2e73bfba83bd6eeaf904b26a7ac1b4a19892cfe16cc7e1701" -dependencies = [ - "cc", -] - -[[package]] -name = "axum" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5694b64066a2459918d8074c2ce0d5a88f409431994c2356617c8ae0c4721fc" -dependencies = [ - "async-trait", - "axum-core", - "bitflags", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower", - "tower-http", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cae3e661676ffbacb30f1a824089a8c9150e71017f7e1e38f2aa32009188d34" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backoff" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" -dependencies = [ - "futures-core", - "getrandom 0.2.8", - "instant", - "pin-project-lite", - "rand 0.8.5", - "tokio", -] - -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - -[[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.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bindgen" -version = "0.60.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "proc-macro2 1.0.50", - "quote 1.0.23", - "regex", - "rustc-hash", - "shlex", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitmaps" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" -dependencies = [ - "typenum", -] - -[[package]] -name = "blake3" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", - "digest 0.10.6", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "block-padding", - "generic-array", -] - -[[package]] -name = "block-buffer" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - -[[package]] -name = "borsh" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" -dependencies = [ - "borsh-derive", - "hashbrown 0.11.2", -] - -[[package]] -name = "borsh-derive" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate 0.1.5", - "proc-macro2 1.0.50", - "syn 1.0.107", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "brotli" -version = "3.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" - -[[package]] -name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - -[[package]] -name = "bv" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" -dependencies = [ - "feature-probe", - "serde", -] - -[[package]] -name = "bytemuck" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aca418a974d83d40a0c1f0c5cba6ff4bc28d8df099109ca459a2118d40b6322" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "caps" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" -dependencies = [ - "libc", - "thiserror", -] - -[[package]] -name = "cassowary" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" -dependencies = [ - "jobserver", -] - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", - "num-traits", - "serde", - "time 0.1.45", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "chrono-humanize" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32dce1ea1988dbdf9f9815ff11425828523bd2a134ec0805d2ac8af26ee6096e" -dependencies = [ - "chrono", -] - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - -[[package]] -name = "cipher" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "clang-sys" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "combine" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" -dependencies = [ - "ascii", - "byteorder", - "either", - "memchr", - "unreachable", -] - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "console_log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" -dependencies = [ - "log", - "web-sys", -] - -[[package]] -name = "constant_time_eq" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279" - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset 0.7.1", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossterm" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" -dependencies = [ - "bitflags", - "crossterm_winapi", - "libc", - "mio", - "parking_lot 0.12.1", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f67c7faacd4db07a939f55d66a983a5355358a1f17d32cc9a8d01d1266b9ce" -dependencies = [ - "bitflags", - "crossterm_winapi", - "libc", - "mio", - "parking_lot 0.12.1", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm_winapi" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" -dependencies = [ - "winapi", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[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 = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "ctr" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" -dependencies = [ - "cipher 0.3.0", -] - -[[package]] -name = "curve25519-dalek" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "serde", - "subtle", - "zeroize", -] - -[[package]] -name = "cxx" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2 1.0.50", - "quote 1.0.23", - "scratch", - "syn 1.0.107", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "dashmap" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" -dependencies = [ - "cfg-if", - "num_cpus", - "rayon", -] - -[[package]] -name = "derivation-path" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "destructure_traitobject" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7" - -[[package]] -name = "diesel" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4391a22b19c916e50bec4d6140f29bdda3e3bb187223fe6e3ea0b6e4d1021c04" -dependencies = [ - "diesel_derives", - "libsqlite3-sys", -] - -[[package]] -name = "diesel_derives" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b758c91dbc3fe1fdcb0dba5bd13276c6a66422f2ef5795b58488248a310aa" -dependencies = [ - "proc-macro-error", - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer 0.10.3", - "crypto-common", - "subtle", -] - -[[package]] -name = "dir-diff" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2860407d7d7e2e004bb2128510ad9e8d669e76fa005ccf567977b5d71b8b4a0b" -dependencies = [ - "walkdir", -] - -[[package]] -name = "dlopen" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e80ad39f814a9abe68583cd50a2d45c8a67561c3361ab8da240587dda80937" -dependencies = [ - "dlopen_derive", - "lazy_static", - "libc", - "winapi", -] - -[[package]] -name = "dlopen_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f236d9e1b1fbd81cea0f9cbdc8dcc7e8ebcd80e6659cd7cb2ad5f6c05946c581" -dependencies = [ - "libc", - "quote 0.6.13", - "syn 0.15.44", -] - -[[package]] -name = "eager" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" - -[[package]] -name = "ed25519" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" -dependencies = [ - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand 0.7.3", - "serde", - "sha2 0.9.9", - "zeroize", -] - -[[package]] -name = "ed25519-dalek-bip32" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" -dependencies = [ - "derivation-path", - "ed25519-dalek", - "hmac 0.12.1", - "sha2 0.10.6", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "encoding_rs" -version = "0.8.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enum-iterator" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91a4ec26efacf4aeff80887a175a419493cb6f8b5480d26387eb0bd038976187" -dependencies = [ - "enum-iterator-derive", -] - -[[package]] -name = "enum-iterator-derive" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "828de45d0ca18782232dfb8f3ea9cc428e8ced380eb26a520baaacfc70de39ce" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "env_logger" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "env_logger" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "errno" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fast-math" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2465292146cdfc2011350fe3b1c616ac83cf0faeedb33463ba1c332ed8948d66" -dependencies = [ - "ieee754", -] - -[[package]] -name = "fastrand" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] - -[[package]] -name = "feature-probe" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" - -[[package]] -name = "filetime" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "windows-sys 0.42.0", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flate2" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[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.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - -[[package]] -name = "futures" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - -[[package]] -name = "futures" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" - -[[package]] -name = "futures-executor" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" - -[[package]] -name = "futures-macro" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "futures-sink" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" - -[[package]] -name = "futures-task" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" - -[[package]] -name = "futures-util" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "serde", - "typenum", - "version_check", -] - -[[package]] -name = "gethostname" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "goauth" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8af59a261bcf42f45d1b261232847b9b850ba0a1419d6100698246fb66e9240" -dependencies = [ - "arc-swap", - "futures 0.3.26", - "log", - "reqwest", - "serde", - "serde_derive", - "serde_json", - "simpl", - "smpl_jwt", - "time 0.3.17", - "tokio", -] - -[[package]] -name = "goblin" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" -dependencies = [ - "log", - "plain", - "scroll", -] - -[[package]] -name = "h2" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "half-baked-client" -version = "0.1.0" -dependencies = [ - "async-trait", - "crossbeam", - "crossterm 0.26.0", - "diesel", - "env_logger 0.10.0", - "futures 0.1.31", - "log", - "log4rs", - "rand 0.8.5", - "rayon", - "reqwest", - "serde", - "serde_derive", - "serde_json", - "solana-ledger", - "solana-sdk 1.14.13", - "thiserror", - "tokio", - "tui", - "tungstenite", - "url", -] - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "headers" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" -dependencies = [ - "base64 0.13.1", - "bitflags", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.6", -] - -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest 0.9.0", - "generic-array", - "hmac 0.8.1", -] - -[[package]] -name = "http" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "http-range-header" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" - -[[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.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[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.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" -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-proxy" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" -dependencies = [ - "bytes", - "futures 0.3.26", - "headers", - "http", - "hyper", - "hyper-tls", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-rustls" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" -dependencies = [ - "http", - "hyper", - "rustls", - "tokio", - "tokio-rustls", -] - -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - -[[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 = "ieee754" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9007da9cacbd3e6343da136e98b0d2df013f553d35bdec8b518f07bea768e19c" - -[[package]] -name = "im" -version = "15.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" -dependencies = [ - "bitmaps", - "rand_core 0.6.4", - "rand_xoshiro", - "rayon", - "serde", - "sized-chunks", - "typenum", - "version_check", -] - -[[package]] -name = "index_list" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9d968042a4902e08810946fc7cd5851eb75e80301342305af755ca06cb82ce" - -[[package]] -name = "indexmap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" -dependencies = [ - "libc", - "windows-sys 0.45.0", -] - -[[package]] -name = "ipnet" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" - -[[package]] -name = "is-terminal" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" -dependencies = [ - "hermit-abi 0.2.6", - "io-lifetimes", - "rustix", - "windows-sys 0.42.0", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" - -[[package]] -name = "jobserver" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "keccak" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "libm" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" - -[[package]] -name = "librocksdb-sys" -version = "0.8.0+7.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" -dependencies = [ - "bindgen", - "bzip2-sys", - "cc", - "glob", - "libc", - "libz-sys", -] - -[[package]] -name = "libsecp256k1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" -dependencies = [ - "arrayref", - "base64 0.12.3", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", - "rand 0.7.3", - "serde", - "sha2 0.9.9", - "typenum", -] - -[[package]] -name = "libsecp256k1-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" -dependencies = [ - "crunchy", - "digest 0.9.0", - "subtle", -] - -[[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "libsecp256k1-gen-genmult" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.25.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" -dependencies = [ - "pkg-config", - "vcpkg", -] - -[[package]] -name = "libz-sys" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - -[[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.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", - "serde", -] - -[[package]] -name = "log-mdc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" - -[[package]] -name = "log4rs" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36ca1786d9e79b8193a68d480a0907b612f109537115c6ff655a3a1967533fd" -dependencies = [ - "anyhow", - "arc-swap", - "chrono", - "derivative", - "fnv", - "humantime", - "libc", - "log", - "log-mdc", - "parking_lot 0.12.1", - "serde", - "serde-value", - "serde_json", - "serde_yaml", - "thiserror", - "thread-id", - "typemap-ors", - "winapi", -] - -[[package]] -name = "lru" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" -dependencies = [ - "hashbrown 0.12.3", -] - -[[package]] -name = "lz4" -version = "1.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" -dependencies = [ - "libc", - "lz4-sys", -] - -[[package]] -name = "lz4-sys" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "matchit" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memmap2" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" -dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - -[[package]] -name = "merlin" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" -dependencies = [ - "byteorder", - "keccak", - "rand_core 0.6.4", - "zeroize", -] - -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - -[[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.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2e212582ede878b109755efd0773a4f0f4ec851584cf0aefbeb4d9ecc114822" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" -dependencies = [ - "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", -] - -[[package]] -name = "modular-bitfield" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" -dependencies = [ - "modular-bitfield-impl", - "static_assertions", -] - -[[package]] -name = "modular-bitfield-impl" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[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.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" -dependencies = [ - "autocfg", - "bitflags", - "cfg-if", - "libc", - "memoffset 0.6.5", - "pin-utils", -] - -[[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 = "nom8" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d829733185c1ca374f17e52b762f24f535ec625d2cc1f070e34c8a9068f341b" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e" -dependencies = [ - "proc-macro-crate 1.3.0", - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "111.24.0+1.1.1s" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3498f259dab01178c6228c6b00dcef0ed2a2d5e20d648c017861227773ea4abd" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" -dependencies = [ - "autocfg", - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "ordered-float" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ouroboros" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbb50b356159620db6ac971c6d5c9ab788c9cc38a6f49619fca2a27acb062ca" -dependencies = [ - "aliasable", - "ouroboros_macro", -] - -[[package]] -name = "ouroboros_macro" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0d9d1a6191c4f391f87219d1ea42b23f09ee84d64763cd05ee6ea88d9f384d" -dependencies = [ - "Inflector", - "proc-macro-error", - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core 0.9.6", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys 0.42.0", -] - -[[package]] -name = "paste" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" - -[[package]] -name = "pbkdf2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" -dependencies = [ - "crypto-mac", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.6", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "pest" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f" -dependencies = [ - "thiserror", - "ucd-trie", -] - -[[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "pin-project" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[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.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - -[[package]] -name = "polyval" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "prettyplease" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" -dependencies = [ - "proc-macro2 1.0.50", - "syn 1.0.107", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" -dependencies = [ - "once_cell", - "toml_edit", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - -[[package]] -name = "proc-macro2" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21dc42e00223fc37204bd4aa177e69420c604ca4a183209a8f9de30c6d934698" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f8ad728fb08fe212df3c05169e940fbb6d9d16a877ddde14644a983ba2012e" -dependencies = [ - "bytes", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 1.0.107", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda8c0881ea9f722eb9629376db3d0b903b462477c1aafcb0566610ac28ac5d" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "prost-types" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e0526209433e96d83d750dd81a99118edbc55739e7e61a46764fd2ad537788" -dependencies = [ - "bytes", - "prost", -] - -[[package]] -name = "protobuf-src" -version = "1.1.0+21.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7ac8852baeb3cc6fb83b93646fb93c0ffe5d14bf138c945ceb4b9948ee0e3c1" -dependencies = [ - "autotools", -] - -[[package]] -name = "qstring" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - -[[package]] -name = "quote" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" -dependencies = [ - "proc-macro2 1.0.50", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[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 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.8", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_xoshiro" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" -dependencies = [ - "rand_core 0.6.4", -] - -[[package]] -name = "rayon" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "reed-solomon-erasure" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7263373d500d4d4f505d43a2a662d475a894aa94503a1ee28e9188b5f3960d4f" -dependencies = [ - "cc", - "libc", - "libm", - "lru", - "parking_lot 0.11.2", - "smallvec", - "spin 0.9.4", -] - -[[package]] -name = "regex" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "reqwest" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" -dependencies = [ - "async-compression", - "base64 0.21.0", - "bytes", - "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", - "tokio", - "tokio-native-tls", - "tokio-rustls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots", - "winreg", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "rocksdb" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9562ea1d70c0cc63a34a22d977753b50cca91cc6b6527750463bd5dd8697bc" -dependencies = [ - "libc", - "librocksdb-sys", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver 1.0.16", -] - -[[package]] -name = "rustix" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.42.0", -] - -[[package]] -name = "rustls" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" -dependencies = [ - "log", - "ring", - "sct", - "webpki", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" -dependencies = [ - "base64 0.21.0", -] - -[[package]] -name = "rustversion" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" - -[[package]] -name = "ryu" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" -dependencies = [ - "windows-sys 0.42.0", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "scratch" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" - -[[package]] -name = "scroll" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "security-framework" -version = "2.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" - -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - -[[package]] -name = "serde" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float", - "serde", -] - -[[package]] -name = "serde_bytes" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718dc5fff5b36f99093fc49b280cfc96ce6fc824317783bff5a1fed0c7a64819" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "serde_json" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" -dependencies = [ - "itoa", - "ryu", - "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_yaml" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" -dependencies = [ - "indexmap", - "ryu", - "serde", - "yaml-rust", -] - -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.6", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "sha2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.6", -] - -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug", -] - -[[package]] -name = "sha3" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" -dependencies = [ - "digest 0.10.6", - "keccak", -] - -[[package]] -name = "shlex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" - -[[package]] -name = "signal-hook" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-mio" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" -dependencies = [ - "libc", - "mio", - "signal-hook", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" - -[[package]] -name = "simpl" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a30f10c911c0355f80f1c2faa8096efc4a58cdf8590b954d5b395efa071c711" - -[[package]] -name = "sized-chunks" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" -dependencies = [ - "bitmaps", - "typenum", -] - -[[package]] -name = "slab" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "smpl_jwt" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b6ff8c21c74ce7744643a7cddbb02579a44f1f77e4316bff1ddb741aca8ac9" -dependencies = [ - "base64 0.13.1", - "log", - "openssl", - "serde", - "serde_derive", - "serde_json", - "simpl", - "time 0.3.17", -] - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "solana-account-decoder" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "Inflector", - "base64 0.13.1", - "bincode", - "bs58", - "bv", - "lazy_static", - "serde", - "serde_derive", - "serde_json", - "solana-address-lookup-table-program", - "solana-config-program", - "solana-sdk 1.15.0", - "spl-token", - "spl-token-2022", - "thiserror", - "zstd", -] - -[[package]] -name = "solana-address-lookup-table-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "bincode", - "bytemuck", - "log", - "num-derive", - "num-traits", - "rustc_version 0.4.0", - "serde", - "solana-frozen-abi 1.15.0", - "solana-frozen-abi-macro 1.15.0", - "solana-program 1.15.0", - "solana-program-runtime", - "solana-sdk 1.15.0", - "thiserror", -] - -[[package]] -name = "solana-bpf-loader-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "bincode", - "byteorder", - "libsecp256k1", - "log", - "rand 0.7.3", - "solana-measure", - "solana-program-runtime", - "solana-sdk 1.15.0", - "solana-zk-token-sdk 1.15.0", - "solana_rbpf", - "thiserror", -] - -[[package]] -name = "solana-bucket-map" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "log", - "memmap2", - "modular-bitfield", - "rand 0.7.3", - "solana-measure", - "solana-sdk 1.15.0", - "tempfile", -] - -[[package]] -name = "solana-compute-budget-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "solana-program-runtime", - "solana-sdk 1.15.0", -] - -[[package]] -name = "solana-config-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "bincode", - "chrono", - "serde", - "serde_derive", - "solana-program-runtime", - "solana-sdk 1.15.0", -] - -[[package]] -name = "solana-entry" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "bincode", - "crossbeam-channel", - "dlopen", - "dlopen_derive", - "lazy_static", - "log", - "rand 0.7.3", - "rayon", - "serde", - "solana-measure", - "solana-merkle-tree", - "solana-metrics", - "solana-perf", - "solana-rayon-threadlimit", - "solana-sdk 1.15.0", -] - -[[package]] -name = "solana-frozen-abi" -version = "1.14.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f44a019070a6cec4d3ad8605c5caa65bdaa13f00b5f1849340f44ffea63b625b" -dependencies = [ - "ahash", - "blake3", - "block-buffer 0.9.0", - "bs58", - "bv", - "byteorder", - "cc", - "either", - "generic-array", - "getrandom 0.1.16", - "hashbrown 0.12.3", - "im", - "lazy_static", - "log", - "memmap2", - "once_cell", - "rand_core 0.6.4", - "rustc_version 0.4.0", - "serde", - "serde_bytes", - "serde_derive", - "serde_json", - "sha2 0.10.6", - "solana-frozen-abi-macro 1.14.13", - "subtle", - "thiserror", -] - -[[package]] -name = "solana-frozen-abi" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "ahash", - "blake3", - "block-buffer 0.9.0", - "bs58", - "bv", - "byteorder", - "cc", - "either", - "generic-array", - "getrandom 0.1.16", - "hashbrown 0.12.3", - "im", - "lazy_static", - "log", - "memmap2", - "once_cell", - "rand_core 0.6.4", - "rustc_version 0.4.0", - "serde", - "serde_bytes", - "serde_derive", - "serde_json", - "sha2 0.10.6", - "solana-frozen-abi-macro 1.15.0", - "subtle", - "thiserror", -] - -[[package]] -name = "solana-frozen-abi-macro" -version = "1.14.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be23cc7a382f54dfe1348edb94610e5cc146b8eb21563cdd04062a403c75ba62" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "rustc_version 0.4.0", - "syn 1.0.107", -] - -[[package]] -name = "solana-frozen-abi-macro" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "rustc_version 0.4.0", - "syn 1.0.107", -] - -[[package]] -name = "solana-ledger" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "assert_matches", - "bincode", - "bitflags", - "byteorder", - "chrono", - "chrono-humanize", - "crossbeam-channel", - "dashmap", - "fs_extra", - "futures 0.3.26", - "itertools", - "lazy_static", - "libc", - "log", - "lru", - "num_cpus", - "num_enum", - "prost", - "rand 0.7.3", - "rand_chacha 0.2.2", - "rayon", - "reed-solomon-erasure", - "rocksdb", - "rustc_version 0.4.0", - "serde", - "serde_bytes", - "sha2 0.10.6", - "solana-account-decoder", - "solana-bpf-loader-program", - "solana-entry", - "solana-frozen-abi 1.15.0", - "solana-frozen-abi-macro 1.15.0", - "solana-measure", - "solana-metrics", - "solana-perf", - "solana-program-runtime", - "solana-rayon-threadlimit", - "solana-runtime", - "solana-sdk 1.15.0", - "solana-stake-program", - "solana-storage-bigtable", - "solana-storage-proto", - "solana-transaction-status", - "solana-vote-program", - "spl-token", - "spl-token-2022", - "static_assertions", - "tempfile", - "thiserror", - "tokio", - "tokio-stream", - "trees", -] - -[[package]] -name = "solana-logger" -version = "1.14.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447d16a70a1b5383736ef44801050c0e1affd022303b22ed899352f958c2de4b" -dependencies = [ - "env_logger 0.9.3", - "lazy_static", - "log", -] - -[[package]] -name = "solana-logger" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "env_logger 0.9.3", - "lazy_static", - "log", -] - -[[package]] -name = "solana-measure" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "log", - "solana-sdk 1.15.0", -] - -[[package]] -name = "solana-merkle-tree" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "fast-math", - "matches", - "solana-program 1.15.0", -] - -[[package]] -name = "solana-metrics" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "crossbeam-channel", - "gethostname", - "lazy_static", - "log", - "reqwest", - "solana-sdk 1.15.0", -] - -[[package]] -name = "solana-perf" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "ahash", - "bincode", - "bv", - "caps", - "curve25519-dalek", - "dlopen", - "dlopen_derive", - "fnv", - "lazy_static", - "libc", - "log", - "nix", - "rand 0.7.3", - "rayon", - "serde", - "solana-metrics", - "solana-rayon-threadlimit", - "solana-sdk 1.15.0", - "solana-vote-program", -] - -[[package]] -name = "solana-program" -version = "1.14.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0937481f080f5dd495fae456c94718a7bacf30fb5fdabb02dcb8a9622e446d5" -dependencies = [ - "base64 0.13.1", - "bincode", - "bitflags", - "blake3", - "borsh", - "borsh-derive", - "bs58", - "bv", - "bytemuck", - "cc", - "console_error_panic_hook", - "console_log", - "curve25519-dalek", - "getrandom 0.2.8", - "itertools", - "js-sys", - "lazy_static", - "libc", - "libsecp256k1", - "log", - "memoffset 0.6.5", - "num-derive", - "num-traits", - "parking_lot 0.12.1", - "rand 0.7.3", - "rand_chacha 0.2.2", - "rustc_version 0.4.0", - "rustversion", - "serde", - "serde_bytes", - "serde_derive", - "serde_json", - "sha2 0.10.6", - "sha3 0.10.6", - "solana-frozen-abi 1.14.13", - "solana-frozen-abi-macro 1.14.13", - "solana-sdk-macro 1.14.13", - "thiserror", - "tiny-bip39", - "wasm-bindgen", - "zeroize", -] - -[[package]] -name = "solana-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "ark-bn254", - "ark-ec", - "ark-ff", - "array-bytes", - "base64 0.13.1", - "bincode", - "bitflags", - "blake3", - "borsh", - "borsh-derive", - "bs58", - "bv", - "bytemuck", - "cc", - "console_error_panic_hook", - "console_log", - "curve25519-dalek", - "getrandom 0.2.8", - "itertools", - "js-sys", - "lazy_static", - "libc", - "libsecp256k1", - "log", - "memoffset 0.6.5", - "num-derive", - "num-traits", - "parking_lot 0.12.1", - "rand 0.7.3", - "rand_chacha 0.2.2", - "rustc_version 0.4.0", - "rustversion", - "serde", - "serde_bytes", - "serde_derive", - "serde_json", - "sha2 0.10.6", - "sha3 0.10.6", - "solana-frozen-abi 1.15.0", - "solana-frozen-abi-macro 1.15.0", - "solana-sdk-macro 1.15.0", - "thiserror", - "tiny-bip39", - "wasm-bindgen", - "zeroize", -] - -[[package]] -name = "solana-program-runtime" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "base64 0.13.1", - "bincode", - "eager", - "enum-iterator", - "itertools", - "libc", - "libloading", - "log", - "num-derive", - "num-traits", - "rand 0.7.3", - "rustc_version 0.4.0", - "serde", - "solana-frozen-abi 1.15.0", - "solana-frozen-abi-macro 1.15.0", - "solana-measure", - "solana-metrics", - "solana-sdk 1.15.0", - "solana_rbpf", - "thiserror", -] - -[[package]] -name = "solana-rayon-threadlimit" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "lazy_static", - "num_cpus", -] - -[[package]] -name = "solana-runtime" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "arrayref", - "bincode", - "blake3", - "bv", - "bytemuck", - "byteorder", - "bzip2", - "crossbeam-channel", - "dashmap", - "dir-diff", - "flate2", - "fnv", - "im", - "index_list", - "itertools", - "lazy_static", - "log", - "lru", - "lz4", - "memmap2", - "num-derive", - "num-traits", - "num_cpus", - "once_cell", - "ouroboros", - "rand 0.7.3", - "rayon", - "regex", - "rustc_version 0.4.0", - "serde", - "serde_derive", - "solana-address-lookup-table-program", - "solana-bpf-loader-program", - "solana-bucket-map", - "solana-compute-budget-program", - "solana-config-program", - "solana-frozen-abi 1.15.0", - "solana-frozen-abi-macro 1.15.0", - "solana-measure", - "solana-metrics", - "solana-perf", - "solana-program-runtime", - "solana-rayon-threadlimit", - "solana-sdk 1.15.0", - "solana-stake-program", - "solana-vote-program", - "solana-zk-token-proof-program", - "solana-zk-token-sdk 1.15.0", - "strum", - "strum_macros", - "symlink", - "tar", - "tempfile", - "thiserror", - "zstd", -] - -[[package]] -name = "solana-sdk" -version = "1.14.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390e7481c56dda2ceab2652beeda30a533e9667b34861a2eb4eec92fa1d826d7" -dependencies = [ - "assert_matches", - "base64 0.13.1", - "bincode", - "bitflags", - "borsh", - "bs58", - "bytemuck", - "byteorder", - "chrono", - "derivation-path", - "digest 0.10.6", - "ed25519-dalek", - "ed25519-dalek-bip32", - "generic-array", - "hmac 0.12.1", - "itertools", - "js-sys", - "lazy_static", - "libsecp256k1", - "log", - "memmap2", - "num-derive", - "num-traits", - "pbkdf2 0.11.0", - "qstring", - "rand 0.7.3", - "rand_chacha 0.2.2", - "rustc_version 0.4.0", - "rustversion", - "serde", - "serde_bytes", - "serde_derive", - "serde_json", - "sha2 0.10.6", - "sha3 0.10.6", - "solana-frozen-abi 1.14.13", - "solana-frozen-abi-macro 1.14.13", - "solana-logger 1.14.13", - "solana-program 1.14.13", - "solana-sdk-macro 1.14.13", - "thiserror", - "uriparse", - "wasm-bindgen", -] - -[[package]] -name = "solana-sdk" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "assert_matches", - "base64 0.13.1", - "bincode", - "bitflags", - "borsh", - "bs58", - "bytemuck", - "byteorder", - "chrono", - "derivation-path", - "digest 0.10.6", - "ed25519-dalek", - "ed25519-dalek-bip32", - "generic-array", - "hmac 0.12.1", - "itertools", - "js-sys", - "lazy_static", - "libsecp256k1", - "log", - "memmap2", - "num-derive", - "num-traits", - "num_enum", - "pbkdf2 0.11.0", - "qstring", - "rand 0.7.3", - "rand_chacha 0.2.2", - "rustc_version 0.4.0", - "rustversion", - "serde", - "serde_bytes", - "serde_derive", - "serde_json", - "sha2 0.10.6", - "sha3 0.10.6", - "solana-frozen-abi 1.15.0", - "solana-frozen-abi-macro 1.15.0", - "solana-logger 1.15.0", - "solana-program 1.15.0", - "solana-sdk-macro 1.15.0", - "thiserror", - "uriparse", - "wasm-bindgen", -] - -[[package]] -name = "solana-sdk-macro" -version = "1.14.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d0acbad862093ea123f3a27364336dcb0c8373522cd6810496a34e932c56c1" -dependencies = [ - "bs58", - "proc-macro2 1.0.50", - "quote 1.0.23", - "rustversion", - "syn 1.0.107", -] - -[[package]] -name = "solana-sdk-macro" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "bs58", - "proc-macro2 1.0.50", - "quote 1.0.23", - "rustversion", - "syn 1.0.107", -] - -[[package]] -name = "solana-stake-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "bincode", - "log", - "rustc_version 0.4.0", - "solana-config-program", - "solana-program-runtime", - "solana-sdk 1.15.0", - "solana-vote-program", -] - -[[package]] -name = "solana-storage-bigtable" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "backoff", - "bincode", - "bytes", - "bzip2", - "enum-iterator", - "flate2", - "futures 0.3.26", - "goauth", - "http", - "hyper", - "hyper-proxy", - "log", - "openssl", - "prost", - "prost-types", - "serde", - "serde_derive", - "smpl_jwt", - "solana-metrics", - "solana-sdk 1.15.0", - "solana-storage-proto", - "solana-transaction-status", - "thiserror", - "tokio", - "tonic", - "zstd", -] - -[[package]] -name = "solana-storage-proto" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "bincode", - "bs58", - "prost", - "protobuf-src", - "serde", - "solana-account-decoder", - "solana-sdk 1.15.0", - "solana-transaction-status", - "tonic-build", -] - -[[package]] -name = "solana-transaction-status" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "Inflector", - "base64 0.13.1", - "bincode", - "borsh", - "bs58", - "lazy_static", - "log", - "serde", - "serde_derive", - "serde_json", - "solana-account-decoder", - "solana-address-lookup-table-program", - "solana-sdk 1.15.0", - "spl-associated-token-account", - "spl-memo", - "spl-token", - "spl-token-2022", - "thiserror", -] - -[[package]] -name = "solana-vote-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "bincode", - "log", - "num-derive", - "num-traits", - "rustc_version 0.4.0", - "serde", - "serde_derive", - "solana-frozen-abi 1.15.0", - "solana-frozen-abi-macro 1.15.0", - "solana-metrics", - "solana-program 1.15.0", - "solana-program-runtime", - "solana-sdk 1.15.0", - "thiserror", -] - -[[package]] -name = "solana-zk-token-proof-program" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "bytemuck", - "getrandom 0.1.16", - "num-derive", - "num-traits", - "solana-program-runtime", - "solana-sdk 1.15.0", - "solana-zk-token-sdk 1.15.0", -] - -[[package]] -name = "solana-zk-token-sdk" -version = "1.14.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cebca4083e982ae01583d1a590c4d679e6f648a4761364ddfb43026d2c433142" -dependencies = [ - "aes-gcm-siv", - "arrayref", - "base64 0.13.1", - "bincode", - "bytemuck", - "byteorder", - "cipher 0.4.3", - "curve25519-dalek", - "getrandom 0.1.16", - "itertools", - "lazy_static", - "merlin", - "num-derive", - "num-traits", - "rand 0.7.3", - "serde", - "serde_json", - "sha3 0.9.1", - "solana-program 1.14.13", - "solana-sdk 1.14.13", - "subtle", - "thiserror", - "zeroize", -] - -[[package]] -name = "solana-zk-token-sdk" -version = "1.15.0" -source = "git+https://github.com/tinydancer-io/diet-rpc-validator?branch=master#845ae5316a1425d362e88d29961430d3ab14c3b0" -dependencies = [ - "aes-gcm-siv", - "arrayref", - "base64 0.13.1", - "bincode", - "bytemuck", - "byteorder", - "cipher 0.4.3", - "curve25519-dalek", - "getrandom 0.1.16", - "itertools", - "lazy_static", - "merlin", - "num-derive", - "num-traits", - "rand 0.7.3", - "serde", - "serde_json", - "sha3 0.9.1", - "solana-program 1.15.0", - "solana-sdk 1.15.0", - "subtle", - "thiserror", - "zeroize", -] - -[[package]] -name = "solana_rbpf" -version = "0.2.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e9e5085099858adba23d0a0b5298da8803f89999cb567ecafab9c916cdf53d" -dependencies = [ - "byteorder", - "combine", - "goblin", - "hash32", - "libc", - "log", - "rand 0.8.5", - "rustc-demangle", - "scroll", - "thiserror", - "winapi", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spin" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" - -[[package]] -name = "spl-associated-token-account" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc000f0fdf1f12f99d77d398137c1751345b18c88258ce0f99b7872cf6c9bd6" -dependencies = [ - "assert_matches", - "borsh", - "num-derive", - "num-traits", - "solana-program 1.14.13", - "spl-token", - "spl-token-2022", - "thiserror", -] - -[[package]] -name = "spl-memo" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0dc6f70db6bacea7ff25870b016a65ba1d1b6013536f08e4fd79a8f9005325" -dependencies = [ - "solana-program 1.14.13", -] - -[[package]] -name = "spl-token" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" -dependencies = [ - "arrayref", - "bytemuck", - "num-derive", - "num-traits", - "num_enum", - "solana-program 1.14.13", - "thiserror", -] - -[[package]] -name = "spl-token-2022" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0edb869dbe159b018f17fb9bfa67118c30f232d7f54a73742bc96794dff77ed8" -dependencies = [ - "arrayref", - "bytemuck", - "num-derive", - "num-traits", - "num_enum", - "solana-program 1.14.13", - "solana-zk-token-sdk 1.14.13", - "spl-memo", - "spl-token", - "thiserror", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2 1.0.50", - "quote 1.0.23", - "rustversion", - "syn 1.0.107", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "symlink" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" - -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", -] - -[[package]] -name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", - "unicode-xid 0.2.4", -] - -[[package]] -name = "tar" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "thread-id" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fdfe0627923f7411a43ec9ec9c39c3a9b4151be313e0922042581fb6c9b717f" -dependencies = [ - "libc", - "redox_syscall", - "winapi", -] - -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "time" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" -dependencies = [ - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" - -[[package]] -name = "tiny-bip39" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" -dependencies = [ - "anyhow", - "hmac 0.8.1", - "once_cell", - "pbkdf2 0.4.0", - "rand 0.7.3", - "rustc-hash", - "sha2 0.9.9", - "thiserror", - "unicode-normalization", - "wasm-bindgen", - "zeroize", -] - -[[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.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "1.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot 0.12.1", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.42.0", -] - -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-macros" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls", - "tokio", - "webpki", -] - -[[package]] -name = "tokio-stream" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_datetime" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" - -[[package]] -name = "toml_edit" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" -dependencies = [ - "indexmap", - "nom8", - "toml_datetime", -] - -[[package]] -name = "tonic" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.13.1", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "prost-derive", - "rustls-pemfile", - "tokio", - "tokio-rustls", - "tokio-stream", - "tokio-util", - "tower", - "tower-layer", - "tower-service", - "tracing", - "tracing-futures", -] - -[[package]] -name = "tonic-build" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" -dependencies = [ - "prettyplease", - "proc-macro2 1.0.50", - "prost-build", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap", - "pin-project", - "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" -dependencies = [ - "bitflags", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - -[[package]] -name = "trees" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de5f738ceab88e2491a94ddc33c3feeadfa95fedc60363ef110845df12f3878" - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "tui" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" -dependencies = [ - "bitflags", - "cassowary", - "crossterm 0.25.0", - "unicode-segmentation", - "unicode-width", -] - -[[package]] -name = "tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand 0.8.5", - "sha1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "typemap-ors" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867" -dependencies = [ - "unsafe-any-ors", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "ucd-trie" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" - -[[package]] -name = "unicode-bidi" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "universal-hash" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -dependencies = [ - "void", -] - -[[package]] -name = "unsafe-any-ors" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad" -dependencies = [ - "destructure_traitobject", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "uriparse" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" -dependencies = [ - "fnv", - "lazy_static", -] - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "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 = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[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.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" -dependencies = [ - "quote 1.0.23", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" - -[[package]] -name = "web-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.22.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] - -[[package]] -name = "which" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" -dependencies = [ - "either", - "libc", - "once_cell", -] - -[[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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[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-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" - -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - -[[package]] -name = "xattr" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" -dependencies = [ - "libc", -] - -[[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.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" -dependencies = [ - "proc-macro2 1.0.50", - "quote 1.0.23", - "syn 1.0.107", - "synstructure", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.6+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a3f9792c0c3dc6c165840a75f47ae1f4da402c2d006881129579f6597e801b" -dependencies = [ - "cc", - "libc", - "pkg-config", -] diff --git a/tinydancer/Cargo.toml b/tinydancer/Cargo.toml index 2a1b231..1ba50e9 100644 --- a/tinydancer/Cargo.toml +++ b/tinydancer/Cargo.toml @@ -14,25 +14,31 @@ categories = ["command-line-utilities","blockchain"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tokio = {version="1.25.0", features=["full"] } -solana-ledger={git="https://github.com/tinydancer-io/diet-rpc-validator", branch="master",version="1.15.0" } -solana-rpc-client = {git="https://github.com/tinydancer-io/diet-rpc-validator", branch="master",version="1.15.0" } -solana-rpc-client-api = {git="https://github.com/tinydancer-io/diet-rpc-validator", branch="master",version="1.15.0" } -solana-client = {git="https://github.com/tinydancer-io/diet-rpc-validator", branch="master",version="1.15.0" } -solana-sdk = {git="https://github.com/tinydancer-io/diet-rpc-validator", branch="master",version="1.15.0" } -solana-tpu-client = {git="https://github.com/tinydancer-io/diet-rpc-validator", branch="master",version="1.15.0" } -solana-version= {git="https://github.com/tinydancer-io/diet-rpc-validator", branch="master",version="1.15.0" } -solana-quic-client = {git="https://github.com/tinydancer-io/diet-rpc-validator", branch="master",version="1.15.0" } -solana-transaction-status = {git="https://github.com/tinydancer-io/diet-rpc-validator", branch="master",version="1.15.0" } + +anchor-lang = {git = "https://github.com/tinydancer-io/anchor", branch = "patch-dep"} +anchor-client = {git = "https://github.com/tinydancer-io/anchor", branch = "patch-dep", features = ["async"]} +copy = { path = "../solana-spv-plugin/onchain_programs/programs/copy" } +borsh = {version = "1.2.1", features = ["derive"]} +tokio = {version="1.35.1", features=["full"] } +account_proof_geyser = { git = "https://github.com/tinydancer-io/solana-spv-plugin" } +# solana-ledger={git="https://github.com/tinydancer-io/solana-1.18", branch="v1.18.7-branch" } +solana-rpc-client = {git="https://github.com/tinydancer-io/solana-1.18", branch="v1.18.7-branch", version="1.18.7"} +solana-rpc-client-api = {git="https://github.com/tinydancer-io/solana-1.18", branch="v1.18.7-branch", version="1.18.7"} +solana-client = {git="https://github.com/tinydancer-io/solana-1.18", branch="v1.18.7-branch"} +solana-sdk = {git="https://github.com/tinydancer-io/solana-1.18", branch="v1.18.7-branch", version = "1.18.7"} +# solana-tpu-client = {git="https://github.com/tinydancer-io/solana-1.18", branch="v1.18.7-branch"} +# solana-version= {git="https://github.com/tinydancer-io/solana-1.18", branch="v1.18.7-branch"} +# solana-quic-client = {git="https://github.com/tinydancer-io/solana-1.18", branch="v1.18.7-branch"} +solana-transaction-status = {git="https://github.com/tinydancer-io/solana-1.18", branch="v1.18.7-branch"} crossbeam = {version="0.8.2", features=["crossbeam-channel"]} reqwest = "0.11.14" rayon = "1.6.1" rand = "0.8.5" itertools = "0.10.5" -async-trait = "0.1.64" +async-trait = "0.1.77" thiserror = "1.0.38" -tungstenite = "0.18.0" -tui = "0.19.0" +# tungstenite = "0.18.0" +# tui = "0.19.0" url="2.2.2" bs58 = "0.4.0" base64 = "0.21.0" @@ -40,13 +46,13 @@ serde="1.0.152" serde_json="1.0.91" const_env = "0.1.2" lazy_static = "1.4.0" -dashmap = "5.4.0" +# dashmap = "5.5.3" bincode = "1.3.3" dotenv = "0.15.0" anyhow = "1.0.69" -prometheus = "0.13.3" +# prometheus = "0.13.3" serde_derive="1.0.152" -jsonrpsee = { version = "0.16.2", features = ["macros", "full"] } +# jsonrpsee = { version = "0.16.2", features = ["macros", "full"] } futures = "0.3.26" async-channel = "1.8.0" tracing-subscriber = "0.3.16" @@ -57,18 +63,23 @@ crossterm = "0.26.0" # log4rs = "1.2.0" spinoff = { version = "0.7.0", features = ["dots", "arc", "line"] } tiny-logger={path="../logger", version="1.16.0"} -solana-metrics="1.15.0" -solana-measure = "1.15.0" +# solana-metrics="1.15.0" +# solana-measure = "1.15.0" clap = { version = "3.2.23", features = ["derive", "env"] } tower-http = { version = "0.4.0", features = ["full"] } -hyper = "0.14.25" -tower = "0.4.13" +# hyper = "0.14.25" +# tower = "0.4.13" home = "0.5.4" colored = "2.0.0" tracing = "0.1.37" # ctrlc = "3.2.5" [dependencies.rocksdb] -version = "0.19.0" +version = "0.21.0" default-features = false features = ["lz4"] + +[patch.crates-io] +solana-program = { git = "https://github.com/tinydancer-io/solana-1.18/sdk/program", branch="v1.18.7-branch", version="1.18.7"} +solana-zk-token-sdk = { git = "https://github.com/tinydancer-io/solana-1.18/zk-token-sdk" ,branch="v1.18.7-branch", version="1.18.7"} +solana-sdk = { git = "https://github.com/tinydancer-io/solana-1.18/sdk", branch="v1.18.7-branch", version="1.18.7"} diff --git a/tinydancer/src/macros.rs b/tinydancer/src/macros.rs index c747f67..21a48db 100644 --- a/tinydancer/src/macros.rs +++ b/tinydancer/src/macros.rs @@ -17,6 +17,15 @@ macro_rules! block_on { rt.handle().block_on($func).expect($error); }; } + +#[macro_export] +macro_rules! datapoint_valid_signature { + ($key:expr, $sig:expr) => { + // use colored::Colorize; + tiny_logger::logs::info!("Validator {:?} with vote {:?} is valid", $key, $sig); + }; +} + #[macro_export] macro_rules! try_coerce_shred { ($response:expr) => {{ diff --git a/tinydancer/src/main.rs b/tinydancer/src/main.rs index 9d1c522..862e3e1 100644 --- a/tinydancer/src/main.rs +++ b/tinydancer/src/main.rs @@ -1,60 +1,41 @@ -//! client struct -//! new -> self -//! join -> JoinHandle -//! -//! -//! things happening at the same time: -//! sampling -> pull data -> run sampling algo -//! monitoring system -> slot number | shreds req/rec | sampling progress | connected nodes -//! ui -> display stats -//! -//! let (rx,tx) = channel(); -//! spawn(move{ -//! let sampler = Sampler::new(tx) -//! sampler.join(); -//! }) -//! -//! spawn(move{ -//! let monitor = Monitor::new(config, rx) -//! }); -//! let rx2 = rx.clone(); -//! spawn(move{ -//! let ui = Ui::new(...) -//! while let r = rx2.recv(){ -//! -//! } -//! }) -#![feature(async_closure)] -#![allow(unused_imports)] -#![allow(dead_code)] -#![feature(mutex_unlock)] +// #![feature(async_closure)] +// #![allow(unused_imports)] +// #![allow(dead_code)] +// #![feature(mutex_unlock)] +// #![feature(inherent_associated_types)] mod tinydancer; use crossterm::style::Stylize; use reqwest::header::{ACCEPT, CONTENT_TYPE}; -use sampler::{pull_and_verify_shreds, ArchiveConfig}; use serde::{Deserialize, Serialize}; use serde_json::Value; +use solana_sdk::pubkey::Pubkey; use spinoff::{spinners, Color, Spinner}; use std::{ f32::consts::E, fs::{self, File, OpenOptions}, io, path::{Path, PathBuf}, + str::FromStr, thread::sleep, time::Duration, }; use tinydancer::{endpoint, Cluster, TinyDancer, TinyDancerConfig}; +use transaction_service::read_validator_set; + mod macros; +mod transaction_service; +mod utils; use colored::Colorize; -mod rpc_wrapper; -mod sampler; -mod ui; use anyhow::{anyhow, Result}; use clap::{ArgGroup, Parser, Subcommand, *}; use tracing::info; use tracing_subscriber; +pub const COPY_PROGRAM: &str = "BgaRwBpqNYbK8WSR4x1rtZn7LMhuwpHqF3nCoFtSjZjg"; +pub const COPY_PDA: &str = "Bg3ZP9GymdRNSojqPs3BrDfwmjS3jXJUMu5jYZ6hR7kv"; +pub const DEFAULT_SIGNER_PATH: &str = "/.config/solana/id.json"; + #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args { @@ -71,28 +52,31 @@ pub enum Commands { #[clap(long, short, default_value_t = true)] enable_ui_service: bool, - /// If you want to enable detailed tui to monitor - #[clap(long, short, default_value_t = false)] - tui_monitor: bool, + #[clap(long, required = true)] + slot: u64, - /// Amount of shreds you want to sample per slot - #[clap(long, short, default_value_t = 10)] - sample_qty: usize, - /// Rocks db path for storing shreds - #[clap(required = false)] - archive_path: Option, + #[clap(long, required = true)] + source_account: String, + // /// If you want to enable detailed tui to monitor + // #[clap(long, short, default_value_t = false)] + // tui_monitor: bool, - /// Duration after which shreds will be purged - #[clap(required = false, default_value_t = 10000000)] - shred_archive_duration: u64, + // /// Amount of shreds you want to sample per slot + // #[clap(long, short, default_value_t = 10)] + // sample_qty: usize, + // /// Rocks db path for storing shreds + // #[clap(required = false)] + // archive_path: Option, + // /// Duration after which shreds will be purged + // #[clap(required = false, default_value_t = 10000000)] + // shred_archive_duration: u64, }, /// Verify the samples for a single slot Verify { #[clap(long, required = false, default_value = "0")] - slot: usize, - - #[clap(long, required = false, default_value = "10")] - sample_qty: usize, + slot: u64, + // #[clap(long, required = false, default_value = "10")] + // sample_qty: usize, }, /// Stream the client logs to your terminal Logs { @@ -109,18 +93,30 @@ pub enum Commands { #[derive(Debug, Subcommand)] pub enum ConfigSubcommands { Set { - #[clap(long, required = false, default_value = "/tmp/client.log")] - log_path: String, + #[clap(long, required = false)] + log_path: Option, /// The cluster you want to run the client on (Mainnet, Localnet,Devnet, ) - #[clap(long, short, required = false, default_value = "Localnet")] - cluster: String, + #[clap(long, short, required = false)] + cluster: Option, + + #[clap(long, short, required = false)] + validator_set_path: Option, + + #[clap(long, short, required = false)] + copy_program: Option, + + #[clap(long, short, required = false)] + copy_pda: Option, + + #[clap(long, short, required = false)] + signer_path: Option, }, Get, } pub fn get_config_file() -> Result { let home_path = std::env::var("HOME")?; - let path = home_path + "/.config/tinydancer/config.json"; + let path = home_path.clone() + "/.config/tinydancer/config.json"; let config_str = std::fs::read_to_string(path)?; Ok(serde_json::from_str::(&config_str)?) } @@ -131,38 +127,51 @@ async fn main() -> Result<()> { match args.command { Commands::Logs { log_path } => { + let log_path = match get_config_file() { + Ok(config) => config.log_path, + Err(_) => log_path, + }; + println!("Log Path: {}", log_path); std::process::Command::new("tail") .arg("-f") .arg(log_path) - .output() + .status() .expect("log command failed"); } Commands::Start { enable_ui_service, - sample_qty, - archive_path, - shred_archive_duration, - tui_monitor, + slot, + source_account, // sample_qty, + // archive_path, + // shred_archive_duration, + // tui_monitor, } => { let config_file = get_config_file().map_err(|_| anyhow!("tinydancer config not set"))?; + println!("genesis path {:?}", config_file.validator_set_path); let config = TinyDancerConfig { - enable_ui_service, + // enable_ui_service, rpc_endpoint: get_cluster(config_file.cluster), - sample_qty, - tui_monitor, + // sample_qty, + // tui_monitor, log_path: config_file.log_path, - archive_config: { - archive_path - .map(|path| { - Ok(ArchiveConfig { - shred_archive_duration, - archive_path: path, - }) - }) - .unwrap_or(Err(anyhow!("shred path not provided...")))? - }, + slot, + validator_set_path: config_file.validator_set_path, + copy_program: Pubkey::from_str(&config_file.copy_program).unwrap(), + copy_pda: Pubkey::from_str(&config_file.copy_pda).unwrap(), + signer_path: config_file.signer_path, + + source_account: Pubkey::from_str(&source_account).unwrap(), // archive_config: { + // archive_path + // .map(|path| { + // Ok(ArchiveConfig { + // shred_archive_duration, + // archive_path: path, + // }) + // }) + // .unwrap_or(Err(anyhow!("shred path not provided...")))? + // }, }; TinyDancer::start(config).await.unwrap(); @@ -215,7 +224,7 @@ async fn main() -> Result<()> { let path = Path::new(&is_existing); if path.exists() { std::process::Command::new("cat") - .arg(home_path + "/.config/tinydancer/config.json") + .arg(home_path.clone() + "/.config/tinydancer/config.json") .spawn() .expect("Config not set"); } else { @@ -226,11 +235,18 @@ async fn main() -> Result<()> { ); } } - ConfigSubcommands::Set { log_path, cluster } => { + ConfigSubcommands::Set { + log_path, + cluster, + validator_set_path, + copy_pda, + copy_program, + signer_path, + } => { // println!("{:?}", fs::create_dir_all("~/.config/tinydancer")); let home_path = std::env::var("HOME").unwrap(); - let tinydancer_dir = home_path + "/.config/tinydancer"; + let tinydancer_dir = home_path.clone() + "/.config/tinydancer"; let path = Path::new(&tinydancer_dir); if !path.exists() { @@ -250,6 +266,18 @@ async fn main() -> Result<()> { .stdout(std::process::Stdio::null()) .spawn() .expect("couldnt make file"); + + std::fs::write( + config_path.clone(), + serde_json::to_string_pretty(&serde_json::json!({ + "cluster":"", + "validatorSetPath":"", + "logPath":"", + "copyProgram":"", + "copyPda": "", + "signerPath":"" + }))?, + )?; } sleep(Duration::from_secs(1)); @@ -257,48 +285,36 @@ async fn main() -> Result<()> { match config_file { Ok(mut config_file) => { // overwrite - config_file.log_path = log_path; - config_file.cluster = cluster; + config_file.cluster = cluster.unwrap_or(config_file.cluster); + config_file.log_path = log_path.unwrap_or(config_file.log_path); + config_file.validator_set_path = + validator_set_path.unwrap_or(config_file.validator_set_path); + config_file.copy_program = copy_program.unwrap_or(config_file.copy_program); + + config_file.copy_pda = copy_pda.unwrap_or(config_file.copy_pda); + config_file.signer_path = signer_path.unwrap_or(config_file.signer_path); std::fs::write(config_path, serde_json::to_string_pretty(&config_file)?)?; } - Err(_) => { + Err(e) => { + println!("Error: {:?}", e.to_string()); // initialize std::fs::write( config_path, serde_json::to_string_pretty(&serde_json::json!({ "cluster":"Localnet", - "logPath":"/tmp/client.log" + "logPath":"/tmp/client.log", + "copyProgram": COPY_PROGRAM, + "copyPda":COPY_PDA, + "signerPath": home_path + DEFAULT_SIGNER_PATH, + "validatorSetPath": "" }))?, )?; } } } }, - Commands::Verify { slot, sample_qty } => { - let _spinner = Spinner::new( - spinners::Dots, - format!("Verifying Shreds for Slot {}", slot), - Color::Green, - ); - - let config_file = - get_config_file().map_err(|_| anyhow!("tinydancer config not set"))?; - let is_verified = - pull_and_verify_shreds(slot, get_endpoint(config_file.cluster), sample_qty).await; - - if is_verified { - println!( - "\nSlot {} is {} ✓", - slot.to_string().yellow(), - "Valid".to_string().green() - ); - } else { - println!( - "\nSlot {} is not {} ❌", - slot.to_string().yellow(), - "Valid".to_string().red() - ); - } + Commands::Verify { slot } => { + todo!() } } @@ -327,6 +343,20 @@ pub fn get_endpoint(cluster: String) -> String { pub struct ConfigSchema { pub log_path: String, pub cluster: String, + pub validator_set_path: String, + pub copy_program: String, + pub copy_pda: String, + pub signer_path: String, +} + +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct ValidatorSet { + pub epoch: u64, + #[serde(rename = "mainnet-beta")] + pub mainnet_beta: Vec<(String, u64)>, + pub testnet: Vec<(String, u64)>, + pub devnet: Vec<(String, u64)>, + pub custom: Vec<(String, u64)>, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/tinydancer/src/rpc_wrapper/block_store.rs b/tinydancer/src/rpc_wrapper/block_store.rs deleted file mode 100644 index d0aafd3..0000000 --- a/tinydancer/src/rpc_wrapper/block_store.rs +++ /dev/null @@ -1,190 +0,0 @@ -use std::sync::Arc; -use std::time::Duration; - -use anyhow::Context; -use dashmap::DashMap; - -use prometheus::core::GenericGauge; -use prometheus::{opts, register_int_gauge}; -use solana_client::{nonblocking::rpc_client::RpcClient, rpc_config::RpcBlockConfig}; -use solana_sdk::commitment_config::CommitmentConfig; -use solana_transaction_status::TransactionDetails; -use tiny_logger::logs::info; -use tokio::sync::RwLock; -use tokio::time::Instant; -lazy_static::lazy_static! { - static ref BLOCKS_IN_BLOCKSTORE: GenericGauge = register_int_gauge!(opts!("literpc_blocks_in_blockstore", "Number of blocks in blockstore")).unwrap(); -} - -#[derive(Clone, Copy, Debug)] -pub struct BlockInformation { - pub slot: u64, - pub block_height: u64, - pub instant: Instant, -} - -#[derive(Clone)] -pub struct BlockStore { - blocks: Arc>, - latest_confirmed_block: Arc>, - latest_finalized_block: Arc>, - last_add_block_metric: Arc>, -} - -impl BlockStore { - pub async fn new(rpc_client: &RpcClient) -> anyhow::Result { - let (confirmed_blockhash, confirmed_block) = - Self::fetch_latest(rpc_client, CommitmentConfig::confirmed()).await?; - let (finalized_blockhash, finalized_block) = - Self::fetch_latest(rpc_client, CommitmentConfig::finalized()).await?; - - Ok(Self { - latest_confirmed_block: Arc::new(RwLock::new(( - confirmed_blockhash.clone(), - confirmed_block, - ))), - latest_finalized_block: Arc::new(RwLock::new(( - finalized_blockhash.clone(), - finalized_block, - ))), - blocks: Arc::new({ - let map = DashMap::new(); - map.insert(confirmed_blockhash, confirmed_block); - map.insert(finalized_blockhash, finalized_block); - map - }), - last_add_block_metric: Arc::new(RwLock::new(Instant::now())), - }) - } - - pub async fn fetch_latest( - rpc_client: &RpcClient, - commitment_config: CommitmentConfig, - ) -> anyhow::Result<(String, BlockInformation)> { - let slot = rpc_client - .get_slot_with_commitment(commitment_config) - .await?; - - let block = rpc_client - .get_block_with_config( - slot, - RpcBlockConfig { - encoding: None, - transaction_details: Some(TransactionDetails::None), - rewards: None, - commitment: Some(commitment_config), - max_supported_transaction_version: Some(0), - }, - ) - .await?; - - let latest_block_hash = block.blockhash; - let block_height = block - .block_height - .context("Couldn't get block height of latest block for block store")?; - - Ok(( - latest_block_hash, - BlockInformation { - slot, - block_height, - instant: Instant::now(), - }, - )) - } - - pub async fn get_block_info(&self, blockhash: &str) -> Option { - let Some(info) = self.blocks.get(blockhash) else { - return None; - }; - - Some(info.value().to_owned()) - } - - fn get_latest_block_arc( - &self, - commitment_config: CommitmentConfig, - ) -> Arc> { - if commitment_config.is_finalized() { - self.latest_finalized_block.clone() - } else { - self.latest_confirmed_block.clone() - } - } - - pub async fn get_latest_blockhash(&self, commitment_config: CommitmentConfig) -> String { - self.get_latest_block_arc(commitment_config) - .read() - .await - .0 - .clone() - } - - pub async fn get_latest_block_info( - &self, - commitment_config: CommitmentConfig, - ) -> BlockInformation { - self.get_latest_block_arc(commitment_config).read().await.1 - } - - pub async fn get_latest_block( - &self, - commitment_config: CommitmentConfig, - ) -> (String, BlockInformation) { - self.get_latest_block_arc(commitment_config) - .read() - .await - .clone() - } - - pub async fn add_block( - &self, - blockhash: String, - block_info: BlockInformation, - commitment_config: CommitmentConfig, - ) { - // create context for add block metric - { - let mut last_add_block_metric = self.last_add_block_metric.write().await; - *last_add_block_metric = Instant::now(); - } - - // Write to block store first in order to prevent - // any race condition i.e prevent some one to - // ask the map what it doesn't have rn - let slot = block_info.slot; - self.blocks.insert(blockhash.clone(), block_info); - BLOCKS_IN_BLOCKSTORE.inc(); - - let latest_block = self.get_latest_block_arc(commitment_config); - if slot > latest_block.read().await.1.slot { - *latest_block.write().await = (blockhash, block_info); - } - } - - pub async fn clean(&self, cleanup_duration: Duration) { - let latest_confirmed = self - .get_latest_blockhash(CommitmentConfig { - commitment: solana_sdk::commitment_config::CommitmentLevel::Confirmed, - }) - .await; - let latest_finalized = self - .get_latest_blockhash(CommitmentConfig { - commitment: solana_sdk::commitment_config::CommitmentLevel::Confirmed, - }) - .await; - - let before_length = self.blocks.len(); - self.blocks.retain(|k, v| { - v.instant.elapsed() < cleanup_duration - || k.eq(&latest_confirmed) - || k.eq(&latest_finalized) - }); - BLOCKS_IN_BLOCKSTORE.set(self.blocks.len() as i64); - - info!( - "Cleaned {} block info", - before_length.saturating_sub(self.blocks.len()) - ); - } -} diff --git a/tinydancer/src/rpc_wrapper/bridge.rs b/tinydancer/src/rpc_wrapper/bridge.rs deleted file mode 100644 index 6cc88d2..0000000 --- a/tinydancer/src/rpc_wrapper/bridge.rs +++ /dev/null @@ -1,470 +0,0 @@ -use crate::{ - get_endpoint, - rpc_wrapper::{ - block_store::{BlockInformation, BlockStore}, - configs::{IsBlockHashValidConfig, SendTransactionConfig}, - encoding::BinaryEncoding, - rpc::LiteRpcServer, - tpu_manager::TpuManager, - workers::{BlockListener, Cleaner, TxSender, WireTransaction}, - }, - sampler::{get_serialized, pull_and_verify_shreds, SHRED_CF}, - tinydancer::Cluster, - ConfigSchema, -}; -use colored::Colorize; -use hyper::Method; -use reqwest::header; -use serde::{self, Deserialize, Serialize}; -use solana_client::rpc_response::RpcApiVersion; -use std::{ - fs, - ops::{Deref, Sub}, - path::Path, - str::FromStr, - sync::Arc, - time::Duration, -}; - -use anyhow::bail; - -use solana_ledger::shred::{Shred, ShredType, Slot}; -use tiny_logger::logs::{info, warn}; - -use jsonrpsee::{server::ServerBuilder, types::SubscriptionResult, SubscriptionSink}; -use prometheus::{core::GenericGauge, opts, register_int_counter, register_int_gauge, IntCounter}; -use solana_rpc_client::{nonblocking::rpc_client::RpcClient, rpc_client::SerializableTransaction}; -use solana_rpc_client_api::{ - config::{RpcContextConfig, RpcRequestAirdropConfig, RpcSignatureStatusConfig}, - response::{Response as RpcResponse, RpcBlockhash, RpcResponseContext, RpcVersionInfo}, -}; -use solana_sdk::{ - blake3::hashv, commitment_config::CommitmentConfig, hash::Hash, pubkey::Pubkey, - signature::Keypair, transaction::VersionedTransaction, -}; -use solana_transaction_status::TransactionStatus; -use tokio::{ - net::ToSocketAddrs, - sync::mpsc::{self, UnboundedSender}, - task::JoinHandle, -}; -use tower_http::cors::{Any, CorsLayer}; - -lazy_static::lazy_static! { - static ref RPC_SEND_TX: IntCounter = - register_int_counter!(opts!("literpc_rpc_send_tx", "RPC call send transaction")).unwrap(); - static ref RPC_GET_LATEST_BLOCKHASH: IntCounter = - register_int_counter!(opts!("literpc_rpc_get_latest_blockhash", "RPC call to get latest block hash")).unwrap(); - static ref RPC_IS_BLOCKHASH_VALID: IntCounter = - register_int_counter!(opts!("literpc_rpc_is_blockhash_valid", "RPC call to check if blockhash is vali calld")).unwrap(); - static ref RPC_GET_SIGNATURE_STATUSES: IntCounter = - register_int_counter!(opts!("literpc_rpc_get_signature_statuses", "RPC call to get signature statuses")).unwrap(); - static ref RPC_GET_VERSION: IntCounter = - register_int_counter!(opts!("literpc_rpc_get_version", "RPC call to version")).unwrap(); - static ref RPC_REQUEST_AIRDROP: IntCounter = - register_int_counter!(opts!("literpc_rpc_airdrop", "RPC call to request airdrop")).unwrap(); - static ref RPC_SIGNATURE_SUBSCRIBE: IntCounter = - register_int_counter!(opts!("literpc_rpc_signature_subscribe", "RPC call to subscribe to signature")).unwrap(); - pub static ref TXS_IN_CHANNEL: GenericGauge = register_int_gauge!(opts!("literpc_txs_in_channel", "Transactions in channel")).unwrap(); -} - -/// A bridge between clients and tpu -pub struct LiteBridge { - pub rpc_client: Arc, - pub tpu_manager: Arc, - pub db_instance: Arc, - // None if LiteBridge is not executed - pub tx_send_channel: Option>, - pub tx_sender: TxSender, - pub block_listner: BlockListener, - pub block_store: BlockStore, -} - -impl LiteBridge { - pub async fn new( - rpc_url: String, - ws_addr: String, - fanout_slots: u64, - identity: Keypair, - db_instance: Arc, - ) -> anyhow::Result { - let rpc_client = Arc::new(RpcClient::new(rpc_url.clone())); - - let tpu_manager = - Arc::new(TpuManager::new(rpc_client.clone(), ws_addr, fanout_slots, identity).await?); - - let tx_sender = TxSender::new(tpu_manager.clone()); - - let block_store = BlockStore::new(&rpc_client).await?; - - let block_listner = - BlockListener::new(rpc_client.clone(), tx_sender.clone(), block_store.clone()); - - Ok(Self { - db_instance, - rpc_client, - tpu_manager, - tx_send_channel: None, - tx_sender, - block_listner, - block_store, - }) - } - - /// List for `JsonRpc` requests - #[allow(clippy::too_many_arguments)] - pub async fn start_services( - mut self, - http_addr: T, - ws_addr: T, - tx_batch_size: usize, - tx_send_interval: Duration, - clean_interval: Duration, - ) -> anyhow::Result>>> { - let (tx_send, tx_recv) = mpsc::unbounded_channel(); - self.tx_send_channel = Some(tx_send); - - let tx_sender = self - .tx_sender - .clone() - .execute(tx_recv, tx_batch_size, tx_send_interval); - - let finalized_block_listener = self - .block_listner - .clone() - .listen(CommitmentConfig::finalized()); - - let confirmed_block_listener = self - .block_listner - .clone() - .listen(CommitmentConfig::confirmed()); - - let cleaner = Cleaner::new( - self.tx_sender.clone(), - self.block_listner.clone(), - self.block_store.clone(), - self.tpu_manager.clone(), - ) - .start(clean_interval); - - let rpc = self.into_rpc(); - - let (ws_server, http_server) = { - let ws_server_handle = ServerBuilder::default() - .ws_only() - .build(ws_addr.clone()) - .await? - .start(rpc.clone())?; - let cors = CorsLayer::new() - .allow_methods([Method::POST, Method::GET]) - .allow_origin(Any) - .allow_headers([ - header::CONTENT_TYPE, - header::ACCESS_CONTROL_ALLOW_HEADERS, - header::ACCESS_CONTROL_ALLOW_ORIGIN, - header::ACCESS_CONTROL_ALLOW_METHODS, - ]); - let middleware = tower::ServiceBuilder::new().layer(cors); - let http_server_handle = ServerBuilder::default() - .http_only() - .set_middleware(middleware) - .set_host_filtering(jsonrpsee::server::AllowHosts::Any) - .build(http_addr.clone()) - .await? - .start(rpc)?; - - let ws_server = tokio::spawn(async move { - info!("Websocket Server started at {ws_addr:?}"); - ws_server_handle.stopped().await; - bail!("Websocket server stopped"); - }); - - let http_server = tokio::spawn(async move { - info!("HTTP Server started at {http_addr:?}"); - http_server_handle.stopped().await; - bail!("HTTP server stopped"); - }); - - (ws_server, http_server) - }; - - let services = vec![ - ws_server, - http_server, - tx_sender, - finalized_block_listener, - confirmed_block_listener, - cleaner, - ]; - - Ok(services) - } -} - -#[jsonrpsee::core::async_trait] -impl LiteRpcServer for LiteBridge { - async fn send_transaction( - &self, - tx: String, - send_transaction_config: Option, - ) -> crate::rpc_wrapper::rpc::Result { - RPC_SEND_TX.inc(); - - let SendTransactionConfig { - encoding, - max_retries: _, - } = send_transaction_config.unwrap_or_default(); - - let raw_tx = match encoding.decode(tx) { - Ok(raw_tx) => raw_tx, - Err(err) => { - return Err(jsonrpsee::core::Error::Custom(err.to_string())); - } - }; - - let tx = match bincode::deserialize::(&raw_tx) { - Ok(tx) => tx, - Err(err) => { - return Err(jsonrpsee::core::Error::Custom(err.to_string())); - } - }; - - let sig = tx.get_signature(); - let Some(BlockInformation { slot, .. }) = self - .block_store - .get_block_info(&tx.get_recent_blockhash().to_string()) - .await else { - warn!("block"); - return Err(jsonrpsee::core::Error::Custom("Blockhash not found in block store".to_string())); - }; - - self.tx_send_channel - .as_ref() - .expect("Lite Bridge Not Executed") - .send((sig.to_string(), raw_tx, slot)) - .unwrap(); - TXS_IN_CHANNEL.inc(); - - Ok(BinaryEncoding::Base58.encode(sig)) - } - - async fn get_latest_blockhash( - &self, - config: Option, - ) -> crate::rpc_wrapper::rpc::Result> { - RPC_GET_LATEST_BLOCKHASH.inc(); - - let commitment_config = config - .map(|config| config.commitment.unwrap_or_default()) - .unwrap_or_default(); - - let ( - blockhash, - BlockInformation { - slot, block_height, .. - }, - ) = self.block_store.get_latest_block(commitment_config).await; - - info!("glb {blockhash} {slot} {block_height}"); - let mut rpc_url = String::from("http://0.0.0.0:8899"); - let home_path = std::env::var("HOME").unwrap(); - let is_existing = home_path.clone() + "/.config/tinydancer/config.json"; - let path = Path::new(&is_existing); - if path.exists() { - let file = fs::File::open(home_path.clone() + "/.config/tinydancer/config.json") - .expect("Error reading config in bridge"); - let config: ConfigSchema = serde_json::from_reader(file).unwrap(); - rpc_url = get_endpoint(config.cluster); - } else { - println!( - "{} {}", - "Initialise a config first using:".to_string().yellow(), - "tinydancer set config".to_string().green() - ); - } - let sampled = - pull_and_verify_shreds(slot as usize, String::from(rpc_url), 10 as usize).await; - - Ok(LiteResponse { - context: LiteRpcResponseContext { - slot, - api_version: None, - sampled, - }, - value: RpcBlockhash { - blockhash, - last_valid_block_height: block_height + 150, - }, - }) - } - - async fn is_blockhash_valid( - &self, - blockhash: String, - config: Option, - ) -> crate::rpc_wrapper::rpc::Result> { - RPC_IS_BLOCKHASH_VALID.inc(); - - let commitment = config.unwrap_or_default().commitment.unwrap_or_default(); - let commitment = CommitmentConfig { commitment }; - - let blockhash = match Hash::from_str(&blockhash) { - Ok(blockhash) => blockhash, - Err(err) => { - return Err(jsonrpsee::core::Error::Custom(err.to_string())); - } - }; - - let is_valid = match self - .rpc_client - .is_blockhash_valid(&blockhash, commitment) - .await - { - Ok(is_valid) => is_valid, - Err(err) => { - return Err(jsonrpsee::core::Error::Custom(err.to_string())); - } - }; - - let slot = self - .block_store - .get_latest_block_info(commitment) - .await - .slot; - - Ok(RpcResponse { - context: RpcResponseContext { - slot, - api_version: None, - }, - value: is_valid, - }) - } - - async fn get_signature_statuses( - &self, - sigs: Vec, - _config: Option, - ) -> crate::rpc_wrapper::rpc::Result>>> { - RPC_GET_SIGNATURE_STATUSES.inc(); - - let sig_statuses = sigs - .iter() - .map(|sig| { - self.tx_sender - .txs_sent_store - .get(sig) - .and_then(|v| v.status.clone()) - }) - .collect(); - let slot = self - .block_store - .get_latest_block_info(CommitmentConfig::finalized()) - .await - .slot; - let mut rpc_url = String::from("http://0.0.0.0:8899"); - let home_path = std::env::var("HOME").unwrap(); - let is_existing = home_path.clone() + "/.config/tinydancer/config.json"; - let path = Path::new(&is_existing); - if path.exists() { - let file = fs::File::open(home_path.clone() + "/.config/tinydancer/config.json") - .expect("Error reading config in bridge"); - let config: ConfigSchema = serde_json::from_reader(file).unwrap(); - rpc_url = get_endpoint(config.cluster); - } else { - println!( - "{} {}", - "Initialise a config first using:".to_string().yellow(), - "tinydancer set config".to_string().green() - ); - } - let sampled = - pull_and_verify_shreds(slot as usize, String::from(rpc_url), 10 as usize).await; - Ok(LiteResponse { - context: LiteRpcResponseContext { - slot, - api_version: None, - sampled, - }, - value: sig_statuses, - }) - } - - fn get_version(&self) -> crate::rpc_wrapper::rpc::Result { - RPC_GET_VERSION.inc(); - - let version = solana_version::Version::default(); - Ok(RpcVersionInfo { - solana_core: version.to_string(), - feature_set: Some(version.feature_set), - }) - } - - async fn request_airdrop( - &self, - pubkey_str: String, - lamports: u64, - config: Option, - ) -> crate::rpc_wrapper::rpc::Result { - RPC_REQUEST_AIRDROP.inc(); - - let pubkey = match Pubkey::from_str(&pubkey_str) { - Ok(pubkey) => pubkey, - Err(err) => { - return Err(jsonrpsee::core::Error::Custom(err.to_string())); - } - }; - - let airdrop_sig = match self - .rpc_client - .request_airdrop_with_config(&pubkey, lamports, config.unwrap_or_default()) - .await - { - Ok(airdrop_sig) => airdrop_sig.to_string(), - Err(err) => { - return Err(jsonrpsee::core::Error::Custom(err.to_string())); - } - }; - - self.tx_sender - .txs_sent_store - .insert(airdrop_sig.clone(), Default::default()); - - Ok(airdrop_sig) - } - - fn signature_subscribe( - &self, - mut sink: SubscriptionSink, - signature: String, - commitment_config: CommitmentConfig, - ) -> SubscriptionResult { - RPC_SIGNATURE_SUBSCRIBE.inc(); - sink.accept()?; - self.block_listner - .signature_subscribe(signature, commitment_config, sink); - Ok(()) - } -} - -impl Deref for LiteBridge { - type Target = RpcClient; - - fn deref(&self) -> &Self::Target { - &self.rpc_client - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct LiteRpcResponseContext { - pub slot: Slot, - #[serde(skip_serializing_if = "Option::is_none")] - pub api_version: Option, - pub sampled: bool, -} -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct LiteResponse { - pub context: LiteRpcResponseContext, - pub value: T, -} diff --git a/tinydancer/src/rpc_wrapper/cli.rs b/tinydancer/src/rpc_wrapper/cli.rs deleted file mode 100644 index 5ce9421..0000000 --- a/tinydancer/src/rpc_wrapper/cli.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::rpc_wrapper::{ - DEFAULT_CLEAN_INTERVAL_MS, DEFAULT_FANOUT_SIZE, DEFAULT_RPC_ADDR, DEFAULT_TX_BATCH_INTERVAL_MS, - DEFAULT_TX_BATCH_SIZE, DEFAULT_WS_ADDR, -}; -use clap::Parser; - -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -pub struct Args { - #[arg(short, long, default_value_t = String::from(DEFAULT_RPC_ADDR))] - pub rpc_addr: String, - #[arg(short, long, default_value_t = String::from(DEFAULT_WS_ADDR))] - pub ws_addr: String, - #[arg(short = 'l', long, default_value_t = String::from("[::]:8890"))] - pub lite_rpc_http_addr: String, - #[arg(short = 's', long, default_value_t = String::from("[::]:8891"))] - pub lite_rpc_ws_addr: String, - /// batch size of each batch forward - #[arg(short = 'b', long, default_value_t = DEFAULT_TX_BATCH_SIZE)] - pub tx_batch_size: usize, - /// tpu fanout - #[arg(short = 'f', long, default_value_t = DEFAULT_FANOUT_SIZE) ] - pub fanout_size: u64, - /// interval between each batch forward - #[arg(short = 'i', long, default_value_t = DEFAULT_TX_BATCH_INTERVAL_MS)] - pub tx_batch_interval_ms: u64, - /// interval between clean - #[arg(short = 'c', long, default_value_t = DEFAULT_CLEAN_INTERVAL_MS)] - pub clean_interval_ms: u64, - #[arg(short = 'k', long, default_value_t = String::new())] - pub identity_keypair: String, -} diff --git a/tinydancer/src/rpc_wrapper/configs.rs b/tinydancer/src/rpc_wrapper/configs.rs deleted file mode 100644 index 357cf5a..0000000 --- a/tinydancer/src/rpc_wrapper/configs.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::rpc_wrapper::encoding::BinaryEncoding; -use serde::{Deserialize, Serialize}; -use solana_sdk::commitment_config::CommitmentLevel; - -#[derive(Debug, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SendTransactionConfig { - // #[serde(default)] - // pub skip_preflight: bool, - // #[serde(default)] - // pub preflight_commitment: CommitmentLevel, - #[serde(default)] - pub encoding: BinaryEncoding, - pub max_retries: Option, - // pub min_context_slot: Option, -} - -#[derive(Debug, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct IsBlockHashValidConfig { - pub commitment: Option, - // pub minContextSlot: Option, -} diff --git a/tinydancer/src/rpc_wrapper/encoding.rs b/tinydancer/src/rpc_wrapper/encoding.rs deleted file mode 100644 index 8bb28c4..0000000 --- a/tinydancer/src/rpc_wrapper/encoding.rs +++ /dev/null @@ -1,36 +0,0 @@ -use base64::Engine; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub enum BinaryEncoding { - #[default] - Base58, - Base64, -} - -#[derive(thiserror::Error, Debug)] -pub enum BinaryCodecError { - #[error("Base58DecodeError {0}")] - Base58DecodeError(#[from] bs58::decode::Error), - #[error("Base58EncodeError {0}")] - Base58EncodeError(#[from] bs58::encode::Error), - #[error("Base64DecodeError {0}")] - Base64DecodeError(#[from] base64::DecodeError), -} - -impl BinaryEncoding { - pub fn decode>(&self, to_decode: D) -> Result, BinaryCodecError> { - match self { - Self::Base58 => Ok(bs58::decode(to_decode).into_vec()?), - Self::Base64 => Ok(base64::engine::general_purpose::STANDARD.decode(to_decode)?), - } - } - - pub fn encode>(&self, to_encode: E) -> String { - match self { - Self::Base58 => bs58::encode(to_encode).into_string(), - Self::Base64 => base64::engine::general_purpose::STANDARD.encode(to_encode), - } - } -} diff --git a/tinydancer/src/rpc_wrapper/errors.rs b/tinydancer/src/rpc_wrapper/errors.rs deleted file mode 100644 index 1aa26ac..0000000 --- a/tinydancer/src/rpc_wrapper/errors.rs +++ /dev/null @@ -1,17 +0,0 @@ -use solana_sdk::{signature::ParseSignatureError, transport::TransportError}; - -use crate::rpc_wrapper::encoding::BinaryCodecError; - -#[derive(thiserror::Error, Debug)] -pub enum JsonRpcError { - #[error("TransportError {0}")] - TransportError(#[from] TransportError), - #[error("BinaryCodecError {0}")] - BinaryCodecError(#[from] BinaryCodecError), - #[error("BincodeDeserializeError {0}")] - BincodeDeserializeError(#[from] bincode::Error), - #[error("SerdeError {0}")] - SerdeError(#[from] serde_json::Error), - #[error("ParseSignatureError {0}")] - ParseSignatureError(#[from] ParseSignatureError), -} diff --git a/tinydancer/src/rpc_wrapper/mod.rs b/tinydancer/src/rpc_wrapper/mod.rs deleted file mode 100644 index 1fffe32..0000000 --- a/tinydancer/src/rpc_wrapper/mod.rs +++ /dev/null @@ -1,147 +0,0 @@ -//! Copyright (c) 2022 Blockworks Foundation -//! Permission is hereby granted, free of charge, to any person obtaining a copy -//! of this software and associated documentation files (the "Software"), to deal -//! in the Software without restriction, including without limitation the rights -//! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -//! copies of the Software, and to permit persons to whom the Software is -//! furnished to do so, subject to the following conditions: -//! The above copyright notice and this permission notice shall be included in all -//! copies or substantial portions of the Software. - -pub mod bridge; -pub mod configs; -pub mod encoding; -pub mod rpc; -pub mod tpu_manager; -pub mod workers; -// pub mod cli; -pub mod block_store; -use crate::convert_to_websocket; -use crate::rpc_wrapper::bridge::LiteBridge; -use crate::tinydancer::{endpoint, ClientService, Cluster}; -use anyhow::bail; -use async_trait::async_trait; -use clap::Parser; -use const_env::from_env; -use dotenv::dotenv; -use solana_client::nonblocking::rpc_client::RpcClient; -use solana_ledger::shred::Signer; -use solana_sdk::signer::keypair::Keypair; -use solana_transaction_status::TransactionConfirmationStatus; -use std::sync::Arc; -use std::{env, time::Duration}; -use tiny_logger::logs::info; -use tokio::task::JoinHandle; - -// use self::cli::Args; - -#[from_env] -pub const DEFAULT_RPC_ADDR: &str = "http://0.0.0.0:8899"; -#[from_env] -pub const DEFAULT_LITE_RPC_ADDR: &str = "http://0.0.0.0:8890"; -#[from_env] -pub const DEFAULT_WS_ADDR: &str = "ws://0.0.0.0:8900"; -#[from_env] -pub const DEFAULT_TX_MAX_RETRIES: u16 = 1; -#[from_env] -pub const DEFAULT_TX_BATCH_SIZE: usize = 128; -#[from_env] -pub const DEFAULT_FANOUT_SIZE: u64 = 32; -#[from_env] -pub const DEFAULT_TX_BATCH_INTERVAL_MS: u64 = 1; -#[from_env] -pub const DEFAULT_CLEAN_INTERVAL_MS: u64 = 5 * 60 * 1000; // five minute -#[from_env] -pub const DEFAULT_TX_SENT_TTL_S: u64 = 12; -pub const DEFAULT_TRANSACTION_CONFIRMATION_STATUS: TransactionConfirmationStatus = - TransactionConfirmationStatus::Finalized; - -pub struct TransactionService { - tx_handle: JoinHandle>, -} - -pub struct TransactionServiceConfig { - pub cluster: Cluster, - pub db_instance: Arc, -} - -async fn get_identity_keypair(identity_from_cli: &String) -> Keypair { - if let Ok(identity_env_var) = env::var("IDENTITY") { - if let Ok(identity_bytes) = serde_json::from_str::>(identity_env_var.as_str()) { - print!("HASIII TO HASU"); - Keypair::from_bytes(identity_bytes.as_slice()).unwrap() - } else { - // must be a file - let identity_file = tokio::fs::read_to_string(identity_env_var.as_str()) - .await - .expect("Cannot find the identity file provided"); - let identity_bytes: Vec = serde_json::from_str(&identity_file).unwrap(); - Keypair::from_bytes(identity_bytes.as_slice()).unwrap() - } - } else if identity_from_cli.is_empty() { - Keypair::new() - } else { - let identity_file = tokio::fs::read_to_string(identity_from_cli.as_str()) - .await - .expect("Cannot find the identity file provided"); - let identity_bytes: Vec = serde_json::from_str(&identity_file).unwrap(); - Keypair::from_bytes(identity_bytes.as_slice()).unwrap() - } -} - -#[async_trait] -impl ClientService for TransactionService { - type ServiceError = tokio::io::Error; - fn new(config: TransactionServiceConfig) -> Self { - let transaction_handle = tokio::spawn(async { - dotenv().ok(); - let rpc_url = endpoint(config.cluster); - - let payer = Keypair::new(); - - let tx_batch_interval_ms = Duration::from_millis(DEFAULT_TX_BATCH_INTERVAL_MS); - let clean_interval_ms = Duration::from_millis(DEFAULT_CLEAN_INTERVAL_MS); - - let light_bridge = LiteBridge::new( - String::from(rpc_url.clone()), - String::from(convert_to_websocket!(rpc_url)), - DEFAULT_FANOUT_SIZE, - payer, - config.db_instance, - ) - .await?; - - let services = light_bridge - .start_services( - String::from("[::]:8890"), - String::from("[::]:8891"), - DEFAULT_TX_BATCH_SIZE, - tx_batch_interval_ms, - clean_interval_ms, - ) - .await?; - - let services = futures::future::try_join_all(services); - - let ctrl_c_signal = tokio::signal::ctrl_c(); - - tokio::select! { - _ = services => { - bail!("Services quit unexpectedly"); - } - _ = ctrl_c_signal => { - info!("Received ctrl+c signal"); - Ok(()) - } - } - }); - Self { - tx_handle: transaction_handle, - } - } - - async fn join(self) -> std::result::Result<(), Self::ServiceError> { - let _ = self.tx_handle.await; - Ok(()) - } -} diff --git a/tinydancer/src/rpc_wrapper/rpc.rs b/tinydancer/src/rpc_wrapper/rpc.rs deleted file mode 100644 index 3da81e3..0000000 --- a/tinydancer/src/rpc_wrapper/rpc.rs +++ /dev/null @@ -1,57 +0,0 @@ -use jsonrpsee::proc_macros::rpc; -use solana_rpc_client_api::config::{ - RpcContextConfig, RpcRequestAirdropConfig, RpcSignatureStatusConfig, -}; -use solana_rpc_client_api::response::{Response as RpcResponse, RpcBlockhash, RpcVersionInfo}; -use solana_sdk::commitment_config::CommitmentConfig; -use solana_transaction_status::TransactionStatus; - -use crate::rpc_wrapper::configs::{IsBlockHashValidConfig, SendTransactionConfig}; - -use super::bridge::LiteResponse; - -pub type Result = std::result::Result; - -#[rpc(server)] -pub trait LiteRpc { - #[method(name = "sendTransaction")] - async fn send_transaction( - &self, - tx: String, - send_transaction_config: Option, - ) -> Result; - - #[method(name = "getLatestBlockhash")] - async fn get_latest_blockhash( - &self, - config: Option, - ) -> Result>; - - #[method(name = "isBlockhashValid")] - async fn is_blockhash_valid( - &self, - blockhash: String, - config: Option, - ) -> Result>; - - #[method(name = "getSignatureStatuses")] - async fn get_signature_statuses( - &self, - signature_strs: Vec, - config: Option, - ) -> Result>>>; - - #[method(name = "getVersion")] - fn get_version(&self) -> Result; - - #[method(name = "requestAirdrop")] - async fn request_airdrop( - &self, - pubkey_str: String, - lamports: u64, - config: Option, - ) -> Result; - - #[subscription(name = "signatureSubscribe" => "signatureNotification", unsubscribe="signatureUnsubscribe", item=RpcResponse)] - fn signature_subscribe(&self, signature: String, commitment_config: CommitmentConfig); -} diff --git a/tinydancer/src/rpc_wrapper/tpu_manager.rs b/tinydancer/src/rpc_wrapper/tpu_manager.rs deleted file mode 100644 index 079f7ab..0000000 --- a/tinydancer/src/rpc_wrapper/tpu_manager.rs +++ /dev/null @@ -1,145 +0,0 @@ -use std::{ - net::{IpAddr, Ipv4Addr}, - sync::{ - atomic::{AtomicU32, Ordering}, - Arc, - }, -}; - -use prometheus::{opts, register_int_counter, IntCounter}; -use solana_quic_client::{QuicConfig, QuicPool}; -use solana_rpc_client::nonblocking::rpc_client::RpcClient; -use solana_sdk::signature::Keypair; -use solana_tpu_client::{ - nonblocking::tpu_client::TpuClient, - tpu_client::TpuClientConfig, - tpu_connection_cache::{NewTpuConfig, TpuConnectionCache}, -}; -use tiny_logger::logs::info; -use tokio::sync::RwLock; - -pub type QuicTpuClient = TpuClient; -pub type QuicConnectionCache = TpuConnectionCache; - -const TPU_CONNECTION_CACHE_SIZE: usize = 8; - -lazy_static::lazy_static! { -static ref TPU_CONNECTION_RESET: IntCounter = - register_int_counter!(opts!("literpc_tpu_connection_reset", "Number of times tpu connection was reseted")).unwrap(); -} - -#[derive(Clone)] -pub struct TpuManager { - error_count: Arc, - rpc_client: Arc, - // why arc twice / one is so that we clone rwlock and other so that we can clone tpu client - tpu_client: Arc>>, - pub ws_addr: String, - fanout_slots: u64, - identity: Arc, -} - -impl TpuManager { - pub async fn new( - rpc_client: Arc, - ws_addr: String, - fanout_slots: u64, - identity: Keypair, - ) -> anyhow::Result { - let mut tpu_config = QuicConfig::new().unwrap(); - tpu_config - .update_client_certificate(&identity, IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))) - .unwrap(); - - let connection_cache = - QuicConnectionCache::new_with_config(TPU_CONNECTION_CACHE_SIZE, tpu_config); - let connection_cache = Arc::new(connection_cache); - let tpu_client = - Self::new_tpu_client(rpc_client.clone(), &ws_addr, fanout_slots, connection_cache) - .await?; - let tpu_client = Arc::new(RwLock::new(Arc::new(tpu_client))); - - Ok(Self { - rpc_client, - tpu_client, - ws_addr, - fanout_slots, - error_count: Default::default(), - identity: Arc::new(identity), - }) - } - - pub async fn new_tpu_client( - rpc_client: Arc, - ws_addr: &str, - fanout_slots: u64, - connection_cache: Arc, - ) -> anyhow::Result { - Ok(TpuClient::new_with_connection_cache( - rpc_client.clone(), - ws_addr, - TpuClientConfig { fanout_slots }, - connection_cache, - ) - .await?) - } - - pub async fn reset_tpu_client(&self) -> anyhow::Result<()> { - let mut tpu_config = QuicConfig::new().unwrap(); - tpu_config - .update_client_certificate(&self.identity, IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))) - .unwrap(); - let connection_cache = - QuicConnectionCache::new_with_config(TPU_CONNECTION_CACHE_SIZE, tpu_config); - let connection_cache = Arc::new(connection_cache); - - let tpu_client = Self::new_tpu_client( - self.rpc_client.clone(), - &self.ws_addr, - self.fanout_slots, - connection_cache, - ) - .await?; - self.error_count.store(0, Ordering::Relaxed); - *self.tpu_client.write().await = Arc::new(tpu_client); - TPU_CONNECTION_RESET.inc(); - Ok(()) - } - - pub async fn reset(&self) -> anyhow::Result<()> { - self.error_count.fetch_add(1, Ordering::Relaxed); - - if self.error_count.load(Ordering::Relaxed) > 5 { - self.reset_tpu_client().await?; - info!("TPU Reset after 5 errors"); - } - - Ok(()) - } - - async fn get_tpu_client(&self) -> Arc { - self.tpu_client.read().await.clone() - } - - pub async fn try_send_wire_transaction_batch( - &self, - wire_transactions: Vec>, - ) -> anyhow::Result<()> { - let tpu_client = self.get_tpu_client().await; - match tpu_client - .try_send_wire_transaction_batch(wire_transactions) - .await - { - Ok(_) => Ok(()), - Err(err) => { - self.reset().await?; - Err(err.into()) - } - } - } - - pub async fn estimated_current_slot(&self) -> u64 { - let tpu_client = self.get_tpu_client().await; - tpu_client.estimated_current_slot() - } -} diff --git a/tinydancer/src/rpc_wrapper/workers/block_listenser.rs b/tinydancer/src/rpc_wrapper/workers/block_listenser.rs deleted file mode 100644 index f966082..0000000 --- a/tinydancer/src/rpc_wrapper/workers/block_listenser.rs +++ /dev/null @@ -1,419 +0,0 @@ -use std::{ - collections::VecDeque, - sync::{atomic::AtomicU64, Arc}, - time::Duration, -}; - -use dashmap::DashMap; -use jsonrpsee::SubscriptionSink; -use prometheus::{ - core::GenericGauge, histogram_opts, opts, register_histogram, register_int_counter, - register_int_gauge, Histogram, IntCounter, -}; -use tiny_logger::logs::{info, warn}; - -use solana_rpc_client::nonblocking::rpc_client::RpcClient; -use solana_rpc_client_api::{ - config::RpcBlockConfig, - response::{Response as RpcResponse, RpcResponseContext}, -}; - -use solana_sdk::{ - commitment_config::{CommitmentConfig, CommitmentLevel}, - slot_history::Slot, -}; - -use solana_transaction_status::{ - option_serializer::OptionSerializer, RewardType, TransactionConfirmationStatus, - TransactionDetails, TransactionStatus, UiConfirmedBlock, UiTransactionEncoding, - UiTransactionStatusMeta, -}; -use tokio::{ - sync::{mpsc::Sender, Mutex}, - task::JoinHandle, - time::Instant, -}; - -use crate::rpc_wrapper::block_store::{BlockInformation, BlockStore}; - -use super::{TxProps, TxSender}; - -lazy_static::lazy_static! { - static ref TT_RECV_CON_BLOCK: Histogram = register_histogram!(histogram_opts!( - "literpc_tt_recv_con_block", - "Time to receive confirmed block from block subscribe", - )) - .unwrap(); - static ref TT_RECV_FIN_BLOCK: Histogram = register_histogram!(histogram_opts!( - "literpc_tt_recv_fin_block", - "Time to receive finalized block from block subscribe", - )) - .unwrap(); - static ref FIN_BLOCKS_RECV: IntCounter = - register_int_counter!(opts!("literpc_fin_blocks_recv", "Number of Finalized Blocks Received")).unwrap(); - static ref CON_BLOCKS_RECV: IntCounter = - register_int_counter!(opts!("literpc_con_blocks_recv", "Number of Confirmed Blocks Received")).unwrap(); - static ref INCOMPLETE_FIN_BLOCKS_RECV: IntCounter = - register_int_counter!(opts!("literpc_incomplete_fin_blocks_recv", "Number of Incomplete Finalized Blocks Received")).unwrap(); - static ref INCOMPLETE_CON_BLOCKS_RECV: IntCounter = - register_int_counter!(opts!("literpc_incomplete_con_blocks_recv", "Number of Incomplete Confirmed Blocks Received")).unwrap(); - static ref TXS_CONFIRMED: IntCounter = - register_int_counter!(opts!("literpc_txs_confirmed", "Number of Transactions Confirmed")).unwrap(); - static ref TXS_FINALIZED: IntCounter = - register_int_counter!(opts!("literpc_txs_finalized", "Number of Transactions Finalized")).unwrap(); - static ref ERRORS_WHILE_FETCHING_SLOTS: IntCounter = - register_int_counter!(opts!("literpc_txs_finalized", "Number of Transactions Finalized")).unwrap(); - static ref BLOCKS_IN_QUEUE: GenericGauge = register_int_gauge!(opts!("literpc_blocks_in_queue", "Number of blocks waiting to deque")).unwrap(); - static ref BLOCKS_IN_RETRY_QUEUE: GenericGauge = register_int_gauge!(opts!("literpc_blocks_in_retry_queue", "Number of blocks waiting in retry")).unwrap(); - static ref NUMBER_OF_SIGNATURE_SUBSCRIBERS: GenericGauge = register_int_gauge!(opts!("literpc_number_of_signature_sub", "Number of signature subscriber")).unwrap(); -} - -/// Background worker which listen's to new blocks -/// and keeps a track of confirmed txs -#[derive(Clone)] -pub struct BlockListener { - tx_sender: TxSender, - block_store: BlockStore, - rpc_client: Arc, - signature_subscribers: Arc>, -} - -pub struct BlockListnerNotificatons { - pub block: Sender, - pub tx: Sender, -} - -impl BlockListener { - pub fn new(rpc_client: Arc, tx_sender: TxSender, block_store: BlockStore) -> Self { - Self { - rpc_client, - tx_sender, - block_store, - signature_subscribers: Default::default(), - } - } - - pub async fn num_of_sigs_commited(&self, sigs: &[String]) -> usize { - let mut num_of_sigs_commited = 0; - for sig in sigs { - if self.tx_sender.txs_sent_store.contains_key(sig) { - num_of_sigs_commited += 1; - } - } - num_of_sigs_commited - } - - #[allow(deprecated)] - fn get_supported_commitment_config(commitment_config: CommitmentConfig) -> CommitmentConfig { - match commitment_config.commitment { - CommitmentLevel::Finalized | CommitmentLevel::Root | CommitmentLevel::Max => { - CommitmentConfig { - commitment: CommitmentLevel::Finalized, - } - } - _ => CommitmentConfig { - commitment: CommitmentLevel::Confirmed, - }, - } - } - - pub fn signature_subscribe( - &self, - signature: String, - commitment_config: CommitmentConfig, - sink: SubscriptionSink, - ) { - let commitment_config = Self::get_supported_commitment_config(commitment_config); - self.signature_subscribers - .insert((signature, commitment_config), (sink, Instant::now())); - NUMBER_OF_SIGNATURE_SUBSCRIBERS.inc(); - } - - pub fn signature_un_subscribe(&self, signature: String, commitment_config: CommitmentConfig) { - let commitment_config = Self::get_supported_commitment_config(commitment_config); - self.signature_subscribers - .remove(&(signature, commitment_config)); - NUMBER_OF_SIGNATURE_SUBSCRIBERS.dec(); - } - - fn increment_invalid_block_metric(commitment_config: CommitmentConfig) { - if commitment_config.is_finalized() { - INCOMPLETE_FIN_BLOCKS_RECV.inc(); - } else { - INCOMPLETE_CON_BLOCKS_RECV.inc(); - } - } - - pub async fn index_slot( - &self, - slot: Slot, - commitment_config: CommitmentConfig, - ) -> anyhow::Result<()> { - //info!("indexing slot {} commitment {}", slot, commitment_config.commitment); - let comfirmation_status = match commitment_config.commitment { - CommitmentLevel::Finalized => TransactionConfirmationStatus::Finalized, - _ => TransactionConfirmationStatus::Confirmed, - }; - - let timer = if commitment_config.is_finalized() { - TT_RECV_FIN_BLOCK.start_timer() - } else { - TT_RECV_CON_BLOCK.start_timer() - }; - - let start = Instant::now(); - - let block = self - .rpc_client - .get_block_with_config( - slot, - RpcBlockConfig { - transaction_details: Some(TransactionDetails::Full), - commitment: Some(commitment_config), - max_supported_transaction_version: Some(0), - encoding: Some(UiTransactionEncoding::Base64), - rewards: Some(true), - }, - ) - .await?; - timer.observe_duration(); - - if commitment_config.is_finalized() { - FIN_BLOCKS_RECV.inc(); - } else { - CON_BLOCKS_RECV.inc(); - }; - - let Some(block_height) = block.block_height else { - Self::increment_invalid_block_metric(commitment_config); - return Ok(()); - }; - - let Some(transactions) = block.transactions else { - Self::increment_invalid_block_metric(commitment_config); - return Ok(()); - }; - - let blockhash = block.blockhash; - //let parent_slot = block.parent_slot; - - self.block_store - .add_block( - blockhash.clone(), - BlockInformation { - slot, - block_height, - instant: Instant::now(), - }, - commitment_config, - ) - .await; - - let mut transactions_processed = 0; - for tx in transactions { - let Some(UiTransactionStatusMeta { err, status, compute_units_consumed: _ ,.. }) = tx.meta else { - info!("tx with no meta"); - continue; - }; - - let tx = match tx.transaction.decode() { - Some(tx) => tx, - None => { - warn!("transaction could not be decoded"); - continue; - } - }; - transactions_processed += 1; - let sig = tx.signatures[0].to_string(); - - if let Some(mut tx_status) = self.tx_sender.txs_sent_store.get_mut(&sig) { - // - // Metrics - // - if status.is_ok() { - if commitment_config.is_finalized() { - TXS_FINALIZED.inc(); - } else { - TXS_CONFIRMED.inc(); - } - } - - tx_status.value_mut().status = Some(TransactionStatus { - slot, - confirmations: None, - status, - err: err.clone(), - confirmation_status: Some(comfirmation_status.clone()), - }); - }; - - // subscribers - if let Some((_sig, (mut sink, _))) = - self.signature_subscribers.remove(&(sig, commitment_config)) - { - // none if transaction succeeded - sink.send(&RpcResponse { - context: RpcResponseContext { - slot, - api_version: None, - }, - value: serde_json::json!({ "err": err }), - })?; - NUMBER_OF_SIGNATURE_SUBSCRIBERS.dec(); - } - } - - info!( - "Number of transactions processed {} for slot {} for commitment {} time taken {} ms", - transactions_processed, - slot, - commitment_config.commitment, - start.elapsed().as_millis() - ); - - Ok(()) - } - pub fn listen(self, commitment_config: CommitmentConfig) -> JoinHandle> { - let slots_task_queue = Arc::new(Mutex::new(VecDeque::<(u64, u8)>::new())); - let (slot_retry_queue_sx, mut slot_retry_queue_rx) = tokio::sync::mpsc::unbounded_channel(); - - // task to fetch blocks - for _i in 0..6 { - let this = self.clone(); - let slots_task_queue = slots_task_queue.clone(); - let slot_retry_queue_sx = slot_retry_queue_sx.clone(); - - tokio::spawn(async move { - let slots_task_queue = slots_task_queue.clone(); - loop { - let (slot, error_count) = { - let mut queue = slots_task_queue.lock().await; - match queue.pop_front() { - Some(t) => t, - None => { - // no task - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - continue; - } - } - }; - - if let Err(_) = this.index_slot(slot, commitment_config).await { - // usually as we index all the slots even if they are not been processed we get some errors for slot - // as they are not in long term storage of the rpc // we check 5 times before ignoring the slot - - if error_count > 5 { - // retried for 10 times / there should be no block for this slot - warn!( - "unable to get block at slot {} and commitment {}", - slot, commitment_config.commitment - ); - continue; - } else { - // add a task to be queued after a delay - let retry_at = tokio::time::Instant::now() - .checked_add(Duration::from_millis(100)) - .unwrap(); - let _ = slot_retry_queue_sx.send((slot, error_count, retry_at)); - BLOCKS_IN_RETRY_QUEUE.inc(); - } - }; - } - }); - } - - // a task that will queue back the slots to be retried after a certain delay - let recent_slot = Arc::new(AtomicU64::new(0)); - { - let slots_task_queue = slots_task_queue.clone(); - let recent_slot = recent_slot.clone(); - tokio::spawn(async move { - loop { - match slot_retry_queue_rx.recv().await { - Some((slot, error_count, instant)) => { - BLOCKS_IN_RETRY_QUEUE.dec(); - let recent_slot = - recent_slot.load(std::sync::atomic::Ordering::Relaxed); - // if slot is too old ignore - if recent_slot.saturating_sub(slot) > 256 { - // slot too old to retry - // most probably its an empty slot - continue; - } - - let now = tokio::time::Instant::now(); - if now < instant { - tokio::time::sleep_until(instant).await; - } - let mut queue = slots_task_queue.lock().await; - queue.push_back((slot, error_count + 1)); - } - None => { - break; - } - } - } - }); - } - - let rpc_client = self.rpc_client.clone(); - tokio::spawn(async move { - let slots_task_queue = slots_task_queue.clone(); - let last_latest_slot = self - .block_store - .get_latest_block_info(commitment_config) - .await - .slot; - // -5 for warmup - let mut last_latest_slot = last_latest_slot - 5; - recent_slot.store(last_latest_slot, std::sync::atomic::Ordering::Relaxed); - - // storage for recent slots processed - let rpc_client = rpc_client.clone(); - loop { - let new_slot = match rpc_client.get_slot_with_commitment(commitment_config).await { - Ok(new_slot) => new_slot, - Err(err) => { - warn!("Error while fetching slot {err:?}"); - ERRORS_WHILE_FETCHING_SLOTS.inc(); - tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; - continue; - } - }; - - if last_latest_slot == new_slot { - warn!("No new slots"); - tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; - continue; - } - - // filter already processed slots - let new_block_slots: Vec = (last_latest_slot..new_slot).collect(); - // context for lock - { - let mut lock = slots_task_queue.lock().await; - for slot in new_block_slots { - lock.push_back((slot, 0)); - } - BLOCKS_IN_QUEUE.set(lock.len() as i64); - } - - last_latest_slot = new_slot; - recent_slot.store(last_latest_slot, std::sync::atomic::Ordering::Relaxed); - tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; - } - }) - } - - pub fn clean(&self, ttl_duration: Duration) { - let length_before = self.signature_subscribers.len(); - self.signature_subscribers - .retain(|_k, (sink, instant)| !sink.is_closed() && instant.elapsed() < ttl_duration); - - NUMBER_OF_SIGNATURE_SUBSCRIBERS.set(self.signature_subscribers.len() as i64); - info!( - "Cleaned {} Signature Subscribers", - length_before - self.signature_subscribers.len() - ); - } -} diff --git a/tinydancer/src/rpc_wrapper/workers/cleaner.rs b/tinydancer/src/rpc_wrapper/workers/cleaner.rs deleted file mode 100644 index 20d0af7..0000000 --- a/tinydancer/src/rpc_wrapper/workers/cleaner.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::{sync::Arc, time::Duration}; - -use tiny_logger::logs::info; -use tokio::task::JoinHandle; - -use crate::rpc_wrapper::{block_store::BlockStore, tpu_manager::TpuManager}; - -use super::{BlockListener, TxSender}; - -/// Background worker which cleans up memory -#[derive(Clone)] -pub struct Cleaner { - tx_sender: TxSender, - block_listenser: BlockListener, - block_store: BlockStore, - tpu_manager: Arc, -} - -impl Cleaner { - pub fn new( - tx_sender: TxSender, - block_listenser: BlockListener, - block_store: BlockStore, - tpu_manager: Arc, - ) -> Self { - Self { - tx_sender, - block_listenser, - block_store, - tpu_manager, - } - } - - pub fn clean_tx_sender(&self, ttl_duration: Duration) { - let length_before = self.tx_sender.txs_sent_store.len(); - self.tx_sender - .txs_sent_store - .retain(|_k, v| v.sent_at.elapsed() < ttl_duration); - info!( - "Cleaned {} transactions", - length_before - self.tx_sender.txs_sent_store.len() - ); - } - - /// Clean Signature Subscribers from Block Listeners - pub fn clean_block_listeners(&self, ttl_duration: Duration) { - self.block_listenser.clean(ttl_duration); - } - - pub async fn clean_block_store(&self, ttl_duration: Duration) { - self.block_store.clean(ttl_duration).await; - } - - pub fn start(self, ttl_duration: Duration) -> JoinHandle> { - let mut ttl = tokio::time::interval(ttl_duration); - - tokio::spawn(async move { - info!("Cleaning memory"); - - loop { - ttl.tick().await; - - self.clean_tx_sender(ttl_duration); - self.clean_block_listeners(ttl_duration); - self.clean_block_store(ttl_duration).await; - let _ = self.tpu_manager.reset_tpu_client().await; - } - }) - } -} diff --git a/tinydancer/src/rpc_wrapper/workers/mod.rs b/tinydancer/src/rpc_wrapper/workers/mod.rs deleted file mode 100644 index 770fc17..0000000 --- a/tinydancer/src/rpc_wrapper/workers/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod block_listenser; -mod cleaner; -mod tx_sender; - -pub use block_listenser::*; -pub use cleaner::*; -pub use tx_sender::*; diff --git a/tinydancer/src/rpc_wrapper/workers/tx_sender.rs b/tinydancer/src/rpc_wrapper/workers/tx_sender.rs deleted file mode 100644 index 3a05824..0000000 --- a/tinydancer/src/rpc_wrapper/workers/tx_sender.rs +++ /dev/null @@ -1,179 +0,0 @@ -use std::{ - sync::Arc, - time::{Duration, Instant}, -}; - -use anyhow::bail; -use dashmap::DashMap; -use tiny_logger::logs::{info, warn}; - -use prometheus::{ - core::GenericGauge, histogram_opts, opts, register_histogram, register_int_counter, - register_int_gauge, Histogram, IntCounter, -}; -use solana_transaction_status::TransactionStatus; -use tokio::{ - sync::Semaphore, - sync::{mpsc::UnboundedReceiver, OwnedSemaphorePermit}, - task::JoinHandle, -}; - -use crate::rpc_wrapper::{bridge::TXS_IN_CHANNEL, tpu_manager::TpuManager}; - -lazy_static::lazy_static! { - static ref TXS_SENT: IntCounter = - register_int_counter!("literpc_txs_sent", "Number of transactions forwarded to tpu").unwrap(); - static ref TXS_SENT_ERRORS: IntCounter = - register_int_counter!("literpc_txs_sent_errors", "Number of errors while transactions forwarded to tpu").unwrap(); - static ref TX_BATCH_SIZES: GenericGauge = register_int_gauge!(opts!("literpc_tx_batch_size", "batchsize of tx sent by literpc")).unwrap(); - static ref TT_SENT_TIMER: Histogram = register_histogram!(histogram_opts!( - "literpc_txs_send_timer", - "Time to send transaction batch", - )) - .unwrap(); -} - -pub type WireTransaction = Vec; -const NUMBER_OF_TX_SENDERS: usize = 5; - -/// Retry transactions to a maximum of `u16` times, keep a track of confirmed transactions -#[derive(Clone)] -pub struct TxSender { - /// Tx(s) forwarded to tpu - pub txs_sent_store: Arc>, - /// TpuClient to call the tpu port - pub tpu_manager: Arc, -} - -/// Transaction Properties -pub struct TxProps { - pub status: Option, - /// Time at which transaction was forwarded - pub sent_at: Instant, -} - -impl Default for TxProps { - fn default() -> Self { - Self { - status: Default::default(), - sent_at: Instant::now(), - } - } -} - -impl TxSender { - pub fn new(tpu_manager: Arc) -> Self { - Self { - tpu_manager, - txs_sent_store: Default::default(), - } - } - - /// retry enqued_tx(s) - async fn forward_txs( - &self, - sigs_and_slots: Vec<(String, u64)>, - txs: Vec, - permit: OwnedSemaphorePermit, - ) { - assert_eq!(sigs_and_slots.len(), txs.len()); - - if sigs_and_slots.is_empty() { - return; - } - - let histo_timer = TT_SENT_TIMER.start_timer(); - let start = Instant::now(); - - let tpu_client = self.tpu_manager.clone(); - let txs_sent = self.txs_sent_store.clone(); - - for (sig, _) in &sigs_and_slots { - txs_sent.insert(sig.to_owned(), TxProps::default()); - } - - let _quic_response = match tpu_client.try_send_wire_transaction_batch(txs).await { - Ok(_) => { - // metrics - TXS_SENT.inc_by(sigs_and_slots.len() as u64); - 1 - } - Err(err) => { - TXS_SENT_ERRORS.inc_by(sigs_and_slots.len() as u64); - warn!("{err}"); - 0 - } - }; - drop(permit); - histo_timer.observe_duration(); - info!( - "It took {} ms to send a batch of {} transaction(s)", - start.elapsed().as_millis(), - sigs_and_slots.len() - ); - } - - /// retry and confirm transactions every 2ms (avg time to confirm tx) - pub fn execute( - self, - mut recv: UnboundedReceiver<(String, WireTransaction, u64)>, - tx_batch_size: usize, - tx_send_interval: Duration, - ) -> JoinHandle> { - tokio::spawn(async move { - info!( - "Batching tx(s) with batch size of {tx_batch_size} every {}ms", - tx_send_interval.as_millis() - ); - let semaphore = Arc::new(Semaphore::new(NUMBER_OF_TX_SENDERS)); - loop { - let mut sigs_and_slots = Vec::with_capacity(tx_batch_size); - let mut txs = Vec::with_capacity(tx_batch_size); - let mut permit = None; - - while txs.len() <= tx_batch_size { - match tokio::time::timeout(tx_send_interval, recv.recv()).await { - Ok(value) => match value { - Some((sig, tx, slot)) => { - TXS_IN_CHANNEL.dec(); - sigs_and_slots.push((sig, slot)); - txs.push(tx); - } - None => { - bail!("Channel Disconnected"); - } - }, - Err(_) => { - permit = semaphore.clone().try_acquire_owned().ok(); - if permit.is_some() { - // we have a permit we can send collected transaction batch - break; - } - } - } - } - assert_eq!(sigs_and_slots.len(), txs.len()); - - if sigs_and_slots.is_empty() { - continue; - } - - let permit = match permit { - Some(permit) => permit, - None => { - // get the permit - semaphore.clone().acquire_owned().await.unwrap() - } - }; - - if !txs.is_empty() { - TX_BATCH_SIZES.set(txs.len() as i64); - let tx_sender = self.clone(); - tokio::spawn(async move { - tx_sender.forward_txs(sigs_and_slots, txs, permit).await; - }); - } - } - }) - } -} diff --git a/tinydancer/src/sampler.rs b/tinydancer/src/sampler.rs deleted file mode 100644 index 4d7448a..0000000 --- a/tinydancer/src/sampler.rs +++ /dev/null @@ -1,599 +0,0 @@ -use crate::tinydancer::{endpoint, ClientService, ClientStatus, Cluster}; -use crate::{convert_to_websocket, send_rpc_call, try_coerce_shred}; -use anyhow::anyhow; -use async_trait::async_trait; -use crossbeam::channel::{Receiver, Sender}; -use futures::Sink; -use itertools::Itertools; -use rand::distributions::Uniform; -use rand::prelude::*; -use rayon::prelude::*; -use reqwest::Request; -use rocksdb::{ColumnFamily, Options as RocksOptions, DB}; -use serde::de::DeserializeOwned; -use solana_ledger::shred::{ShredId, ShredType}; -use solana_ledger::{ - ancestor_iterator::{AncestorIterator, AncestorIteratorWithHash}, - blockstore::Blockstore, - // blockstore_db::columns::ShredCode, - shred::{Nonce, Shred, ShredCode, ShredData, ShredFetchStats, SIZE_OF_NONCE}, -}; -use solana_sdk::hash::hashv; -use solana_sdk::{ - clock::Slot, - genesis_config::ClusterType, - hash::{Hash, HASH_BYTES}, - packet::PACKET_DATA_SIZE, - pubkey::{Pubkey, PUBKEY_BYTES}, - signature::{Signable, Signature, Signer, SIGNATURE_BYTES}, - signer::keypair::Keypair, - timing::{duration_as_ms, timestamp}, -}; -use std::str::FromStr; -use std::sync::atomic::{AtomicU32, Ordering}; -use std::sync::{Arc, Mutex, MutexGuard}; -use std::{error::Error, ops::Add}; -use std::{ - net::{SocketAddr, UdpSocket}, - thread::Builder, -}; -use tiny_logger::logs::{debug, error, info}; -use tokio::{ - sync::mpsc::UnboundedSender, - task::{JoinError, JoinHandle}, -}; -use tungstenite::{connect, Message}; -use url::Url; - -pub const SHRED_CF: &str = "archived_shreds"; - -pub struct SampleService { - sample_indices: Vec, - // peers: Vec<(Pubkey, SocketAddr)>, - sampler_handle: JoinHandle<()>, -} -pub struct SampleServiceConfig { - pub cluster: Cluster, - pub archive_config: ArchiveConfig, - pub instance: Arc, - pub status_sampler: Arc>, - pub sample_qty: usize, -} - -#[derive(Clone, Debug)] -pub struct ArchiveConfig { - pub shred_archive_duration: u64, - pub archive_path: String, -} - -#[async_trait] -impl ClientService for SampleService { - type ServiceError = tokio::task::JoinError; - - fn new(config: SampleServiceConfig) -> Self { - let sampler_handle = tokio::spawn(async move { - let rpc_url = endpoint(config.cluster); - let pub_sub = convert_to_websocket!(rpc_url); - - let mut threads = Vec::default(); - - let (slot_update_tx, slot_update_rx) = crossbeam::channel::unbounded::(); - let (shred_tx, shred_rx) = crossbeam::channel::unbounded(); - let (verified_shred_tx, verified_shred_rx) = crossbeam::channel::unbounded(); - - let status_arc = config.status_sampler.clone(); - - // waits on new slots => triggers shred_update_loop - threads.push(tokio::spawn(slot_update_loop( - slot_update_tx, - pub_sub, - config.status_sampler, - ))); - - // sample shreds from new slot - // verify each shred in shred_verify_loop - threads.push(tokio::spawn(shred_update_loop( - slot_update_rx, - rpc_url, - shred_tx, - status_arc, - config.sample_qty, - ))); - - // verify shreds + store in db in shred_archiver - threads.push(tokio::spawn(shred_verify_loop(shred_rx, verified_shred_tx))); - - threads.push(tokio::spawn(shred_archiver( - verified_shred_rx, - config.archive_config, - config.instance, - ))); - - for thread in threads { - thread.await; - } - }); - - Self { - sampler_handle, - sample_indices: Vec::default(), - } - } - - async fn join(self) -> std::result::Result<(), Self::ServiceError> { - self.sampler_handle.await - } -} - -pub fn gen_random_indices(max_shreds_per_slot: usize, sample_qty: usize) -> Vec { - let mut rng = StdRng::from_entropy(); - let vec = (0..sample_qty) - .map(|_| rng.gen_range(0..max_shreds_per_slot)) - .collect::>(); - vec -} - -pub async fn request_shreds( - slot: usize, - indices: Vec, - endpoint: String, -) -> Result { - let request = serde_json::json!({ - "jsonrpc": "2.0", - "id": 1, - "method": "getShreds", - "params":[ - slot, - indices, - { "commitment": "confirmed" } - ] - }) // getting one shred just to get max shreds per slot, can maybe randomize the selection here - .to_string(); - - let res = send_rpc_call!(endpoint, request); - // info!("{:?}", res); - serde_json::from_str::(&res) -} - -async fn slot_update_loop( - slot_update_tx: Sender, - pub_sub: String, - status_sampler: Arc>, -) -> anyhow::Result<()> { - let result = match connect(Url::parse(pub_sub.as_str()).unwrap()) { - Ok((socket, _response)) => Some((socket, _response)), - Err(_) => { - let mut status = status_sampler.lock().unwrap(); - *status = ClientStatus::Crashed(String::from("Client can't connect to socket")); - None - } - }; - - if result.is_none() { - return Err(anyhow!("")); - } - let (mut socket, _response) = result.unwrap(); - - socket.write_message(Message::Text( - r#"{ "jsonrpc": "2.0", "id": 1, "method": "slotSubscribe" }"#.into(), - ))?; - - loop { - match socket.read_message() { - Ok(msg) => { - let res = serde_json::from_str::(msg.to_string().as_str()); - - // info!("res: {:?}", msg.to_string().as_str()); - if let Ok(res) = res { - match slot_update_tx.send(res.params.result.root as u64) { - Ok(_) => { - info!("slot updated: {:?}", res.params.result.root); - } - Err(e) => { - info!("error here: {:?} {:?}", e, res.params.result.root as u64); - continue; // @TODO: we should add retries here incase send fails for some reason - } - } - } - } - Err(e) => info!("err: {:?}", e), - } - } -} - -macro_rules! unwrap_or_return { - (Result $var:ident) => { - if let Err(e) = $var { - return Err(e.into()); - } else { - $var.unwrap() - } - }; - (Option $var:ident $err:expr) => { - if $var.is_none() { - return Err(anyhow!($err)); - } else { - $var.unwrap() - } - }; - (OptionRef $var:ident $err:expr) => { - if $var.is_none() { - return Err(anyhow!($err)); - } else { - $var.as_ref().unwrap() - } - }; -} - -async fn get_shreds_and_leader_for_slot( - slot: u64, - endpoint: &String, - sample_qty: usize, -) -> anyhow::Result<(Vec>, Pubkey)> { - // get shred length (max_shreds_per_slot) - let first_shred = request_shreds(slot as usize, vec![0], endpoint.clone()).await; - let first_shred = unwrap_or_return!(Result first_shred); - - let first_shred = &first_shred.result.shreds[1]; - let first_shred = unwrap_or_return!(OptionRef first_shred "first shred not found"); - - let max_shreds_per_slot = { - if let Some(data_shred) = &first_shred.shred_data { - Shred::ShredData(data_shred.clone()) - .num_data_shreds() - .expect("num data shreds error") - } else if let Some(code_shred) = &first_shred.shred_code { - Shred::ShredCode(code_shred.clone()) - .num_coding_shreds() - .expect("num code shreds error") - } else { - // todo - return Err(anyhow!("shred isnt either data or code type")); - } - }; - - // get a random sample of shreds - let mut shred_indices_for_slot = gen_random_indices(max_shreds_per_slot as usize, sample_qty); // unwrap only temporary - shred_indices_for_slot.push(0_usize); - info!("indices of: {:?} {:?}", shred_indices_for_slot, slot); - - let shreds_for_slot = request_shreds( - slot as usize, - shred_indices_for_slot.clone(), - endpoint.clone(), - ) - .await; - let shreds_for_slot = unwrap_or_return!(Result shreds_for_slot); - - info!("get shred for slot in 2nd req"); - let mut shreds: Vec> = shreds_for_slot - .result - .shreds - .par_iter() - .map(|s| try_coerce_shred!(s)) - .collect(); - - // info!("before leader"); - let leader = solana_ledger::shred::Pubkey::from_str(shreds_for_slot.result.leader.as_str())?; - - // info!("leader {:?}", leader); - let mut fullfill_count = AtomicU32::new(0u32); - shreds.dedup(); - shreds.iter().for_each(|f| { - if let Some(s) = f { - info!("{:?}", s.index()); - } - }); - - shreds.par_iter().for_each(|s| { - if let Some(s) = s { - match shred_indices_for_slot.contains(&(s.index() as usize)) { - true => { - fullfill_count.fetch_add(1, Ordering::Relaxed); - info!( - "Received requested shred: {:?} for slot: {:?}", - s.index(), - s.slot() - ) - } - false => info!( - "Received unrequested shred index: {:?} for slot: {:?}", - s.index(), - s.slot() - ), - } - } else { - info!("Received empty") - } - }); - - if (fullfill_count.get_mut().to_owned() as usize) < shred_indices_for_slot.len() { - info!("Received incomplete number of shreds, requested {:?} shreds for slot {:?} and received {:?}", shred_indices_for_slot.len(),slot, fullfill_count); - } - - Ok((shreds, leader)) -} - -async fn shred_update_loop( - slot_update_rx: Receiver, - endpoint: String, - shred_tx: Sender<(Vec>, solana_ledger::shred::Pubkey)>, - status_sampler: Arc>, - sample_qty: usize, -) -> anyhow::Result<()> { - loop { - { - let mut status = status_sampler.lock().unwrap(); - if let ClientStatus::Crashed(_) = &*status { - return Err(anyhow!("Client crashed")); - } else { - *status = ClientStatus::Active(String::from( - "Monitoring Tinydancer: Actively Sampling Shreds", - )); - } - } - - if let Ok(slot) = slot_update_rx.recv() { - let shreds = get_shreds_and_leader_for_slot(slot, &endpoint, sample_qty).await; - if let Err(e) = shreds { - info!("{}", e); - continue; - } - let (shreds, leader) = shreds.unwrap(); - - shred_tx - .send((shreds, leader)) - .expect("shred tx send error"); - } - } -} - -// use solana_ledger::shred::dispatch; - -// verifies the merkle proof of the shread -pub fn verify_sample(shred: &Shred, leader: solana_ledger::shred::Pubkey) -> bool { - // @TODO fix error handling here - let verify_merkle_root = match shred { - Shred::ShredData(ShredData::Merkle(shred)) => Some(shred.verify_merkle_proof()), - Shred::ShredCode(ShredCode::Merkle(shred)) => Some(shred.verify_merkle_proof()), - _ => None, - }; - - let verified = vec![shred.verify(&leader), { - if let Some(proof) = verify_merkle_root { - match proof { - Ok(validated) => validated, - Err(e) => panic!("{}", e), - } - } else { - panic!("This was not a merkle shred"); // @TODO figure out how to handle this properly - } - }] - .iter() - .all(|s| *s); - verified -} - -pub async fn shred_verify_loop( - shred_rx: Receiver<(Vec>, solana_ledger::shred::Pubkey)>, - verified_shred_tx: Sender<(Shred, solana_ledger::shred::Pubkey)>, -) -> anyhow::Result<()> { - loop { - if let Ok((shreds, leader)) = shred_rx.recv() { - shreds.par_iter().for_each(|sh| match sh { - Some(shred) => { - let verified = verify_sample(shred, leader); - match verified { - true => { - info!( - "sample {:?} verified for slot: {:?}", - shred.index(), - shred.slot() - ); - match verified_shred_tx.send((shred.clone(), leader)) { - Ok(_) => {} - Err(e) => error!("Error verified_shred_tx: {}", e), - } - } - false => info!("sample INVALID for slot : {:?}", shred.slot()), - } - } - None => { - // info!("none") - } - }); - } else { - // info!("None") - } - } -} - -// store verified shreds in db -pub async fn shred_archiver( - verified_shred_rx: Receiver<(Shred, solana_ledger::shred::Pubkey)>, - _archive_config: ArchiveConfig, - instance: Arc, -) -> anyhow::Result<()> { - loop { - if let Ok((verified_shred, leader)) = verified_shred_rx.recv() { - let mut opts = RocksOptions::default(); - opts.create_if_missing(true); - opts.set_error_if_exists(false); - opts.create_missing_column_families(true); - - let key = hashv(&[ - &verified_shred.slot().to_le_bytes(), - &u8::from(verified_shred.shred_type()).to_le_bytes(), - &verified_shred.index().to_le_bytes(), - ]) - .to_bytes(); - // info!("archiver {:?}", verified_shred.slot(),); - // let cfs = - // rocksdb::DB::list_cf(&opts, archive_config.archive_path.clone()).unwrap_or(vec![]); - // let shred_cf = cfs.clone().into_iter().find(|cf| cf.as_str() == SHRED_CF); - // let instance = - // DB::open_cf(&opts, archive_config.archive_path.clone(), vec![SHRED_CF]).unwrap(); - // match shred_cf { - // Some(cf_name) => { - let cf = instance.cf_handle(SHRED_CF).unwrap(); - let put_response = put_serialized(&instance, cf, key, &verified_shred); - match put_response { - Ok(_) => info!("Saved Shred {:?} to db", verified_shred.id().seed(&leader)), - Err(e) => info!("{:?}", e), - } - // } - // None => instance - // .create_cf(SHRED_CF, &RocksOptions::default()) - // .unwrap(), - // } - } - } -} - -pub async fn pull_and_verify_shreds(slot: usize, endpoint: String, sample_qty: usize) -> bool { - let shreds = get_shreds_and_leader_for_slot(slot as u64, &endpoint, sample_qty).await; - if let Err(e) = shreds { - info!("{}", e); - return false; - } - let (shreds, leader) = shreds.unwrap(); - - let sampled = shreds - .par_iter() - .flatten() - .all(|s| verify_sample(s, leader)); - - info!("pull and verify {:?}", sampled); - sampled -} - -pub fn put_serialized( - instance: &rocksdb::DB, - cf: &ColumnFamily, - key: [u8; 32], - value: &T, -) -> Result<(), String> { - match serde_json::to_string(&value) { - Ok(serialized) => instance - .put_cf(cf, key, serialized.into_bytes()) - .map_err(|err| format!("Failed to put to ColumnFamily:{:?}", err)), - Err(err) => Err(format!( - "Failed to serialize to String. T: {:?}, err: {:?}", - value, err - )), - } -} -pub fn get_serialized( - instance: &rocksdb::DB, - cf: &ColumnFamily, - key: [u8; 32], -) -> Result, String> { - match instance.get_cf(cf, key) { - Ok(opt) => match opt { - Some(found) => match String::from_utf8(found) { - Ok(s) => match serde_json::from_str::(&s) { - Ok(t) => Ok(Some(t)), - Err(err) => Err(format!("Failed to deserialize: {:?}", err)), - }, - Err(err) => Err(format!("Failed to convert to String: {:?}", err)), - }, - None => Ok(None), - }, - Err(err) => Err(format!("Failed to get from ColumnFamily: {:?}", err)), - } -} -use serde_derive::Deserialize; -use serde_derive::Serialize; - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SlotSubscribeResponse { - pub jsonrpc: String, - pub method: String, - pub params: SlotSubscribeParams, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SlotSubscribeParams { - pub result: SlotSubscribeResult, - pub subscription: i64, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SlotSubscribeResult { - pub parent: i64, - pub root: i64, - pub slot: i64, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GetShredResponse { - pub jsonrpc: String, - pub result: GetShredResult, - pub id: i64, -} -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GetShredResult { - pub leader: String, - pub shreds: Vec>, // This has to be an option -} -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RpcShred { - #[serde(rename = "ShredData")] - pub shred_data: Option, - #[serde(rename = "ShredCode")] - pub shred_code: Option, -} - -#[cfg(test)] -mod tests { - use super::{get_serialized, SHRED_CF}; - use rocksdb::{Options as RocksOptions, DB}; - use solana_client::nonblocking::rpc_client::RpcClient; - use solana_ledger::shred::{hashv, Shred, ShredType, Signer}; - use solana_sdk::signer::keypair::Keypair; - use tiny_logger::logs::info; - - #[test] - fn get_shred_from_db() { - let mut opts = RocksOptions::default(); - opts.create_if_missing(true); - opts.set_error_if_exists(false); - opts.create_missing_column_families(true); - let instance = DB::open_cf(&opts, "/tmp", vec![SHRED_CF]).unwrap(); - let slot: u64 = 1963754; - let _index: u32 = 11; - let key = hashv(&[ - &slot.to_le_bytes(), - &u8::from(ShredType::Data).to_le_bytes(), - &0_u32.to_le_bytes(), // can be random - ]) - .to_bytes(); - let cf = instance.cf_handle(SHRED_CF).unwrap(); - let shred = get_serialized::(&instance, cf, key); - println!("shred {:?}", shred); - assert!( - shred.is_ok(), - "error retrieving and serializing shred from db" - ); - } - - #[tokio::test] - async fn call_lite_rpc() { - let rpc_client = RpcClient::new("http://0.0.0.0:8890".to_string()); - - //let identity = get_identity_keypair(&identity_keypair).await; - // let blockhash = rpc_client.get_latest_blockhash().await.unwrap(); - let payer = Keypair::new(); - let airdrop_sign = rpc_client - .request_airdrop(&payer.try_pubkey().unwrap(), 2000000000) - .await - .unwrap(); - println!("AIRDROP CONFIRMED:{}", airdrop_sign); - } -} diff --git a/tinydancer/src/tinydancer.rs b/tinydancer/src/tinydancer.rs index 09cbcb3..04044d3 100644 --- a/tinydancer/src/tinydancer.rs +++ b/tinydancer/src/tinydancer.rs @@ -3,27 +3,26 @@ use std::{ env, - sync::{Arc, Mutex, MutexGuard}, + sync::{Arc, MutexGuard}, thread::Result, }; // use tokio::time::Duration; use crate::{ block_on, - rpc_wrapper::{TransactionService, TransactionServiceConfig}, - sampler::{ArchiveConfig, SampleService, SampleServiceConfig, SHRED_CF}, - ui::{UiConfig, UiService}, + transaction_service::{read_validator_set, TransactionService, TransactionServiceConfig}, }; use anyhow::anyhow; use async_trait::async_trait; use futures::{future::join_all, TryFutureExt}; use rand::seq::index::sample; use serde::{Deserialize, Serialize}; +use solana_sdk::pubkey::Pubkey; use tiny_logger::logs::info; // use log::info; // use log4rs; use std::error::Error; -use tokio::{runtime::Runtime, task::JoinError, try_join}; +use tokio::{runtime::Runtime, sync::Mutex, task::JoinError, try_join}; // use std::{thread, thread::JoinHandle, time::Duration}; #[async_trait] @@ -35,44 +34,52 @@ pub trait ClientService { } pub struct TinyDancer { - sample_service: SampleService, - ui_service: Option, - sample_qty: u64, config: TinyDancerConfig, transaction_service: TransactionService, + epoch_validator_set: Vec<(String, u64)>, + // current_epoch: u64 } #[derive(Clone)] pub struct TinyDancerConfig { pub rpc_endpoint: Cluster, - pub sample_qty: usize, - pub enable_ui_service: bool, - pub archive_config: ArchiveConfig, - pub tui_monitor: bool, + pub validator_set_path: String, + // pub archive_config: ArchiveConfig, pub log_path: String, + pub slot: u64, + pub copy_program: Pubkey, + pub copy_pda: Pubkey, + pub signer_path: String, + pub source_account: Pubkey, } -use solana_metrics::datapoint_info; -use std::ffi::OsString; -use std::fs::read_dir; -use std::io; -use std::io::ErrorKind; -use std::path::PathBuf; - +// use solana_metrics::datapoint_info; +// use std::ffi::OsString; +// use std::fs::read_dir; +// use std::io; +// use std::io::ErrorKind; +// use std::path::PathBuf; +// impl TinyDancer { - pub async fn start(config: TinyDancerConfig) -> Result<()> { + pub async fn start(config: TinyDancerConfig) -> anyhow::Result<()> { let status = ClientStatus::Initializing(String::from("Starting Up Tinydancer")); let client_status = Arc::new(Mutex::new(status)); - let status_sampler = client_status.clone(); + // let status_sampler = client_status.clone(); + let validator_set = + read_validator_set(&config.validator_set_path).map_err(|e| anyhow!(e.to_string()))?; + let current_epoch = validator_set.epoch; let TinyDancerConfig { - enable_ui_service, rpc_endpoint, - sample_qty, - tui_monitor, log_path, - archive_config, + slot, + validator_set_path, // archive_config, + + copy_program, + copy_pda, + signer_path, + source_account, } = config.clone(); std::env::set_var("RUST_LOG", "info"); tiny_logger::setup_file_with_default(&log_path, "RUST_LOG"); @@ -82,49 +89,39 @@ impl TinyDancer { opts.set_error_if_exists(false); opts.create_missing_column_families(true); - // setup db - let db = rocksdb::DB::open_cf(&opts, archive_config.clone().archive_path, vec![SHRED_CF]) - .unwrap(); - let db = Arc::new(db); - - let sample_service_config = SampleServiceConfig { - cluster: rpc_endpoint.clone(), - archive_config, - instance: db.clone(), - status_sampler, - sample_qty, + let validator_set = match config.rpc_endpoint { + Cluster::Mainnet => validator_set.mainnet_beta, + Cluster::Testnet => validator_set.testnet, + Cluster::Devnet => validator_set.devnet, + _ => validator_set.custom, }; - let sample_service = SampleService::new(sample_service_config); + + let validator_set = Arc::new(Mutex::new(validator_set)); + // setup db + // let db = rocksdb::DB::open_cf(&opts, archive_config.clone().archive_path, vec![SHRED_CF]) + // .unwrap(); + // let db = Arc::new(db); let transaction_service = TransactionService::new(TransactionServiceConfig { cluster: rpc_endpoint.clone(), - db_instance: db.clone(), + // db_instance: db.clone(), + validator_set, + slot, + current_epoch, + copy_program, + copy_pda, + signer_path, + source_account, }); - let ui_service = if enable_ui_service || tui_monitor { - Some(UiService::new(UiConfig { - client_status, - enable_ui_service, - tui_monitor, - })) - } else { - None - }; - - // run - sample_service - .join() - .await - .expect("error in sample service thread"); - transaction_service .join() .await - .expect("ERROR IN SIMPLE PAYMENT SERVICE"); + .expect("error in transaction_service"); - if let Some(ui_service) = ui_service { - block_on!(async { ui_service.join().await }, "Ui Service Error"); - } + // if let Some(ui_service) = ui_service { + // block_on!(async { ui_service.join().await }, "Ui Service Error"); + // } Ok(()) } @@ -134,6 +131,7 @@ impl TinyDancer { pub enum Cluster { Mainnet, Devnet, + Testnet, Localnet, Custom(String), } @@ -142,11 +140,15 @@ pub fn endpoint(cluster: Cluster) -> String { let cluster = cluster; match cluster { Cluster::Mainnet => String::from("https://api.mainnet-beta.solana.com"), + Cluster::Testnet => String::from("https://api.testnet.solana.com"), Cluster::Devnet => String::from("https://api.devnet.solana.com"), Cluster::Localnet => String::from("http://0.0.0.0:8899"), Cluster::Custom(url) => url, } } +pub fn geyser_endpoint(rpc_url: String) -> String { + rpc_url.replace("8899", "5000").replace("http://", "") +} pub enum ClientStatus { Initializing(String), SearchingForRPCService(String), diff --git a/tinydancer/src/transaction_service.rs b/tinydancer/src/transaction_service.rs new file mode 100644 index 0000000..52df524 --- /dev/null +++ b/tinydancer/src/transaction_service.rs @@ -0,0 +1,194 @@ +use std::{str::FromStr, sync::Arc}; + +use crate::{ + convert_to_websocket, datapoint_valid_signature, send_rpc_call, + tinydancer::{endpoint, geyser_endpoint, ClientService, Cluster}, + utils::{monitor_and_verify_updates, query_account, send_transaction}, + ValidatorSet, +}; +use anyhow::anyhow; +use async_trait::async_trait; +use colored::Colorize; +use serde::{Deserialize, Serialize}; +use solana_sdk::{ + pubkey::Pubkey, + signature::{read_keypair_file, Signable, Signature}, + vote::program::ID as VOTE_PROGRAM_ID, +}; +use std::collections::HashMap; +use tiny_logger::logs::info; +use tokio::{sync::Mutex, task::JoinHandle}; + +pub struct TransactionService { + pub handler: JoinHandle<()>, + // pub status: Arc>, +} + +pub struct TransactionServiceConfig { + pub cluster: Cluster, + pub validator_set: Arc>>, + pub slot: u64, + pub current_epoch: u64, + + pub copy_program: Pubkey, + pub copy_pda: Pubkey, + pub signer_path: String, + pub source_account: Pubkey, +} + +#[async_trait] +impl ClientService for TransactionService { + type ServiceError = tokio::task::JoinError; + + fn new(config: TransactionServiceConfig) -> Self { + // let validator_set = Arc::new( + // read_validator_set(&config.validator_set_path).unwrap_or(ValidatorSet::default()), + // ); + let mut verified_signatures: HashMap = + HashMap::new(); + let validator_set = config.validator_set; + // let slot = config.slot; + + let keypair = Arc::new( + read_keypair_file(config.signer_path) + .unwrap() + .insecure_clone(), + ); + let handler = tokio::spawn(async move { + info!("Source Account: {:?}", config.source_account); + info!("Copy Account: {:?}", config.copy_pda); + let source_account_data = + query_account(&config.source_account, endpoint(config.cluster.clone())).await; + let keypair = Arc::clone(&keypair); + let rpc_url = endpoint(config.cluster); + let sig = send_transaction( + keypair, + rpc_url.clone(), + convert_to_websocket!(rpc_url), + config.copy_program, + &config.source_account, + config.copy_pda, + ) + .await; + println!("Sent txn!: {:?}", sig); + monitor_and_verify_updates( + geyser_endpoint(rpc_url), + &config.source_account, + &source_account_data, + ) + .await; + // let vote_pubkeys: Vec = validator_set + // .lock() + // .await + // .iter() + // .map(|item| item.0.clone()) + // .collect(); + // // println!("keys: {:?}", vote_pubkeys); + // let vote_signatures = request_vote_signatures(config.slot, rpc_url, vote_pubkeys).await; + // // println!("votes: {:?}", vote_signatures); + // let signatures: Vec = vote_signatures + // .as_ref() + // .unwrap() + // .result + // .vote_signature + // .iter() + // .map(|sig| Signature::from_str(sig.as_str())) + // .flatten() + // .collect(); + // let vote_messages: Vec = vote_signatures + // .unwrap() + // .result + // .vote_messages + // .iter() + // .map(|raw_message| bincode::deserialize(raw_message.as_slice()).unwrap()) + // .collect(); + // let vote_pair: Vec<(&Signature, &solana_sdk::message::Message)> = + // signatures.iter().zip(vote_messages.iter()).collect(); + // //println!("pairs: {:?}", vote_pair); + // for (signature, message) in vote_pair { + // let message_pubkey = message.account_keys[0]; + // assert!( + // message.account_keys.contains(&VOTE_PROGRAM_ID), + // "This txn is not a vote txn" + // ); + // let validator_set_w = validator_set.lock().await; + // let maybe_trusted_pubkey = + // validator_set_w + // .iter() + // .find(|(validator_key, active_stake)| { + // *validator_key == message_pubkey.to_string() + // }); + // match maybe_trusted_pubkey { + // Some(key) => { + // let validator_pubkey = Pubkey::from_str(key.0.as_str()).unwrap(); + // let is_signature_valid = signature.verify( + // validator_pubkey.to_bytes().as_slice(), + // message.serialize().as_slice(), + // ); + // if is_signature_valid { + // verified_signatures + // .insert(validator_pubkey, (message.clone(), signature.clone())); + // datapoint_valid_signature!(validator_pubkey, signature); + // } else { + // println!("{:?} is not valid", key); + // } + // } + // None => panic!("not a trusted validator: {:?}", message_pubkey), + // } + // } + }); + Self { handler } + } + async fn join(self) -> std::result::Result<(), Self::ServiceError> { + self.handler.await + } +} + +pub async fn request_vote_signatures( + slot: u64, + endpoint: String, + vote_pubkeys: Vec, +) -> Result { + let request = serde_json::json!({ + "jsonrpc": "2.0", + "id": 1, + "method": "getVoteSignatures", + "params":[ + slot, + { + "votePubkey": vote_pubkeys, + "commitment": "confirmed" + } + ] + }) // getting one shred just to get max shreds per slot, can maybe randomize the selection here + .to_string(); + + let res = send_rpc_call!(endpoint, request); + // info!("{:?}", res); + serde_json::from_str::(&res) +} + +pub fn read_validator_set(path: &str) -> anyhow::Result { + match std::fs::read_to_string(path) { + Ok(data) => { + let validator_set: Result = + serde_json::from_str(&data); + validator_set.map_err(|e| anyhow!(e.to_string())) + } + Err(e) => Err(anyhow!(e.to_string())), + } +} +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetVoteSignaturesResponse { + pub jsonrpc: String, + pub result: GetVoteSignaturesResult, + pub id: i64, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetVoteSignaturesResult { + pub vote_signature: Vec, + pub vote_messages: Vec>, +} diff --git a/tinydancer/src/ui/mod.rs b/tinydancer/src/ui/mod.rs deleted file mode 100644 index ca6cf49..0000000 --- a/tinydancer/src/ui/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod ui; -pub use ui::*; diff --git a/tinydancer/src/ui/ui.rs b/tinydancer/src/ui/ui.rs deleted file mode 100644 index c4703f6..0000000 --- a/tinydancer/src/ui/ui.rs +++ /dev/null @@ -1,308 +0,0 @@ -use crate::sampler::GetShredResponse; -use crate::tinydancer::{ClientService, ClientStatus, TinyDancer}; -use async_trait::async_trait; -use crossterm::event::{KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}; -use crossterm::{ - event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}, - execute, - terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, -}; -use spinoff::{spinners, Color as SpinColor, Spinner}; -use std::sync::{Arc, Mutex}; -use std::thread::sleep; -use std::time::Duration; -use std::{any::Any, thread::Thread}; -use std::{fmt, thread::JoinHandle}; -use thiserror::Error; -use tiny_logger::logs::info; -use tui::layout::Rect; -use tui::style::{Color, Modifier, Style}; -use tui::text::{Span, Spans}; -use tui::{ - backend::{Backend, CrosstermBackend}, - layout::Direction, - layout::{Constraint, Layout}, - widgets::{ - Axis, BarChart, Block, Borders, Cell, Chart, Dataset, Gauge, LineGauge, List, ListItem, - ListState, Paragraph, Row, Sparkline, Table, TableState, Tabs, Wrap, - }, - Frame, Terminal, -}; - -pub struct UiService { - //pub views: Vec, //placeholder - pub ui_service_handle: JoinHandle<()>, // pub table: TableState, // placeholder view -} - -pub struct App { - title: String, - tabs: TabsState, - table: TableState, - slot_list: StatefulList<(String, usize)>, - peers_list: StatefulList>, - full_nodes_list: StatefulList>, -} - -// pub struct SlotList { -// title: String, -// state: ListState, -// items: Vec>, -// } -pub struct StatefulList { - state: ListState, - items: Vec, -} -impl StatefulList { - fn with_items(items: Vec) -> StatefulList { - StatefulList { - state: ListState::default(), - items, - } - } - - fn next(&mut self) { - let _i = match self.state.selected() { - Some(i) => { - if i >= self.items.len() - 1 { - 0 - } else { - i + 1 - } - } - None => 0, - }; - } - fn previous(&mut self) { - let i = match self.state.selected() { - Some(i) => { - if i == 0 { - self.items.len() - 1 - } else { - i - 1 - } - } - None => 0, - }; - self.state.select(Some(i)); - } - fn unselect(&mut self) { - self.state.select(None); - } -} - -pub struct TabsState { - pub titles: Vec, - pub index: usize, -} -impl TabsState { - pub fn new(titles: Vec) -> TabsState { - TabsState { titles, index: 0 } - } - pub fn next(&mut self) { - self.index = (self.index + 1) % self.titles.len(); - } - - pub fn previous(&mut self) { - if self.index > 0 { - self.index -= 1; - } else { - self.index = self.titles.len() - 1; - } - } -} -pub struct UiConfig { - pub client_status: Arc>, - pub enable_ui_service: bool, - pub tui_monitor: bool, -} -// main draw function -pub fn draw(f: &mut Frame) { - let _chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints( - [ - Constraint::Percentage(20), - Constraint::Percentage(40), - Constraint::Percentage(40), - ] - .as_ref(), - ) - .split(f.size()); -} - -fn draw_first_tab(f: &mut Frame, app: &mut App, area: Rect) -where - B: Backend, -{ - let chunks = Layout::default() - .constraints( - [ - Constraint::Length(20), - Constraint::Length(3), - Constraint::Length(2), - ] - .as_ref(), - ) - .split(area); - - //ui(f, app, chunks[0]); - draw_slot_list(f, app, chunks[0]); -} -fn draw_second_tab(_f: &mut Frame, _app: &mut App, area: Rect) -where - B: Backend, -{ - let _chunks = Layout::default() - .constraints( - [ - Constraint::Length(20), - Constraint::Length(3), - Constraint::Length(2), - ] - .as_ref(), - ) - .split(area); - //todo: Draw network usage metrics here - todo!() -} - -// draws list of slots -fn draw_slot_list(f: &mut Frame, app: &mut App, area: Rect) { - // let selected_style = Style::default().add_modifier(Modifier::REVERSED); - // let normal_style = Style::default().bg(Color::LightBlue); - let items: Vec = app - .slot_list - .items - .iter() - .map(|i| { - let mut lines = vec![Spans::from(i.0.clone())]; - for _ in 0..i.1 { - lines.push(Spans::from(Span::styled( - // dummy values in list that would be replaced by slot numbers - "slots 1", - Style::default().add_modifier(Modifier::ITALIC), - ))); - } - ListItem::new(lines).style(Style::default().fg(Color::Black).bg(Color::White)) - }) - .collect(); - let list = List::new(items) - .block(Block::default().borders(Borders::ALL).title("SLOTS")) - .highlight_style( - Style::default() - .bg(Color::Cyan) - .add_modifier(Modifier::BOLD), - ) - .highlight_symbol(">>"); - f.render_stateful_widget(list, area, &mut app.slot_list.state); - // let peers_list: Vec = app - // .peers_list - // .items - // .iter() - // .map(|i|{ - - // }) -} - -#[async_trait] -impl ClientService for UiService { - type ServiceError = ThreadJoinError; - fn new(config: UiConfig) -> Self { - let ui_service_handle = std::thread::spawn(move || loop { - let mut threads = Vec::default(); - - if config.enable_ui_service { - threads.push(std::thread::spawn(|| { - info!("rendering ui"); - std::thread::sleep(std::time::Duration::from_secs(2)); - })); - } - - if config.tui_monitor { - let client_status = config.client_status.clone(); - let mut spinner = - Spinner::new(spinners::Dots, "Initializing Client...", SpinColor::Yellow); - - threads.push(std::thread::spawn(move || loop { - sleep(Duration::from_millis(100)); - - let status = client_status.lock().unwrap(); - match &*status { - ClientStatus::Active(msg) => { - spinner.update(spinners::Dots, msg.clone(), SpinColor::Green); - // sleep(Duration::from_secs(100)); - } - ClientStatus::Initializing(msg) => { - spinner.update(spinners::Dots, msg.clone(), SpinColor::Yellow); - } - ClientStatus::Crashed(msg) => { - spinner.update(spinners::Dots, msg.clone(), SpinColor::Red); - } - ClientStatus::ShuttingDown(msg) => { - spinner.update(spinners::Dots, msg.clone(), SpinColor::White); - sleep(Duration::from_millis(500)); - std::process::exit(0); - } - _ => {} - } - Mutex::unlock(status); - enable_raw_mode(); - if crossterm::event::poll(Duration::from_millis(100)).unwrap() { - let ev = crossterm::event::read().unwrap(); - - if ev - == Event::Key(KeyEvent { - code: KeyCode::Char('c'), - modifiers: KeyModifiers::CONTROL, - kind: KeyEventKind::Press, - state: KeyEventState::NONE, - }) - { - let mut status = client_status.lock().unwrap(); - *status = ClientStatus::ShuttingDown(String::from( - "Shutting Down Gracefully...", - )); - Mutex::unlock(status); - disable_raw_mode(); - } - } - })); - } - - for handle in threads { - handle.join(); - } - }); - - Self { ui_service_handle } - } - async fn join(self) -> std::result::Result<(), Self::ServiceError> { - match self.ui_service_handle.join() { - Ok(_) => Ok(()), - Err(error) => Err(ThreadJoinError { error }), - } - } -} - -#[derive(Debug, Error)] -pub struct ThreadJoinError { - error: Box, -} - -// impl ThreadJoinError { -// fn new(msg: Box) -> ThreadJoinError { -// ThreadJoinError { error: msg } -// } -// } - -impl fmt::Display for ThreadJoinError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.error) - } -} - -// impl Error for ThreadJoinError { -// fn description(&self) -> &str { -// &self.error.into() -// } -// } diff --git a/tinydancer/src/utils.rs b/tinydancer/src/utils.rs new file mode 100644 index 0000000..42cd7b6 --- /dev/null +++ b/tinydancer/src/utils.rs @@ -0,0 +1,156 @@ +use alloc::rc::Rc; +use anchor_client::{Client, Cluster}; +use solana_client::rpc_config::RpcSendTransactionConfig; +use solana_rpc_client::nonblocking::rpc_client::RpcClient; +use solana_sdk::account::Account; +use solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel}; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::{Keypair, Signature, Signer}; +use solana_transaction_status::UiTransactionEncoding; +// use solana_transaction_status::UiTransactionEncoding; +// use solana_transaction_status::{UiTransaction, UiTransactionEncoding}; +use std::str::FromStr; +use std::sync::Arc; +use std::time::Duration; +pub async fn query_account(addr: &Pubkey, url: String) -> Account { + // let url = DEFAULT_RPC_URL.to_string(); + let client = RpcClient::new(url); + client.get_account(addr).await.unwrap() +} +use account_proof_geyser::types::Update; +use account_proof_geyser::utils::verify_leaves_against_bankhash; +use borsh::de::BorshDeserialize; +use copy::{ + account_hasher, accounts as copy_accounts, instruction as copy_instruction, CopyAccount, PREFIX, +}; +use tokio::io::AsyncReadExt; +use tokio::net::TcpStream; +use tokio::runtime::Runtime; +extern crate alloc; +pub async fn monitor_and_verify_updates( + geyser_ip: String, + rpc_pubkey: &Pubkey, + rpc_account: &Account, +) -> anyhow::Result<()> { + println!("starting monitor: {:?}", geyser_ip); + let mut stream = TcpStream::connect(&geyser_ip) + .await + .expect("unable to connect to 127.0.0.1 on port 5000"); + println!("got stream"); + let mut buffer = vec![0u8; 65536]; + let mut n = stream + .read(&mut buffer) + .await + .expect("unable to read to mutable buffer"); + println!("Reading stream"); + loop { + if n == 0 { + tokio::time::sleep(Duration::from_millis(400)).await; + n = stream + .read(&mut buffer) + .await + .expect("unable to read to mutable buffer"); + + // anyhow::bail!("Connection closed"); + } else { + break; + } + } + let received_update: Update = BorshDeserialize::try_from_slice(&buffer[..n]).unwrap(); + + let bankhash = received_update.root; + let bankhash_proof = received_update.proof; + let slot_num = received_update.slot; + for p in bankhash_proof.proofs { + verify_leaves_against_bankhash( + &p, + bankhash, + bankhash_proof.num_sigs, + bankhash_proof.account_delta_root, + bankhash_proof.parent_bankhash, + bankhash_proof.blockhash, + ) + .unwrap(); + + println!( + "\nBankHash proof verification succeeded for account with Pubkey: {:?} in slot {}", + &p.0, slot_num + ); + println!("Bankhash is: {:?}", received_update.root); + let copy_account: CopyAccount = + anchor_lang::AccountDeserialize::try_deserialize(&mut p.1 .0.account.data.as_slice())?; + let rpc_account_hash = account_hasher( + &rpc_pubkey, + rpc_account.lamports, + &rpc_account.data, + &rpc_account.owner, + rpc_account.rent_epoch, + ); + assert_eq!(rpc_account_hash.as_ref(), ©_account.digest); + println!( + "Hash for rpc account matches Hash verified as part of the BankHash: {}", + rpc_account_hash + ); + println!("{:?}", &rpc_account); + } + Ok(()) +} + +pub async fn send_transaction( + signer: Arc, + rpc_url: String, + ws_url: String, + copy_program: Pubkey, + source_account: &Pubkey, + copy_pda: Pubkey, +) -> anyhow::Result { + let creator_pubkey = signer.pubkey(); + let c = Arc::new(Client::new_with_options( + Cluster::Custom(rpc_url.clone(), ws_url.clone()), + signer.clone(), + CommitmentConfig::confirmed(), + )); + let prog = c.program(copy_program).unwrap(); + let copy_pda_bump = Pubkey::find_program_address(&[b"copy_hash"], ©_program).1; + let mut txn = prog + .request() + .accounts(copy_accounts::CopyHash { + creator: creator_pubkey, + source_account: *source_account, + copy_account: copy_pda, + clock: solana_sdk::sysvar::clock::id(), + system_program: solana_sdk::system_program::id(), + }) + .args(copy_instruction::CopyHash { + bump: copy_pda_bump, + }) + .options(CommitmentConfig { + commitment: CommitmentLevel::Processed, + }) + .transaction()?; + + let client = RpcClient::new_with_commitment(rpc_url.clone(), CommitmentConfig::confirmed()); + let (hash, slot) = client + .get_latest_blockhash_with_commitment(CommitmentConfig::processed()) + .await + .unwrap(); + println!("min slot: {:?}", slot); + let send_cfg = RpcSendTransactionConfig { + skip_preflight: true, + preflight_commitment: Some(CommitmentLevel::Processed), + encoding: Some(UiTransactionEncoding::Base64), + max_retries: Some(0), + min_context_slot: Some(slot), + }; + // let signer_c = Arc::clone(&signer); + txn.sign(&[&signer], hash); + let signature = client + .send_and_confirm_transaction_with_spinner_and_config( + &txn, + CommitmentConfig::processed(), + send_cfg, + ) + .await?; + println!("{:?}", signature.to_string()); + Ok(signature) +} diff --git a/validator-set.json b/validator-set.json new file mode 100644 index 0000000..f8a06c4 --- /dev/null +++ b/validator-set.json @@ -0,0 +1,18 @@ +{ + "epoch": 583, + "mainnet-beta": [ + ["HSX42dhQPTaVjtwMQXwGTCobrs1HnxZ8G2J6JTnPXpgP", 60021], + ["sce3PzrJU8j5Qa7WtRejXq7hFywUBh8jutVx929Hagw",0], + ["sce1TVNf6tBniHXqhkj7NY9wxaBsoQrpXKzfYXBG9v2",0] + ], + "testnet": [ + ["J7v9ndmcoBuo9to2MnHegLnBkC9x3SAVbQBJo5MMJrN1",8268013], + ["141vSYKGRPNGieSrGJy8EeDVBcbjSr6aWkimNgrNZ6xN",6832509], + ["3ANJb42D3pkVtntgT6VtW2cD3icGVyoHi2NGwtXYHQAs",3435332] + ], + "devnet": [], + + "custom": [ + [ "HgvBVrFLnYAUXVxgoAqrQMiuxiFYuZ6hxE7VxgZk5YG",999999 + ]] +} diff --git a/vote.sh b/vote.sh new file mode 100755 index 0000000..77127ad --- /dev/null +++ b/vote.sh @@ -0,0 +1,37 @@ +#! /bin/bash + +content=$(curl http://$RPC_IP:$PORT -X POST -H "Content-Type: application/json" -d ' + { + "id":1, + "jsonrpc":"2.0", + "method":"getLatestBlockhash", + "params":[ + { + "commitment":"confirmed" + } + ] + } + ') + echo "done1" + blockhash=$(jq -r '.result.context.slot' <<<"$content") + + + echo $blockhash + validator_set=[\"tiv13UpNPRdZgazPCjRBxtff5SPuctQC1UmhHdGgUrc\",\"CV3F19YAhoW7DpfHQ5W9t2Zomb9h21NRi8k6hCA36Sk6\",\"ELY6u8Reinx7k2s9wgQA6jHHTsog7eN6qAYeTh2bNYx\"] +# echo $validator_set +# #echo $body + curl http://$RPC_IP:$PORT -X POST -H "Content-Type: application/json" -d @<( cat <