diff --git a/Cargo.lock b/Cargo.lock index d1089207c..46f637be1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,6 +1160,19 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "asynchronous-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + [[package]] name = "atomic-take" version = "1.1.0" @@ -1366,6 +1379,34 @@ dependencies = [ "serde", ] +[[package]] +name = "beetswap" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55f2cf2244bd65e9f00adb06c6b5e951bab980fdacdd572ff035bf610628be99" +dependencies = [ + "asynchronous-codec 0.7.0", + "blockstore", + "bytes", + "cid 0.11.1", + "fnv", + "futures-core", + "futures-timer", + "futures-util", + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-swarm 0.45.1", + "multihash-codetable", + "quick-protobuf", + "smallvec", + "thiserror 1.0.69", + "time", + "tracing", + "unsigned-varint 0.8.0", + "void", + "web-time", +] + [[package]] name = "bellpepper" version = "0.2.1" @@ -1692,6 +1733,18 @@ dependencies = [ "piper", ] +[[package]] +name = "blockstore" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a8962daed8fb337472d9c4215006443acba1e40c6c91c9d4a3f440d1fb30436" +dependencies = [ + "cid 0.11.1", + "dashmap 6.1.0", + "multihash 0.19.3", + "thiserror 1.0.69", +] + [[package]] name = "bls12_381" version = "0.8.0" @@ -2337,7 +2390,7 @@ checksum = "3147d8272e8fa0ccd29ce51194dd98f79ddfb8191ba9e3409884e751798acf3a" dependencies = [ "core2", "multibase", - "multihash 0.19.2", + "multihash 0.19.3", "parity-scale-codec", "serde", "serde_bytes", @@ -3999,6 +4052,20 @@ dependencies = [ "parking_lot_core 0.9.10", ] +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core 0.9.10", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -5896,6 +5963,17 @@ dependencies = [ "rustls 0.21.12", ] +[[package]] +name = "futures-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" +dependencies = [ + "futures-io", + "rustls 0.23.18", + "rustls-pki-types", +] + [[package]] name = "futures-sink" version = "0.3.31" @@ -5987,8 +6065,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -6057,7 +6137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" dependencies = [ "cfg-if", - "dashmap", + "dashmap 5.5.3", "futures", "futures-timer", "no-std-compat", @@ -6280,6 +6360,7 @@ dependencies = [ "ipnet", "once_cell", "rand", + "socket2 0.5.7", "thiserror 1.0.69", "tinyvec", "tokio", @@ -7770,25 +7851,54 @@ dependencies = [ "futures-timer", "getrandom", "instant", - "libp2p-allow-block-list", - "libp2p-connection-limits", - "libp2p-core", - "libp2p-dns", + "libp2p-allow-block-list 0.2.0", + "libp2p-connection-limits 0.2.1", + "libp2p-core 0.40.1", + "libp2p-dns 0.40.1", "libp2p-identify", "libp2p-identity", "libp2p-kad", - "libp2p-mdns", + "libp2p-mdns 0.44.0", "libp2p-metrics", - "libp2p-noise", + "libp2p-noise 0.43.2", "libp2p-ping", - "libp2p-quic", + "libp2p-quic 0.9.3", "libp2p-request-response", - "libp2p-swarm", - "libp2p-tcp", - "libp2p-upnp", + "libp2p-swarm 0.43.7", + "libp2p-tcp 0.40.1", + "libp2p-upnp 0.1.1", "libp2p-wasm-ext", "libp2p-websocket", - "libp2p-yamux", + "libp2p-yamux 0.44.1", + "multiaddr 0.18.2", + "pin-project", + "rw-stream-sink", + "thiserror 1.0.69", +] + +[[package]] +name = "libp2p" +version = "0.54.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbe80f9c7e00526cd6b838075b9c171919404a4732cb2fa8ece0a093223bfc4" +dependencies = [ + "bytes", + "either", + "futures", + "futures-timer", + "getrandom", + "libp2p-allow-block-list 0.4.0", + "libp2p-connection-limits 0.4.0", + "libp2p-core 0.42.0", + "libp2p-dns 0.42.0", + "libp2p-identity", + "libp2p-mdns 0.46.0", + "libp2p-noise 0.45.0", + "libp2p-quic 0.11.1", + "libp2p-swarm 0.45.1", + "libp2p-tcp 0.42.0", + "libp2p-upnp 0.3.0", + "libp2p-yamux 0.46.0", "multiaddr 0.18.2", "pin-project", "rw-stream-sink", @@ -7801,9 +7911,21 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55b46558c5c0bf99d3e2a1a38fd54ff5476ca66dd1737b12466a1824dd219311" dependencies = [ - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.43.7", + "void", +] + +[[package]] +name = "libp2p-allow-block-list" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1027ccf8d70320ed77e984f273bc8ce952f623762cb9bf2d126df73caef8041" +dependencies = [ + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-swarm 0.45.1", "void", ] @@ -7813,9 +7935,21 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f5107ad45cb20b2f6c3628c7b6014b996fcb13a88053f4569c872c6e30abf58" dependencies = [ - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.43.7", + "void", +] + +[[package]] +name = "libp2p-connection-limits" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d003540ee8baef0d254f7b6bfd79bac3ddf774662ca0abf69186d517ef82ad8" +dependencies = [ + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-swarm 0.45.1", "void", ] @@ -7833,7 +7967,7 @@ dependencies = [ "libp2p-identity", "log", "multiaddr 0.18.2", - "multihash 0.19.2", + "multihash 0.19.3", "multistream-select", "once_cell", "parking_lot 0.12.3", @@ -7847,6 +7981,34 @@ dependencies = [ "void", ] +[[package]] +name = "libp2p-core" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a61f26c83ed111104cd820fe9bc3aaabbac5f1652a1d213ed6e900b7918a1298" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-identity", + "multiaddr 0.18.2", + "multihash 0.19.3", + "multistream-select", + "once_cell", + "parking_lot 0.12.3", + "pin-project", + "quick-protobuf", + "rand", + "rw-stream-sink", + "smallvec", + "thiserror 1.0.69", + "tracing", + "unsigned-varint 0.8.0", + "void", + "web-time", +] + [[package]] name = "libp2p-dns" version = "0.40.1" @@ -7855,7 +8017,7 @@ checksum = "e6a18db73084b4da2871438f6239fef35190b05023de7656e877c18a00541a3b" dependencies = [ "async-trait", "futures", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", "log", "parking_lot 0.12.3", @@ -7863,20 +8025,36 @@ dependencies = [ "trust-dns-resolver", ] +[[package]] +name = "libp2p-dns" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97f37f30d5c7275db282ecd86e54f29dd2176bd3ac656f06abf43bedb21eb8bd" +dependencies = [ + "async-trait", + "futures", + "hickory-resolver", + "libp2p-core 0.42.0", + "libp2p-identity", + "parking_lot 0.12.3", + "smallvec", + "tracing", +] + [[package]] name = "libp2p-identify" version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45a96638a0a176bec0a4bcaebc1afa8cf909b114477209d7456ade52c61cd9cd" dependencies = [ - "asynchronous-codec", + "asynchronous-codec 0.6.2", "either", "futures", "futures-bounded", "futures-timer", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.43.7", "log", "lru 0.12.5", "quick-protobuf", @@ -7895,7 +8073,7 @@ dependencies = [ "bs58", "ed25519-dalek", "hkdf", - "multihash 0.19.2", + "multihash 0.19.3", "quick-protobuf", "rand", "sha2 0.10.8", @@ -7911,16 +8089,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16ea178dabba6dde6ffc260a8e0452ccdc8f79becf544946692fff9d412fc29d" dependencies = [ "arrayvec 0.7.6", - "asynchronous-codec", + "asynchronous-codec 0.6.2", "bytes", "either", "fnv", "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.43.7", "log", "quick-protobuf", "quick-protobuf-codec", @@ -7942,9 +8120,9 @@ dependencies = [ "data-encoding", "futures", "if-watch", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.43.7", "log", "rand", "smallvec", @@ -7954,6 +8132,27 @@ dependencies = [ "void", ] +[[package]] +name = "libp2p-mdns" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b8546b6644032565eb29046b42744aee1e9f261ed99671b2c93fb140dba417" +dependencies = [ + "data-encoding", + "futures", + "hickory-proto", + "if-watch", + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-swarm 0.45.1", + "rand", + "smallvec", + "socket2 0.5.7", + "tokio", + "tracing", + "void", +] + [[package]] name = "libp2p-metrics" version = "0.13.1" @@ -7961,12 +8160,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239ba7d28f8d0b5d77760dc6619c05c7e88e74ec8fbbe97f856f20a56745e620" dependencies = [ "instant", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identify", "libp2p-identity", "libp2p-kad", "libp2p-ping", - "libp2p-swarm", + "libp2p-swarm 0.43.7", "once_cell", "prometheus-client", ] @@ -7980,11 +8179,11 @@ dependencies = [ "bytes", "curve25519-dalek 4.1.3", "futures", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", "log", "multiaddr 0.18.2", - "multihash 0.19.2", + "multihash 0.19.3", "once_cell", "quick-protobuf", "rand", @@ -7996,6 +8195,32 @@ dependencies = [ "zeroize", ] +[[package]] +name = "libp2p-noise" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36b137cb1ae86ee39f8e5d6245a296518912014eaa87427d24e6ff58cfc1b28c" +dependencies = [ + "asynchronous-codec 0.7.0", + "bytes", + "curve25519-dalek 4.1.3", + "futures", + "libp2p-core 0.42.0", + "libp2p-identity", + "multiaddr 0.18.2", + "multihash 0.19.3", + "once_cell", + "quick-protobuf", + "rand", + "sha2 0.10.8", + "snow", + "static_assertions", + "thiserror 1.0.69", + "tracing", + "x25519-dalek", + "zeroize", +] + [[package]] name = "libp2p-ping" version = "0.43.1" @@ -8006,9 +8231,9 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.43.7", "log", "rand", "void", @@ -8024,12 +8249,12 @@ dependencies = [ "futures", "futures-timer", "if-watch", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", - "libp2p-tls", + "libp2p-tls 0.2.1", "log", "parking_lot 0.12.3", - "quinn", + "quinn 0.10.2", "rand", "ring 0.16.20", "rustls 0.21.12", @@ -8038,6 +8263,30 @@ dependencies = [ "tokio", ] +[[package]] +name = "libp2p-quic" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46352ac5cd040c70e88e7ff8257a2ae2f891a4076abad2c439584a31c15fd24e" +dependencies = [ + "bytes", + "futures", + "futures-timer", + "if-watch", + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-tls 0.5.0", + "parking_lot 0.12.3", + "quinn 0.11.6", + "rand", + "ring 0.17.8", + "rustls 0.23.18", + "socket2 0.5.7", + "thiserror 1.0.69", + "tokio", + "tracing", +] + [[package]] name = "libp2p-request-response" version = "0.25.3" @@ -8047,9 +8296,9 @@ dependencies = [ "async-trait", "futures", "instant", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", - "libp2p-swarm", + "libp2p-swarm 0.43.7", "log", "rand", "smallvec", @@ -8067,9 +8316,9 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", - "libp2p-swarm-derive", + "libp2p-swarm-derive 0.33.0", "log", "multistream-select", "once_cell", @@ -8079,6 +8328,30 @@ dependencies = [ "void", ] +[[package]] +name = "libp2p-swarm" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7dd6741793d2c1fb2088f67f82cf07261f25272ebe3c0b0c311e0c6b50e851a" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-core 0.42.0", + "libp2p-identity", + "libp2p-swarm-derive 0.35.0", + "lru 0.12.5", + "multistream-select", + "once_cell", + "rand", + "smallvec", + "tokio", + "tracing", + "void", + "web-time", +] + [[package]] name = "libp2p-swarm-derive" version = "0.33.0" @@ -8092,6 +8365,18 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "libp2p-swarm-derive" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206e0aa0ebe004d778d79fb0966aa0de996c19894e2c0605ba2f8524dd4443d8" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "libp2p-tcp" version = "0.40.1" @@ -8102,13 +8387,30 @@ dependencies = [ "futures-timer", "if-watch", "libc", - "libp2p-core", + "libp2p-core 0.40.1", "libp2p-identity", "log", "socket2 0.5.7", "tokio", ] +[[package]] +name = "libp2p-tcp" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad964f312c59dcfcac840acd8c555de8403e295d39edf96f5240048b5fcaa314" +dependencies = [ + "futures", + "futures-timer", + "if-watch", + "libc", + "libp2p-core 0.42.0", + "libp2p-identity", + "socket2 0.5.7", + "tokio", + "tracing", +] + [[package]] name = "libp2p-tls" version = "0.2.1" @@ -8116,10 +8418,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8218d1d5482b122ccae396bbf38abdcb283ecc96fa54760e1dfd251f0546ac61" dependencies = [ "futures", - "futures-rustls", - "libp2p-core", + "futures-rustls 0.24.0", + "libp2p-core 0.40.1", "libp2p-identity", - "rcgen", + "rcgen 0.10.0", "ring 0.16.20", "rustls 0.21.12", "rustls-webpki 0.101.7", @@ -8128,6 +8430,25 @@ dependencies = [ "yasna", ] +[[package]] +name = "libp2p-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b23dddc2b9c355f73c1e36eb0c3ae86f7dc964a3715f0731cfad352db4d847" +dependencies = [ + "futures", + "futures-rustls 0.26.0", + "libp2p-core 0.42.0", + "libp2p-identity", + "rcgen 0.11.3", + "ring 0.17.8", + "rustls 0.23.18", + "rustls-webpki 0.101.7", + "thiserror 1.0.69", + "x509-parser 0.16.0", + "yasna", +] + [[package]] name = "libp2p-upnp" version = "0.1.1" @@ -8137,13 +8458,29 @@ dependencies = [ "futures", "futures-timer", "igd-next", - "libp2p-core", - "libp2p-swarm", + "libp2p-core 0.40.1", + "libp2p-swarm 0.43.7", "log", "tokio", "void", ] +[[package]] +name = "libp2p-upnp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01bf2d1b772bd3abca049214a3304615e6a36fa6ffc742bdd1ba774486200b8f" +dependencies = [ + "futures", + "futures-timer", + "igd-next", + "libp2p-core 0.42.0", + "libp2p-swarm 0.45.1", + "tokio", + "tracing", + "void", +] + [[package]] name = "libp2p-wasm-ext" version = "0.40.0" @@ -8152,7 +8489,7 @@ checksum = "1e5d8e3a9e07da0ef5b55a9f26c009c8fb3c725d492d8bb4b431715786eea79c" dependencies = [ "futures", "js-sys", - "libp2p-core", + "libp2p-core 0.40.1", "send_wrapper", "wasm-bindgen", "wasm-bindgen-futures", @@ -8166,8 +8503,8 @@ checksum = "004ee9c4a4631435169aee6aad2f62e3984dc031c43b6d29731e8e82a016c538" dependencies = [ "either", "futures", - "futures-rustls", - "libp2p-core", + "futures-rustls 0.24.0", + "libp2p-core 0.40.1", "libp2p-identity", "log", "parking_lot 0.12.3", @@ -8186,10 +8523,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eedcb62824c4300efb9cfd4e2a6edaf3ca097b9e68b36dabe45a44469fd6a85" dependencies = [ "futures", - "libp2p-core", + "libp2p-core 0.40.1", "log", "thiserror 1.0.69", - "yamux", + "yamux 0.12.1", +] + +[[package]] +name = "libp2p-yamux" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "788b61c80789dba9760d8c669a5bedb642c8267555c803fabd8396e4ca5c5882" +dependencies = [ + "either", + "futures", + "libp2p-core 0.42.0", + "thiserror 1.0.69", + "tracing", + "yamux 0.12.1", + "yamux 0.13.4", ] [[package]] @@ -8375,7 +8727,7 @@ dependencies = [ "prost 0.12.6", "prost-build", "rand", - "rcgen", + "rcgen 0.10.0", "ring 0.16.20", "rustls 0.20.9", "serde", @@ -8589,6 +8941,7 @@ version = "0.1.0" dependencies = [ "async-stream", "bitflags 2.6.0", + "blockstore", "byteorder", "bytes", "criterion", @@ -8910,7 +9263,7 @@ dependencies = [ "data-encoding", "libp2p-identity", "multibase", - "multihash 0.19.2", + "multihash 0.19.3", "percent-encoding", "serde", "static_assertions", @@ -8965,9 +9318,9 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.2" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" +checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" dependencies = [ "core2", "parity-scale-codec", @@ -8982,8 +9335,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67996849749d25f1da9f238e8ace2ece8f9d6bdf3f9750aaf2ae7de3a5cad8ea" dependencies = [ "blake2b_simd", + "blake2s_simd 1.0.2", + "blake3", "core2", + "digest 0.10.7", "multihash-derive 0.9.1", + "ripemd", + "sha1", + "sha2 0.10.8", + "sha3", + "strobe-rs", ] [[package]] @@ -9007,7 +9368,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f1b7edab35d920890b88643a765fc9bd295cf0201f4154dda231bef9b8404eb" dependencies = [ "core2", - "multihash 0.19.2", + "multihash 0.19.3", "multihash-derive-impl", ] @@ -15710,8 +16071,8 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b" dependencies = [ - "heck 0.4.1", - "itertools 0.10.5", + "heck 0.5.0", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -15744,7 +16105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.89", @@ -15804,7 +16165,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ededb1cd78531627244d51dd0c7139fbe736c7d57af0092a76f0ffb2f56e98" dependencies = [ - "asynchronous-codec", + "asynchronous-codec 0.6.2", "bytes", "quick-protobuf", "thiserror 1.0.69", @@ -15820,8 +16181,8 @@ dependencies = [ "bytes", "futures-io", "pin-project-lite", - "quinn-proto", - "quinn-udp", + "quinn-proto 0.10.6", + "quinn-udp 0.4.1", "rustc-hash 1.1.0", "rustls 0.21.12", "thiserror 1.0.69", @@ -15829,6 +16190,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "futures-io", + "pin-project-lite", + "quinn-proto 0.11.9", + "quinn-udp 0.5.9", + "rustc-hash 2.0.0", + "rustls 0.23.18", + "socket2 0.5.7", + "thiserror 2.0.3", + "tokio", + "tracing", +] + [[package]] name = "quinn-proto" version = "0.10.6" @@ -15846,6 +16226,26 @@ dependencies = [ "tracing", ] +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom", + "rand", + "ring 0.17.8", + "rustc-hash 2.0.0", + "rustls 0.23.18", + "rustls-pki-types", + "slab", + "thiserror 2.0.3", + "tinyvec", + "tracing", + "web-time", +] + [[package]] name = "quinn-udp" version = "0.4.1" @@ -15859,6 +16259,20 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "quinn-udp" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +dependencies = [ + "cfg_aliases 0.2.1", + "libc", + "once_cell", + "socket2 0.5.7", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.37" @@ -15985,6 +16399,18 @@ dependencies = [ "yasna", ] +[[package]] +name = "rcgen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6" +dependencies = [ + "pem 3.0.4", + "ring 0.16.20", + "time", + "yasna", +] + [[package]] name = "reconnecting-jsonrpsee-ws-client" version = "0.4.3" @@ -16742,6 +17168,9 @@ name = "rustls-pki-types" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +dependencies = [ + "web-time", +] [[package]] name = "rustls-platform-verifier" @@ -16926,10 +17355,10 @@ dependencies = [ "futures", "futures-timer", "ip_network", - "libp2p", + "libp2p 0.52.4", "linked_hash_set", "log", - "multihash 0.19.2", + "multihash 0.19.3", "parity-scale-codec", "prost 0.12.6", "prost-build", @@ -17586,7 +18015,7 @@ dependencies = [ "array-bytes", "async-channel 1.9.0", "async-trait", - "asynchronous-codec", + "asynchronous-codec 0.6.2", "bytes", "cid 0.9.0", "either", @@ -17594,7 +18023,7 @@ dependencies = [ "futures", "futures-timer", "ip_network", - "libp2p", + "libp2p 0.52.4", "linked_hash_set", "litep2p", "log", @@ -17753,7 +18182,7 @@ dependencies = [ "litep2p", "log", "multiaddr 0.18.2", - "multihash 0.19.2", + "multihash 0.19.3", "rand", "thiserror 1.0.69", "zeroize", @@ -18048,7 +18477,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk?tag=polkadot-stable2412 dependencies = [ "chrono", "futures", - "libp2p", + "libp2p 0.52.4", "log", "parking_lot 0.12.3", "pin-project", @@ -21849,6 +22278,28 @@ dependencies = [ "storage-proofs-porep", ] +[[package]] +name = "storage-retrieval" +version = "0.1.0" +dependencies = [ + "anyhow", + "beetswap", + "blockstore", + "cid 0.11.1", + "futures", + "libp2p 0.54.1", + "libp2p-core 0.42.0", + "libp2p-swarm 0.45.1", + "mater", + "multihash-codetable", + "polka-index", + "thiserror 2.0.3", + "tokio", + "tracing", + "tracing-appender", + "tracing-subscriber 0.3.18", +] + [[package]] name = "storagext" version = "0.1.0" @@ -21909,6 +22360,19 @@ dependencies = [ "serde", ] +[[package]] +name = "strobe-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98fe17535ea31344936cc58d29fec9b500b0452ddc4cc24c429c8a921a0e84e5" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "keccak", + "subtle 2.6.1", + "zeroize", +] + [[package]] name = "strsim" version = "0.10.0" @@ -23501,7 +23965,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" dependencies = [ - "asynchronous-codec", + "asynchronous-codec 0.6.2", "bytes", "futures-io", "futures-util", @@ -24798,6 +25262,22 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "yamux" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17610762a1207ee816c6fadc29220904753648aba0a9ed61c7b8336e80a559c4" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot 0.12.3", + "pin-project", + "rand", + "static_assertions", + "web-time", +] + [[package]] name = "yansi" version = "1.0.1" @@ -24968,7 +25448,7 @@ dependencies = [ "futures", "glob-match", "hex", - "libp2p", + "libp2p 0.52.4", "libsecp256k1", "multiaddr 0.18.2", "rand", diff --git a/Cargo.toml b/Cargo.toml index f5c3eea0c..77694e5f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "storage-provider/client", "storage-provider/common", "storage-provider/server", + "storage-retrieval", "storage/polka-index", "storagext/cli", "storagext/lib", @@ -51,8 +52,10 @@ async-stream = "0.3.6" async-trait = "0.1.80" axum = "0.7.5" base64 = "0.22.1" +beetswap = "0.4.0" bitflags = "2.5.0" blake2b_simd = { version = "1.0.2", default-features = false } +blockstore = "0.7.1" bls12_381 = "0.8" bs58 = "0.5.1" byteorder = "1.5.0" @@ -78,6 +81,9 @@ ipld-core = "0.4.1" ipld-dagpb = "0.2.1" itertools = "0.13.0" jsonrpsee = { version = "0.24.7" } +libp2p = "0.54.1" +libp2p-core = "0.42.0" +libp2p-swarm = "0.45.1" log = { version = "0.4.21", default-features = false } multihash-codetable = { version = "0.1.1", default-features = false } num-bigint = { version = "0.4.5", default-features = false } @@ -136,6 +142,7 @@ pallet-market = { path = "pallets/market", default-features = false } pallet-proofs = { path = "pallets/proofs", default-features = false } pallet-randomness = { path = "pallets/randomness", default-features = false } pallet-storage-provider = { path = "pallets/storage-provider", default-features = false } +polka-index = { path = "storage/polka-index" } polka-storage-proofs = { path = "lib/polka-storage-proofs", default-features = false } polka-storage-provider-common = { path = "storage-provider/common" } polka-storage-runtime = { path = "runtime" } diff --git a/mater/lib/Cargo.toml b/mater/lib/Cargo.toml index ba72449ea..5066859d9 100644 --- a/mater/lib/Cargo.toml +++ b/mater/lib/Cargo.toml @@ -10,6 +10,7 @@ version = "0.1.0" [dependencies] async-stream.workspace = true bitflags.workspace = true +blockstore = { workspace = true } byteorder = { workspace = true, features = ["i128"] } bytes.workspace = true digest.workspace = true diff --git a/mater/lib/src/lib.rs b/mater/lib/src/lib.rs index e9e6dd62e..48740b945 100644 --- a/mater/lib/src/lib.rs +++ b/mater/lib/src/lib.rs @@ -19,7 +19,7 @@ mod v2; // We need to re-expose this because `read_block` returns `(Cid, Vec)`. pub use ipld_core::cid::Cid; -pub use stores::{create_filestore, Blockstore, Config}; +pub use stores::{create_filestore, Blockstore, Config, InMemory}; pub use v1::{Header as CarV1Header, Reader as CarV1Reader, Writer as CarV1Writer}; pub use v2::{ verify_cid, Characteristics, Header as CarV2Header, Index, IndexEntry, IndexSorted, diff --git a/mater/lib/src/stores/blockstore.rs b/mater/lib/src/stores/blockstore.rs index 69e6a29c1..a7cb75df9 100644 --- a/mater/lib/src/stores/blockstore.rs +++ b/mater/lib/src/stores/blockstore.rs @@ -1,12 +1,15 @@ // NOTE(@jmg-duarte,28/05/2024): the blockstore can (and should) evolve to support other backends. // At the time of writing, there is no need invest more time in it because the current PR(#25) is delayed enough. -use std::collections::{HashMap, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + sync::Mutex, +}; use bytes::Bytes; use indexmap::IndexMap; use integer_encoding::VarInt; -use ipld_core::cid::Cid; +use ipld_core::cid::{Cid, CidGeneric}; use sha2::{Digest, Sha256}; use tokio::io::{AsyncRead, AsyncWrite}; use tokio_stream::StreamExt; @@ -14,10 +17,73 @@ use tokio_util::io::ReaderStream; use super::{DEFAULT_BLOCK_SIZE, DEFAULT_TREE_WIDTH}; use crate::{ - multicodec::SHA_256_CODE, unixfs::stream_balanced_tree, CarV1Header, CarV2Header, CarV2Writer, - Error, Index, IndexEntry, MultihashIndexSorted, SingleWidthIndex, + multicodec::SHA_256_CODE, unixfs::stream_balanced_tree, CarV1Header, CarV2Header, CarV2Reader, + CarV2Writer, Error, Index, IndexEntry, MultihashIndexSorted, SingleWidthIndex, }; +/// Thread-safe in memory blockstore +pub struct InMemory(Mutex); + +impl From for InMemory { + fn from(value: Blockstore) -> Self { + Self(Mutex::new(value)) + } +} + +impl InMemory { + /// Create a new InMemory blockstore + pub fn new() -> Self { + Self(Mutex::new(Blockstore::new())) + } +} + +impl blockstore::Blockstore for InMemory { + async fn get( + &self, + cid: &CidGeneric, + ) -> Result>, blockstore::Error> { + // Convert to the cid that the store uses + let cid = Cid::try_from(cid.to_bytes()).map_err(|_err| blockstore::Error::CidTooLarge)?; + + let inner_lock = self + .0 + .lock() + .map_err(|err| blockstore::Error::FatalDatabaseError(err.to_string()))?; + + let block = inner_lock.blocks.get(&cid).map(|b| b.to_vec()); + + Ok(block) + } + + async fn put_keyed( + &self, + cid: &CidGeneric, + data: &[u8], + ) -> Result<(), blockstore::Error> { + // Convert to the cid that the store uses + let cid = Cid::try_from(cid.to_bytes()).map_err(|_err| blockstore::Error::CidTooLarge)?; + + let mut inner_lock = self + .0 + .lock() + .map_err(|err| blockstore::Error::FatalDatabaseError(err.to_string()))?; + + inner_lock.blocks.insert(cid, Bytes::from(data.to_vec())); + + Ok(()) + } + + async fn remove(&self, _cid: &CidGeneric) -> Result<(), blockstore::Error> { + // Remove is not supported + unreachable!() + } + + async fn close(self) -> Result<(), blockstore::Error> { + // Nothing to do here + Ok(()) + } +} + /// The [`Blockstore`] stores pairs of [`Cid`] and [`Bytes`] in memory. /// /// The store will chunk data blocks into `chunk_size` and "gather" nodes in groups with at most `tree_width` children. @@ -81,6 +147,23 @@ impl Blockstore { } } + /// Read the contents of a CARv2 file into the [`Blockstore`]. + pub async fn read_car(&mut self, mut reader: CarV2Reader) -> Result<(), Error> + where + R: AsyncRead + Unpin, + { + reader.read_pragma().await?; + reader.read_header().await?; + let car_v1_header = reader.read_v1_header().await?; + self.root = car_v1_header.roots.first().cloned(); + + while let Ok((cid, data)) = reader.read_block().await { + self.insert(cid, data.into(), true); + } + + Ok(()) + } + /// Fully read the contents of an arbitrary `reader` into the [`Blockstore`], /// converting the contents into a CARv2 file. pub async fn read(&mut self, reader: R) -> Result<(), Error> diff --git a/mater/lib/src/stores/mod.rs b/mater/lib/src/stores/mod.rs index 948023ce1..48eb33cca 100644 --- a/mater/lib/src/stores/mod.rs +++ b/mater/lib/src/stores/mod.rs @@ -1,7 +1,7 @@ mod blockstore; mod filestore; -pub use blockstore::Blockstore; +pub use blockstore::{Blockstore, InMemory}; pub use filestore::create_filestore; /// The default block size, as defined in diff --git a/storage-retrieval/Cargo.toml b/storage-retrieval/Cargo.toml new file mode 100644 index 000000000..6ef5170e9 --- /dev/null +++ b/storage-retrieval/Cargo.toml @@ -0,0 +1,32 @@ +[package] +authors.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +name = "storage-retrieval" +repository.workspace = true +version = "0.1.0" + +[lints] +workspace = true + +[dependencies] +anyhow = { workspace = true } +beetswap = { workspace = true } +blockstore = { workspace = true } +cid = { workspace = true } +futures = { workspace = true } +libp2p = { workspace = true, features = ["macros", "noise", "tcp", "tokio", "yamux"] } +libp2p-core = { workspace = true } +libp2p-swarm = { workspace = true } +mater = { workspace = true } +polka-index = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread", "sync", "time"] } +tracing = { workspace = true } + +[dev-dependencies] +# multihash = "0.19.3" +multihash-codetable = { workspace = true, features = ["sha2"] } +tracing-appender = { workspace = true } +tracing-subscriber = { workspace = true, features = ["env-filter"] } diff --git a/storage-retrieval/README.md b/storage-retrieval/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/storage-retrieval/examples/simple_retrieval.rs b/storage-retrieval/examples/simple_retrieval.rs new file mode 100644 index 000000000..fa5030b24 --- /dev/null +++ b/storage-retrieval/examples/simple_retrieval.rs @@ -0,0 +1,97 @@ +use std::{str::FromStr, sync::Arc, time::Duration}; + +use anyhow::Result; +use blockstore::{ + block::{Block, CidError}, + InMemoryBlockstore, +}; +use cid::Cid; +use libp2p::Multiaddr; +use mater::{Blockstore, CarV2Reader, InMemory}; +use multihash_codetable::{Code, MultihashDigest}; +use storage_retrieval::{client::Client, server::Server}; +use tokio::{fs::File, time::sleep}; + +#[tokio::main] +async fn main() -> Result<()> { + // Init tracing + let _guard = init_tracing(); + + // Setup indexer + // let indexer_path = temp_dir(); + // let indexer = Arc::new(RocksDBLid::new(RocksDBStateStoreConfig { + // path: indexer_path, + // })?); + + // TODO: Blocks should not be hold in memory. Implement blockstore that can + // source blocks directly from sectors on disk with the help of an index. + let file = File::open("./examples/test-data-big.car").await?; + let car_reader = CarV2Reader::new(file); + let mut blockstore = Blockstore::new(); + blockstore.read_car(car_reader).await?; + + let blockstore: InMemory = blockstore.into(); + + // let blockstore = Arc::new(InMemoryBlockstore::<64>::new()); + // blockstore.put(StringBlock("12345".to_string())).await?; + + // Setup server + let server = Server::new(Arc::new(blockstore))?; + let address: Multiaddr = format!("/ip4/127.0.0.1/tcp/8989").parse()?; + + tokio::spawn({ + let address = address.clone(); + async move { + let _ = server.run(vec![address]).await; + } + }); + + // TODO: Implement blockstore that persist blocks directly to disk as car file. + let blockstore = Arc::new(InMemoryBlockstore::<64>::new()); + let client = Client::new(blockstore, vec![address])?; + + // Payload cid of the car file we want to fetch + let payload_cid = + Cid::from_str("bafkreiechz74drg7tg5zswmxf4g2dnwhemlwdv7e3l5ypehdqdwaoyz3dy").unwrap(); + // let payload_cid = + // Cid::from_str("bafkreiczsrdrvoybcevpzqmblh3my5fu6ui3tgag3jm3hsxvvhaxhswpyu").unwrap(); + client + .download(payload_cid, sleep(Duration::from_secs(10))) + .await?; + + Ok(()) +} + +struct StringBlock(pub String); + +impl Block<64> for StringBlock { + fn cid(&self) -> Result { + const RAW_CODEC: u64 = 0x55; + 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/storage-retrieval/src/client.rs b/storage-retrieval/src/client.rs new file mode 100644 index 000000000..710392e69 --- /dev/null +++ b/storage-retrieval/src/client.rs @@ -0,0 +1,189 @@ +use std::{collections::HashMap, sync::Arc}; + +use beetswap::QueryId; +use blockstore::Blockstore; +use cid::Cid; +use futures::{pin_mut, Future, StreamExt}; +use libp2p::{Multiaddr, PeerId, Swarm}; +use libp2p_core::ConnectedPoint; +use libp2p_swarm::{ConnectionId, DialError, SwarmEvent}; +use thiserror::Error; +use tracing::{debug, info, instrument, trace}; + +use crate::{new_swarm, Behaviour, BehaviourEvent, InitSwarmError}; + +#[derive(Debug, Error)] +pub enum ClientError { + /// Error occurred while initialing swarm + #[error("Swarm initialization error: {0}")] + InitSwarm(#[from] InitSwarmError), + /// Error occurred when trying to establish or upgrade an outbound connection. + #[error("Dial error: {0}")] + Dial(#[from] DialError), + /// This error indicates that the download was canceled + #[error("Download canceled")] + DownloadCanceled, +} + +/// A client is used to download blocks from the storage provider. Single client +/// supports getting a single payload. +pub struct Client +where + B: Blockstore + 'static, +{ + // Providers of data + providers: Vec, + // Swarm instance + swarm: Swarm>, + /// The in flight block queries. If empty we know that the client received + /// all requested data. + queries: HashMap, +} + +impl Client +where + B: Blockstore, +{ + pub fn new(blockstore: Arc, providers: Vec) -> Result { + let swarm = new_swarm(blockstore)?; + + Ok(Self { + providers, + swarm, + queries: HashMap::new(), + }) + } + + /// Start download of some content with a payload cid. + pub async fn download( + mut self, + payload_cid: Cid, + cancellation: impl Future, + ) -> Result<(), ClientError> { + // Dial all providers + for provider in self.providers.clone() { + self.swarm.dial(provider)?; + } + + // Request the root node of the car file + let query_id = self.swarm.behaviour_mut().bitswap.get(&payload_cid); + self.queries.insert(query_id, payload_cid); + + // Pin cancellation future + pin_mut!(cancellation); + + loop { + tokio::select! { + // Data download was canceled + _ = &mut cancellation => { + // Return an error as indication that the download was cancelled + return Err(ClientError::DownloadCanceled); + } + // Handle events received when we get some blocks back + event = self.swarm.select_next_some() => { + // Handle event received from the providers + self.on_swarm_event(event).await?; + + // if no inflight queries, that means we received + // everything requested. + if self.queries.is_empty() { + info!("Download of payload {payload_cid} finished"); + break; + } + } + } + } + + Ok(()) + } + + async fn on_swarm_event( + &mut self, + event: SwarmEvent>, + ) -> Result<(), ClientError> { + trace!(?event, "Received swarm event"); + + match event { + SwarmEvent::ConnectionEstablished { + peer_id, + connection_id, + endpoint, + .. + } => { + self.on_peer_connected(peer_id, connection_id, endpoint); + } + SwarmEvent::ConnectionClosed { + peer_id, + connection_id, + .. + } => { + self.on_peer_disconnected(peer_id, connection_id)?; + } + SwarmEvent::Behaviour(BehaviourEvent::Bitswap(event)) => { + self.on_bitswap_event(event)?; + } + _ => { + // Nothing to do here + } + } + + Ok(()) + } + + #[instrument(skip_all, fields(peer_id = %peer_id))] + fn on_peer_connected( + &mut self, + peer_id: PeerId, + _connection_id: ConnectionId, + _endpoint: ConnectedPoint, + ) { + debug!("Peer connected"); + + // TODO: Track connections to the storage providers. We need statuses so + // that we know if there is still some peer viable to download data + // from. + } + + #[instrument(skip_all, fields(peer_id = %peer_id))] + fn on_peer_disconnected( + &mut self, + peer_id: PeerId, + _connection_id: ConnectionId, + ) -> Result<(), ClientError> { + debug!("Peer disconnected"); + + // TODO: Remove connection from tracked. If there are no established + // connections return an error. The download can never finish. + + Ok(()) + } + + fn on_bitswap_event(&mut self, event: beetswap::Event) -> Result<(), ClientError> { + match event { + beetswap::Event::GetQueryResponse { query_id, data } => { + if let Some(cid) = self.queries.remove(&query_id) { + info!("received response for {cid:?}: {data:?}"); + } + + // TODO: Extract linked blocks from the cid. Then request those + // new unknown blocks from the providers. Received blocks are + // added automatically to the blockstore used by the client. + + // TODO: Figure out how the sequence of blocks is guaranteed. Do + // we request each of them in sequence and wait for each of them + // before requesting for a new one? Is there a better way? + } + beetswap::Event::GetQueryError { query_id, error } => { + if let Some(cid) = self.queries.remove(&query_id) { + info!("received error for {cid:?}: {error}"); + } + + // TODO: Track errors for blocks. There is a case when no + // providers can have a requested block. In that case we + // should return an error and cancel download. + } + } + + Ok(()) + } +} diff --git a/storage-retrieval/src/lib.rs b/storage-retrieval/src/lib.rs new file mode 100644 index 000000000..e4850784f --- /dev/null +++ b/storage-retrieval/src/lib.rs @@ -0,0 +1,49 @@ +pub mod client; +pub mod server; + +use std::{sync::Arc, time::Duration}; + +use ::blockstore::Blockstore; +use libp2p::{noise, swarm::NetworkBehaviour, tcp, yamux, Swarm, SwarmBuilder}; +use thiserror::Error; + +const MAX_MULTIHASH_LENGHT: usize = 64; + +/// Custom Behaviour used by the server and client. +#[derive(NetworkBehaviour)] +struct Behaviour +where + B: Blockstore + 'static, +{ + bitswap: beetswap::Behaviour, +} + +/// Error that can occur while initializing a swarm +#[derive(Debug, Error)] +pub enum InitSwarmError { + /// Failed to initialize noise protocol. + #[error("Failed to initialize noise: {0}")] + Noise(#[from] noise::Error), +} + +/// Initialize a new swarm with our custom Behaviour. +fn new_swarm(blockstore: Arc) -> Result>, InitSwarmError> +where + B: Blockstore + 'static, +{ + let swarm = SwarmBuilder::with_new_identity() + .with_tokio() + .with_tcp( + tcp::Config::default(), + noise::Config::new, + yamux::Config::default, + )? + .with_behaviour(|_| Behaviour { + bitswap: beetswap::Behaviour::new(blockstore), + }) + .expect("infallible") + .with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) + .build(); + + Ok(swarm) +} diff --git a/storage-retrieval/src/server.rs b/storage-retrieval/src/server.rs new file mode 100644 index 000000000..1cf755857 --- /dev/null +++ b/storage-retrieval/src/server.rs @@ -0,0 +1,56 @@ +use std::{io, sync::Arc}; + +use blockstore::Blockstore; +use futures::StreamExt; +use libp2p::{Multiaddr, Swarm, TransportError}; +use thiserror::Error; +use tracing::trace; + +use crate::{new_swarm, Behaviour, InitSwarmError}; + +/// Error that can occur while running storage retrieval server. +#[derive(Debug, Error)] +pub enum ServerError { + /// Error occurred while initialing swarm + #[error("Swarm initialization error: {0}")] + InitSwarm(#[from] InitSwarmError), + /// An error propagated from the libp2p transport. + #[error("Transport error: {0}")] + Transport(#[from] TransportError), +} + +/// Storage retrieval server. Server listens on the block requests and provide +/// them to the client. +pub struct Server +where + B: Blockstore + 'static, +{ + // Swarm instance + swarm: Swarm>, +} + +impl Server +where + B: Blockstore + 'static, +{ + pub fn new(blockstore: Arc) -> Result { + let swarm = new_swarm(blockstore)?; + + Ok(Self { swarm }) + } + + // Start the server. The server can only stop if it received a cancellation + // event or some error occurred. + pub async fn run(mut self, listeners: Vec) -> Result<(), ServerError> { + // Listen on + for listener in listeners { + self.swarm.listen_on(listener)?; + } + + // Keep server running + loop { + let event = self.swarm.select_next_some().await; + trace!(?event, "Received swarm event"); + } + } +}