From 9c6b7d5fc26bc428f791d3a15a4653d5bd950022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Florkiewicz?= Date: Fri, 23 Feb 2024 09:16:11 +0100 Subject: [PATCH] feat: Add bitswap server --- Cargo.lock | 2063 +++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 11 +- examples/client.rs | 150 ++++ src/builder.rs | 4 +- src/client.rs | 46 +- src/lib.rs | 59 +- src/server.rs | 438 ++++++++++ tests/bitswap.rs | 152 ++++ tests/utils/mod.rs | 184 ++++ 9 files changed, 3059 insertions(+), 48 deletions(-) create mode 100644 examples/client.rs create mode 100644 src/server.rs create mode 100644 tests/bitswap.rs create mode 100644 tests/utils/mod.rs diff --git a/Cargo.lock b/Cargo.lock index a125606..02b5a2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,122 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "anstream" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + [[package]] name = "arrayref" version = "0.3.7" @@ -29,6 +145,75 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-io" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + [[package]] name = "async-trait" version = "0.1.77" @@ -53,6 +238,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "attohttpc" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" +dependencies = [ + "http", + "log", + "url", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -80,6 +276,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64ct" version = "1.6.0" @@ -90,24 +292,32 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" name = "beetswap" version = "0.1.0" dependencies = [ + "anyhow", "async-trait", "asynchronous-codec", "blockstore", "bytes", "cid", + "clap", "fnv", "futures", "futures-timer", "hex", + "libp2p", "libp2p-core", + "libp2p-identify", "libp2p-identity", + "libp2p-noise", "libp2p-swarm", + "libp2p-yamux", "multihash-codetable", "quick-protobuf", "smallvec", "thiserror", "tokio", "tracing", + "tracing-appender", + "tracing-subscriber", "unsigned-varint 0.8.0", "void", ] @@ -118,6 +328,21 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "blake2b_simd" version = "1.0.2" @@ -217,6 +442,30 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + [[package]] name = "cid" version = "0.11.0" @@ -229,6 +478,72 @@ dependencies = [ "unsigned-varint 0.8.0", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "clap" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -241,6 +556,22 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "core2" version = "0.4.0" @@ -259,6 +590,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "crypto-common" version = "0.1.6" @@ -266,9 +612,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "curve25519-dalek" version = "4.1.2" @@ -346,6 +702,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "digest" version = "0.10.7" @@ -357,6 +736,23 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + [[package]] name = "ed25519" version = "2.2.3" @@ -388,12 +784,55 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "enum-as-inner" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fiat-crypto" version = "0.2.5" @@ -431,12 +870,22 @@ dependencies = [ ] [[package]] -name = "futures-channel" -version = "0.3.30" +name = "futures-bounded" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "e1e2774cc104e198ef3d3e1ff4ab40f86fa3245d6cb6a3a46174f21463cee173" dependencies = [ - "futures-core", + "futures-timer", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", "futures-sink", ] @@ -464,6 +913,16 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -475,6 +934,16 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "futures-rustls" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd3cf68c183738046838e300353e4716c674dc5e56890de4826801a6622a28" +dependencies = [ + "futures-io", + "rustls", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -536,6 +1005,16 @@ dependencies = [ "wasi", ] +[[package]] +name = "ghash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.28.1" @@ -554,11 +1033,40 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "h2" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -572,6 +1080,52 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hickory-proto" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "091a6fbccf4860009355e3efc52ff4acf37a63489aad7435372d44ceeb6fbbcf" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "socket2", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35b8f021164e6a984c9030023544c57789c51760065cd510572fedcfb04164e8" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -590,6 +1144,85 @@ dependencies = [ "digest", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -600,6 +1233,54 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "if-addrs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "if-watch" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" +dependencies = [ + "async-io", + "core-foundation", + "fnv", + "futures", + "if-addrs", + "ipnet", + "log", + "rtnetlink", + "system-configuration", + "tokio", + "windows", +] + +[[package]] +name = "igd-next" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064d90fec10d541084e7b39ead8875a5a80d9114a2b18791565253bae25f49e4" +dependencies = [ + "async-trait", + "attohttpc", + "bytes", + "futures", + "http", + "hyper", + "log", + "rand", + "tokio", + "url", + "xmltree", +] + [[package]] name = "indexmap" version = "2.1.0" @@ -610,6 +1291,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -619,6 +1309,30 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + [[package]] name = "js-sys" version = "0.3.67" @@ -637,12 +1351,72 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +[[package]] +name = "libp2p" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681fb3f183edfbedd7a57d32ebe5dcdc0b9f94061185acf3c30249349cc6fc99" +dependencies = [ + "bytes", + "either", + "futures", + "futures-timer", + "getrandom", + "instant", + "libp2p-allow-block-list", + "libp2p-connection-limits", + "libp2p-core", + "libp2p-dns", + "libp2p-identify", + "libp2p-identity", + "libp2p-mdns", + "libp2p-metrics", + "libp2p-quic", + "libp2p-swarm", + "libp2p-tcp", + "libp2p-upnp", + "multiaddr", + "pin-project", + "rw-stream-sink", + "thiserror", +] + +[[package]] +name = "libp2p-allow-block-list" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "107b238b794cb83ab53b74ad5dcf7cca3200899b72fe662840cfb52f5b0a32e6" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "void", +] + +[[package]] +name = "libp2p-connection-limits" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7cd50a78ccfada14de94cbacd3ce4b0138157f376870f13d3a8422cd075b4fd" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "void", +] + [[package]] name = "libp2p-core" version = "0.41.2" @@ -671,6 +1445,45 @@ dependencies = [ "void", ] +[[package]] +name = "libp2p-dns" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d17cbcf7160ff35c3e8e560de4a068fe9d6cb777ea72840e48eb76ff9576c4b6" +dependencies = [ + "async-trait", + "futures", + "hickory-resolver", + "libp2p-core", + "libp2p-identity", + "parking_lot", + "smallvec", + "tracing", +] + +[[package]] +name = "libp2p-identify" +version = "0.44.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20499a945d2f0221fdc6269b3848892c0f370d2ee3e19c7f65a29d8f860f6126" +dependencies = [ + "asynchronous-codec", + "either", + "futures", + "futures-bounded", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "lru", + "quick-protobuf", + "quick-protobuf-codec", + "smallvec", + "thiserror", + "tracing", + "void", +] + [[package]] name = "libp2p-identity" version = "0.2.8" @@ -689,6 +1502,93 @@ dependencies = [ "zeroize", ] +[[package]] +name = "libp2p-mdns" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49007d9a339b3e1d7eeebc4d67c05dbf23d300b7d091193ec2d3f26802d7faf2" +dependencies = [ + "data-encoding", + "futures", + "hickory-proto", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand", + "smallvec", + "socket2", + "tokio", + "tracing", + "void", +] + +[[package]] +name = "libp2p-metrics" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdac91ae4f291046a3b2660c039a2830c931f84df2ee227989af92f7692d3357" +dependencies = [ + "futures", + "instant", + "libp2p-core", + "libp2p-identify", + "libp2p-identity", + "libp2p-swarm", + "pin-project", + "prometheus-client", +] + +[[package]] +name = "libp2p-noise" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecd0545ce077f6ea5434bcb76e8d0fe942693b4380aaad0d34a358c2bd05793" +dependencies = [ + "asynchronous-codec", + "bytes", + "curve25519-dalek", + "futures", + "libp2p-core", + "libp2p-identity", + "multiaddr", + "multihash", + "once_cell", + "quick-protobuf", + "rand", + "sha2", + "snow", + "static_assertions", + "thiserror", + "tracing", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "libp2p-quic" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0375cdfee57b47b313ef1f0fdb625b78aed770d33a40cf1c294a371ff5e6666" +dependencies = [ + "bytes", + "futures", + "futures-timer", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-tls", + "parking_lot", + "quinn", + "rand", + "ring 0.16.20", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "libp2p-swarm" version = "0.44.1" @@ -702,14 +1602,107 @@ dependencies = [ "instant", "libp2p-core", "libp2p-identity", + "libp2p-swarm-derive", "multistream-select", "once_cell", "rand", "smallvec", + "tokio", + "tracing", + "void", +] + +[[package]] +name = "libp2p-swarm-derive" +version = "0.34.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b644268b4acfdaa6a6100b31226ee7a36d96ab4c43287d113bfd2308607d8b6f" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "libp2p-tcp" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2460fc2748919adff99ecbc1aab296e4579e41f374fb164149bd2c9e529d4c" +dependencies = [ + "futures", + "futures-timer", + "if-watch", + "libc", + "libp2p-core", + "libp2p-identity", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ce7e3c2e7569d685d08ec795157981722ff96e9e9f9eae75df3c29d02b07a5" +dependencies = [ + "futures", + "futures-rustls", + "libp2p-core", + "libp2p-identity", + "rcgen", + "ring 0.16.20", + "rustls", + "rustls-webpki", + "thiserror", + "x509-parser", + "yasna", +] + +[[package]] +name = "libp2p-upnp" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49cc89949bf0e06869297cd4fe2c132358c23fe93e76ad43950453df4da3d35" +dependencies = [ + "futures", + "futures-timer", + "igd-next", + "libp2p-core", + "libp2p-swarm", + "tokio", "tracing", "void", ] +[[package]] +name = "libp2p-yamux" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200cbe50349a44760927d50b431d77bed79b9c0a3959de1af8d24a63434b71e5" +dependencies = [ + "either", + "futures", + "libp2p-core", + "thiserror", + "tracing", + "yamux 0.12.1", + "yamux 0.13.1", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + [[package]] name = "lock_api" version = "0.4.11" @@ -726,12 +1719,51 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "lru" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2c024b41519440580066ba82aab04092b333e09066a5eb86c7c4890df31f22" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -741,6 +1773,17 @@ dependencies = [ "adler", ] +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + [[package]] name = "multiaddr" version = "0.18.1" @@ -831,12 +1874,151 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" dependencies = [ - "bytes", - "futures", - "log", - "pin-project", - "smallvec", - "unsigned-varint 0.7.2", + "bytes", + "futures", + "log", + "pin-project", + "smallvec", + "unsigned-varint 0.7.2", +] + +[[package]] +name = "netlink-packet-core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" +dependencies = [ + "anyhow", + "byteorder", + "libc", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror", +] + +[[package]] +name = "netlink-proto" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +dependencies = [ + "bytes", + "futures", + "log", + "netlink-packet-core", + "netlink-sys", + "thiserror", + "tokio", +] + +[[package]] +name = "netlink-sys" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" +dependencies = [ + "bytes", + "futures", + "libc", + "log", + "tokio", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", ] [[package]] @@ -858,12 +2040,39 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.12.1" @@ -884,7 +2093,23 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pem" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" +dependencies = [ + "base64", + "serde", ] [[package]] @@ -941,6 +2166,49 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" +[[package]] +name = "polling" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -990,6 +2258,35 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prometheus-client" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f87c10af16e0af74010d2a123d202e8363c04db5acfa91d8747f64a8524da3a" +dependencies = [ + "dtoa", + "itoa", + "parking_lot", + "prometheus-client-derive-encode", +] + +[[package]] +name = "prometheus-client-derive-encode" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quick-protobuf" version = "0.8.1" @@ -999,6 +2296,67 @@ dependencies = [ "byteorder", ] +[[package]] +name = "quick-protobuf-codec" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a0580ab32b169745d7a39db2ba969226ca16738931be152a3209b409de2474" +dependencies = [ + "asynchronous-codec", + "bytes", + "quick-protobuf", + "thiserror", + "unsigned-varint 0.8.0", +] + +[[package]] +name = "quinn" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +dependencies = [ + "bytes", + "futures-io", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +dependencies = [ + "bytes", + "rand", + "ring 0.16.20", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +dependencies = [ + "bytes", + "libc", + "socket2", + "tracing", + "windows-sys 0.48.0", +] + [[package]] name = "quote" version = "1.0.35" @@ -1038,13 +2396,108 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rcgen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6" +dependencies = [ + "pem", + "ring 0.16.20", + "time", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.5", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", ] [[package]] @@ -1056,12 +2509,33 @@ dependencies = [ "digest", ] +[[package]] +name = "rtnetlink" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" +dependencies = [ + "futures", + "log", + "netlink-packet-route", + "netlink-proto", + "nix", + "thiserror", + "tokio", +] + [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1071,6 +2545,50 @@ dependencies = [ "semver", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring 0.17.7", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + [[package]] name = "rw-stream-sink" version = "0.4.0" @@ -1088,6 +2606,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + [[package]] name = "semver" version = "1.0.21" @@ -1152,6 +2680,15 @@ dependencies = [ "keccak", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signature" version = "2.2.0" @@ -1176,6 +2713,45 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +[[package]] +name = "snow" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" +dependencies = [ + "aes-gcm", + "blake2", + "chacha20poly1305", + "curve25519-dalek", + "rand_core", + "ring 0.17.7", + "rustc_version", + "sha2", + "subtle", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "spki" version = "0.7.3" @@ -1198,13 +2774,19 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fabb238a1cccccfa4c4fb703670c0d157e1256c1ba695abf1b93bd2bb14bab2d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "byteorder", "keccak", "subtle", "zeroize", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.5.0" @@ -1234,15 +2816,36 @@ dependencies = [ ] [[package]] -name = "synstructure" -version = "0.12.6" +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", + "core-foundation-sys", + "libc", ] [[package]] @@ -1265,6 +2868,47 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1287,8 +2931,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", "pin-project-lite", + "socket2", "tokio-macros", + "windows-sys 0.48.0", ] [[package]] @@ -1302,6 +2952,20 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + [[package]] name = "toml_datetime" version = "0.6.5" @@ -1319,6 +2983,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + [[package]] name = "tracing" version = "0.1.40" @@ -1330,6 +3000,18 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.27" @@ -1348,8 +3030,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typenum" version = "1.17.0" @@ -1383,6 +3101,16 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unsigned-varint" version = "0.7.2" @@ -1395,6 +3123,18 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" +[[package]] +name = "untrusted" +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.5.0" @@ -1402,10 +3142,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" @@ -1418,6 +3170,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1478,19 +3239,109 @@ version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +[[package]] +name = "web-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +dependencies = [ + "windows-core", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -1499,42 +3350,84 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" version = "0.5.34" @@ -1544,6 +3437,120 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" + +[[package]] +name = "xmltree" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" +dependencies = [ + "xml-rs", +] + +[[package]] +name = "yamux" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed0164ae619f2dc144909a9f082187ebb5893693d8c0196e8085283ccd4b776" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand", + "static_assertions", +] + +[[package]] +name = "yamux" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1d0148b89300047e72994bee99ecdabd15a9166a7b70c8b8c37c314dcc9002" +dependencies = [ + "futures", + "instant", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand", + "static_assertions", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "zeroize" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 8c17c8f..5596694 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,10 +26,19 @@ unsigned-varint = "0.8" void = "1" [dev-dependencies] +anyhow = "1.0" +clap = { version = "4.4", features = ["derive"] } hex = "0.4" +libp2p = { version = "0.53", features = ["tokio", "tcp", "identify", "macros"] } libp2p-identity = { version = "0.2", features = ["rand"] } +libp2p-identify = "0.44" +libp2p-noise = "0.44" +libp2p-yamux = "0.45" multihash-codetable = { version = "0.1", features = ["digest", "sha2"] } -tokio = { version = "1", features = ["rt", "macros", "time"] } +tokio = { version = "1", features = ["rt", "macros", "time", "sync"] } + +tracing-appender = "0.2.2" +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } [features] wasm-bindgen = ["futures-timer/wasm-bindgen"] diff --git a/examples/client.rs b/examples/client.rs new file mode 100644 index 0000000..94ac03e --- /dev/null +++ b/examples/client.rs @@ -0,0 +1,150 @@ +use std::collections::HashMap; +use std::time::Duration; + +use anyhow::Result; +use blockstore::{ + block::{Block, CidError}, + Blockstore, InMemoryBlockstore, +}; +use cid::Cid; +use clap::Parser; +use libp2p::{ + futures::StreamExt, identify, swarm::NetworkBehaviour, swarm::SwarmEvent, tcp, Multiaddr, + SwarmBuilder, +}; +use multihash_codetable::{Code, MultihashDigest}; +use tracing::{debug, info}; + +const MAX_MULTIHASH_LENGHT: usize = 64; +const RAW_CODEC: u64 = 0x55; + +#[derive(Debug, Parser)] +struct Args { + /// Peers to connect to + #[arg(short, long = "peer")] + pub(crate) peers: Vec, + + /// CIDs to request + pub(crate) cids: Vec, + + /// Listen on provided port + #[arg(short, long = "listen")] + pub(crate) listen_port: Option, + + /// Load provided string into blockstore on start + #[arg(long)] + pub(crate) preload_blockstore_string: Vec, +} + +#[derive(NetworkBehaviour)] +struct Behaviour { + identify: identify::Behaviour, + bitswap: beetswap::Behaviour>, +} + +#[tokio::main(flavor = "current_thread")] +async fn main() -> Result<()> { + let args = Args::parse(); + + let _guard = init_tracing(); + + let store = InMemoryBlockstore::new(); + for preload_string in args.preload_blockstore_string { + let block = StringBlock(preload_string); + let cid = block.cid()?; + info!("inserted {cid} with content '{}'", block.0); + store.put_keyed(&cid, block.data()).await?; + } + + let mut swarm = SwarmBuilder::with_new_identity() + .with_tokio() + .with_tcp( + tcp::Config::default(), + libp2p_noise::Config::new, + libp2p_yamux::Config::default, + )? + .with_behaviour(|key| Behaviour { + identify: identify::Behaviour::new(identify::Config::new( + "/ipfs/id/1.0.0".to_string(), + key.public(), + )), + bitswap: beetswap::Behaviour::new(store), + })? + .with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) + .build(); + + if let Some(port) = args.listen_port { + swarm.listen_on(format!("/ip4/0.0.0.0/tcp/{port}").parse()?)?; + } + + for peer in args.peers { + swarm.dial(peer)?; + } + + let mut queries = HashMap::new(); + for cid in args.cids { + let query_id = swarm.behaviour_mut().bitswap.get(&cid); + queries.insert(query_id, cid); + info!("requested cid {cid}: {query_id:?}"); + } + + loop { + match swarm.select_next_some().await { + SwarmEvent::NewListenAddr { address, .. } => debug!("Listening on {address:?}"), + // Prints peer id identify info is being sent to. + SwarmEvent::Behaviour(BehaviourEvent::Identify(identify)) => match identify { + identify::Event::Sent { peer_id, .. } => { + info!("Sent identify info to {peer_id:?}"); + } + identify::Event::Received { info, .. } => { + info!("Received {info:?}") + } + _ => (), + }, + SwarmEvent::Behaviour(BehaviourEvent::Bitswap(bitswap)) => match bitswap { + beetswap::Event::GetQueryResponse { query_id, data } => { + let cid = queries.get(&query_id).expect("unknown cid received"); + info!("received response for {cid:?}: {data:?}"); + } + beetswap::Event::GetQueryError { query_id, error } => { + let cid = queries.get(&query_id).expect("unknown cid received"); + info!("received error for {cid:?}: {error}"); + } + }, + _ => (), + } + } +} + +struct StringBlock(pub String); + +impl Block<64> for StringBlock { + fn cid(&self) -> Result { + let hash = Code::Sha2_256.digest(self.0.as_ref()); + Ok(Cid::new_v1(RAW_CODEC, hash)) + } + + fn data(&self) -> &[u8] { + self.0.as_ref() + } +} + +fn init_tracing() -> tracing_appender::non_blocking::WorkerGuard { + let (non_blocking, guard) = tracing_appender::non_blocking(std::io::stdout()); + + let filter = tracing_subscriber::EnvFilter::builder() + .with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into()) + .from_env_lossy(); + + tracing_subscriber::fmt() + .event_format( + tracing_subscriber::fmt::format() + .with_file(true) + .with_line_number(true), + ) + .with_env_filter(filter) + .with_writer(non_blocking) + .init(); + + guard +} diff --git a/src/builder.rs b/src/builder.rs index f57b416..609db75 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -4,6 +4,7 @@ use blockstore::Blockstore; use crate::client::{ClientBehaviour, ClientConfig}; use crate::multihasher::{Multihasher, MultihasherTable}; +use crate::server::ServerBehaviour; use crate::utils::stream_protocol; use crate::{Behaviour, Error, Result}; @@ -117,7 +118,8 @@ where Behaviour { protocol: stream_protocol(protocol_prefix, "/ipfs/bitswap/1.2.0") .expect("prefix checked by beetswap::BehaviourBuilder::protocol_prefix"), - client: ClientBehaviour::new(self.client, blockstore, protocol_prefix), + client: ClientBehaviour::new(self.client, blockstore.clone(), protocol_prefix), + server: ServerBehaviour::new(blockstore, protocol_prefix), multihasher, } } diff --git a/src/client.rs b/src/client.rs index 5b21d70..cc41ae2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,5 +1,6 @@ use std::collections::{hash_map, VecDeque}; use std::fmt; +use std::mem::take; use std::sync::Arc; use std::task::{ready, Context, Poll}; use std::time::Duration; @@ -27,6 +28,7 @@ use crate::proto::message::mod_Message::{BlockPresenceType, Wantlist as ProtoWan use crate::proto::message::Message; use crate::utils::{convert_cid, stream_protocol}; use crate::wantlist::{Wantlist, WantlistState}; +use crate::StreamRequester; use crate::{Error, Event, Result, ToBehaviourEvent, ToHandlerEvent}; const SEND_FULL_INTERVAL: Duration = Duration::from_secs(30); @@ -54,7 +56,7 @@ enum TaskResult { CidGeneric, Result>, BlockstoreError>, ), - Set(Result<(), BlockstoreError>), + Set(Result, Vec)>, BlockstoreError>), Cancelled, } @@ -74,6 +76,8 @@ where next_query_id: u64, waker: Arc, send_full_timer: Delay, + + new_blocks: Vec<(CidGeneric, Vec)>, } #[derive(Debug)] @@ -113,6 +117,7 @@ where next_query_id: 0, waker: Arc::new(AtomicWaker::new()), send_full_timer: Delay::new(SEND_FULL_INTERVAL), + new_blocks: Vec::new(), } } @@ -178,7 +183,10 @@ where self.tasks.push( async move { - let res = store.put_many_keyed(blocks.into_iter()).await; + let res = store + .put_many_keyed(blocks.clone().into_iter()) + .await + .map(|_| blocks); TaskResult::Set(res) } .boxed(), @@ -372,7 +380,9 @@ where })); } - TaskResult::Set(Ok(_)) => {} + TaskResult::Set(Ok(blocks)) => { + self.new_blocks.extend(blocks); + } // TODO: log it TaskResult::Set(Err(_e)) => {} @@ -383,7 +393,7 @@ where // If we didn't return an event, we need to retry the whole loop continue; - } + }; if self.update_handlers() { // New events generated, loop again to send them. @@ -393,6 +403,10 @@ where return Poll::Pending; } } + + pub(crate) fn get_new_blocks(&mut self) -> Vec<(CidGeneric, Vec)> { + take(&mut self.new_blocks) + } } pub(crate) struct ClientConnectionHandler { @@ -434,7 +448,9 @@ impl ClientConnectionHandler { fn poll_outgoing_no_stream( &mut self, - ) -> Poll, (), ToBehaviourEvent>> { + ) -> Poll< + ConnectionHandlerEvent, StreamRequester, ToBehaviourEvent>, + > { // `stream_requested` already checked in `poll_outgoing` debug_assert!(!self.stream_requested); // `wantlist` and `sending_state` must be both `Some` or both `None` @@ -445,13 +461,13 @@ impl ClientConnectionHandler { return Poll::Pending; } - // There are data to send, so request a new stream. + // There is data to send, so request a new stream. self.stream_requested = true; Poll::Ready(ConnectionHandlerEvent::OutboundSubstreamRequest { protocol: SubstreamProtocol::new( ReadyUpgrade::new(self.protocol.clone()), - (), // TODO: maybe we can say here that we are the client? + StreamRequester::Client, ), }) } @@ -470,9 +486,11 @@ impl ClientConnectionHandler { fn poll_outgoing( &mut self, cx: &mut Context, - ) -> Poll, (), ToBehaviourEvent>> { + ) -> Poll< + ConnectionHandlerEvent, StreamRequester, ToBehaviourEvent>, + > { loop { - if self.stream_requested { + if self.stream_requested() { // We can not progress until we have a stream return Poll::Pending; } @@ -514,8 +532,14 @@ impl ClientConnectionHandler { pub(crate) fn poll( &mut self, cx: &mut Context, - ) -> Poll, (), ToBehaviourEvent>> { - self.poll_outgoing(cx) + ) -> Poll< + ConnectionHandlerEvent, StreamRequester, ToBehaviourEvent>, + > { + if let Poll::Ready(ready) = self.poll_outgoing(cx) { + return Poll::Ready(ready); + } + + Poll::Pending } } diff --git a/src/lib.rs b/src/lib.rs index dd57c93..97d20a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ use libp2p_swarm::{ ConnectionHandlerEvent, ConnectionId, FromSwarm, NetworkBehaviour, StreamProtocol, SubstreamProtocol, THandlerInEvent, THandlerOutEvent, ToSwarm, }; +use tracing::trace; mod builder; mod cid_prefix; @@ -21,6 +22,7 @@ mod incoming_stream; mod message; pub mod multihasher; mod proto; +mod server; #[cfg(test)] mod test_utils; pub mod utils; @@ -30,6 +32,7 @@ use crate::client::{ClientBehaviour, ClientConnectionHandler}; use crate::incoming_stream::IncomingStream; use crate::multihasher::MultihasherTable; use crate::proto::message::mod_Message::Wantlist as ProtoWantlist; +use crate::server::{ServerBehaviour, ServerConnectionHandler}; pub use crate::builder::BehaviourBuilder; pub use crate::client::QueryId; @@ -42,6 +45,7 @@ where { protocol: StreamProtocol, client: ClientBehaviour, + server: ServerBehaviour, multihasher: Arc>, } @@ -115,6 +119,7 @@ where peer, protocol: self.protocol.clone(), client_handler: self.client.new_connection_handler(peer), + server_handler: self.server.new_connection_handler(peer), incoming_streams: SelectAll::new(), multihasher: self.multihasher.clone(), }) @@ -131,6 +136,7 @@ where peer, protocol: self.protocol.clone(), client_handler: self.client.new_connection_handler(peer), + server_handler: self.server.new_connection_handler(peer), incoming_streams: SelectAll::new(), multihasher: self.multihasher.clone(), }) @@ -158,7 +164,13 @@ where self.client.process_incoming_message(peer, client_msg); } - // TODO: handle server message + if let Some(server_msg) = msg.server.take() { + self.server.process_incoming_message(peer, server_msg); + } + } + ToBehaviourEvent::NewBlocksAvailable(blocks) => { + trace!("received new blocks: {}", blocks.len()); + self.server.new_blocks_available(blocks); } } } @@ -167,7 +179,24 @@ where &mut self, cx: &mut Context<'_>, ) -> Poll>> { - self.client.poll(cx) + loop { + if let ready @ Poll::Ready(_) = self.client.poll(cx) { + return ready; + } + + let new_blocks = self.client.get_new_blocks(); + if !new_blocks.is_empty() { + self.server.new_blocks_available(new_blocks); + } + + // call server last so that it can process new blocks from client and blockstore + // together + if let ready @ Poll::Ready(_) = self.server.poll(cx) { + return ready; + } + + return Poll::Pending; + } } } @@ -175,12 +204,19 @@ where #[doc(hidden)] pub enum ToBehaviourEvent { IncomingMessage(PeerId, IncomingMessage), + NewBlocksAvailable(Vec<(CidGeneric, Vec)>), } #[derive(Debug)] #[doc(hidden)] pub enum ToHandlerEvent { SendWantlist(ProtoWantlist, Arc>), + SendSendlist(Vec<(Vec, Vec)>), +} + +pub enum StreamRequester { + Client, + Server, } #[derive(Debug)] @@ -189,6 +225,7 @@ pub struct ConnHandler { peer: PeerId, protocol: StreamProtocol, client_handler: ClientConnectionHandler, + server_handler: ServerConnectionHandler, incoming_streams: SelectAll>, multihasher: Arc>, } @@ -199,7 +236,7 @@ impl ConnectionHandler for ConnHandler; type InboundOpenInfo = (); type OutboundProtocol = ReadyUpgrade; - type OutboundOpenInfo = (); + type OutboundOpenInfo = StreamRequester; fn listen_protocol(&self) -> SubstreamProtocol { SubstreamProtocol::new(ReadyUpgrade::new(self.protocol.clone()), ()) @@ -210,6 +247,9 @@ impl ConnectionHandler for ConnHandler { self.client_handler.send_wantlist(wantlist, state); } + ToHandlerEvent::SendSendlist(data) => { + self.server_handler.send_sendlist(data); + } } } @@ -224,16 +264,17 @@ impl ConnectionHandler for ConnHandler, ) { match event { - ConnectionEvent::FullyNegotiatedOutbound(ev) => { - if self.client_handler.stream_requested() { - self.client_handler.set_stream(ev.protocol); + ConnectionEvent::FullyNegotiatedOutbound(outbound) => { + match outbound.info { + StreamRequester::Client => self.client_handler.set_stream(outbound.protocol), + StreamRequester::Server => self.server_handler.set_stream(outbound.protocol), } } ConnectionEvent::FullyNegotiatedInbound(ev) => { let stream = IncomingStream::new(ev.protocol, self.multihasher.clone()); self.incoming_streams.push(stream); } - _ => {} + _ => (), } } @@ -262,6 +303,10 @@ impl ConnectionHandler for ConnHandler; +type BlockWithCid = (CidGeneric, Vec); + +#[derive(Debug)] +pub(crate) struct ServerBehaviour +where + B: Blockstore + Send + Send, +{ + protocol: StreamProtocol, + store: Arc, + peers: FnvHashMap>, + global_waitlist: FnvHashMap, Vec>, + + outgoing_queue: Vec>, + outgoing_event_queue: VecDeque>, + + blockstore_tasks: FuturesUnordered>>, + blockstore_tasks_abort_handles: FnvHashMap<(PeerId, CidGeneric), AbortHandle>, +} + +#[derive(Debug)] +enum BlockstoreResult { + Get( + PeerId, + CidGeneric, + Result>, BlockstoreError>, + ), + Cancelled, +} + +#[derive(Debug, Default)] +struct PeerState { + map: FnvHashMap, ()>, +} + +impl PeerState { + pub fn process_wantlist(&mut self, wantlist: ProtoWantlist) -> Vec> { + let (add, remove): (Vec<_>, Vec<_>) = wantlist.entries.into_iter().partition(|e| !e.cancel); + let add = add + .into_iter() + .map(|e| CidGeneric::try_from(e.block).unwrap()) + .collect(); + let remove = remove + .into_iter() + .map(|e| CidGeneric::try_from(e.block).unwrap()) + .collect(); + + let mut results = vec![]; + if wantlist.full { + results.extend(self.wantlist_replace(add)); + } else { + results.extend(self.wantlist_add(add)); + results.extend(self.wantlist_remove(remove)); + } + + results + } + + fn wantlist_add(&mut self, cids: Vec>) -> Vec> { + let mut r = vec![]; + for cid in cids { + if self.map.insert(cid, ()).is_none() { + r.push(WishlistChange::WantCid(cid)) + } + } + r + } + + fn wantlist_remove(&mut self, cids: Vec>) -> Vec> { + let mut r = vec![]; + for cid in cids { + if self.map.remove(&cid).is_some() { + r.push(WishlistChange::DoesntWantCid(cid)) + } + } + r + } + + fn wantlist_replace(&mut self, cids: Vec>) -> Vec> { + let mut r = vec![]; + // TODO smarter algo + for cid in &cids { + if !self.map.contains_key(cid) { + r.push(WishlistChange::WantCid(*cid)); + } + } + for key in self.map.keys() { + if !cids.contains(key) { + r.push(WishlistChange::DoesntWantCid(*key)); + } + } + + self.map.clear(); + for c in cids { + self.map.insert(c, ()); + } + + r + } +} + +#[derive(Debug)] +enum WishlistChange { + WantCid(CidGeneric), + DoesntWantCid(CidGeneric), +} + +impl ServerBehaviour +where + B: Blockstore + Send + Sync + 'static, +{ + pub(crate) fn new(store: Arc, protocol_prefix: Option<&str>) -> Self { + let protocol = stream_protocol(protocol_prefix, "/ipfs/bitswap/1.2.0") + .expect("prefix checked by beetswap::BehaviourBuilder::protocol_prefix"); + + ServerBehaviour { + protocol, + store, + peers: FnvHashMap::default(), + global_waitlist: FnvHashMap::default(), + blockstore_tasks: Default::default(), + blockstore_tasks_abort_handles: FnvHashMap::default(), + outgoing_queue: Default::default(), + outgoing_event_queue: Default::default(), + } + } + + fn schedule_store_get(&mut self, peer: PeerId, cid: CidGeneric) { + let store = self.store.clone(); + let (handle, reg) = AbortHandle::new_pair(); + + self.blockstore_tasks.push( + async move { + match Abortable::new(store.get(&cid), reg).await { + Ok(result) => BlockstoreResult::Get(peer, cid, result), + Err(_) => BlockstoreResult::Cancelled, + } + } + .boxed(), + ); + + self.blockstore_tasks_abort_handles + .insert((peer, cid), handle); + } + + fn cancel_request(&mut self, peer: PeerId, cid: CidGeneric) { + // remove pending blockstore read, if any + if let Some(abort_handle) = self.blockstore_tasks_abort_handles.remove(&(peer, cid)) { + abort_handle.abort(); + } + + // remove peer from the waitlist for cid, in case we happen to get it later + if let Entry::Occupied(mut entry) = self.global_waitlist.entry(cid) { + if entry.get() == &vec![peer] { + entry.remove(); + } else { + let peers = entry.get_mut(); + if let Some(index) = peers.iter().position(|p| *p == peer) { + peers.swap_remove(index); + } + } + } + + if let Some(peer_state) = self.peers.get_mut(&peer) { + peer_state.map.remove(&cid); + } + } + + pub(crate) fn process_incoming_message(&mut self, peer: PeerId, msg: ServerMessage) { + // TODO: or default once, and then rely on the data being there + let rs = self + .peers + .entry(peer) + .or_default() + .process_wantlist(msg.wantlist); + + info!("{peer}: {rs:?}"); + + for r in rs { + match r { + WishlistChange::WantCid(cid) => { + self.schedule_store_get(peer, cid); + self.global_waitlist.entry(cid).or_default().push(peer); + } + WishlistChange::DoesntWantCid(cid) => { + self.cancel_request(peer, cid); + match self.global_waitlist.entry(cid) { + Entry::Occupied(mut entry) => { + let v = entry.get_mut(); + // TODO better algo? + if let Some(index) = v.iter().position(|p| *p == peer) { + v.swap_remove(index); + } else { + warn!("Requesting to remove CID for unexpected peer"); + } + } + Entry::Vacant(_) => { + warn!("Requesting to remove unexpected CID from wishlist") + } + } + } + } + } + } + + pub(crate) fn new_blocks_available(&mut self, blocks: Vec>) { + self.outgoing_queue.extend(blocks); + } + + pub(crate) fn new_connection_handler(&mut self, peer: PeerId) -> ServerConnectionHandler { + self.peers.entry(peer).or_default(); + + ServerConnectionHandler { + protocol: self.protocol.clone(), + sink: Default::default(), + sendlist: None, + } + } + + fn update_handlers(&mut self) -> bool { + if self.outgoing_queue.is_empty() { + return false; + } + + let outgoing = take(&mut self.outgoing_queue); + + let mut peer_to_block = FnvHashMap::, Vec)>>::default(); + + for (cid, data) in outgoing { + let Some(waitlist) = self.global_waitlist.remove(&cid) else { + continue; + }; + + for peer in waitlist { + peer_to_block + .entry(peer) + .or_default() + .push((cid.to_bytes(), data.clone())) + } + } + + if peer_to_block.is_empty() { + return false; + } + + trace!("sending response to {} peer(s)", peer_to_block.len()); + + for (peer, data) in peer_to_block { + self.outgoing_event_queue.push_back(ToSwarm::NotifyHandler { + peer_id: peer, + handler: NotifyHandler::Any, + event: ToHandlerEvent::SendSendlist(data), + }) + } + + true + } + + pub(crate) fn poll(&mut self, cx: &mut Context) -> Poll> { + loop { + if let Some(ev) = self.outgoing_event_queue.pop_front() { + return Poll::Ready(ev); + } + + if let Poll::Ready(Some(blockstore_result)) = self.blockstore_tasks.poll_next_unpin(cx) + { + match blockstore_result { + BlockstoreResult::Get(peer, cid, Ok(None)) => { + // requested CID isn't present locally. If we happen to get it, we'll + // forward it to the peer later + debug!("Cid {cid} not in blockstore for {peer}"); + } + BlockstoreResult::Get(peer, cid, Ok(Some(data))) => { + trace!("Cid {cid} for {peer} present in blockstore"); + self.outgoing_queue.push((cid, data)); + } + BlockstoreResult::Get(_peer, cid, Err(error)) => { + warn!("Fetching {cid} from blockstore failed: {error}"); + } + BlockstoreResult::Cancelled => (), + } + continue; + } + + if self.update_handlers() { + continue; + } + + return Poll::Pending; + } + } +} + +pub(crate) struct ServerConnectionHandler { + protocol: StreamProtocol, + sink: SinkState, + sendlist: Option>, +} + +impl fmt::Debug for ServerConnectionHandler { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("ServerConnectionHandler") + } +} + +#[derive(Default)] +enum SinkState { + #[default] + None, + Requested, + Ready(Sink), +} + +impl ServerConnectionHandler { + pub(crate) fn set_stream(&mut self, stream: libp2p_swarm::Stream) { + info!("got set stream"); + + // Convert `AsyncWrite` stream to `Sink` + self.sink = SinkState::Ready(FramedWrite::new(stream, Codec)); + } + + pub(crate) fn send_sendlist(&mut self, sendlist: Vec<(Vec, Vec)>) { + let block_list = sendlist + .into_iter() + .map(|(prefix, data)| ProtoBlock { prefix, data }) + .collect::>(); + + self.sendlist + .get_or_insert(Vec::with_capacity(block_list.len())) + .extend(block_list); + + info!( + "updated sendlist len: {:?}", + self.sendlist.as_ref().map(|s| s.len()) + ); + } + + fn open_new_substream( + &mut self, + ) -> Poll< + ConnectionHandlerEvent, StreamRequester, ToBehaviourEvent>, + > { + info!("requesting new substream"); + + self.sink = SinkState::Requested; + + Poll::Ready(ConnectionHandlerEvent::OutboundSubstreamRequest { + protocol: SubstreamProtocol::new( + ReadyUpgrade::new(self.protocol.clone()), + StreamRequester::Server, + ), + }) + } + + fn poll_outgoing( + &mut self, + cx: &mut Context, + ) -> Poll< + ConnectionHandlerEvent, StreamRequester, ToBehaviourEvent>, + > { + loop { + match (&mut self.sendlist, &mut self.sink) { + (_, SinkState::Requested) => return Poll::Pending, + (None, SinkState::None) => return Poll::Pending, + (None, SinkState::Ready(sink)) => { + if ready!(sink.poll_flush_unpin(cx)).is_err() { + self.close_sink("poll_flush_unpin"); + } + return Poll::Pending; + } + (Some(_), SinkState::None) => return self.open_new_substream(), + (sendlist @ Some(_), SinkState::Ready(sink)) => { + let sendlist = sendlist.take().expect("sendlist can't be None here"); + let blocks = sendlist.len(); + + let message = Message { + payload: sendlist, + ..Message::default() + }; + + if ready!(sink.poll_flush_unpin(cx)).is_err() { + self.close_sink("poll_flush_unpin"); + continue; + } + + info!("start_send: {} blocks", blocks); + if sink.start_send_unpin(&message).is_err() { + self.close_sink("start_send_unpin"); + continue; + } + } + } + } + } + + fn close_sink(&mut self, location: &str) { + warn!("sink operation failed, closing: {location}"); + self.sink = SinkState::None; + } + + pub(crate) fn poll( + &mut self, + cx: &mut Context, + ) -> Poll< + ConnectionHandlerEvent, StreamRequester, ToBehaviourEvent>, + > { + self.poll_outgoing(cx) + } +} diff --git a/tests/bitswap.rs b/tests/bitswap.rs new file mode 100644 index 0000000..db2c591 --- /dev/null +++ b/tests/bitswap.rs @@ -0,0 +1,152 @@ +use blockstore::{Blockstore, InMemoryBlockstore}; +use futures::{future::FutureExt, poll}; +use tokio::time::{sleep, Duration}; + +use crate::utils::{cid, spawn_node}; + +mod utils; + +#[tokio::test] +async fn test_client_request() { + let data = "foo"; + let cid = cid(data.as_bytes()); + let store = InMemoryBlockstore::new(); + store.put_keyed(&cid, data.as_ref()).await.unwrap(); + + let server = spawn_node(Some(store)).await; + let mut client = spawn_node(None).await; + + let _ = client.connect(&server); + let received = client.request_cid(cid).await.expect("could not get CID"); + + assert_eq!(&received[..], data.as_bytes()); +} + +#[tokio::test] +async fn test_server_request() { + let data = "foo"; + let cid = cid(data.as_bytes()); + let store = InMemoryBlockstore::new(); + store.put_keyed(&cid, data.as_ref()).await.unwrap(); + + let mut client = spawn_node(Some(store)).await; + let mut server = spawn_node(None).await; + + let _ = client.connect(&server); + let received = server.request_cid(cid).await.expect("could not get CID"); + + assert_eq!(&received[..], data.as_bytes()); +} + +#[tokio::test] +async fn test_chain_of_nodes() { + let data = "foo"; + let cid = cid(data.as_bytes()); + let store = InMemoryBlockstore::new(); + store.put_keyed(&cid, data.as_ref()).await.unwrap(); + + let mut node_with_data = spawn_node(Some(store)).await; + let mut node0 = spawn_node(None).await; + let mut node1 = spawn_node(None).await; + let mut node2 = spawn_node(None).await; + + let _ = node_with_data.connect(&node0); + let _ = node0.connect(&node1); + let _ = node1.connect(&node2); + + let mut node2_request = node2.request_cid(cid); + sleep(Duration::from_millis(100)).await; + assert!(poll!(&mut node2_request).is_pending()); + + let mut node1_request = node1.request_cid(cid); + sleep(Duration::from_millis(100)).await; + assert!(poll!(&mut node1_request).is_pending()); + assert!(poll!(&mut node2_request).is_pending()); + + let node0_request = node0.request_cid(cid); + sleep(Duration::from_millis(100)).await; + let data0 = node0_request + .now_or_never() + .expect("data should be ready") + .unwrap(); + let data1 = node1_request + .now_or_never() + .expect("data should be ready") + .unwrap(); + let data2 = node2_request + .now_or_never() + .expect("data should be ready") + .unwrap(); + + assert_eq!(data0, data.as_bytes()); + assert_eq!(data1, data.as_bytes()); + assert_eq!(data2, data.as_bytes()); +} + +#[tokio::test] +async fn test_node_with_data_coming_online() { + let data = "foo"; + let cid = cid(data.as_bytes()); + let store = InMemoryBlockstore::new(); + store.put_keyed(&cid, data.as_ref()).await.unwrap(); + + let node_with_data = spawn_node(Some(store)).await; + + let mut node0 = spawn_node(None).await; + let mut node1 = spawn_node(None).await; + let _ = node0.connect(&node1); + + let mut node0_request = node0.request_cid(cid); + let mut node1_request = node1.request_cid(cid); + sleep(Duration::from_millis(100)).await; + assert!(poll!(&mut node0_request).is_pending()); + assert!(poll!(&mut node1_request).is_pending()); + + node1 + .connect(&node_with_data) + .await + .expect("could not connect"); + sleep(Duration::from_millis(100)).await; + + let data0 = node0_request + .now_or_never() + .expect("data should be ready") + .unwrap(); + let data1 = node1_request + .now_or_never() + .expect("data should be ready") + .unwrap(); + assert_eq!(data0, data.as_bytes()); + assert_eq!(data1, data.as_bytes()); +} + +#[tokio::test] +async fn test_node_with_invalid_data() { + let data = "foo"; + let cid = cid(data.as_bytes()); + let store = InMemoryBlockstore::new(); + store.put_keyed(&cid, data.as_ref()).await.unwrap(); + + let invalid_data = "bar"; + let invalid_store = InMemoryBlockstore::new(); + invalid_store + .put_keyed(&cid, invalid_data.as_ref()) + .await + .unwrap(); + + let mut client = spawn_node(None).await; + let node = spawn_node(Some(store)).await; + let malicious_node = spawn_node(Some(invalid_store)).await; + + client + .connect(&malicious_node) + .await + .expect("could not connect"); + let mut request = client.request_cid(cid); + sleep(Duration::from_millis(100)).await; + assert!(poll!(&mut request).is_pending()); + + let _ = client.connect(&node); + let received = request.await.expect("could not get CID"); + assert_eq!(received, data.as_bytes()); +} diff --git a/tests/utils/mod.rs b/tests/utils/mod.rs new file mode 100644 index 0000000..136e7e7 --- /dev/null +++ b/tests/utils/mod.rs @@ -0,0 +1,184 @@ +use beetswap::{Error, Event, QueryId}; +use blockstore::InMemoryBlockstore; +use cid::CidGeneric; +use fnv::FnvHashMap; +use futures::future::{Future, FutureExt}; +use libp2p::{ + futures::StreamExt, + swarm::{DialError, SwarmEvent}, + tcp, Multiaddr, PeerId, Swarm, SwarmBuilder, +}; +use multihash_codetable::{Code, MultihashDigest}; +use tokio::select; +use tokio::sync::{mpsc, oneshot}; + +const RAW_CODEC: u64 = 0x55; +const CID_SIZE: usize = 64; +type Cid = CidGeneric; + +pub fn cid(bytes: &[u8]) -> Cid { + let hash = Code::Sha2_256.digest(bytes); + Cid::new_v1(RAW_CODEC, hash) +} + +type BitswapSwarm = Swarm>>; + +pub struct TestBitswapNode { + cmd: mpsc::UnboundedSender, + pub addr: Multiaddr, + pub peer_id: PeerId, +} + +impl TestBitswapNode { + fn cmd(&mut self, cmd: NodeCommand) { + self.cmd.send(cmd).unwrap() + } + + pub fn connect( + &mut self, + node: &TestBitswapNode, + ) -> impl Future> { + let (notify_connected, response) = oneshot::channel(); + + self.cmd(NodeCommand::Connect { + addr: node.addr.clone(), + peer_id: node.peer_id, + notify_connected, + }); + + // unwrap oneshot closed channel error + response.map(|f| f.unwrap()).boxed() + } + + pub fn request_cid(&mut self, cid: Cid) -> impl Future, Error>> { + let (respond_to, response) = oneshot::channel(); + self.cmd(NodeCommand::WaitForCid { cid, respond_to }); + + // unwrap oneshot closed channel error + response.map(|f| f.unwrap()).boxed() + } +} + +pub enum NodeCommand { + Connect { + addr: Multiaddr, + peer_id: PeerId, + notify_connected: oneshot::Sender>, + }, + WaitForCid { + cid: Cid, + respond_to: oneshot::Sender, Error>>, + }, +} + +struct TestBitswapWorker { + swarm: BitswapSwarm, + cmd: mpsc::UnboundedReceiver, + queried_cids: FnvHashMap, Error>>>, + dials_requested: FnvHashMap>>, +} + +impl TestBitswapWorker { + async fn run(&mut self) { + loop { + select! { + ev = self.swarm.select_next_some() => { + self.on_event(ev); + }, + cmd = self.cmd.recv() => if let Some(cmd) = cmd { + self.on_cmd(cmd).await; + } else { + break; + } + } + } + } + + fn on_event(&mut self, ev: SwarmEvent) { + match ev { + SwarmEvent::Behaviour(bev) => match bev { + Event::GetQueryResponse { query_id, data } => { + let tx = self.queried_cids.remove(&query_id).unwrap(); + tx.send(Ok(data)).unwrap(); + } + Event::GetQueryError { query_id, error } => { + let tx = self.queried_cids.remove(&query_id).unwrap(); + tx.send(Err(error)).unwrap(); + } + }, + SwarmEvent::ConnectionEstablished { peer_id, .. } => { + if let Some(tx) = self.dials_requested.remove(&peer_id) { + // receiver might have been dropped already if caller doesn't care about + // waiting for connecion to be established + let _ = tx.send(Ok(())); + } + } + _ => (), + } + } + + async fn on_cmd(&mut self, cmd: NodeCommand) { + match cmd { + NodeCommand::Connect { + addr, + peer_id, + notify_connected, + } => { + if let e @ Err(_) = self.swarm.dial(addr.clone()) { + notify_connected.send(e).unwrap(); + } else { + self.dials_requested.insert(peer_id, notify_connected); + } + } + NodeCommand::WaitForCid { cid, respond_to } => { + let query_id = self.swarm.behaviour_mut().get(&cid); + self.queried_cids.insert(query_id, respond_to); + } + } + } +} + +pub async fn spawn_node(store: Option>) -> TestBitswapNode { + let store = store.unwrap_or_default(); + + let mut swarm = SwarmBuilder::with_new_identity() + .with_tokio() + .with_tcp( + tcp::Config::default(), + libp2p_noise::Config::new, + libp2p_yamux::Config::default, + ) + .unwrap() + .with_behaviour(|_key| beetswap::Behaviour::::new(store)) + .unwrap() + .build(); + + swarm + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + .unwrap(); + + let mut events = Vec::new(); + let addr = loop { + match swarm.select_next_some().await { + SwarmEvent::NewListenAddr { address, .. } => break address, + ev => events.push(ev), + } + }; + let peer_id = swarm.local_peer_id().to_owned(); + + let (cmd_tx, cmd_rx) = mpsc::unbounded_channel(); + let mut worker = TestBitswapWorker { + swarm, + cmd: cmd_rx, + queried_cids: FnvHashMap::default(), + dials_requested: FnvHashMap::default(), + }; + + let _handle = tokio::spawn(async move { worker.run().await }); + + TestBitswapNode { + cmd: cmd_tx, + addr, + peer_id, + } +}