diff --git a/Cargo.lock b/Cargo.lock index 5e9a3c58..e2608d80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,9 +150,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" +checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" [[package]] name = "anstyle-parse" @@ -254,7 +254,7 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint 0.4.4", "num-traits 0.2.16", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -290,7 +290,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -342,7 +342,7 @@ dependencies = [ "num-traits 0.2.16", "rusticata-macros", "thiserror", - "time 0.3.28", + "time", ] [[package]] @@ -351,7 +351,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", "synstructure", @@ -363,7 +363,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -387,9 +387,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d495b6dc0184693324491a5ac05f559acc97bf937ab31d7a1c33dd0016be6d2b" +checksum = "bb42b2197bf15ccb092b62c74515dbd8b86d0effd934795f6687c93b6e679a2c" dependencies = [ "brotli", "flate2", @@ -434,9 +434,9 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -445,9 +445,9 @@ version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -550,9 +550,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.3" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "base64ct" @@ -574,7 +574,8 @@ name = "bench" version = "0.2.3" dependencies = [ "anyhow", - "clap 4.4.2", + "bincode", + "clap 4.4.3", "csv", "dashmap", "dirs", @@ -585,8 +586,10 @@ dependencies = [ "rand_chacha 0.3.1", "serde", "serde_json", + "solana-lite-rpc-quic-forward-proxy", "solana-rpc-client", "solana-sdk", + "solana-streamer", "tokio", "tracing-subscriber", ] @@ -689,7 +692,7 @@ dependencies = [ "borsh-derive-internal 0.9.3", "borsh-schema-derive-internal 0.9.3", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "syn 1.0.109", ] @@ -702,7 +705,7 @@ dependencies = [ "borsh-derive-internal 0.10.3", "borsh-schema-derive-internal 0.10.3", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "syn 1.0.109", ] @@ -712,7 +715,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -723,7 +726,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -734,7 +737,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -745,7 +748,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -789,9 +792,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bv" @@ -805,22 +808,22 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -831,9 +834,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "caps" @@ -863,16 +866,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.28" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits 0.2.16", "serde", - "time 0.1.45", "wasm-bindgen", "windows-targets 0.48.5", ] @@ -919,9 +921,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.2" +version = "4.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" +checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6" dependencies = [ "clap_builder", "clap_derive", @@ -946,9 +948,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -1048,7 +1050,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a4f51209740b5e1589e702b3044cdd4562cef41b6da404904192ffffb852d62" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -1239,10 +1241,10 @@ checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "strsim 0.10.0", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -1253,7 +1255,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -1316,7 +1318,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -1328,7 +1330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "rustc_version", "syn 1.0.109", @@ -1393,9 +1395,9 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -1504,9 +1506,9 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -1573,6 +1575,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1673,9 +1681,9 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -1955,6 +1963,15 @@ dependencies = [ "hmac 0.8.1", ] +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "http" version = "0.2.9" @@ -2292,7 +2309,7 @@ checksum = "d814a21d9a819f8de1a41b819a263ffd68e4bb5f043d936db1c49b54684bde0a" dependencies = [ "heck", "proc-macro-crate 1.3.1", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -2371,9 +2388,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libsecp256k1" @@ -2425,9 +2442,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" [[package]] name = "lite-rpc" @@ -2436,13 +2453,13 @@ dependencies = [ "anyhow", "async-channel", "async-trait", - "base64 0.21.3", + "base64 0.21.4", "bench", "bincode", "bs58", "bytes", "chrono", - "clap 4.4.2", + "clap 4.4.3", "const_env", "dashmap", "dotenv", @@ -2696,7 +2713,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -2787,7 +2804,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -2799,9 +2816,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -2861,9 +2878,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -2874,9 +2891,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.92" +version = "0.9.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" dependencies = [ "cc", "libc", @@ -3016,9 +3033,9 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -3093,7 +3110,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" dependencies = [ - "base64 0.21.3", + "base64 0.21.4", "byteorder", "bytes", "fallible-iterator", @@ -3129,7 +3146,7 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "syn 1.0.109", ] @@ -3163,9 +3180,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -3225,7 +3242,7 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] @@ -3274,7 +3291,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.20.8", + "rustls 0.20.9", "thiserror", "tokio", "tracing", @@ -3291,7 +3308,7 @@ dependencies = [ "rand 0.8.5", "ring", "rustc-hash", - "rustls 0.20.8", + "rustls 0.20.9", "rustls-native-certs", "slab", "thiserror", @@ -3328,7 +3345,7 @@ version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", ] [[package]] @@ -3441,7 +3458,7 @@ checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", "ring", - "time 0.3.28", + "time", "yasna", ] @@ -3453,7 +3470,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", - "time 0.3.28", + "time", "yasna", ] @@ -3537,7 +3554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ "async-compression", - "base64 0.21.3", + "base64 0.21.4", "bytes", "encoding_rs", "futures-core", @@ -3639,9 +3656,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.11" +version = "0.38.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453" +checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" dependencies = [ "bitflags 2.4.0", "errno", @@ -3652,9 +3669,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" dependencies = [ "log", "ring", @@ -3670,7 +3687,7 @@ checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" dependencies = [ "log", "ring", - "rustls-webpki 0.101.4", + "rustls-webpki 0.101.5", "sct", ] @@ -3692,14 +3709,14 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.3", + "base64 0.21.4", ] [[package]] name = "rustls-webpki" -version = "0.100.2" +version = "0.100.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e98ff011474fa39949b7e5c0428f9b4937eda7da7848bbb947786b7be0b27dab" +checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3" dependencies = [ "ring", "untrusted", @@ -3707,9 +3724,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.4" +version = "0.101.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" +checksum = "45a27e3b59326c16e23d30aeb7a36a24cc0d29e71d68ff611cdfb4a01d013bed" dependencies = [ "ring", "untrusted", @@ -3757,9 +3774,9 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -3831,16 +3848,16 @@ version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -3876,9 +3893,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ "darling", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -4024,9 +4041,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" dependencies = [ "libc", "windows-sys 0.48.0", @@ -4050,12 +4067,12 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e0074eb8b7115c7648de67d1dd1cc31505afcc9ebe16eb4ba3cff6f1520385" +checksum = "b83daa56035885dac1a47f5bd3d4e02379e3fc5915b2c3ce978a9af9eeecf07d" dependencies = [ "Inflector", - "base64 0.21.3", + "base64 0.21.4", "bincode", "bs58", "bv", @@ -4074,9 +4091,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85261ec5a2cee18d926e1c48265a760896fa06a6b431b3f1d43a8b0f7a3aa28d" +checksum = "2dd3f3e85d67e559985fbdc6b5b4d5dd9c8462b78e6079c3b465496c1f3c55d6" dependencies = [ "bincode", "bytemuck", @@ -4095,9 +4112,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dae8384f3a2fa5f765de3f4c2d6dc2b26d4a6ac0b740f5318d17326158fa0c0a" +checksum = "3669a399b8ef60642471e68e1f93d3f3050248a4fa1436341596cfcb2a484e8b" dependencies = [ "chrono", "clap 2.34.0", @@ -4113,9 +4130,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84514073c108af24e0408e00d7e490e4f90e87c1a4ee4dcffa34b200d1da446b" +checksum = "e96d8a28ca30cd385f7c2c4a7f93edc32c18bc041baa0e8b25bd56cd28c51cbb" dependencies = [ "async-trait", "bincode", @@ -4146,9 +4163,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f2c6b161fc8e7bd86733559eaf6142f271dda233efd7fa1e2edacf98b4cc4cd" +checksum = "0a35e4cc9f2996a2ef95aac398443fc4a110ef585521e11a7685b3591648b7cf" dependencies = [ "bincode", "chrono", @@ -4160,9 +4177,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1162b7d11807c5b5c77b2da3fbf9df7bd7fc71c9d6ecf3c13a5ff8541928a7b" +checksum = "5ecb12464ee1322a02635345522839958d78a2bacff18298991cacf298178f64" dependencies = [ "async-trait", "bincode", @@ -4181,9 +4198,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0447b0bb6ab6c6fc0e83bd106618c23d241c4fb8090de715a9811fb993fbfd07" +checksum = "35b9e2169fd13394af838b13f047067c35ce69372aea0fb46e026405b5e931f9" dependencies = [ "ahash 0.8.3", "blake3", @@ -4214,14 +4231,14 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cc86a118888cef8a3878f6dc9c291787cb21ef50cd98e7271f1e0ff548153b8" +checksum = "db08ab0af4007dc0954b900aa5febc0c0ae50d9f9f598be27263c3195d90240b" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "rustc_version", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -4231,7 +4248,7 @@ dependencies = [ "anyhow", "async-channel", "async-trait", - "base64 0.21.3", + "base64 0.21.4", "bincode", "bs58", "bytes", @@ -4242,7 +4259,7 @@ dependencies = [ "itertools", "log", "quinn", - "rustls 0.20.8", + "rustls 0.20.9", "serde", "serde_json", "solana-client", @@ -4266,7 +4283,7 @@ version = "0.2.3" dependencies = [ "anyhow", "async-trait", - "base64 0.21.3", + "base64 0.21.4", "bincode", "bs58", "bytes", @@ -4276,7 +4293,7 @@ dependencies = [ "itertools", "log", "quinn", - "rustls 0.20.8", + "rustls 0.20.9", "serde", "serde_json", "solana-client", @@ -4298,12 +4315,12 @@ dependencies = [ "anyhow", "async-channel", "async-trait", - "base64 0.21.3", + "base64 0.21.4", "bincode", "bs58", "bytes", "chrono", - "clap 4.4.2", + "clap 4.4.3", "dashmap", "dotenv", "futures", @@ -4314,10 +4331,11 @@ dependencies = [ "prometheus", "quinn", "rcgen 0.9.3", - "rustls 0.20.8", + "rustls 0.20.9", "serde", "serde_json", "solana-lite-rpc-core", + "solana-lite-rpc-services", "solana-net-utils", "solana-sdk", "solana-streamer", @@ -4336,12 +4354,12 @@ dependencies = [ "anyhow", "async-channel", "async-trait", - "base64 0.21.3", + "base64 0.21.4", "bincode", "bs58", "bytes", "chrono", - "clap 4.4.2", + "clap 4.4.3", "countmap", "crossbeam-channel", "dashmap", @@ -4354,7 +4372,7 @@ dependencies = [ "prometheus", "quinn", "rcgen 0.9.3", - "rustls 0.20.8", + "rustls 0.20.9", "serde", "serde_json", "solana-lite-rpc-core", @@ -4367,6 +4385,7 @@ dependencies = [ "spl-memo", "thiserror", "tokio", + "tracing", "tracing-subscriber", ] @@ -4377,7 +4396,7 @@ dependencies = [ "anyhow", "async-channel", "async-trait", - "base64 0.21.3", + "base64 0.21.4", "bincode", "bs58", "bytes", @@ -4391,7 +4410,7 @@ dependencies = [ "log", "prometheus", "quinn", - "rustls 0.20.8", + "rustls 0.20.9", "serde", "serde_json", "solana-client", @@ -4411,9 +4430,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ac77d7fc0144181d4f6c8eb4203bb5fe54d486fa19ccaab7615ccb4b874b0de" +checksum = "bf8a48e734f78a44399516f7c130c114b455911e351f001abc0d96e7c5694efa" dependencies = [ "env_logger", "lazy_static", @@ -4422,9 +4441,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "441deecebeb23ff7da89df5db5ec712458903c7cc733c8ae1e0a26daf2c1130a" +checksum = "d3529d2ff63ceedd3707c51188aacb9e3c142118de3f55447c40584a78223ffd" dependencies = [ "log", "solana-sdk", @@ -4432,9 +4451,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229583448485d731afb88e2bfd3a6b978312d4690c7452a35f8da47c02d4fd4f" +checksum = "4792f29de5378a13c51be3fa9fdd526a20550b5ffabd7d1a57a4e49468e17d90" dependencies = [ "crossbeam-channel", "gethostname", @@ -4446,9 +4465,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8e246018a28e65d02d2b0e5141d3f89865a92e8b495a468a632b7028396626c" +checksum = "7ed75beb465e211c79d31ae2049cb85974203e5ac21ae89396378d5a2fe71962" dependencies = [ "bincode", "clap 3.2.25", @@ -4468,9 +4487,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "103fe87a578aa1771ee992e2654b2830ffc16709d429c3bb0d2c36ef8fee4d1d" +checksum = "9218d9c823b22a465f91c966e8254a5f57b6817e0121ec6d4bf9a5ddc8307f18" dependencies = [ "ahash 0.8.3", "bincode", @@ -4495,16 +4514,16 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3841458623bd80b8291e8991f7353d674bb39656b1db83ec1aa5916a1b6ed7c" +checksum = "2f17a1fbcf1e94e282db16153d323b446d6386ac99f597f78e76332265829336" dependencies = [ "ark-bn254", "ark-ec", "ark-ff", "ark-serialize", "array-bytes", - "base64 0.21.3", + "base64 0.21.4", "bincode", "bitflags 1.3.2", "blake3", @@ -4550,11 +4569,11 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72cc1b1f3a5a9f6735668a67e3d1fe161ec2d4931ef523acc4d716704b9fc11f" +checksum = "2ff9f0c8043b2e7921e25a3fee88fa253b8cb5dbab1e521a4d83e78e8874c551" dependencies = [ - "base64 0.21.3", + "base64 0.21.4", "bincode", "eager", "enum-iterator", @@ -4578,9 +4597,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df90f4a572b3d5d601ca6a8bde0d6024b45fc4204753b74a5156a538aac3b7c6" +checksum = "6e0659db803f68fb440c87f43a603e2da7adb3dd11d68e119c3209ed3ca02073" dependencies = [ "crossbeam-channel", "futures-util", @@ -4603,9 +4622,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3433148255e4f526a0bb50f3f33e58e9552616c7c942235abd64fee66c0d1787" +checksum = "fd4e0689f7b3b2e98e73089bf3aa6b3290cb8a2cbff97fca2ee579cc3ca2717e" dependencies = [ "async-mutex", "async-trait", @@ -4617,7 +4636,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rcgen 0.10.0", - "rustls 0.20.8", + "rustls 0.20.9", "solana-connection-cache", "solana-measure", "solana-metrics", @@ -4631,9 +4650,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e85499464599434befb08ba5b89d4bed5cd58bf67d1d36fc8f2025605576e2" +checksum = "ab3c3996bd418c45a540ee2c2d23e9796c244d3e5c9f135a86aa8501e1afea19" dependencies = [ "lazy_static", "num_cpus", @@ -4641,9 +4660,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1012c7d172982f89efefddadc07679dcc82ebf9efc9031313860c622d31725eb" +checksum = "40927d4df440e354f618cbf9e5eb81e02cf4563ef8360782b5493f395b63f61a" dependencies = [ "console", "dialoguer", @@ -4660,12 +4679,12 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cead295f632db6a5c9806f483dc05be50dc4e02cf54e7b8b5afb470064c8e2e3" +checksum = "871cf6d60098c556755a3a7dbd1742201718220a13b988d012f0658eddaad674" dependencies = [ "async-trait", - "base64 0.21.3", + "base64 0.21.4", "bincode", "bs58", "indicatif", @@ -4686,11 +4705,11 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f94b4b99de2430a5baa6c27f713dec67b934aa693fc2045f8aead5168adabea3" +checksum = "3214d68e3b661ddfd960271f67eb8042298ac7d90d9bd86d330200c3a5518404" dependencies = [ - "base64 0.21.3", + "base64 0.21.4", "bs58", "jsonrpc-core", "reqwest", @@ -4708,9 +4727,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe2970736880aa250ea05a3b62dd07e5ee8e8650440f1217d3f9b6edac05d2f" +checksum = "bcf08c480fb3d0d861abe10a0517990edea8151529ccf537c0a833233f1381d8" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -4721,12 +4740,12 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87608d9cbf39d4f72cfb61179c320b3cea7f972671ec74dea99d255fd3a99ca9" +checksum = "74a01f25b9f4022fc222c21c589ef7943027fb0fa2b9f6ae943fc4a65c2c01a2" dependencies = [ "assert_matches", - "base64 0.21.3", + "base64 0.21.4", "bincode", "bitflags 1.3.2", "borsh 0.10.3", @@ -4774,22 +4793,22 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9077bd44586a902c9949d4e0cf4647ae2723ae2f0feca1e94d8fe9dcd4e2160d" +checksum = "a75b33716470fa4a65a23ddc2d4abcb8d28532c6e3ae3f04f4fe79b5e1f8c247" dependencies = [ "bs58", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "rustversion", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] name = "solana-streamer" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f43f8a5e4d579a41cab0195de05fe44f8c9a171debdf355cb284320ffbf916f" +checksum = "705ef2b2649c4162061a74aaf12f02b244828ed847ad981581e3e51155279ca5" dependencies = [ "async-channel", "bytes", @@ -4809,7 +4828,7 @@ dependencies = [ "quinn-udp", "rand 0.7.3", "rcgen 0.10.0", - "rustls 0.20.8", + "rustls 0.20.9", "solana-metrics", "solana-perf", "solana-sdk", @@ -4820,9 +4839,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cc93907e18bf298da73b067ae4844c6d542d4d89aadf2e18443079ab893ef7" +checksum = "dc8a9f9c101395d314c4e5e1b19801dd54f4cd501e40b8c2d7d8b896cd2e0980" dependencies = [ "bincode", "log", @@ -4835,9 +4854,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aec22964554632c96e2d82a4da17422ae98534bd75ea69e29f7f44c39537109d" +checksum = "18a8a4d90f74e666cd2a5f7ac9ed230ca186d8f7351a927f061801b3ba4e8f2f" dependencies = [ "async-trait", "bincode", @@ -4860,12 +4879,12 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccc2fae62bb9266a196c9de6c25e484305d95a18bc05e304a176f95811a4e916" +checksum = "c9266f75afa4163c9a5f29f1066f907e87482858749942380d6538af567b44c7" dependencies = [ "Inflector", - "base64 0.21.3", + "base64 0.21.4", "bincode", "borsh 0.9.3", "bs58", @@ -4886,9 +4905,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ad75fc5355aacc4acdf8c5e4201e425c76769a74b842d1618ef58e8cdca66f" +checksum = "e0f475a0a0faa55f7783084258c1e88be39ed3ea5c4f945bf728b7ca8c7a3262" dependencies = [ "async-trait", "solana-connection-cache", @@ -4901,9 +4920,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8eed97d5addc338b857991dd26496e236f9711373cdf470682ec8548af454a3" +checksum = "886a0c01be1e2b3a7ec3bed63f2112cd7f80c4b8182e95fa98b7ab7e37faf90a" dependencies = [ "log", "rustc_version", @@ -4917,9 +4936,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5fb2eb8114089c792929f2a2e9b4f1fa1c7d6296bbb8e5120b0a18fa6f8b75a" +checksum = "01b1102b13ca7c760439545dba83588419d208b500a93eb61f6565be26bef490" dependencies = [ "bincode", "log", @@ -4939,12 +4958,12 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.16.12" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0d498188b9ff5dcef1f356888d128a9b583aee8bfe87bc6746db02b2d492f97" +checksum = "1669c9d223d850cd96cad69d3ba1a4234bc3e2f83ac837fbdbc0ce774dac7b92" dependencies = [ "aes-gcm-siv", - "base64 0.21.3", + "base64 0.21.4", "bincode", "bytemuck", "byteorder", @@ -5061,10 +5080,11 @@ dependencies = [ [[package]] name = "stringprep" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3737bde7edce97102e0e2b15365bf7a20bfdb5f60f4f9e8d7004258a51a8da" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" dependencies = [ + "finl_unicode", "unicode-bidi", "unicode-normalization", ] @@ -5104,18 +5124,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.31" +version = "2.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +checksum = "9caece70c63bfba29ec2fed841a09851b14a235c60010fa4de58089b6c025668" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "unicode-ident", ] @@ -5132,7 +5152,7 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", "unicode-xid 0.2.4", @@ -5190,9 +5210,9 @@ version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -5205,17 +5225,6 @@ dependencies = [ "once_cell", ] -[[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.28" @@ -5292,7 +5301,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.3", + "socket2 0.5.4", "tokio-macros", "windows-sys 0.48.0", ] @@ -5313,9 +5322,9 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -5348,7 +5357,7 @@ dependencies = [ "postgres-protocol", "postgres-types", "rand 0.8.5", - "socket2 0.5.3", + "socket2 0.5.4", "tokio", "tokio-util", "whoami", @@ -5360,7 +5369,7 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls 0.20.8", + "rustls 0.20.9", "tokio", "webpki", ] @@ -5394,7 +5403,7 @@ checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" dependencies = [ "futures-util", "log", - "rustls 0.20.8", + "rustls 0.20.9", "tokio", "tokio-rustls 0.23.4", "tungstenite", @@ -5434,9 +5443,9 @@ checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.0.0", "toml_datetime", @@ -5452,7 +5461,7 @@ dependencies = [ "async-stream", "async-trait", "axum", - "base64 0.21.3", + "base64 0.21.4", "bytes", "flate2", "futures-core", @@ -5483,7 +5492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6fdaae4c2c638bb70fe42803a26fbd6fc6ac8c72f5c59f67ecc2a2dcabf4b07" dependencies = [ "prettyplease", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "prost-build", "quote 1.0.33", "syn 1.0.109", @@ -5553,9 +5562,9 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] @@ -5616,7 +5625,7 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "rustls 0.20.8", + "rustls 0.20.9", "sha-1 0.10.1", "thiserror", "url", @@ -5639,9 +5648,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -5773,12 +5782,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" @@ -5804,9 +5807,9 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", "wasm-bindgen-shared", ] @@ -5838,9 +5841,9 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5886,7 +5889,7 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" dependencies = [ - "rustls-webpki 0.100.2", + "rustls-webpki 0.100.3", ] [[package]] @@ -5897,12 +5900,12 @@ checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "which" -version = "4.4.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad25fe5717e59ada8ea33511bbbf7420b11031730a24c65e82428766c307006" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ - "dirs", "either", + "home", "once_cell", "rustix", ] @@ -6138,7 +6141,7 @@ dependencies = [ "oid-registry", "rusticata-macros", "thiserror", - "time 0.3.28", + "time", ] [[package]] @@ -6147,7 +6150,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "time 0.3.28", + "time", ] [[package]] @@ -6193,9 +6196,9 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2 1.0.67", "quote 1.0.33", - "syn 2.0.31", + "syn 2.0.33", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8a4e7efa..1dc8c1fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,8 +50,8 @@ prometheus = "0.13.3" lazy_static = "1.4.0" dotenv = "0.15.0" async-channel = "1.8.0" -quinn = "0.9.3" -rustls = { version = "=0.20.8", default-features = false } +quinn = "0.9.4" +rustls = { version = "0.20.9", default-features = false } solana-lite-rpc-services = {path = "services", version="0.2.3"} solana-lite-rpc-core = {path = "core", version="0.2.3"} solana-lite-rpc-cluster-endpoints = {path = "cluster-endpoints", version="0.2.3"} diff --git a/Dockerfile b/Dockerfile index 72356cf8..4c856301 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,11 +14,13 @@ FROM base as build COPY --from=plan /app/recipe.json recipe.json RUN cargo chef cook --release --recipe-path recipe.json COPY . . -RUN cargo build --release --bin lite-rpc --bin solana-lite-rpc-quic-forward-proxy +RUN cargo build --release --bin lite-rpc --bin solana-lite-rpc-quic-forward-proxy --bin bench-rpc --bin bench-direct-quic FROM debian:bullseye-slim as run RUN apt-get update && apt-get -y install ca-certificates libc6 COPY --from=build /app/target/release/solana-lite-rpc-quic-forward-proxy /usr/local/bin/ COPY --from=build /app/target/release/lite-rpc /usr/local/bin/ +COPY --from=build /app/target/release/bench-rpc /usr/local/bin/ +COPY --from=build /app/target/release/bench-direct-quic /usr/local/bin/ -CMD lite-rpc --rpc-addr "$RPC_URL" --ws-addr "$WS_URL" \ No newline at end of file +CMD lite-rpc --rpc-addr "$RPC_URL" --ws-addr "$WS_URL" diff --git a/bench/Cargo.toml b/bench/Cargo.toml index 3def8bf0..cb42ef62 100644 --- a/bench/Cargo.toml +++ b/bench/Cargo.toml @@ -3,9 +3,19 @@ name = "bench" version = "0.2.3" edition = "2021" +[[bin]] +name = "bench-rpc" +path = "src/bench_rpc.rs" + +[[bin]] +name = "bench-direct-quic" +path = "src/bench_direct_quic.rs" + [dependencies] +solana-lite-rpc-quic-forward-proxy = { path = "../quic-forward-proxy" } solana-sdk = { workspace = true } solana-rpc-client = { workspace = true } +solana-streamer = {workspace = true} log = { workspace = true } anyhow = { workspace = true } serde = { workspace = true } @@ -13,6 +23,7 @@ serde_json = { workspace = true } clap = { workspace = true } tokio = { version = "1.28.2", features = ["full", "fs"]} tracing-subscriber = { workspace = true } +bincode = { workspace = true } csv = "1.2.1" dirs = "5.0.0" rand = "0.8.5" diff --git a/bench/src/bench_direct_quic.rs b/bench/src/bench_direct_quic.rs new file mode 100644 index 00000000..a4bc8a33 --- /dev/null +++ b/bench/src/bench_direct_quic.rs @@ -0,0 +1,300 @@ +/// bench tool that uses the TPU client from quic proxy to submit transactions to TPUs via QUIC +/// +/// note: this tool requires a lite-rpc service that is configured to dump the current leader list to a file (leaders.dat) +/// important: need to enable flag ENABLE_LEADERSDAT_FOR_BENCH in tpu_service.rs +mod cli_direct_quic; +mod helpers; +mod metrics; + +use anyhow::Context; +use helpers::BenchHelper; +use metrics::{AvgMetric, Metric, TxMetricData}; + +use clap::Parser; +use dashmap::DashMap; +use futures::future::join_all; +use log::{debug, error, info}; +use solana_lite_rpc_quic_forward_proxy::outbound::tx_forward::tx_forwarder; +use solana_lite_rpc_quic_forward_proxy::shared::ForwardPacket; +use solana_lite_rpc_quic_forward_proxy::validator_identity::ValidatorIdentity; + +use solana_rpc_client::nonblocking::rpc_client::RpcClient; +use solana_rpc_client::rpc_client::SerializableTransaction; +use solana_sdk::signature::Signature; +use solana_sdk::transaction::Transaction; +use solana_sdk::{ + commitment_config::CommitmentConfig, hash::Hash, signature::Keypair, signer::Signer, + slot_history::Slot, +}; +use std::fs; +use std::fs::read_to_string; +use std::net::{SocketAddr, SocketAddrV4}; +use std::str::FromStr; +use std::sync::atomic::AtomicBool; +use std::sync::{ + atomic::{AtomicU64, Ordering}, + Arc, +}; +use std::time::SystemTime; +use tokio::{ + sync::{mpsc::UnboundedSender, RwLock}, + time::{Duration, Instant}, +}; + +#[tokio::main(flavor = "multi_thread", worker_threads = 16)] +async fn main() { + tracing_subscriber::fmt::init(); + + let cli_direct_quic::Args { + tx_count, + runs, + run_interval_ms, + metrics_file_name, + rpc_addr, + transaction_save_file, + } = cli_direct_quic::Args::parse(); + + let mut run_interval_ms = tokio::time::interval(Duration::from_millis(run_interval_ms)); + + info!("Using RPC service on {rpc_addr}"); + + let mut avg_metric = AvgMetric::default(); + + let mut tasks = vec![]; + + let funded_payer = BenchHelper::get_payer().await.unwrap(); + println!("payer : {}", funded_payer.pubkey()); + + let rpc_client = Arc::new(RpcClient::new_with_commitment( + rpc_addr.clone(), + CommitmentConfig::confirmed(), + )); + let bh = rpc_client.get_latest_blockhash().await.unwrap(); + let slot = rpc_client.get_slot().await.unwrap(); + let block_hash: Arc> = Arc::new(RwLock::new(bh)); + let current_slot = Arc::new(AtomicU64::new(slot)); + + { + // block hash updater task + let block_hash = block_hash.clone(); + let rpc_client = rpc_client.clone(); + let current_slot = current_slot.clone(); + tokio::spawn(async move { + loop { + let bh = rpc_client.get_latest_blockhash().await; + match bh { + Ok(bh) => { + let mut lock = block_hash.write().await; + *lock = bh; + } + Err(e) => println!("blockhash update error {}", e), + } + + let slot = rpc_client.get_slot().await; + match slot { + Ok(slot) => { + current_slot.store(slot, std::sync::atomic::Ordering::Relaxed); + } + Err(e) => println!("slot {}", e), + } + tokio::time::sleep(Duration::from_millis(100)).await; + } + }) + }; + + // transaction logger + let (tx_log_sx, mut tx_log_rx) = tokio::sync::mpsc::unbounded_channel::(); + let log_transactions = !transaction_save_file.is_empty(); + if log_transactions { + tokio::spawn(async move { + let mut tx_writer = csv::Writer::from_path(transaction_save_file).unwrap(); + while let Some(x) = tx_log_rx.recv().await { + tx_writer.serialize(x).unwrap(); + } + }); + } + + for seed in 0..runs { + let funded_payer = Keypair::from_bytes(funded_payer.to_bytes().as_slice()).unwrap(); + tasks.push(tokio::spawn(bench( + rpc_client.clone(), + tx_count, + funded_payer, + seed as u64, + block_hash.clone(), + current_slot.clone(), + tx_log_sx.clone(), + log_transactions, + ))); + // wait for an interval + run_interval_ms.tick().await; + } + + let join_res = join_all(tasks).await; + + let mut run_num = 1; + + let mut csv_writer = csv::Writer::from_path(metrics_file_name).unwrap(); + for res in join_res { + match res { + Ok(metric) => { + info!("Run {run_num}: Sent and Confirmed {tx_count} tx(s) in {metric:?} with",); + // update avg metric + avg_metric += &metric; + csv_writer.serialize(metric).unwrap(); + } + Err(_) => { + error!("join error for run {}", run_num); + } + } + run_num += 1; + } + + let avg_metric = Metric::from(avg_metric); + + info!("Avg Metric {avg_metric:?}",); + csv_writer.serialize(avg_metric).unwrap(); + + csv_writer.flush().unwrap(); +} + +#[derive(Clone, Debug, Copy)] +struct TxSendData { + sent_duration: Duration, + sent_instant: Instant, + sent_slot: Slot, +} + +#[allow(clippy::too_many_arguments)] +async fn bench( + rpc_client: Arc, + tx_count: usize, + funded_payer: Keypair, + seed: u64, + block_hash: Arc>, + current_slot: Arc, + tx_metric_sx: UnboundedSender, + log_txs: bool, +) -> Metric { + let map_of_txs: Arc> = Arc::new(DashMap::new()); + let (forwarder_channel, forward_receiver) = tokio::sync::mpsc::channel(1000); + + { + let validator_identity = ValidatorIdentity::new(None); + let exit_signal = Arc::new(AtomicBool::new(false)); + let _jh = tokio::spawn(tx_forwarder( + validator_identity, + forward_receiver, + exit_signal, + )); + } + // transaction sender task + { + let map_of_txs = map_of_txs.clone(); + let current_slot = current_slot.clone(); + // let forwarder_channel = forwarder_channel.clone(); + tokio::spawn(async move { + let map_of_txs = map_of_txs.clone(); + let rand_strings = BenchHelper::generate_random_strings(tx_count, Some(seed)); + for rand_string in rand_strings { + let blockhash = { *block_hash.read().await }; + let tx = BenchHelper::create_memo_tx(&rand_string, &funded_payer, blockhash); + + let leader_addrs = read_leaders_from_file("leaders.dat").expect("leaders.dat file"); + + let start_time = Instant::now(); + + debug!( + "sent tx {} to {} tpu nodes", + tx.get_signature(), + leader_addrs.len() + ); + for tpu_address in &leader_addrs { + let tx_raw = bincode::serialize::(&tx).unwrap(); + let packet = ForwardPacket::new( + vec![tx_raw], + SocketAddr::from(*tpu_address), + 0xdeadbeef, + ); + + forwarder_channel.send(packet).await.unwrap(); + + map_of_txs.insert( + *tx.get_signature(), + TxSendData { + sent_duration: start_time.elapsed(), + sent_instant: Instant::now(), + sent_slot: current_slot.load(std::sync::atomic::Ordering::Relaxed), + }, + ); + } + } + }); + } + + let mut metric = Metric::default(); + let confirmation_time = Instant::now(); + let mut confirmed_count = 0; + while confirmation_time.elapsed() < Duration::from_secs(60) + && !(map_of_txs.is_empty() && confirmed_count == tx_count) + { + let signatures = map_of_txs.iter().map(|x| *x.key()).collect::>(); + if signatures.is_empty() { + tokio::time::sleep(Duration::from_millis(1)).await; + continue; + } + let chunks = signatures.chunks(100).collect::>(); + for chunk in chunks { + if let Ok(res) = rpc_client.get_signature_statuses(chunk).await { + for (i, signature) in chunk.iter().enumerate() { + let tx_status = &res.value[i]; + if tx_status.is_some() { + let tx_data = map_of_txs.get(signature).unwrap(); + let time_to_confirm = tx_data.sent_instant.elapsed(); + metric.add_successful_transaction(tx_data.sent_duration, time_to_confirm); + + if log_txs { + let _ = tx_metric_sx.send(TxMetricData { + signature: signature.to_string(), + sent_slot: tx_data.sent_slot, + confirmed_slot: current_slot.load(Ordering::Relaxed), + time_to_send_in_millis: tx_data.sent_duration.as_millis() as u64, + time_to_confirm_in_millis: time_to_confirm.as_millis() as u64, + }); + } + drop(tx_data); + map_of_txs.remove(signature); + confirmed_count += 1; + } + } + } + tokio::time::sleep(Duration::from_millis(50)).await; + } + } + + for tx in map_of_txs.iter() { + metric.add_unsuccessful_transaction(tx.sent_duration); + } + metric.finalize(); + metric +} + +// note: this file gets written by tpu_services::dump_leaders_to_file; see docs how to activate +fn read_leaders_from_file(leaders_file: &str) -> anyhow::Result> { + let last_modified = fs::metadata("leaders.dat")?.modified().unwrap(); + let file_age = SystemTime::now().duration_since(last_modified).unwrap(); + assert!( + file_age.as_millis() < 1000, + "leaders.dat is outdated ({:?}) - pls run patched lite-rpc service", + file_age + ); + let leader_file = read_to_string(leaders_file)?; + let mut leader_addrs = vec![]; + for line in leader_file.lines() { + let socket_addr = SocketAddrV4::from_str(line) + .context(format!("error parsing line: {}", line)) + .unwrap(); + leader_addrs.push(socket_addr); + } + Ok(leader_addrs) +} diff --git a/bench/src/main.rs b/bench/src/bench_rpc.rs similarity index 97% rename from bench/src/main.rs rename to bench/src/bench_rpc.rs index 3b278bda..b2053e3e 100644 --- a/bench/src/main.rs +++ b/bench/src/bench_rpc.rs @@ -1,8 +1,10 @@ -use bench::{ - cli::Args, - helpers::BenchHelper, - metrics::{AvgMetric, Metric, TxMetricData}, -}; +mod cli_rpc; +mod helpers; +mod metrics; + +use helpers::BenchHelper; +use metrics::{AvgMetric, Metric, TxMetricData}; + use clap::Parser; use dashmap::DashMap; use futures::future::join_all; @@ -25,14 +27,14 @@ use tokio::{ async fn main() { tracing_subscriber::fmt::init(); - let Args { + let cli_rpc::Args { tx_count, runs, run_interval_ms, metrics_file_name, lite_rpc_addr, transaction_save_file, - } = Args::parse(); + } = cli_rpc::Args::parse(); let mut run_interval_ms = tokio::time::interval(Duration::from_millis(run_interval_ms)); diff --git a/bench/src/cli_direct_quic.rs b/bench/src/cli_direct_quic.rs new file mode 100644 index 00000000..2038c534 --- /dev/null +++ b/bench/src/cli_direct_quic.rs @@ -0,0 +1,23 @@ +use clap::{command, Parser}; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +pub struct Args { + /// Number of tx(s) sent in each run + #[arg(short = 'n', long, default_value_t = 5_000)] + pub tx_count: usize, + /// Number of bench runs + #[arg(short = 'r', long, default_value_t = 1)] + pub runs: usize, + /// Interval between each bench run (ms) + #[arg(short = 'i', long, default_value_t = 1000)] + pub run_interval_ms: u64, + /// Metrics output file name + #[arg(short = 'm', long, default_value_t = String::from("metrics.csv"))] + pub metrics_file_name: String, + /// Rpc Address to connect to + #[arg(long, default_value_t = String::from("http://127.0.0.1:8899"))] + pub rpc_addr: String, + #[arg(short = 't', long, default_value_t = String::from("transactions.csv"))] + pub transaction_save_file: String, +} diff --git a/bench/src/cli.rs b/bench/src/cli_rpc.rs similarity index 100% rename from bench/src/cli.rs rename to bench/src/cli_rpc.rs diff --git a/bench/src/lib.rs b/bench/src/lib.rs deleted file mode 100644 index 2733319e..00000000 --- a/bench/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod cli; -pub mod helpers; -pub mod metrics; diff --git a/cd/quic-forward-proxy.toml b/cd/quic-forward-proxy.toml index edefe136..21d34d60 100644 --- a/cd/quic-forward-proxy.toml +++ b/cd/quic-forward-proxy.toml @@ -11,3 +11,10 @@ kill_timeout = 5 [env] PROXY_LISTEN_ADDR = "[::]:11111" RUST_LOG = "debug" + +[[services]] + internal_port = 11111 + protocol = "udp" + +[[services.ports]] + port = "11111" diff --git a/core/src/structures/proxy_request_format.rs b/core/src/structures/proxy_request_format.rs index f1f32c4d..100fe70c 100644 --- a/core/src/structures/proxy_request_format.rs +++ b/core/src/structures/proxy_request_format.rs @@ -40,7 +40,7 @@ impl Display for TpuForwardingRequest { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "TpuForwardingRequest t9 {} tpu nodes", + "TpuForwardingRequest to {} tpu nodes", &self.tpu_nodes.len(), ) } diff --git a/lite-rpc/src/main.rs b/lite-rpc/src/main.rs index 77113717..786627be 100644 --- a/lite-rpc/src/main.rs +++ b/lite-rpc/src/main.rs @@ -265,7 +265,7 @@ fn configure_tpu_connection_path(quic_proxy_addr: Option) -> TpuConnecti Some(prox_address) => { let proxy_socket_addr = parse_host_port(prox_address.as_str()).unwrap(); TpuConnectionPath::QuicForwardProxyPath { - // e.g. "127.0.0.1:11111" or "localhost:11111" + // e.g. "127.0.0.1:11111" forward_proxy_address: proxy_socket_addr, } } diff --git a/quic-forward-proxy-integration-test/Cargo.toml b/quic-forward-proxy-integration-test/Cargo.toml index d2481d2a..8de47263 100644 --- a/quic-forward-proxy-integration-test/Cargo.toml +++ b/quic-forward-proxy-integration-test/Cargo.toml @@ -30,6 +30,7 @@ log = { workspace = true } clap = { workspace = true } dashmap = { workspace = true } itertools = { workspace = true } +tracing = { workspace = true } tracing-subscriber = { workspace = true, features = ["std", "env-filter"] } native-tls = { workspace = true } prometheus = { workspace = true } diff --git a/quic-forward-proxy-integration-test/src/bin/send_test_proxy_forward_requests.rs b/quic-forward-proxy-integration-test/src/bin/send_test_proxy_forward_requests.rs new file mode 100644 index 00000000..be45b3db --- /dev/null +++ b/quic-forward-proxy-integration-test/src/bin/send_test_proxy_forward_requests.rs @@ -0,0 +1,48 @@ +use solana_lite_rpc_services::tpu_utils::quic_proxy_connection_manager::{ + QuicProxyConnectionManager, TpuNode, +}; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::{Keypair, Signer}; +use solana_sdk::transaction::Transaction; +use std::net::SocketAddr; +use std::str::FromStr; + +/// +/// test with test-validator and quic-proxy +/// +#[tokio::main(flavor = "multi_thread", worker_threads = 16)] +pub async fn main() { + tracing_subscriber::fmt::fmt() + .with_max_level(tracing::Level::DEBUG) + .init(); + + send_test_to_proxy().await; +} + +async fn send_test_to_proxy() { + let tx = create_tx().await; + + // note: use the propaged TPU port - NOT port+6 + let tpu_address: SocketAddr = "127.0.0.1:1027".parse().unwrap(); + let proxy_address: SocketAddr = "127.0.0.1:11111".parse().unwrap(); + + let tpu_node = TpuNode { + tpu_address, + // tpu pubkey is only used for logging + tpu_identity: Pubkey::from_str("1111111jepwNWbYG87sgwnBbUJnQHrPiUJzMpqJXZ").unwrap(), + }; + QuicProxyConnectionManager::send_simple_transactions(vec![tx], vec![tpu_node], proxy_address) + .await + .unwrap(); +} + +async fn create_tx() -> Transaction { + let payer = Keypair::from_base58_string( + "rKiJ7H5UUp3JR18kNyTF1XPuwPKHEM7gMLWHZPWP5djrW1vSjfwjhvJrevxF9MPmUmN9gJMLHZdLMgc9ao78eKr", + ); + let payer_pubkey = payer.pubkey(); + + let memo_ix = spl_memo::build_memo("Hello world".as_bytes(), &[&payer_pubkey]); + + Transaction::new_with_payer(&[memo_ix], Some(&payer_pubkey)) +} diff --git a/quic-forward-proxy-integration-test/tests/quic_proxy_tpu_integrationtest.rs b/quic-forward-proxy-integration-test/tests/quic_proxy_tpu_integrationtest.rs index 20a2b1c6..cf7c1b4d 100644 --- a/quic-forward-proxy-integration-test/tests/quic_proxy_tpu_integrationtest.rs +++ b/quic-forward-proxy-integration-test/tests/quic_proxy_tpu_integrationtest.rs @@ -186,7 +186,6 @@ fn wireup_and_send_txs_via_channel(test_case_params: TestCaseParams) { // lite-rpc let runtime_literpc = Builder::new_multi_thread() - // see lite-rpc -> main.rs .worker_threads(16) // also works with 1 .enable_all() .build() diff --git a/quic-forward-proxy/Cargo.toml b/quic-forward-proxy/Cargo.toml index 95dddc80..dc373154 100644 --- a/quic-forward-proxy/Cargo.toml +++ b/quic-forward-proxy/Cargo.toml @@ -11,6 +11,8 @@ publish = false [dependencies] solana-lite-rpc-core = { workspace = true } +# required for promentheus-sync +solana-lite-rpc-services = { workspace = true } solana-sdk = { workspace = true } solana-streamer = { workspace = true } solana-transaction-status = { workspace = true } diff --git a/quic-forward-proxy/src/cli.rs b/quic-forward-proxy/src/cli.rs index 4c9d1d97..498a865a 100644 --- a/quic-forward-proxy/src/cli.rs +++ b/quic-forward-proxy/src/cli.rs @@ -5,7 +5,10 @@ use clap::Parser; pub struct Args { #[arg(short = 'k', long, default_value_t = String::new())] pub identity_keypair: String, - // e.g. 0.0.0.0:11111 or "localhost:11111" + // e.g. 0.0.0.0:11111 #[arg(short = 'l', long, env)] pub proxy_listen_addr: String, + /// enable metrics to prometheus at addr + #[arg(short = 'm', long, default_value_t = String::from("[::]:9092"))] + pub prometheus_addr: String, } diff --git a/quic-forward-proxy/src/inbound/proxy_listener.rs b/quic-forward-proxy/src/inbound/proxy_listener.rs index 49d5b17d..f98d30d9 100644 --- a/quic-forward-proxy/src/inbound/proxy_listener.rs +++ b/quic-forward-proxy/src/inbound/proxy_listener.rs @@ -4,7 +4,7 @@ use crate::shared::ForwardPacket; use crate::tls_config_provider_server::ProxyTlsConfigProvider; use crate::tls_self_signed_pair_generator::SelfSignedTlsConfigProvider; use crate::util::FALLBACK_TIMEOUT; -use anyhow::{anyhow, bail, Context}; +use anyhow::{bail, Context}; use log::{debug, error, info, trace, warn}; use quinn::{Connecting, Endpoint, ServerConfig, VarInt}; use solana_sdk::packet::PACKET_DATA_SIZE; @@ -133,7 +133,8 @@ impl ProxyListener { for tpu_node in proxy_request.get_tpu_nodes() { let tpu_address = tpu_node.tpu_socket_addr; - forwarder_channel_copy + + let send_result = forwarder_channel_copy .send_timeout( ForwardPacket::new( txs.clone(), @@ -143,8 +144,12 @@ impl ProxyListener { FALLBACK_TIMEOUT, ) .await - .context("sending internal packet from proxy to forwarder") - .unwrap(); + .context("sending internal packet from proxy to forwarder"); + + if let Err(err) = send_result { + error!("send failed: {}", err); + return; + } } }); @@ -156,10 +161,10 @@ impl ProxyListener { Err(quinn::ConnectionError::ApplicationClosed(reason)) => { debug!("connection closed by client - reason: {:?}", reason); if reason.error_code != VarInt::from_u32(0) { - return Err(anyhow!( + bail!( "connection closed by client with unexpected reason: {:?}", reason - )); + ); } debug!("connection gracefully closed by client"); return Ok(()); diff --git a/quic-forward-proxy/src/lib.rs b/quic-forward-proxy/src/lib.rs index ffc51a52..34921817 100644 --- a/quic-forward-proxy/src/lib.rs +++ b/quic-forward-proxy/src/lib.rs @@ -2,12 +2,12 @@ mod cli; mod inbound; -mod outbound; +pub mod outbound; pub mod proxy; pub mod proxy_request_format; mod quic_util; mod quinn_auto_reconnect; -mod shared; +pub mod shared; pub mod tls_config_provider_client; pub mod tls_config_provider_server; pub mod tls_self_signed_pair_generator; diff --git a/quic-forward-proxy/src/main.rs b/quic-forward-proxy/src/main.rs index 729fbd2c..1c7d96dd 100644 --- a/quic-forward-proxy/src/main.rs +++ b/quic-forward-proxy/src/main.rs @@ -6,6 +6,7 @@ use clap::Parser; use dotenv::dotenv; use log::info; use solana_lite_rpc_core::keypair_loader::load_identity_keypair; +use solana_lite_rpc_services::prometheus_sync::PrometheusSync; use std::sync::Arc; use crate::validator_identity::ValidatorIdentity; @@ -31,6 +32,7 @@ pub async fn main() -> anyhow::Result<()> { let Args { identity_keypair, proxy_listen_addr, + prometheus_addr, } = Args::parse(); dotenv().ok(); @@ -42,15 +44,17 @@ pub async fn main() -> anyhow::Result<()> { .await? .start_services(); + let prometheus = PrometheusSync::sync(prometheus_addr); + let ctrl_c_signal = tokio::signal::ctrl_c(); tokio::select! { res = main_services => { bail!("Services quit unexpectedly {res:?}"); }, - // res = test_client => { - // bail!("Test Client quit unexpectedly {res:?}"); - // }, + res = prometheus => { + bail!("Prometheus sync service exited unexpectedly {res:?}"); + } _ = ctrl_c_signal => { info!("Received ctrl+c signal"); diff --git a/quic-forward-proxy/src/outbound/tx_forward.rs b/quic-forward-proxy/src/outbound/tx_forward.rs index 8aeab522..e4843d9b 100644 --- a/quic-forward-proxy/src/outbound/tx_forward.rs +++ b/quic-forward-proxy/src/outbound/tx_forward.rs @@ -8,6 +8,7 @@ use crate::validator_identity::ValidatorIdentity; use anyhow::{bail, Context}; use futures::future::join_all; use log::{debug, info, trace, warn}; +use prometheus::{opts, register_int_counter, register_int_gauge, IntCounter, IntGauge}; use quinn::{ ClientConfig, Endpoint, EndpointConfig, IdleTimeout, TokioRuntime, TransportConfig, VarInt, }; @@ -26,6 +27,17 @@ const MAX_PARALLEL_STREAMS: usize = 6; pub const PARALLEL_TPU_CONNECTION_COUNT: usize = 4; const AGENT_SHUTDOWN_IDLE: Duration = Duration::from_millis(2500); // ms; should be 4x400ms+buffer +lazy_static::lazy_static! { + static ref OUTBOUND_SEND_TX: IntCounter = + register_int_counter!(opts!("literpcproxy_send_tx", "Proxy to TPU send transaction")).unwrap(); + static ref OUTBOUND_SEND_ERRORS: IntCounter = + register_int_counter!(opts!("literpcproxy_send_errors", "Proxy to TPU send errors")).unwrap(); + static ref OUTBOUND_BATCH_SIZE: IntGauge = + register_int_gauge!(opts!("literpcproxy_batch_size", "Proxy to TPU tx batch size")).unwrap(); + static ref OUTBOUND_PACKET_SIZE: IntGauge = + register_int_gauge!(opts!("literpcproxy_packet_size", "Proxy to TPU packet size")).unwrap(); +} + struct AgentHandle { pub tpu_address: SocketAddr, pub agent_exit_signal: Arc, @@ -63,7 +75,7 @@ pub async fn tx_forwarder( transaction_channel .recv() .await - .expect("channel closed unexpectedly"), + .ok_or(anyhow::anyhow!("transaction_channel closed"))?, ); let tpu_address = forward_packet.tpu_address; @@ -166,8 +178,13 @@ pub async fn tx_forwarder( auto_connection.target_address )); + OUTBOUND_BATCH_SIZE.set(transactions_batch.len() as i64); + + OUTBOUND_PACKET_SIZE.set(count_bytes(&transactions_batch)); + match result { Ok(()) => { + OUTBOUND_SEND_TX.inc(); debug!("send_txs_to_tpu_static sent {}", transactions_batch.len()); debug!( "Outbound connection stats: {}", @@ -175,6 +192,7 @@ pub async fn tx_forwarder( ); } Err(err) => { + OUTBOUND_SEND_ERRORS.inc(); warn!("got send_txs_to_tpu_static error {} - loop over errors", err); } } @@ -208,14 +226,24 @@ pub async fn tx_forwarder( debug!("tx-forward queue len: {}", broadcast_in.len()) } - broadcast_in - .send(forward_packet) - .expect("send must succeed"); + let enqueue_result = broadcast_in.send(forward_packet); + + if let Err(e) = enqueue_result { + warn!("broadcast channel send error: {}", e); + } } // -- loop over transactions from upstream channels // not reachable } +fn count_bytes(tx_vec: &Vec>) -> i64 { + let mut total_bytes = 0; + for tx in tx_vec { + total_bytes += tx.len(); + } + total_bytes as i64 +} + async fn cleanup_agents( agents: &mut HashMap, current_tpu_address: &SocketAddr, diff --git a/quic-forward-proxy/src/proxy_request_format.rs b/quic-forward-proxy/src/proxy_request_format.rs index 15b7af3d..5d2acafc 100644 --- a/quic-forward-proxy/src/proxy_request_format.rs +++ b/quic-forward-proxy/src/proxy_request_format.rs @@ -37,7 +37,7 @@ impl Display for TpuForwardingRequest { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "TpuForwardingRequest t9 {} tpu nodes", + "TpuForwardingRequest to {} tpu nodes", &self.tpu_nodes.len(), ) } diff --git a/quic-forward-proxy/src/quinn_auto_reconnect.rs b/quic-forward-proxy/src/quinn_auto_reconnect.rs index 14c0120c..e6147220 100644 --- a/quic-forward-proxy/src/quinn_auto_reconnect.rs +++ b/quic-forward-proxy/src/quinn_auto_reconnect.rs @@ -50,11 +50,12 @@ impl AutoReconnect { } pub async fn send_uni(&self, payload: &Vec) -> anyhow::Result<()> { - let mut send_stream = timeout(SEND_TIMEOUT, self.refresh_and_get().await?.open_uni()) + let connection = self.refresh_and_get().await?; + let mut send_stream = timeout(SEND_TIMEOUT, connection.open_uni()) .await .context("open uni stream for sending")??; - send_stream.write_all(payload.as_slice()).await?; - send_stream.finish().await?; + timeout(SEND_TIMEOUT, send_stream.write_all(payload.as_slice())).await??; + timeout(SEND_TIMEOUT, send_stream.finish()).await??; Ok(()) } diff --git a/services/src/tpu_utils/quic_proxy_connection_manager.rs b/services/src/tpu_utils/quic_proxy_connection_manager.rs index c1d4052e..ecee6119 100644 --- a/services/src/tpu_utils/quic_proxy_connection_manager.rs +++ b/services/src/tpu_utils/quic_proxy_connection_manager.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::net::{SocketAddr, UdpSocket}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket}; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering::Relaxed; use std::sync::Arc; @@ -11,6 +11,9 @@ use itertools::Itertools; use log::{debug, info, trace, warn}; use quinn::{ClientConfig, Endpoint, EndpointConfig, TokioRuntime, TransportConfig, VarInt}; use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::Keypair; +use solana_sdk::transaction::Transaction; +use solana_streamer::tls_certificates::new_self_signed_tls_certificate; use tokio::sync::broadcast::error::TryRecvError; use tokio::sync::{broadcast::Receiver, RwLock}; @@ -18,6 +21,7 @@ use tokio::sync::{broadcast::Receiver, RwLock}; use solana_lite_rpc_core::quic_connection_utils::{ QuicConnectionParameters, SkipServerVerification, }; +use solana_lite_rpc_core::solana_utils::SerializableTransaction; use solana_lite_rpc_core::structures::proxy_request_format::{TpuForwardingRequest, TxData}; use crate::tpu_utils::quinn_auto_reconnect::AutoReconnect; @@ -111,6 +115,7 @@ impl QuicProxyConnectionManager { const ALPN_TPU_FORWARDPROXY_PROTOCOL_ID: &[u8] = b"solana-tpu-forward-proxy"; let mut endpoint = { + // Binding on :: will also listen on IPv4 (dual-stack). let client_socket = UdpSocket::bind("[::]:0").unwrap(); let config = EndpointConfig::default(); Endpoint::new(config, None, client_socket, TokioRuntime) @@ -248,4 +253,42 @@ impl QuicProxyConnectionManager { Ok(()) } + + // testing only + pub async fn send_simple_transactions( + txs: Vec, + tpu_fanout_nodes: Vec, + proxy_address: SocketAddr, + ) -> anyhow::Result<()> { + let identity = Keypair::new(); + + let (certificate, key) = + new_self_signed_tls_certificate(&identity, IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))) + .unwrap(); + + let txs_data = txs + .iter() + .map(|tx| { + let tx_raw = bincode::serialize(tx).unwrap(); + let sig = tx.get_signature().to_string(); + TxData::new(sig, tx_raw) + }) + .collect_vec(); + + let endpoint = Self::create_proxy_client_endpoint(certificate, key); + let auto_reconnect = AutoReconnect::new(endpoint, proxy_address); + + info!("Sending {} transactions to quic proxy:", txs_data.len()); + for tx in &txs_data { + info!("- {:?}", tx) + } + + Self::send_copy_of_txs_to_quicproxy( + txs_data.as_slice(), + &auto_reconnect, + proxy_address, + tpu_fanout_nodes, + ) + .await + } } diff --git a/services/src/tpu_utils/quinn_auto_reconnect.rs b/services/src/tpu_utils/quinn_auto_reconnect.rs index 32f05367..a1011234 100644 --- a/services/src/tpu_utils/quinn_auto_reconnect.rs +++ b/services/src/tpu_utils/quinn_auto_reconnect.rs @@ -8,20 +8,29 @@ use tokio::sync::RwLock; use tokio::time::timeout; use tracing::debug; -/// copy of quic-proxy AutoReconnect - used that for reference +/// specialized connection manager with automatic reconnect; designated for connection lite-rpc -> quic proxy +/// +/// assumptions: +/// * connection to proxy service is reliable +/// * connection to proxy service is fast (50ms-200ms) and high-bandwidth +/// * proxy service will eventually be up again +/// * proxy location/IP address might change transparently +/// * proxy might be operated behind a load-balancer +/// * proxy will propagate backpressure by closing the connection +/// * proxy will not stall/delay connection but will respond fast with an error signal const SEND_TIMEOUT: Duration = Duration::from_secs(5); -const MAX_RETRY_ATTEMPTS: u32 = 10; enum ConnectionState { NotConnected, Connection(Connection), - PermanentError, + // not used for connection to proxy + _PermanentError, FailedAttempt(u32), } pub struct AutoReconnect { - // endoint should be configures with keep-alive and idle timeout + // endpoint should be configures with keep-alive and idle timeout endpoint: Endpoint, current: RwLock, pub target_address: SocketAddr, @@ -36,17 +45,18 @@ impl AutoReconnect { } } - pub async fn is_permanent_dead(&self) -> bool { + pub async fn _is_permanent_dead(&self) -> bool { let lock = self.current.read().await; - matches!(&*lock, ConnectionState::PermanentError) + matches!(&*lock, ConnectionState::_PermanentError) } pub async fn send_uni(&self, payload: &Vec) -> anyhow::Result<()> { - let mut send_stream = timeout(SEND_TIMEOUT, self.refresh_and_get().await?.open_uni()) + let connection = self.refresh_and_get().await?; + let mut send_stream = timeout(SEND_TIMEOUT, connection.open_uni()) .await .context("open uni stream for sending")??; - send_stream.write_all(payload.as_slice()).await?; - send_stream.finish().await?; + timeout(SEND_TIMEOUT, send_stream.write_all(payload.as_slice())).await??; + timeout(SEND_TIMEOUT, send_stream.finish()).await??; Ok(()) } @@ -57,7 +67,7 @@ impl AutoReconnect { match &*lock { ConnectionState::NotConnected => bail!("not connected"), ConnectionState::Connection(conn) => Ok(conn.clone()), - ConnectionState::PermanentError => bail!("permanent error"), + ConnectionState::_PermanentError => bail!("permanent error"), ConnectionState::FailedAttempt(_) => bail!("failed connection attempt"), } } @@ -90,7 +100,7 @@ impl AutoReconnect { ); match self.create_connection().await { - Some(new_connection) => { + Ok(new_connection) => { *lock = ConnectionState::Connection(new_connection.clone()); info!( "Restored closed connection {} with {} to target {}", @@ -99,10 +109,10 @@ impl AutoReconnect { self.target_address, ); } - None => { + Err(err) => { warn!( - "Reconnect to {} failed for connection {}", - self.target_address, old_stable_id + "Reconnect to {} failed for connection {}: {}", + self.target_address, old_stable_id, err ); *lock = ConnectionState::FailedAttempt(1); } @@ -117,7 +127,7 @@ impl AutoReconnect { } ConnectionState::NotConnected => { match self.create_connection().await { - Some(new_connection) => { + Ok(new_connection) => { *lock = ConnectionState::Connection(new_connection.clone()); info!( @@ -126,13 +136,16 @@ impl AutoReconnect { self.target_address ); } - None => { - warn!("Failed connect initially to target {}", self.target_address); + Err(err) => { + warn!( + "Failed connect initially to target {}: {}", + self.target_address, err + ); *lock = ConnectionState::FailedAttempt(1); } }; } - ConnectionState::PermanentError => { + ConnectionState::_PermanentError => { // no nothing debug!( "Not using connection to {} with permanent error", @@ -141,44 +154,37 @@ impl AutoReconnect { } ConnectionState::FailedAttempt(attempts) => { match self.create_connection().await { - Some(new_connection) => { + Ok(new_connection) => { *lock = ConnectionState::Connection(new_connection); } - None => { - if *attempts < MAX_RETRY_ATTEMPTS { - warn!( - "Reconnect to {} failed (attempt {})", - self.target_address, attempts - ); - *lock = ConnectionState::FailedAttempt(attempts + 1); - } else { - warn!( - "Reconnect to {} failed permanently (attempt {})", - self.target_address, attempts - ); - *lock = ConnectionState::PermanentError; - } + Err(err) => { + warn!( + "Reconnect to {} failed (attempt {}): {}", + self.target_address, attempts, err + ); + *lock = ConnectionState::FailedAttempt(attempts + 1); } }; } } } - async fn create_connection(&self) -> Option { + async fn create_connection(&self) -> anyhow::Result { let connection = self .endpoint .connect(self.target_address, "localhost") - .expect("handshake"); + .context("handshake")?; match connection.await { - Ok(conn) => Some(conn), - Err(ConnectionError::TimedOut) => None, + Ok(conn) => Ok(conn), + Err(ConnectionError::TimedOut) => bail!("timeout"), // maybe we should also treat TransportError explicitly Err(unexpected_error) => { - panic!( + warn!( "Connection to {} failed with unexpected error: {}", self.target_address, unexpected_error ); + bail!("Unecpected error connecting"); } } } @@ -200,7 +206,7 @@ impl AutoReconnect { conn.stats().path.rtt ), ConnectionState::NotConnected => "n/c".to_string(), - ConnectionState::PermanentError => "n/a (permanent)".to_string(), + ConnectionState::_PermanentError => "n/a (permanent)".to_string(), ConnectionState::FailedAttempt(_) => "fail".to_string(), } } diff --git a/services/src/tpu_utils/tpu_service.rs b/services/src/tpu_utils/tpu_service.rs index 703293a1..83f70db2 100644 --- a/services/src/tpu_utils/tpu_service.rs +++ b/services/src/tpu_utils/tpu_service.rs @@ -5,18 +5,28 @@ use super::tpu_connection_manager::TpuConnectionManager; use crate::tpu_utils::quic_proxy_connection_manager::QuicProxyConnectionManager; use crate::tpu_utils::tpu_connection_path::TpuConnectionPath; use crate::tpu_utils::tpu_service::ConnectionManager::{DirectTpu, QuicProxy}; +use itertools::Itertools; use solana_lite_rpc_core::quic_connection_utils::QuicConnectionParameters; use solana_lite_rpc_core::stores::data_cache::DataCache; use solana_lite_rpc_core::traits::leaders_fetcher_interface::LeaderFetcherInterface; use solana_lite_rpc_core::types::SlotStream; use solana_lite_rpc_core::AnyhowJoinHandle; +use solana_sdk::pubkey::Pubkey; use solana_sdk::{quic::QUIC_PORT_OFFSET, signature::Keypair, slot_history::Slot}; use solana_streamer::tls_certificates::new_self_signed_tls_certificate; +use std::collections::HashMap; +use std::fs::File; +use std::io::Write; +use std::net::SocketAddr; +use std::path::Path; use std::{ net::{IpAddr, Ipv4Addr}, sync::Arc, }; +// enable unless it is needed for bench_direct_quic.rs for performance reasons +const ENABLE_LEADERSDAT_FOR_BENCH: bool = false; + lazy_static::lazy_static! { static ref NB_CLUSTER_NODES: GenericGauge = register_int_gauge!(opts!("literpc_nb_cluster_nodes", "Number of cluster nodes in saved")).unwrap(); @@ -122,7 +132,7 @@ impl TpuService { .get_slot_leaders(current_slot, last_slot) .await?; // get next leader with its tpu port - let connections_to_keep = next_leaders + let connections_to_keep: HashMap = next_leaders .iter() .map(|x| { let contact_info = cluster_nodes.get(&x.pubkey); @@ -141,6 +151,10 @@ impl TpuService { }) .collect(); + if ENABLE_LEADERSDAT_FOR_BENCH { + dump_leaders_to_file(connections_to_keep.values().collect_vec()); + } + match &self.connection_manager { DirectTpu { tpu_connection_manager, @@ -189,3 +203,21 @@ impl TpuService { }) } } + +// used for bench tool +// optionally dumps the leaders to disk for later use +fn dump_leaders_to_file(leaders: Vec<&SocketAddr>) { + // files acts as feature flag - create it on filesystem to enable + if !Path::exists(Path::new("leaders.dat")) { + return; + } + // will create/truncate file + let mut out_file = File::create("leaders.dat.tmp").unwrap(); + for leader_addr in &leaders { + // 69.197.20.37:8009 + writeln!(out_file, "{}", leader_addr).unwrap(); + } + out_file.flush().unwrap(); + + std::fs::rename("leaders.dat.tmp", "leaders.dat").unwrap(); +}