diff --git a/Cargo.lock b/Cargo.lock index 9e82e978f..2052d0aa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,9 +64,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ "getrandom", "once_cell", @@ -75,14 +75,15 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -169,11 +170,20 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "arbitrary" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2e1373abdaa212b704512ec2bd8b26bd0b7d5c3f70117411a5d9a451383c859" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" dependencies = [ "derive_arbitrary", ] @@ -257,9 +267,9 @@ dependencies = [ "log", "parking", "polling", - "rustix 0.37.25", + "rustix 0.37.27", "slab", - "socket2 0.4.9", + "socket2 0.4.10", "waker-fn", ] @@ -280,7 +290,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -354,7 +364,7 @@ checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", - "base64 0.21.4", + "base64 0.21.5", "bitflags 1.3.2", "bytes", "futures-util", @@ -426,9 +436,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "base64ct" @@ -463,7 +473,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -719,9 +729,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ "clap_builder", "clap_derive", @@ -729,9 +739,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstream", "anstyle", @@ -741,21 +751,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "cloudabi" @@ -862,9 +872,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -963,9 +973,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crossbeam" @@ -1075,7 +1085,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "socket2 0.4.9", + "socket2 0.4.10", "winapi", ] @@ -1113,13 +1123,13 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1143,7 +1153,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1154,7 +1164,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1164,7 +1174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.1", + "hashbrown 0.14.2", "lock_api", "once_cell", "parking_lot_core", @@ -1255,13 +1265,13 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1305,7 +1315,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1380,7 +1390,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1421,7 +1431,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1499,7 +1509,7 @@ dependencies = [ "tar", "thiserror", "tokio", - "toml 0.8.2", + "toml 0.8.6", "tracing", "tracing-subscriber", "xz2", @@ -1507,9 +1517,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" +checksum = "a481586acf778f1b1455424c343f71124b048ffa5f4fc3f8f6ae9dc432dcb3c7" [[package]] name = "filetime" @@ -1610,6 +1620,7 @@ dependencies = [ "serde_json", "serde_with", "sqlx", + "statrs", "stretto", "tar", "thiserror", @@ -1630,7 +1641,7 @@ version = "0.0.5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1652,7 +1663,7 @@ dependencies = [ "rand 0.8.5", "semver", "serde", - "serde-wasm-bindgen 0.6.0", + "serde-wasm-bindgen 0.6.1", "serde_bytes", "serde_json", "serde_with", @@ -1689,9 +1700,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -1714,9 +1725,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -1724,15 +1735,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -1753,9 +1764,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-lite" @@ -1774,13 +1785,13 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1795,15 +1806,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-timer" @@ -1813,9 +1824,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -1919,16 +1930,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.7", ] [[package]] name = "hashbrown" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "allocator-api2", ] @@ -1938,7 +1949,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.1", + "hashbrown 0.14.2", ] [[package]] @@ -1947,7 +1958,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "bytes", "headers-core", "http", @@ -2081,7 +2092,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -2199,12 +2210,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown 0.14.2", "serde", ] @@ -2269,7 +2280,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.4", + "socket2 0.5.5", "widestring", "windows-sys 0.48.0", "winreg", @@ -2277,9 +2288,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "isahc" @@ -2332,9 +2343,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -2393,9 +2404,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libloading" @@ -2590,7 +2601,7 @@ dependencies = [ "log", "rand 0.8.5", "smallvec", - "socket2 0.5.4", + "socket2 0.5.5", "tokio", "trust-dns-proto 0.22.0", "void", @@ -2672,18 +2683,18 @@ dependencies = [ "parking_lot", "quinn", "rand 0.8.5", - "ring", + "ring 0.16.20", "rustls", - "socket2 0.5.4", + "socket2 0.5.5", "thiserror", "tokio", ] [[package]] name = "libp2p-request-response" -version = "0.25.2" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c772216645a224da196588418bf562e99a87413c6f49d74b4a1e3b4f5c8add3d" +checksum = "d8e3b4d67870478db72bac87bfc260ee6641d0734e0e3e275798f089c3fecfd4" dependencies = [ "async-trait", "futures", @@ -2699,9 +2710,9 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.43.6" +version = "0.43.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ff0e918a45fec0b6f27b30b0547a57c6c214aa8b13be3647b7701bfd8b8797" +checksum = "580189e0074af847df90e75ef54f3f30059aedda37ea5a1659e8b9fca05c0141" dependencies = [ "either", "fnv", @@ -2730,7 +2741,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2746,7 +2757,7 @@ dependencies = [ "libp2p-core", "libp2p-identity", "log", - "socket2 0.5.4", + "socket2 0.5.5", "tokio", ] @@ -2761,7 +2772,7 @@ dependencies = [ "libp2p-core", "libp2p-identity", "rcgen", - "ring", + "ring 0.16.20", "rustls", "rustls-webpki", "thiserror", @@ -2798,6 +2809,17 @@ dependencies = [ "yamux", ] +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "librocksdb-sys" version = "0.11.0+8.1.1" @@ -2875,7 +2897,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efa59af2ddfad1854ae27d75009d538d0998b4b2fd47083e743ac1a10e46c60" dependencies = [ - "hashbrown 0.14.1", + "hashbrown 0.14.2", ] [[package]] @@ -2934,6 +2956,16 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "matrixmultiply" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +dependencies = [ + "autocfg 1.1.0", + "rawpointer", +] + [[package]] name = "md-5" version = "0.10.6" @@ -3019,9 +3051,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "log", @@ -3089,6 +3121,35 @@ dependencies = [ "unsigned-varint", ] +[[package]] +name = "nalgebra" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d506eb7e08d6329505faa8a3a00a5dcc6de9f76e0c77e4b75763ae3c770831ff" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "rand 0.8.5", + "rand_distr", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "netlink-packet-core" version = "0.4.2" @@ -3250,6 +3311,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -3271,6 +3341,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg 1.1.0", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -3329,9 +3410,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" dependencies = [ "cc", "libc", @@ -3558,9 +3639,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" dependencies = [ "memchr", "thiserror", @@ -3569,9 +3650,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" dependencies = [ "pest", "pest_generator", @@ -3579,22 +3660,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "pest_meta" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" dependencies = [ "once_cell", "pest", @@ -3624,7 +3705,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3668,9 +3749,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" -version = "3.1.2" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" [[package]] name = "polling" @@ -3741,7 +3822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3776,7 +3857,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3808,7 +3889,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3885,7 +3966,7 @@ checksum = "2c78e758510582acc40acb90458401172d41f1016f8c9dde89e49677afb7eec1" dependencies = [ "bytes", "rand 0.8.5", - "ring", + "ring 0.16.20", "rustc-hash", "rustls", "slab", @@ -3902,7 +3983,7 @@ checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" dependencies = [ "bytes", "libc", - "socket2 0.5.4", + "socket2 0.5.5", "tracing", "windows-sys 0.48.0", ] @@ -3996,6 +4077,16 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "rand_hc" version = "0.1.0" @@ -4059,6 +4150,12 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.8.0" @@ -4086,7 +4183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", - "ring", + "ring 0.16.20", "time", "yasna", ] @@ -4100,15 +4197,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.3.5" @@ -4129,12 +4217,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] @@ -4235,11 +4323,25 @@ dependencies = [ "libc", "once_cell", "spin 0.5.2", - "untrusted", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", +] + [[package]] name = "rkyv" version = "0.7.42" @@ -4292,16 +4394,14 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +checksum = "86ef35bf3e7fe15a53c4ab08a998e42271eab13eb0db224126bc7bc4c4bad96d" dependencies = [ - "byteorder", "const-oid", "digest", "num-bigint-dig", "num-integer", - "num-iter", "num-traits", "pkcs1", "pkcs8", @@ -4369,9 +4469,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.25" +version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4eb579851244c2c03e7c24f501c3432bed80b8f720af1d6e5b0e0f01555a035" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ "bitflags 1.3.2", "errno", @@ -4383,9 +4483,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.19" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ "bitflags 2.4.1", "errno", @@ -4396,12 +4496,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" dependencies = [ "log", - "ring", + "ring 0.17.5", "rustls-webpki", "sct", ] @@ -4412,17 +4512,17 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", ] [[package]] name = "rustls-webpki" -version = "0.101.6" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.5", + "untrusted 0.9.0", ] [[package]] @@ -4448,6 +4548,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "safe_arch" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -4474,12 +4583,12 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[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.5", + "untrusted 0.9.0", ] [[package]] @@ -4505,9 +4614,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] @@ -4525,9 +4634,9 @@ dependencies = [ [[package]] name = "serde-wasm-bindgen" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c9933e5689bd420dc6c87b7a1835701810cbc10cd86a26e4da45b73e6b1d78" +checksum = "17ba92964781421b6cef36bf0d7da26d201e96d84e1b10e7ae6ed416e516906d" dependencies = [ "js-sys", "serde", @@ -4545,20 +4654,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -4567,9 +4676,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] @@ -4592,11 +4701,11 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_json", "serde_with_macros", @@ -4612,7 +4721,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4681,6 +4790,19 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simba" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0b7840f121a46d63066ee7a99fc81dcabbc6105e437cae43528cea199b5a05f" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + [[package]] name = "simdutf8" version = "0.1.4" @@ -4730,7 +4852,7 @@ dependencies = [ "chacha20poly1305 0.9.1", "curve25519-dalek", "rand_core 0.6.4", - "ring", + "ring 0.16.20", "rustc_version", "sha2", "subtle", @@ -4738,9 +4860,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -4748,9 +4870,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys 0.48.0", @@ -4811,7 +4933,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d6753e460c998bbd4cd8c6f0ed9a64346fcca0723d6e75e52fdc351c5d2169d" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "atoi", "byteorder", "bytes", @@ -4827,7 +4949,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.0.2", + "indexmap 2.1.0", "log", "memchr", "once_cell", @@ -4893,7 +5015,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db" dependencies = [ "atoi", - "base64 0.21.4", + "base64 0.21.5", "bitflags 2.4.1", "byteorder", "bytes", @@ -4935,7 +5057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624" dependencies = [ "atoi", - "base64 0.21.4", + "base64 0.21.5", "bitflags 2.4.1", "byteorder", "crc", @@ -5001,6 +5123,19 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "statrs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d08e5e1748192713cc281da8b16924fb46be7b0c2431854eadc785823e5696e" +dependencies = [ + "approx", + "lazy_static", + "nalgebra", + "num-traits", + "rand 0.8.5", +] + [[package]] name = "stretto" version = "0.8.2" @@ -5058,9 +5193,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -5125,41 +5260,41 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.11" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" +checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand 2.0.1", - "redox_syscall 0.3.5", - "rustix 0.38.19", + "redox_syscall 0.4.1", + "rustix 0.38.21", "windows-sys 0.48.0", ] [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5252,7 +5387,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.4", + "socket2 0.5.5", "tokio-macros", "windows-sys 0.48.0", ] @@ -5265,7 +5400,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5293,9 +5428,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -5316,11 +5451,11 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "8ff9e3abce27ee2c9a37f9ad37238c1bdd4e789c84ba37df76aa4d528f5072cc" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -5329,20 +5464,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -5422,7 +5557,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5447,12 +5582,12 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] @@ -5508,7 +5643,7 @@ dependencies = [ "lazy_static", "rand 0.8.5", "smallvec", - "socket2 0.4.9", + "socket2 0.4.10", "thiserror", "tinyvec", "tokio", @@ -5518,9 +5653,9 @@ dependencies = [ [[package]] name = "trust-dns-proto" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559ac980345f7f5020883dd3bcacf176355225e01916f8c2efecad7534f682c6" +checksum = "3119112651c157f4488931a01e586aa459736e9d6046d3bd9105ffb69352d374" dependencies = [ "async-trait", "cfg-if", @@ -5543,9 +5678,9 @@ dependencies = [ [[package]] name = "trust-dns-resolver" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c723b0e608b24ad04c73b2607e0241b2c98fd79795a95e98b068b6966138a29d" +checksum = "10a3e6c3aff1718b3c73e395d1f35202ba2ffa847c6a62eea0db8fb4cfe30be6" dependencies = [ "cfg-if", "futures-util", @@ -5559,7 +5694,7 @@ dependencies = [ "thiserror", "tokio", "tracing", - "trust-dns-proto 0.23.1", + "trust-dns-proto 0.23.2", ] [[package]] @@ -5701,6 +5836,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 = "url" version = "2.4.1" @@ -5793,9 +5934,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "serde", @@ -5805,16 +5946,16 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-shared", ] @@ -5843,9 +5984,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5853,37 +5994,37 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "wasm-encoder" -version = "0.35.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca90ba1b5b0a70d3d49473c5579951f3bddc78d47b59256d2f9d4922b150aca" +checksum = "1ba64e81215916eaeb48fee292f29401d69235d62d8b8fd92a7b2844ec5ae5f7" dependencies = [ "leb128", ] [[package]] name = "wasmer" -version = "4.2.2" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e626f958755a90a6552b9528f59b58a62ae288e6c17fcf40e99495bc33c60f0" +checksum = "50cb1ae2956aac1fbbcf334c543c1143cdf7d5b0a5fb6c3d23a17bf37dd1f47b" dependencies = [ "bytes", "cfg-if", @@ -5910,9 +6051,9 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "4.2.2" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848e1922694cf97f4df680a0534c9d72c836378b5eb2313c1708fe1a75b40044" +checksum = "12fd9aeef339095798d1e04957d5657d97490b1112f145cbf08b98f6393b4a0a" dependencies = [ "backtrace", "bytes", @@ -5937,9 +6078,9 @@ dependencies = [ [[package]] name = "wasmer-compiler-cranelift" -version = "4.2.2" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d96bce6fad15a954edcfc2749b59e47ea7de524b6ef3df392035636491a40b4" +checksum = "344f5f1186c122756232fe7f156cc8d2e7bf333d5a658e81e25efa3415c26d07" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -5956,9 +6097,9 @@ dependencies = [ [[package]] name = "wasmer-derive" -version = "4.2.2" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f08f80d166a9279671b7af7a09409c28ede2e0b4e3acabbf0e3cb22c8038ba7" +checksum = "2ac8c1f2dc0ed3c7412a5546e468365184a461f8ce7dfe2a707b621724339f91" dependencies = [ "proc-macro-error", "proc-macro2", @@ -5968,9 +6109,9 @@ dependencies = [ [[package]] name = "wasmer-types" -version = "4.2.2" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae2c892882f0b416783fb4310e5697f5c30587f6f9555f9d4f2be85ab39d5d3d" +checksum = "5a57ecbf218c0a9348d4dfbdac0f9d42d9201ae276dffb13e61ea4ff939ecce7" dependencies = [ "bytecheck", "enum-iterator", @@ -5984,9 +6125,9 @@ dependencies = [ [[package]] name = "wasmer-vm" -version = "4.2.2" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c0a9a57b627fb39e5a491058d4365f099bc9b140031c000fded24a3306d9480" +checksum = "60c3513477bc0097250f6e34a640e2a903bb0ee57e6bb518c427f72c06ac7728" dependencies = [ "backtrace", "cc", @@ -6022,9 +6163,9 @@ dependencies = [ [[package]] name = "wast" -version = "66.0.2" +version = "64.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93cb43b0ac6dd156f2c375735ccfd72b012a7c0a6e6d09503499b8d3cb6e6072" +checksum = "a259b226fd6910225aa7baeba82f9d9933b6d00f2ce1b49b80fa4214328237cc" dependencies = [ "leb128", "memchr", @@ -6034,18 +6175,18 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.77" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e367582095d2903caeeea9acbb140e1db9c7677001efa4347c3687fd34fe7072" +checksum = "53253d920ab413fca1c7dc2161d601c79b4fdf631d0ba51dd4343bf9b556c3f6" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -6075,6 +6216,16 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" +[[package]] +name = "wide" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68938b57b33da363195412cfc5fc37c9ed49aa9cfe2156fde64b8d2c9498242" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "widestring" version = "1.0.2" @@ -6242,9 +6393,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.17" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] @@ -6369,6 +6520,26 @@ dependencies = [ "time", ] +[[package]] +name = "zerocopy" +version = "0.7.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "zeroize" version = "1.6.0" @@ -6386,5 +6557,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 52474ae34..2a18499a6 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -88,6 +88,7 @@ tracing = "0.1" arbitrary = { version = "1", features = ["derive"] } itertools = "0.11" pico-args = "0.5" +statrs = "0.16.0" freenet-stdlib = { workspace = true, features = ["testing", "net"] } [features] diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index e26ed2240..fa71d6a6d 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -10,6 +10,7 @@ mod router; mod runtime; #[cfg(feature = "websocket")] pub mod server; +mod topology; pub mod util; type DynError = Box; diff --git a/crates/core/src/ring.rs b/crates/core/src/ring.rs index eca228473..664f2bdd9 100644 --- a/crates/core/src/ring.rs +++ b/crates/core/src/ring.rs @@ -10,11 +10,13 @@ //! - next node //! - final location +use std::hash::Hash; use std::{ collections::BTreeMap, convert::TryFrom, fmt::Display, hash::Hasher, + ops::Add, sync::{ atomic::{AtomicU64, AtomicUsize, Ordering::SeqCst}, Arc, @@ -446,6 +448,11 @@ impl Location { Location(location) } + /// Returns a new location rounded to ensure it is between 0.0 and 1.0 + pub fn new_rounded(location: f64) -> Self { + Self::new(location.rem_euclid(1.0)) + } + /// Returns a new random location. pub fn random() -> Self { use rand::prelude::*; @@ -462,6 +469,10 @@ impl Location { Distance::new(1.0f64 - d) } } + + pub fn as_f64(&self) -> f64 { + self.0 + } } /// Ensure at compile time locations can only be constructed from well formed contract keys @@ -535,10 +546,14 @@ impl Distance { pub fn new(value: f64) -> Self { debug_assert!(!value.is_nan(), "Distance cannot be NaN"); debug_assert!( - (0.0..=0.5).contains(&value), - "Distance must be in the range [0, 0.5]" + (0.0..=1.0).contains(&value), + "Distance must be in the range [0, 1.0]" ); - Distance(value) + if value <= 0.5 { + Distance(value) + } else { + Distance(1.0 - value) + } } pub fn as_f64(&self) -> f64 { @@ -546,12 +561,26 @@ impl Distance { } } +impl Add for Distance { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + let d = self.0 + rhs.0; + if d > 0.5 { + Distance::new(1.0 - d) + } else { + Distance::new(d) + } + } +} + impl PartialEq for Distance { fn eq(&self, other: &Self) -> bool { (self.0 - other.0).abs() < f64::EPSILON } } +#[allow(clippy::incorrect_partial_ord_impl_on_ord_type)] impl PartialOrd for Distance { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) diff --git a/crates/core/src/topology/connection_evaluator/mod.rs b/crates/core/src/topology/connection_evaluator/mod.rs new file mode 100644 index 000000000..c7b46d004 --- /dev/null +++ b/crates/core/src/topology/connection_evaluator/mod.rs @@ -0,0 +1,63 @@ +use std::collections::VecDeque; +use std::time::{Duration, Instant}; + +/// `ConnectionEvaluator` is used to evaluate connection scores within a specified time window. +/// +/// The evaluator records scores and determines whether a given score is better (higher) than +/// any other scores within a predefined time window. A score is considered better if it's higher +/// than all other scores in the time window, or if no scores were recorded within the window's +/// duration. +/// +/// In the Freenet context, this will be used to titrate the rate of new connection requests accepted +/// by a node. The node will only accept a new connection if the score of the connection is better +/// than all other scores within the time window. +pub(crate) struct ConnectionEvaluator { + scores: VecDeque<(Instant, f64)>, + window_duration: Duration, +} + +impl ConnectionEvaluator { + pub fn new(window_duration: Duration) -> Self { + ConnectionEvaluator { + scores: VecDeque::new(), + window_duration, + } + } + + pub fn record_only(&mut self, score: f64) { + self.record_only_with_current_time(score, Instant::now()); + } + + pub fn record_only_with_current_time(&mut self, score: f64, current_time: Instant) { + self.remove_outdated_scores(current_time); + self.scores.push_back((current_time, score)); + } + + pub fn record_and_eval(&mut self, score: f64) -> bool { + self.record_and_eval_with_current_time(score, Instant::now()) + } + + pub fn record_and_eval_with_current_time(&mut self, score: f64, current_time: Instant) -> bool { + self.remove_outdated_scores(current_time); + + let is_better = self.scores.is_empty() || self.scores.iter().all(|&(_, s)| score > s); + + // Important to add new score *after* checking if it's better than all other scores + self.record_only_with_current_time(score, current_time); + + is_better + } + + fn remove_outdated_scores(&mut self, current_time: Instant) { + while let Some(&(time, _)) = self.scores.front() { + if current_time.duration_since(time) > self.window_duration { + self.scores.pop_front(); + } else { + break; + } + } + } +} + +#[cfg(test)] +mod tests; diff --git a/crates/core/src/topology/connection_evaluator/tests.rs b/crates/core/src/topology/connection_evaluator/tests.rs new file mode 100644 index 000000000..52bbf4974 --- /dev/null +++ b/crates/core/src/topology/connection_evaluator/tests.rs @@ -0,0 +1,84 @@ +use super::*; + +#[test] +fn test_record_first_score() { + let mut evaluator = ConnectionEvaluator::new(Duration::from_secs(10)); + let current_time = Instant::now(); + assert!(evaluator.record_and_eval_with_current_time(5.0, current_time)); + // Assert evaluator.scores contains the new score + assert_eq!(evaluator.scores.len(), 1); + assert_eq!(evaluator.scores[0].1, 5.0); + assert_eq!(evaluator.scores[0].0, current_time); +} + +#[test] +fn test_not_best_in_time_window() { + let mut evaluator = ConnectionEvaluator::new(Duration::from_secs(10)); + + let start_time = Instant::now(); + evaluator.record_and_eval_with_current_time(5.0, start_time); + assert!(!evaluator.record_and_eval_with_current_time(4.0, start_time + Duration::from_secs(5)),); +} + +#[test] +fn test_best_in_time_window() { + let mut evaluator = ConnectionEvaluator::new(Duration::from_secs(10)); + + let start_time = Instant::now(); + evaluator.record_and_eval_with_current_time(5.0, start_time); + assert!(evaluator.record_and_eval_with_current_time(4.0, start_time + Duration::from_secs(11)),); +} + +#[test] +fn test_remove_outdated_scores() { + let mut evaluator = ConnectionEvaluator::new(Duration::from_secs(10)); + + let start_time = Instant::now(); + evaluator.record_and_eval_with_current_time(5.0, start_time); + evaluator.record_and_eval_with_current_time(6.0, start_time + Duration::from_secs(5)); + evaluator.record_and_eval_with_current_time(4.5, start_time + Duration::from_secs(11)); + assert_eq!(evaluator.scores.len(), 2); +} + +#[test] +fn test_empty_window_duration() { + let mut evaluator = ConnectionEvaluator::new(Duration::from_secs(0)); + let current_time = Instant::now(); + assert!(evaluator.record_and_eval_with_current_time(5.0, current_time)); + assert!(!evaluator.record_and_eval_with_current_time(4.0, current_time)); +} + +#[test] +fn test_multiple_scores_same_timestamp() { + let mut evaluator = ConnectionEvaluator::new(Duration::from_secs(10)); + let current_time = Instant::now(); + evaluator.record_only_with_current_time(5.0, current_time); + evaluator.record_only_with_current_time(6.0, current_time); + assert_eq!(evaluator.scores.len(), 2); + assert!( + !evaluator.record_and_eval_with_current_time(4.0, current_time + Duration::from_secs(5)), + ); +} + +#[test] +fn test_negative_scores() { + let mut evaluator = ConnectionEvaluator::new(Duration::from_secs(10)); + let start_time = Instant::now(); + assert!(evaluator.record_and_eval_with_current_time(-5.0, start_time),); + assert!(evaluator.record_and_eval_with_current_time(-4.0, start_time + Duration::from_secs(5)),); + assert!( + !evaluator.record_and_eval_with_current_time(-6.0, start_time + Duration::from_secs(5)), + ); +} + +#[test] +fn test_large_number_of_scores() { + let mut evaluator = ConnectionEvaluator::new(Duration::from_secs(10)); + let start_time = Instant::now(); + for i in 0..1000 { + evaluator.record_only_with_current_time(i as f64, start_time + Duration::from_secs(i)); + } + assert!( + evaluator.record_and_eval_with_current_time(1000.0, start_time + Duration::from_secs(1001)), + ); +} diff --git a/crates/core/src/topology/mod.rs b/crates/core/src/topology/mod.rs new file mode 100644 index 000000000..3135ae4f8 --- /dev/null +++ b/crates/core/src/topology/mod.rs @@ -0,0 +1,241 @@ +#![allow(unused_variables, dead_code)] + +use crate::ring::{Distance, Location}; +use request_density_tracker::cached_density_map::CachedDensityMap; +use std::{ + collections::BTreeMap, + rc::Rc, + time::{Duration, Instant}, +}; +use tracing::{debug, error, info}; + +use self::{request_density_tracker::DensityMapError, small_world_rand::random_link_distance}; + +mod connection_evaluator; +mod request_density_tracker; +mod small_world_rand; + +const SLOW_CONNECTION_EVALUATOR_WINDOW_DURATION: Duration = Duration::from_secs(5 * 60); +const FAST_CONNECTION_EVALUATOR_WINDOW_DURATION: Duration = Duration::from_secs(60); +const REQUEST_DENSITY_TRACKER_WINDOW_SIZE: usize = 10_000; +const REGENERATE_DENSITY_MAP_INTERVAL: Duration = Duration::from_secs(60); +const RANDOM_CLOSEST_DISTANCE: f64 = 1.0 / 1000.0; + +/// The goal of `TopologyManager` is to select new connections such that the +/// distribution of connections is as close as possible to the +/// distribution of outbound requests. +/// +/// This is done by maintaining a `RequestDensityTracker` which tracks the +/// distribution of requests in the network. The `TopologyManager` uses this +/// tracker to create a `DensityMap` which is used to evaluate the density of +/// requests at a given location. +/// +/// The `TopologyManager` uses the density map to select the best candidate +/// location, which is assumed to be close to peer connections that are +/// currently receiving a lot of requests. This should have the effect of +/// "balancing" out requests over time. +/// +/// The `TopologyManager` also uses a `ConnectionEvaluator` to evaluate whether +/// a given connection is better than all other connections within a predefined +/// time window. The goal of this is to select the best connections over time +/// from incoming join requests. +pub(crate) struct TopologyManager { + slow_connection_evaluator: connection_evaluator::ConnectionEvaluator, + fast_connection_evaluator: connection_evaluator::ConnectionEvaluator, + request_density_tracker: request_density_tracker::RequestDensityTracker, + cached_density_map: CachedDensityMap, + this_peer_location: Location, +} + +impl TopologyManager { + /// Create a new TopologyManager specifying the peer's own Location + pub(crate) fn new(this_peer_location: Location) -> Self { + info!("Creating a new TopologyManager instance"); + TopologyManager { + slow_connection_evaluator: connection_evaluator::ConnectionEvaluator::new( + SLOW_CONNECTION_EVALUATOR_WINDOW_DURATION, + ), + fast_connection_evaluator: connection_evaluator::ConnectionEvaluator::new( + FAST_CONNECTION_EVALUATOR_WINDOW_DURATION, + ), + request_density_tracker: request_density_tracker::RequestDensityTracker::new( + REQUEST_DENSITY_TRACKER_WINDOW_SIZE, + ), + cached_density_map: CachedDensityMap::new(REGENERATE_DENSITY_MAP_INTERVAL), + this_peer_location, + } + } + + /// Record a request and the location it's targeting + pub(crate) fn record_request( + &mut self, + requested_location: Location, + request_type: RequestType, + ) { + debug!("Recording request for location: {:?}", requested_location); + self.request_density_tracker.sample(requested_location); + } + + /// Decide whether to accept a connection from a new candidate peer based on its location + /// and current neighbors and request density, along with how it compares to other + /// recent candidates. + pub(crate) fn evaluate_new_connection( + &mut self, + current_neighbors: &BTreeMap, + candidate_location: Location, + acquisition_strategy: AcquisitionStrategy, + ) -> Result { + self.evaluate_new_connection_with_current_time( + current_neighbors, + candidate_location, + acquisition_strategy, + Instant::now(), + ) + } + + fn evaluate_new_connection_with_current_time( + &mut self, + current_neighbors: &BTreeMap, + candidate_location: Location, + acquisition_strategy: AcquisitionStrategy, + current_time: Instant, + ) -> Result { + debug!( + "Evaluating new connection for candidate location: {:?}", + candidate_location + ); + let density_map = self.get_or_create_density_map(current_neighbors)?; + let score = density_map.get_density_at(candidate_location)?; + + let accept = match acquisition_strategy { + AcquisitionStrategy::Slow => { + self.fast_connection_evaluator + .record_only_with_current_time(score, current_time); + self.slow_connection_evaluator + .record_and_eval_with_current_time(score, current_time) + } + AcquisitionStrategy::Fast => { + self.slow_connection_evaluator + .record_only_with_current_time(score, current_time); + self.fast_connection_evaluator + .record_and_eval_with_current_time(score, current_time) + } + }; + + Ok(accept) + } + + /// Get the ideal location for a new connection based on current neighbors and request density + pub(crate) fn get_best_candidate_location( + &mut self, + current_neighbors: &BTreeMap, + ) -> Result { + debug!("Retrieving best candidate location"); + let density_map = self.get_or_create_density_map(current_neighbors)?; + + let best_location = match density_map.get_max_density() { + Ok(location) => { + debug!("Max density found at location: {:?}", location); + location + } + Err(_) => { + error!( + "An error occurred while getting max density, falling back to random location" + ); + self.random_location() + } + }; + + Ok(best_location) + } + + /// Generates a random location that is close to the current peer location with a small + /// world distribution. + fn random_location(&self) -> Location { + debug!("Generating random location"); + let distance = random_link_distance(Distance::new(RANDOM_CLOSEST_DISTANCE)); + let location_f64 = if rand::random() { + self.this_peer_location.as_f64() - distance.as_f64() + } else { + self.this_peer_location.as_f64() + distance.as_f64() + }; + let location_f64 = location_f64.rem_euclid(1.0); // Ensure result is in [0.0, 1.0) + Location::new(location_f64) + } + + fn get_or_create_density_map( + &mut self, + current_neighbors: &BTreeMap, + ) -> Result, DensityMapError> { + debug!("Getting or creating density map"); + self.cached_density_map + .get_or_create(&self.request_density_tracker, current_neighbors) + } +} + +pub(crate) enum RequestType { + Get, + Put, + Join, + Subscribe, +} + +pub(crate) enum AcquisitionStrategy { + /// Acquire new connections slowly, be picky + Slow, + + /// Acquire new connections aggressively, be less picky + Fast, +} + +#[cfg(test)] +mod tests { + use super::TopologyManager; + use crate::ring::Location; + + #[test] + fn test_topology_manager() { + let mut topology_manager = TopologyManager::new(Location::new(0.39)); + let mut current_neighbors = std::collections::BTreeMap::new(); + + // Insert neighbors from 0.0 to 0.9 + for i in 0..10 { + current_neighbors.insert(Location::new(i as f64 / 10.0), 0); + } + + let mut requests = vec![]; + // Simulate a bunch of random requests clustered around 0.35 + for _ in 0..1000 { + let requested_location = topology_manager.random_location(); + topology_manager.record_request(requested_location, super::RequestType::Get); + requests.push(requested_location); + } + + let best_candidate_location = topology_manager + .get_best_candidate_location(¤t_neighbors) + .unwrap(); + // Should be half way between 0.3 and 0.4 as that is where the most requests were + assert_eq!(best_candidate_location, Location::new(0.35)); + + // call evaluate_new_connection for locations 0.0 to 1.0 at 0.01 intervals and find the + // location with the highest score + let mut best_score = 0.0; + let mut best_location = Location::new(0.0); + for i in 0..100 { + let candidate_location = Location::new(i as f64 / 100.0); + let score = topology_manager + .get_or_create_density_map(¤t_neighbors) + .unwrap() + .get_density_at(candidate_location) + .unwrap(); + if score > best_score { + best_score = score; + best_location = candidate_location; + } + } + + // Best location should be 0.4 as that is closest to 0.39 which is the peer's location and + // the request epicenter + assert_eq!(best_location, Location::new(0.4)); + } +} diff --git a/crates/core/src/topology/request_density_tracker/cached_density_map.rs b/crates/core/src/topology/request_density_tracker/cached_density_map.rs new file mode 100644 index 000000000..db18ff85c --- /dev/null +++ b/crates/core/src/topology/request_density_tracker/cached_density_map.rs @@ -0,0 +1,40 @@ +use crate::ring::Location; +use crate::topology::request_density_tracker::{self, DensityMapError}; +use std::{ + collections::BTreeMap, + rc::Rc, + time::{Duration, Instant}, +}; + +/// Struct to handle caching of DensityMap +pub(in crate::topology) struct CachedDensityMap { + density_map: Option<(Rc, Instant)>, + regenerate_interval: Duration, +} + +impl CachedDensityMap { + pub(in crate::topology) fn new(regenerate_interval: Duration) -> Self { + CachedDensityMap { + density_map: None, + regenerate_interval, + } + } + + pub(in crate::topology) fn get_or_create( + &mut self, + tracker: &request_density_tracker::RequestDensityTracker, + current_neighbors: &BTreeMap, + ) -> Result, DensityMapError> { + let now = Instant::now(); + if let Some((density_map, last_update)) = &self.density_map { + if now.duration_since(*last_update) < self.regenerate_interval { + return Ok(density_map.clone()); + } + } + + let density_map = Rc::new(tracker.create_density_map(current_neighbors)?); + self.density_map = Some((density_map.clone(), now)); + + Ok(density_map) + } +} diff --git a/crates/core/src/topology/request_density_tracker/mod.rs b/crates/core/src/topology/request_density_tracker/mod.rs new file mode 100644 index 000000000..8449162ae --- /dev/null +++ b/crates/core/src/topology/request_density_tracker/mod.rs @@ -0,0 +1,210 @@ +pub mod cached_density_map; + +#[cfg(test)] +mod tests; + +use crate::ring::Location; +use std::collections::{BTreeMap, LinkedList}; +use thiserror::Error; + +/// Tracks requests sent by a node to its neighbors and creates a density map, which +/// is useful for determining which new neighbors to connect to based on their +/// location. +pub(crate) struct RequestDensityTracker { + ordered_map: BTreeMap, + list: LinkedList, + window_size: usize, + samples: usize, +} + +impl RequestDensityTracker { + pub(crate) fn new(window_size: usize) -> Self { + Self { + ordered_map: BTreeMap::new(), + list: LinkedList::new(), + window_size, + samples: 0, + } + } + + pub(crate) fn sample(&mut self, value: Location) { + self.samples += 1; + + self.list.push_back(value); + *self.ordered_map.entry(value).or_insert(0) += 1; + + if self.list.len() > self.window_size { + if let Some(oldest) = self.list.pop_front() { + if let Some(count) = self.ordered_map.get_mut(&oldest) { + *count -= 1; + if *count == 0 { + self.ordered_map.remove(&oldest); + } + } + } + } + } + + pub(crate) fn create_density_map( + &self, + neighbors: &BTreeMap, + ) -> Result { + if neighbors.is_empty() { + return Err(DensityMapError::EmptyNeighbors); + } + + let smoothing_radius = 2; + let mut density_map = DensityMap { + neighbor_request_counts: BTreeMap::new(), + }; + + for (sample_location, sample_count) in self.ordered_map.iter() { + let previous_neighbor = neighbors + .range(..*sample_location) + .next_back() + .or_else(|| neighbors.iter().next_back()); + let next_neighbor = neighbors + .range(*sample_location..) + .next() + .or_else(|| neighbors.iter().next()); + + match (previous_neighbor, next_neighbor) { + (Some((previous_neighbor_location, _)), Some((next_neighbor_location, _))) => { + if sample_location.distance(*previous_neighbor_location) + < sample_location.distance(*next_neighbor_location) + { + *density_map + .neighbor_request_counts + .entry(*previous_neighbor_location) + .or_insert(0) += sample_count; + } else { + *density_map + .neighbor_request_counts + .entry(*next_neighbor_location) + .or_insert(0) += sample_count; + } + } + // The None cases have been removed as they should not occur given the new logic + _ => unreachable!( + "This shouldn't be possible given that we verify neighbors is not empty" + ), + } + } + + Ok(density_map) + } +} + +pub(crate) struct DensityMap { + neighbor_request_counts: BTreeMap, +} + +impl DensityMap { + pub(crate) fn get_density_at(&self, location: Location) -> Result { + if self.neighbor_request_counts.is_empty() { + return Err(DensityMapError::EmptyNeighbors); + } + + // Determine the locations below and above the given location + let previous_neighbor = self + .neighbor_request_counts + .range(..location) + .next_back() + .or_else(|| self.neighbor_request_counts.iter().next_back()); + + let next_neighbor = self + .neighbor_request_counts + .range(location..) + .next() + .or_else(|| self.neighbor_request_counts.iter().next()); + + // Determine the value proportionate to the distance to the previous and next neighbor + let count_estimate = match (previous_neighbor, next_neighbor) { + ( + Some((previous_neighbor_location, previous_neighbor_count)), + Some((next_neighbor_location, next_neighbor_count)), + ) => { + let previous_neighbor_dist = + location.distance(*previous_neighbor_location).as_f64(); + let next_neighbor_dist = location.distance(*next_neighbor_location).as_f64(); + let total_dist = previous_neighbor_dist + next_neighbor_dist; + let previous_neighbor_prop = previous_neighbor_dist / total_dist; + let next_neighbor_prop = next_neighbor_dist / total_dist; + next_neighbor_prop * *previous_neighbor_count as f64 + + previous_neighbor_prop * *next_neighbor_count as f64 + } + // The None cases have been removed as they should not occur given the new logic + _ => unreachable!( + "This shouldn't be possible given that we verify neighbors is not empty" + ), + }; + + Ok(count_estimate) + } + + pub(crate) fn get_max_density(&self) -> Result { + if self.neighbor_request_counts.is_empty() { + return Err(DensityMapError::EmptyNeighbors); + } + + // Identify the midpoint Location between the pair of neighbors + // with the highest combined request count + let mut max_density_location = Location::new(0.0); + let mut max_density = 0; + + for ( + (previous_neighbor_location, previous_neighbor_count), + (next_neighbor_location, next_neighbor_count), + ) in self + .neighbor_request_counts + .iter() + .zip(self.neighbor_request_counts.iter().skip(1)) + { + let combined_count = previous_neighbor_count + next_neighbor_count; + if combined_count > max_density { + max_density = combined_count; + max_density_location = Location::new( + (previous_neighbor_location.as_f64() + next_neighbor_location.as_f64()) / 2.0, + ); + } + } + + // We need to also check the first and last neighbors as locations are circular + let first_neighbor = self.neighbor_request_counts.iter().next(); + let last_neighbor = self.neighbor_request_counts.iter().next_back(); + if let ( + Some((first_neighbor_location, first_neighbor_count)), + Some((last_neighbor_location, last_neighbor_count)), + ) = (first_neighbor, last_neighbor) + { + let combined_count = first_neighbor_count + last_neighbor_count; + if combined_count > max_density { + // max_density = combined_count; Not needed as this is the last check + let distance = first_neighbor_location.distance(*last_neighbor_location); + let mut mp = first_neighbor_location.as_f64() - (distance.as_f64() / 2.0); + if mp < 0.0 { + mp += 1.0; + } + max_density_location = Location::new(mp); + } + } + + Ok(max_density_location) + } +} + +// Define the custom error type using thiserror +#[derive(Error, Debug)] +pub enum DensityError { + #[error("Not enough samples to determine lower and upper bounds")] + CantFindBounds, + + #[error("Window radius too big. Window radius should be <= 50% of the number of samples ({samples}) and window size ({window_size}).")] + WindowTooBig { samples: usize, window_size: usize }, +} + +#[derive(Error, Debug)] +pub enum DensityMapError { + #[error("The neighbors BTreeMap is empty.")] + EmptyNeighbors, +} diff --git a/crates/core/src/topology/request_density_tracker/tests.rs b/crates/core/src/topology/request_density_tracker/tests.rs new file mode 100644 index 000000000..8f9a3fb39 --- /dev/null +++ b/crates/core/src/topology/request_density_tracker/tests.rs @@ -0,0 +1,266 @@ +use super::*; + +#[test] +fn test_create_density_map() { + let mut sw = RequestDensityTracker::new(5); + sw.sample(Location::new(0.21)); + sw.sample(Location::new(0.22)); + sw.sample(Location::new(0.23)); + sw.sample(Location::new(0.61)); + sw.sample(Location::new(0.62)); + + let mut neighbors = BTreeMap::new(); + neighbors.insert(Location::new(0.2), 1); + neighbors.insert(Location::new(0.6), 1); + + let result = sw.create_density_map(&neighbors); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!( + result.neighbor_request_counts.get(&Location::new(0.2)), + Some(&3) + ); + assert_eq!( + result.neighbor_request_counts.get(&Location::new(0.6)), + Some(&2) + ); +} + +#[test] +fn test_wrap_around() { + let mut sw = RequestDensityTracker::new(5); + sw.sample(Location::new(0.21)); + sw.sample(Location::new(0.22)); + sw.sample(Location::new(0.23)); + sw.sample(Location::new(0.61)); + sw.sample(Location::new(0.62)); + + let mut neighbors = BTreeMap::new(); + neighbors.insert(Location::new(0.6), 1); + neighbors.insert(Location::new(0.9), 1); + + let result = sw.create_density_map(&neighbors); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!( + result.neighbor_request_counts.get(&Location::new(0.9)), + Some(&3) + ); + assert_eq!( + result.neighbor_request_counts.get(&Location::new(0.6)), + Some(&2) + ); +} + +#[test] +fn test_interpolate() { + let mut sw = RequestDensityTracker::new(10); + sw.sample(Location::new(0.19)); + sw.sample(Location::new(0.20)); + sw.sample(Location::new(0.21)); + sw.sample(Location::new(0.59)); + sw.sample(Location::new(0.60)); + + let mut neighbors = BTreeMap::new(); + neighbors.insert(Location::new(0.2), 1); + neighbors.insert(Location::new(0.6), 1); + + let result = sw.create_density_map(&neighbors); + assert!(result.is_ok()); + let result = result.unwrap(); + + // Scan and dumb densities 0.0 to 1.0 at 0.01 intervals + println!("Location\tDensity"); + for i in 0..100 { + let location = Location::new(i as f64 / 100.0); + let density = result.get_density_at(location).unwrap(); + // Print and round density to 2 decimals + println!( + "{}\t{}", + location.as_f64(), + (density * 100.0).round() / 100.0 + ); + } + + assert_eq!(result.get_density_at(Location::new(0.2)).unwrap(), 3.0); + assert_eq!(result.get_density_at(Location::new(0.6)).unwrap(), 2.0); + assert_eq!(result.get_density_at(Location::new(0.4)).unwrap(), 2.5); + assert_eq!(result.get_density_at(Location::new(0.5)).unwrap(), 2.25); +} + +#[test] +fn test_drop() { + let mut sw = RequestDensityTracker::new(4); + sw.sample(Location::new(0.21)); + sw.sample(Location::new(0.22)); + sw.sample(Location::new(0.23)); + sw.sample(Location::new(0.61)); + sw.sample(Location::new(0.62)); + + let mut neighbors = BTreeMap::new(); + neighbors.insert(Location::new(0.2), 1); + neighbors.insert(Location::new(0.6), 1); + + let result = sw.create_density_map(&neighbors); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!( + result.neighbor_request_counts.get(&Location::new(0.2)), + Some(&2) + ); + assert_eq!( + result.neighbor_request_counts.get(&Location::new(0.6)), + Some(&2) + ); +} + +#[test] +fn test_empty_neighbors_error() { + let sw = RequestDensityTracker::new(10); + let empty_neighbors = BTreeMap::new(); + let result = sw.create_density_map(&empty_neighbors); + assert!(matches!(result, Err(DensityMapError::EmptyNeighbors))); +} + +#[test] +fn test_get_max_density() { + let mut density_map = DensityMap { + neighbor_request_counts: BTreeMap::new(), + }; + + density_map + .neighbor_request_counts + .insert(Location::new(0.2), 1); + density_map + .neighbor_request_counts + .insert(Location::new(0.6), 2); + density_map + .neighbor_request_counts + .insert(Location::new(0.8), 2); + + let result = density_map.get_max_density(); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!(result, Location::new(0.7)); +} + +#[test] +fn test_get_max_density_2() { + let mut density_map = DensityMap { + neighbor_request_counts: BTreeMap::new(), + }; + + density_map + .neighbor_request_counts + .insert(Location::new(0.2), 1); + density_map + .neighbor_request_counts + .insert(Location::new(0.6), 2); + density_map + .neighbor_request_counts + .insert(Location::new(0.8), 2); + density_map + .neighbor_request_counts + .insert(Location::new(0.9), 1); + + let result = density_map.get_max_density(); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!(result, Location::new(0.7)); +} + +#[test] +fn test_get_max_density_first_last() { + let mut density_map = DensityMap { + neighbor_request_counts: BTreeMap::new(), + }; + + density_map + .neighbor_request_counts + .insert(Location::new(0.0), 2); + density_map + .neighbor_request_counts + .insert(Location::new(0.2), 1); + density_map + .neighbor_request_counts + .insert(Location::new(0.6), 1); + density_map + .neighbor_request_counts + .insert(Location::new(0.8), 1); + density_map + .neighbor_request_counts + .insert(Location::new(0.9), 2); + + let result = density_map.get_max_density(); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!(result, Location::new(0.95)); +} + +#[test] +fn test_get_max_density_first_last_2() { + // Verify the other case in max_density_location calculation + let mut density_map = DensityMap { + neighbor_request_counts: BTreeMap::new(), + }; + + density_map + .neighbor_request_counts + .insert(Location::new(0.3), 2); + density_map + .neighbor_request_counts + .insert(Location::new(0.4), 1); + density_map + .neighbor_request_counts + .insert(Location::new(0.6), 1); + density_map + .neighbor_request_counts + .insert(Location::new(0.8), 1); + density_map + .neighbor_request_counts + .insert(Location::new(0.9), 2); + + let result = density_map.get_max_density(); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!(result, Location::new(0.1)); +} + +#[test] +fn test_get_max_density_first_last_3() { + // Verify the other case in max_density_location calculation + let mut density_map = DensityMap { + neighbor_request_counts: BTreeMap::new(), + }; + + density_map + .neighbor_request_counts + .insert(Location::new(0.1), 2); + density_map + .neighbor_request_counts + .insert(Location::new(0.2), 1); + density_map + .neighbor_request_counts + .insert(Location::new(0.3), 1); + density_map + .neighbor_request_counts + .insert(Location::new(0.4), 1); + density_map + .neighbor_request_counts + .insert(Location::new(0.7), 2); + + let result = density_map.get_max_density(); + assert!(result.is_ok()); + let result = result.unwrap(); + assert_eq!(result, Location::new(0.9)); +} + +#[test] +fn test_get_max_density_empty_neighbors_error() { + let density_map = DensityMap { + neighbor_request_counts: BTreeMap::new(), + }; + + let result = density_map.get_max_density(); + assert!(matches!(result, Err(DensityMapError::EmptyNeighbors))); +} diff --git a/crates/core/src/topology/small_world_rand.rs b/crates/core/src/topology/small_world_rand.rs new file mode 100644 index 000000000..57fb309fe --- /dev/null +++ b/crates/core/src/topology/small_world_rand.rs @@ -0,0 +1,70 @@ +use rand::Rng; + +use crate::ring::Distance; + +// Function to generate a random link distance based on Kleinberg's d^{-1} distribution +pub(crate) fn random_link_distance(d_min: Distance) -> Distance { + let d_max = 0.5; + + // Generate a uniform random number between 0 and 1 + let u: f64 = rand::thread_rng().gen_range(0.0..1.0); + + // Correct Inverse CDF: F^{-1}(u) = d_min * (d_max / d_min).powf(u) + let d = d_min.as_f64() * (d_max / d_min.as_f64()).powf(u); + + Distance::new(d) +} + +#[cfg(test)] +mod tests { + + use super::*; + use statrs::distribution::*; + + #[test] + fn chi_squared_test() { + let d_min = 0.01; + let d_max = 0.5; + let n = 10000; // Number of samples + let num_bins = 20; // Number of bins for histogram + let mut bins = vec![0; num_bins]; + + // Generate a bunch of link distances + for _ in 0..n { + let d = random_link_distance(Distance::new(d_min)).as_f64(); + let bin_index = ((d - d_min) / (d_max - d_min) * (num_bins as f64)).floor() as usize; + if bin_index < num_bins { + bins[bin_index] += 1; + } + } + + // Perform chi-squared test + let expected_counts: Vec<_> = (0..num_bins) + .map(|i| { + let lower = d_min + (d_max - d_min) * (i as f64 / num_bins as f64); + let upper = d_min + (d_max - d_min) * ((i as f64 + 1.0) / num_bins as f64); + ((upper - lower) / (upper.powf(-1.0) - lower.powf(-1.0))).floor() * n as f64 + / num_bins as f64 + }) + .collect(); + + let chi_squared = expected_counts + .iter() + .zip(bins.iter()) + .map(|(&e, &o)| ((o as f64 - e) * (o as f64 - e)) / e) + .sum::(); + + // Degrees of freedom is num_bins - 1 + let dof = num_bins - 1; + let chi = ChiSquared::new(dof as f64).unwrap(); + + let p_value = 1.0 - chi.cdf(chi_squared); + + // Check if p_value is above 0.05, indicating that we fail to reject the null hypothesis + assert!( + p_value > 0.05, + "Chi-squared test failed, p_value = {}", + p_value + ); + } +}