From 701171889d66b66bd970b271741ecc06ed2a0713 Mon Sep 17 00:00:00 2001 From: Roland Kuhn Date: Sat, 15 Oct 2022 09:10:22 +0200 Subject: [PATCH 1/4] some tests passing --- Cargo.lock | 810 ++++++++++++++++++++++++++----------------- Cargo.toml | 25 +- cli/Cargo.toml | 1 + cli/src/main.rs | 66 ++-- examples/compat.rs | 6 +- examples/sync.rs | 5 +- harness/Cargo.toml | 6 +- src/db.rs | 2 +- src/lib.rs | 228 +++++++----- src/net/behaviour.rs | 339 +++++++++--------- src/net/mod.rs | 807 ++++++++++++++++++++++++++++-------------- src/net/peers.rs | 183 +++++----- src/net/tests.rs | 35 +- src/variable.rs | 62 ++++ 14 files changed, 1611 insertions(+), 964 deletions(-) create mode 100644 src/variable.rs diff --git a/Cargo.lock b/Cargo.lock index c25a6b8..10683fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aead" version = "0.3.2" @@ -125,6 +140,9 @@ name = "anyhow" version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +dependencies = [ + "backtrace", +] [[package]] name = "arrayref" @@ -138,6 +156,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + [[package]] name = "asn1_der" version = "0.7.5" @@ -232,7 +256,7 @@ dependencies = [ "http-types", "httparse", "log", - "pin-project 1.0.10", + "pin-project", ] [[package]] @@ -249,7 +273,7 @@ dependencies = [ "parking", "polling", "slab", - "socket2 0.4.4", + "socket2", "waker-fn", "winapi", ] @@ -300,7 +324,7 @@ dependencies = [ "async-trait", "base64 0.12.3", "bincode", - "blake3", + "blake3 0.3.8", "chrono", "hmac 0.8.1", "kv-log-macro", @@ -355,15 +379,16 @@ dependencies = [ [[package]] name = "async-std-resolver" -version = "0.20.4" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf3e776afdf3a2477ef4854b85ba0dff3bd85792f685fb3c68948b4d304e4f0" +checksum = "0f2f8a4a203be3325981310ab243a28e6e4ea55b6519bffce05d41ab60e09ad8" dependencies = [ "async-std", "async-trait", "futures-io", "futures-util", "pin-utils", + "socket2", "trust-dns-resolver", ] @@ -397,15 +422,6 @@ dependencies = [ "pin-project-lite 0.2.8", ] -[[package]] -name = "atomic" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" -dependencies = [ - "autocfg", -] - [[package]] name = "atomic-waker" version = "1.0.0" @@ -429,6 +445,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base-x" version = "0.2.8" @@ -478,7 +509,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b64485778c4f16a6a5a9d335e80d449ac6c70cdd6a06d2af18a6f6f775a125b3" dependencies = [ "arrayref", - "arrayvec", + "arrayvec 0.5.2", "cc", "cfg-if 0.1.10", "constant_time_eq", @@ -486,6 +517,19 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "blake3" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" +dependencies = [ + "arrayref", + "arrayvec 0.7.2", + "cc", + "cfg-if 1.0.0", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -576,6 +620,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "cached" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4dfac631a8e77b2f327f7852bb6172771f5279c4512efe79fad6067b37be3d" +dependencies = [ + "hashbrown 0.11.2", + "once_cell", +] + [[package]] name = "cc" version = "1.0.73" @@ -644,6 +698,18 @@ dependencies = [ "unsigned-varint", ] +[[package]] +name = "cid" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5d90881dc52bb7867dd4341dfe6836077370f879df51cee353daa74e035a13" +dependencies = [ + "core2", + "multibase", + "multihash 0.16.1", + "unsigned-varint", +] + [[package]] name = "cipher" version = "0.2.5" @@ -707,6 +773,15 @@ dependencies = [ "syn", ] +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + [[package]] name = "concurrent-queue" version = "1.2.2" @@ -1025,9 +1100,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "enum-as-inner" -version = "0.3.4" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "570d109b813e904becc80d8d5da38376818a143348413f7149f1340fe04754d4" +checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" dependencies = [ "heck 0.4.0", "proc-macro2", @@ -1090,12 +1165,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "fixedbitset" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" - [[package]] name = "fixedbitset" version = "0.4.1" @@ -1135,9 +1204,9 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "futures" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" dependencies = [ "futures-channel", "futures-core", @@ -1150,9 +1219,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" dependencies = [ "futures-core", "futures-sink", @@ -1160,15 +1229,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" dependencies = [ "futures-core", "futures-task", @@ -1178,9 +1247,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" [[package]] name = "futures-lite" @@ -1199,9 +1268,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" dependencies = [ "proc-macro2", "quote", @@ -1210,15 +1279,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" [[package]] name = "futures-timer" @@ -1228,9 +1297,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" dependencies = [ "futures-channel", "futures-core", @@ -1296,6 +1365,12 @@ dependencies = [ "polyval 0.5.3", ] +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" + [[package]] name = "gloo-timers" version = "0.2.3" @@ -1320,10 +1395,10 @@ dependencies = [ "escargot", "futures", "ipfs-embed-cli", - "libipld", + "libipld 0.14.0", "libp2p", "maplit", - "multihash 0.14.0", + "multihash 0.16.1", "netsim-embed", "predicates", "rand 0.8.5", @@ -1498,9 +1573,9 @@ dependencies = [ [[package]] name = "if-watch" -version = "1.0.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8f4a3c3d4c89351ca83e120c1c00b27df945d38e05695668c9d4b4f7bc52f3" +checksum = "015a7df1eb6dda30df37f34b63ada9b7b352984b0e84de2a20ed526345000791" dependencies = [ "async-io", "core-foundation", @@ -1547,11 +1622,11 @@ checksum = "7f9d0b6b23885487578d10590edc36fd95426257c7017973b20633e34df23b08" [[package]] name = "ipconfig" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" +checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" dependencies = [ - "socket2 0.3.19", + "socket2", "widestring", "winapi", "winreg", @@ -1573,14 +1648,14 @@ dependencies = [ "futures-timer", "ipfs-sqlite-block-store", "lazy_static", - "libipld", + "libipld 0.14.0", "libp2p", "libp2p-bitswap", "libp2p-broadcast", - "multihash 0.14.0", + "multihash 0.16.1", "names", "parking_lot 0.11.2", - "pin-project 1.0.10", + "pin-project", "prometheus", "rand 0.8.5", "regex", @@ -1602,8 +1677,9 @@ dependencies = [ "async-process", "async-std", "chrono", + "futures", "ipfs-embed", - "libipld", + "libipld 0.12.0", "multihash 0.14.0", "parking_lot 0.11.2", "serde", @@ -1615,16 +1691,16 @@ dependencies = [ [[package]] name = "ipfs-sqlite-block-store" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025ff3ea1adb63aed8cb6cebd3a7fcf992847c6ce7604b2c07823d6bbc1f1a77" +checksum = "9cb925e7e17691fdb4cc5179c010b6a12e78a9588d257f16cbcb8f8503778f97" dependencies = [ "anyhow", "derive_more", "fnv", "futures", - "itertools 0.10.3", - "libipld", + "itertools", + "libipld 0.14.0", "parking_lot 0.11.2", "rusqlite", "tracing", @@ -1636,15 +1712,6 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c" -[[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.10.3" @@ -1703,19 +1770,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373a32b8d77bf13d6d5552b068e55991cc26f6f43edae25409fec5f555494438" dependencies = [ "async-trait", - "cached", + "cached 0.23.0", "fnv", - "libipld-cbor", - "libipld-cbor-derive", - "libipld-core", - "libipld-macro", - "libipld-pb", + "libipld-cbor 0.12.1", + "libipld-core 0.12.0", + "libipld-macro 0.12.0", "log", "multihash 0.14.0", "parking_lot 0.11.2", "thiserror", ] +[[package]] +name = "libipld" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9c3aa309c260aa2f174bac968901eddc546e9d85950c28eae6a7bec402f926" +dependencies = [ + "async-trait", + "cached 0.30.0", + "fnv", + "libipld-cbor 0.14.0", + "libipld-cbor-derive", + "libipld-core 0.14.0", + "libipld-macro 0.14.0", + "libipld-pb", + "log", + "multihash 0.16.1", + "parking_lot 0.12.0", + "thiserror", +] + [[package]] name = "libipld-cbor" version = "0.12.1" @@ -1723,16 +1808,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51882ee3a6ebc8b770b507558b8bc993659d7e96e160fb796bc1fc7c290d74c4" dependencies = [ "byteorder", - "libipld-core", + "libipld-core 0.12.0", + "thiserror", +] + +[[package]] +name = "libipld-cbor" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd1ab68c9d26f20c7d0dfea6eecbae8c00359875210001b33ca27d4a02f3d09" +dependencies = [ + "byteorder", + "libipld-core 0.14.0", "thiserror", ] [[package]] name = "libipld-cbor-derive" -version = "0.12.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80cf5eeddac31280a924ac77ad90df98887ccc8c351c324b11d15b620f8cf74f" +checksum = "69ec2f49393a1347a2d95ebcb248ff75d0d47235919b678036c010a8cd927375" dependencies = [ + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -1746,40 +1843,62 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29a8a4ac024d51f15cc7b71d888b51bf3ab5d26a502e3f48fc9df33d7fd02ac" dependencies = [ "anyhow", - "cid", + "cid 0.7.0", "multibase", "multihash 0.14.0", "thiserror", ] +[[package]] +name = "libipld-core" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d44790246ec6b7314cba745992c23d479d018073e66d49ae40ae1b64e5dd8eb5" +dependencies = [ + "anyhow", + "cid 0.8.3", + "core2", + "multibase", + "multihash 0.16.1", + "thiserror", +] + [[package]] name = "libipld-macro" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d553f07747f7cb5e62d15de5fb416bf0e22968b2ee685226e91faaffd43a464" dependencies = [ - "libipld-core", + "libipld-core 0.12.0", +] + +[[package]] +name = "libipld-macro" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852c011562ae5059b67c3a917f9f5945af5a68df8e39ede4444fff33274d25e2" +dependencies = [ + "libipld-core 0.14.0", ] [[package]] name = "libipld-pb" -version = "0.12.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ddbe8356b2bb59c6875d329b3f28cb323d3c0cd07a2b9804a7008e1856e4727" +checksum = "c003be513496578115256a1b4ac7b80d4ece2462c9869dfb736fd30d8bb1d1c0" dependencies = [ - "libipld-core", - "prost 0.7.0", - "prost-build 0.7.0", + "libipld-core 0.14.0", + "prost 0.10.4", + "prost-build 0.10.4", "thiserror", ] [[package]] name = "libp2p" -version = "0.43.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e8570e25fa03d4385405dbeaf540ba00e3ee50942f03d84e1a8928a029f35f9" +checksum = "94c996fe5bfdba47f5a5af71d48ecbe8cec900b7b97391cc1d3ba1afb0e2d3b6" dependencies = [ - "atomic", "bytes", "futures", "futures-timer", @@ -1804,22 +1923,22 @@ dependencies = [ "libp2p-yamux", "multiaddr", "parking_lot 0.12.0", - "pin-project 1.0.10", + "pin-project", "rand 0.7.3", "smallvec", ] [[package]] name = "libp2p-bitswap" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fa67bc4cb40f8dd949d05bb23488e99943930a3eca3c907941f224cd7ed51e9" +checksum = "81fb5bcac99a4b8fb98d3a15ff61325381584e863ab7e5b1da70f8d6b7970891" dependencies = [ "async-trait", "fnv", "futures", "lazy_static", - "libipld", + "libipld 0.14.0", "libp2p", "prometheus", "prost 0.9.0", @@ -1831,9 +1950,9 @@ dependencies = [ [[package]] name = "libp2p-broadcast" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cd79a74c02aecb0de47b6e0517706ecb6f325207d30c06b9d771c5954caf4e" +checksum = "7f379ed573c4f77564de5933b1bb9cd82853fe3da16d829db680ba5b266f84f1" dependencies = [ "fnv", "futures", @@ -1842,9 +1961,9 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.32.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9164ec41455856e8187addc870bb4fe1ea2ee28e1a9244831d449a2429b32c1a" +checksum = "b1fff5bd889c82a0aec668f2045edd066f559d4e5c40354e5a4c77ac00caac38" dependencies = [ "asn1_der", "bs58", @@ -1860,11 +1979,10 @@ dependencies = [ "multihash 0.16.1", "multistream-select", "parking_lot 0.12.0", - "pin-project 1.0.10", - "prost 0.9.0", - "prost-build 0.9.0", + "pin-project", + "prost 0.11.0", + "prost-build 0.11.1", "rand 0.8.5", - "ring", "rw-stream-sink", "sha2 0.10.2", "smallvec", @@ -1876,23 +1994,24 @@ dependencies = [ [[package]] name = "libp2p-dns" -version = "0.32.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7838647d33978b77f943687412f4a39e74234c8342cbfdad14282b465b272cb4" +checksum = "6cb3c16e3bb2f76c751ae12f0f26e788c89d353babdded40411e7923f01fc978" dependencies = [ "async-std-resolver", "futures", "libp2p-core", "log", + "parking_lot 0.12.0", "smallvec", "trust-dns-resolver", ] [[package]] name = "libp2p-gossipsub" -version = "0.36.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f62943fba0b0dae02b87868620c52a581c54ec9fb04b5e195cf20313fc510c3" +checksum = "2185aac44b162c95180ae4ddd1f4dfb705217ea1cb8e16bdfc70d31496fd80fa" dependencies = [ "asynchronous-codec", "base64 0.13.0", @@ -1906,8 +2025,8 @@ dependencies = [ "libp2p-swarm", "log", "prometheus-client", - "prost 0.9.0", - "prost-build 0.9.0", + "prost 0.11.0", + "prost-build 0.11.1", "rand 0.7.3", "regex", "sha2 0.10.2", @@ -1918,28 +2037,32 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.34.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f219b4d4660fe3a04bf5fe6b5970902b7c1918e25b2536be8c70efc480f88f8" +checksum = "f19440c84b509d69b13f0c9c28caa9bd3a059d25478527e937e86761f25c821e" dependencies = [ + "asynchronous-codec", "futures", "futures-timer", "libp2p-core", "libp2p-swarm", "log", "lru", - "prost 0.9.0", - "prost-build 0.9.0", + "prost 0.11.0", + "prost-build 0.11.1", + "prost-codec", "smallvec", + "thiserror", + "void", ] [[package]] name = "libp2p-kad" -version = "0.35.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aead5ee2322a7b825c7633065370909c8383046f955cda5b56797e6904db7a72" +checksum = "f840579eed6503ec8a7a0c7e919bcd645df11c991be8e54640ff09f7109b8a43" dependencies = [ - "arrayvec", + "arrayvec 0.7.2", "asynchronous-codec", "bytes", "either", @@ -1950,8 +2073,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost 0.9.0", - "prost-build 0.9.0", + "prost 0.11.0", + "prost-build 0.11.1", "rand 0.7.3", "sha2 0.10.2", "smallvec", @@ -1963,9 +2086,9 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.35.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54d1914576978e5f3b15ac99e2cda9b56471ce64f1cfc7c2b09ac0cee147175e" +checksum = "ff531fbceee32be0e39409e985c5536897e4578addb1c702fd4973e2c381fc76" dependencies = [ "async-io", "data-encoding", @@ -1978,15 +2101,16 @@ dependencies = [ "log", "rand 0.8.5", "smallvec", - "socket2 0.4.4", + "socket2", + "tokio", "void", ] [[package]] name = "libp2p-metrics" -version = "0.4.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29e4e5e4c5aa567fe1ee3133afe088dc2d2fd104e20c5c2c5c2649f75129677" +checksum = "a74ab339e8b5d989e8c1000a78adb5c064a6319245bb22d1e70b415ec18c39b8" dependencies = [ "libp2p-core", "libp2p-gossipsub", @@ -1999,9 +2123,9 @@ dependencies = [ [[package]] name = "libp2p-mplex" -version = "0.32.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "442eb0c9fff0bf22a34f015724b4143ce01877e079ed0963c722d94c07c72160" +checksum = "ce53169351226ee0eb18ee7bef8d38f308fa8ad7244f986ae776390c0ae8a44d" dependencies = [ "asynchronous-codec", "bytes", @@ -2017,9 +2141,9 @@ dependencies = [ [[package]] name = "libp2p-noise" -version = "0.35.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd7e0c94051cda67123be68cf6b65211ba3dde7277be9068412de3e7ffd63ef" +checksum = "7cb0f939a444b06779ce551b3d78ebf13970ac27906ada452fd70abd160b09b8" dependencies = [ "bytes", "curve25519-dalek 3.2.1", @@ -2027,8 +2151,8 @@ dependencies = [ "lazy_static", "libp2p-core", "log", - "prost 0.9.0", - "prost-build 0.9.0", + "prost 0.11.0", + "prost-build 0.11.1", "rand 0.8.5", "sha2 0.10.2", "snow", @@ -2039,9 +2163,9 @@ dependencies = [ [[package]] name = "libp2p-ping" -version = "0.34.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab44a12d372d6abdd326c468c1d5b002be06fbd923c5a799d6a9d3b36646ca3" +checksum = "76a36f78e107bb55330341018874c5168851f455f8bdc3e0cd44e6c84e0a7069" dependencies = [ "futures", "futures-timer", @@ -2061,7 +2185,7 @@ checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" dependencies = [ "futures", "log", - "pin-project 1.0.10", + "pin-project", "rand 0.7.3", "salsa20", "sha3", @@ -2069,9 +2193,9 @@ dependencies = [ [[package]] name = "libp2p-request-response" -version = "0.16.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12388a73626d1727524069cce0bb05a9c428581de435278a070c55ae27cc7e73" +checksum = "2344aa93dc8b1de90e26091d7cf63044519bbea7b0b03d829f350563a2dd26f7" dependencies = [ "async-trait", "bytes", @@ -2087,9 +2211,9 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.34.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53ab2d4eb8ef2966b10fdf859245cdd231026df76d3c6ed2cf9e418a8f688ec9" +checksum = "70ad2db60c06603606b54b58e4247e32efec87a93cb4387be24bf32926c600f2" dependencies = [ "either", "fnv", @@ -2098,7 +2222,7 @@ dependencies = [ "instant", "libp2p-core", "log", - "pin-project 1.0.10", + "pin-project", "rand 0.7.3", "smallvec", "thiserror", @@ -2107,19 +2231,20 @@ dependencies = [ [[package]] name = "libp2p-swarm-derive" -version = "0.27.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf2fe8c80b43561355f4d51875273b5b6dfbac37952e8f64b1270769305c9d7" +checksum = "1f02622b9dd150011b4eeec387f8bd013189a2f27da08ba363e7c6e606d77a48" dependencies = [ + "heck 0.4.0", "quote", "syn", ] [[package]] name = "libp2p-tcp" -version = "0.32.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193447aa729c85aac2376828df76d171c1a589c9e6b58fcc7f9d9a020734122c" +checksum = "9675432b4c94b3960f3d2c7e57427b81aea92aab67fd0eebef09e2ae0ff54895" dependencies = [ "async-io", "futures", @@ -2130,15 +2255,15 @@ dependencies = [ "libc", "libp2p-core", "log", - "socket2 0.4.4", + "socket2", "tokio", ] [[package]] name = "libp2p-yamux" -version = "0.36.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be902ebd89193cd020e89e89107726a38cfc0d16d18f613f4a37d046e92c7517" +checksum = "b74ec8dc042b583f0b2b93d52917f3b374c1e4b1cfa79ee74c7672c41257694c" dependencies = [ "futures", "libp2p-core", @@ -2263,35 +2388,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] -name = "memoffset" -version = "0.6.5" +name = "miniz_oxide" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" dependencies = [ - "autocfg", + "adler", ] [[package]] name = "mio" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" dependencies = [ "libc", "log", - "miow", - "ntapi", "wasi 0.11.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", + "windows-sys 0.36.1", ] [[package]] @@ -2329,7 +2443,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "752a61cd890ff691b4411423d23816d5866dd5621e4d1c5687a53b94b5a979d8" dependencies = [ - "blake3", + "blake3 0.3.8", "generic-array", "multihash-derive 0.7.2", "unsigned-varint", @@ -2341,6 +2455,7 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7392bffd88bc0c4f8297e36a777ab9f80b7127409c4a1acb8fee99c9f27addcd" dependencies = [ + "blake3 1.3.1", "core2", "digest 0.10.3", "multihash-derive 0.8.0", @@ -2391,7 +2506,7 @@ dependencies = [ "bytes", "futures", "log", - "pin-project 1.0.10", + "pin-project", "smallvec", "unsigned-varint", ] @@ -2420,9 +2535,9 @@ dependencies = [ [[package]] name = "netlink-packet-route" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733ea73609acfd7fa7ddadfb7bf709b0471668c456ad9513685af543a06342b2" +checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" dependencies = [ "anyhow", "bitflags", @@ -2446,23 +2561,24 @@ dependencies = [ [[package]] name = "netlink-proto" -version = "0.9.2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8785b8141e8432aa45fceb922a7e876d7da3fad37fa7e7ec702ace3aa0826b" +checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" dependencies = [ "bytes", "futures", "log", "netlink-packet-core", "netlink-sys", + "thiserror", "tokio", ] [[package]] name = "netlink-sys" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c9f9547a08241bee7b6558b9b98e1f290d187de8b7cfca2bbb4937bcaa8f8" +checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027" dependencies = [ "async-io", "bytes", @@ -2545,15 +2661,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.22.3" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" dependencies = [ "bitflags", - "cc", "cfg-if 1.0.0", "libc", - "memoffset", ] [[package]] @@ -2568,15 +2682,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" -[[package]] -name = "ntapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" -dependencies = [ - "winapi", -] - [[package]] name = "num-integer" version = "0.1.44" @@ -2606,6 +2711,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.10.0" @@ -2627,15 +2741,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "owning_ref" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" -dependencies = [ - "stable_deref_trait", -] - [[package]] name = "parking" version = "2.0.0" @@ -2687,7 +2792,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.32.0", ] [[package]] @@ -2702,53 +2807,23 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -[[package]] -name = "petgraph" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" -dependencies = [ - "fixedbitset 0.2.0", - "indexmap", -] - [[package]] name = "petgraph" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" dependencies = [ - "fixedbitset 0.4.1", + "fixedbitset", "indexmap", ] -[[package]] -name = "pin-project" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9615c18d31137579e9ff063499264ddc1278e7b1982757ebc111028c4d1dc909" -dependencies = [ - "pin-project-internal 0.4.29", -] - [[package]] name = "pin-project" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" dependencies = [ - "pin-project-internal 1.0.10", -] - -[[package]] -name = "pin-project-internal" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "044964427019eed9d49d9d5bbce6047ef18f37100ea400912a9fa4a3523ab12a" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "pin-project-internal", ] [[package]] @@ -2847,7 +2922,7 @@ checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c" dependencies = [ "difflib", "float-cmp", - "itertools 0.10.3", + "itertools", "normalize-line-endings", "predicates-core", "regex", @@ -2935,21 +3010,21 @@ dependencies = [ [[package]] name = "prometheus-client" -version = "0.15.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a896938cc6018c64f279888b8c7559d3725210d5db9a3a1ee6bc7188d51d34" +checksum = "3c473049631c233933d6286c88bbb7be30e62ec534cf99a9ae0079211f7fa603" dependencies = [ "dtoa", "itoa", - "owning_ref", + "parking_lot 0.12.0", "prometheus-client-derive-text-encode", ] [[package]] name = "prometheus-client-derive-text-encode" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8e12d01b9d66ad9eb4529c57666b6263fc1993cb30261d83ead658fdd932652" +checksum = "66a455fbcb954c1a7decf3c586e860fd7889cddf4b8e164be736dbac95a953cd" dependencies = [ "proc-macro2", "quote", @@ -2958,70 +3033,117 @@ dependencies = [ [[package]] name = "prost" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e6984d2f1a23009bd270b8bb56d0926810a3d483f59c987d77969e9d8e840b2" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ "bytes", - "prost-derive 0.7.0", + "prost-derive 0.9.0", ] [[package]] name = "prost" -version = "0.9.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" dependencies = [ "bytes", - "prost-derive 0.9.0", + "prost-derive 0.10.1", +] + +[[package]] +name = "prost" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "399c3c31cdec40583bb68f0b18403400d01ec4289c383aa047560439952c4dd7" +dependencies = [ + "bytes", + "prost-derive 0.11.0", ] [[package]] name = "prost-build" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d3ebd75ac2679c2af3a92246639f9fcc8a442ee420719cc4fe195b98dd5fa3" +checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" dependencies = [ "bytes", "heck 0.3.3", - "itertools 0.9.0", + "itertools", + "lazy_static", "log", "multimap", - "petgraph 0.5.1", - "prost 0.7.0", - "prost-types 0.7.0", + "petgraph", + "prost 0.9.0", + "prost-types 0.9.0", + "regex", "tempfile", "which", ] [[package]] name = "prost-build" -version = "0.9.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" +checksum = "8ae5a4388762d5815a9fc0dea33c56b021cdc8dde0c55e0c9ca57197254b0cab" dependencies = [ "bytes", - "heck 0.3.3", - "itertools 0.10.3", + "cfg-if 1.0.0", + "cmake", + "heck 0.4.0", + "itertools", "lazy_static", "log", "multimap", - "petgraph 0.6.0", - "prost 0.9.0", - "prost-types 0.9.0", + "petgraph", + "prost 0.10.4", + "prost-types 0.10.1", "regex", "tempfile", "which", ] +[[package]] +name = "prost-build" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f835c582e6bd972ba8347313300219fed5bfa52caf175298d860b61ff6069bb" +dependencies = [ + "bytes", + "heck 0.4.0", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prost 0.11.0", + "prost-types 0.11.1", + "regex", + "tempfile", + "which", +] + +[[package]] +name = "prost-codec" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011ae9ff8359df7915f97302d591cdd9e0e27fbd5a4ddc5bd13b71079bb20987" +dependencies = [ + "asynchronous-codec", + "bytes", + "prost 0.11.0", + "thiserror", + "unsigned-varint", +] + [[package]] name = "prost-derive" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "169a15f3008ecb5160cba7d37bcd690a7601b6d30cfb87a117d45e59d52af5d4" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" dependencies = [ "anyhow", - "itertools 0.9.0", + "itertools", "proc-macro2", "quote", "syn", @@ -3029,25 +3151,28 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" dependencies = [ "anyhow", - "itertools 0.10.3", + "itertools", "proc-macro2", "quote", "syn", ] [[package]] -name = "prost-types" -version = "0.7.0" +name = "prost-derive" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b518d7cdd93dab1d1122cf07fa9a60771836c668dde9d9e2a139f957f0d9f1bb" +checksum = "7345d5f0e08c0536d7ac7229952590239e77abf0a0100a1b1d890add6ea96364" dependencies = [ - "bytes", - "prost 0.7.0", + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -3060,6 +3185,26 @@ dependencies = [ "prost 0.9.0", ] +[[package]] +name = "prost-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" +dependencies = [ + "bytes", + "prost 0.10.4", +] + +[[package]] +name = "prost-types" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dfaa718ad76a44b3415e6c4d53b17c8f99160dcb3a99b10470fce8ad43f6e3e" +dependencies = [ + "bytes", + "prost 0.11.0", +] + [[package]] name = "protobuf" version = "2.27.1" @@ -3266,9 +3411,9 @@ checksum = "56770675ebc04927ded3e60633437841581c285dc6236109ea25fbf3beb7b59e" [[package]] name = "rtnetlink" -version = "0.9.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f54290e54521dac3de4149d83ddf9f62a359b3cc93bcb494a794a41e6f4744b" +checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" dependencies = [ "async-global-executor", "futures", @@ -3294,6 +3439,12 @@ dependencies = [ "smallvec", ] +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc_version" version = "0.2.3" @@ -3314,12 +3465,12 @@ dependencies = [ [[package]] name = "rw-stream-sink" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" +checksum = "26338f5e09bb721b85b135ea05af7767c90b52f6de4f087d4f4a3a9d64e7dc04" dependencies = [ "futures", - "pin-project 0.4.29", + "pin-project", "static_assertions", ] @@ -3367,18 +3518,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", @@ -3542,17 +3693,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "socket2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.4.4" @@ -3569,12 +3709,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "standback" version = "0.2.17" @@ -3689,9 +3823,9 @@ checksum = "45f6ee7c7b87caf59549e9fe45d6a69c75c8019e79e212a835c5da0e92f0ba08" [[package]] name = "syn" -version = "1.0.89" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" +checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a" dependencies = [ "proc-macro2", "quote", @@ -3903,17 +4037,18 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.17.0" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ + "autocfg", "bytes", "libc", "memchr", "mio", "num_cpus", "pin-project-lite 0.2.8", - "socket2 0.4.4", + "socket2", "winapi", ] @@ -3990,9 +4125,9 @@ dependencies = [ [[package]] name = "trust-dns-proto" -version = "0.20.4" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca94d4e9feb6a181c690c4040d7a24ef34018d8313ac5044a61d21222ae24e31" +checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" dependencies = [ "async-trait", "cfg-if 1.0.0", @@ -4015,9 +4150,9 @@ dependencies = [ [[package]] name = "trust-dns-resolver" -version = "0.20.4" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecae383baad9995efaa34ce8e57d12c3f305e545887472a492b838f4b5cfb77a" +checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" dependencies = [ "cfg-if 1.0.0", "futures-util", @@ -4025,7 +4160,7 @@ dependencies = [ "lazy_static", "log", "lru-cache", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "resolv-conf", "smallvec", "thiserror", @@ -4314,9 +4449,9 @@ dependencies = [ [[package]] name = "widestring" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" [[package]] name = "winapi" @@ -4351,15 +4486,15 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.29.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac7fef12f4b59cd0a29339406cc9203ab44e440ddff6b3f5a41455349fa9cf3" +checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" dependencies = [ - "windows_aarch64_msvc 0.29.0", - "windows_i686_gnu 0.29.0", - "windows_i686_msvc 0.29.0", - "windows_x86_64_gnu 0.29.0", - "windows_x86_64_msvc 0.29.0", + "windows_aarch64_msvc 0.34.0", + "windows_i686_gnu 0.34.0", + "windows_i686_msvc 0.34.0", + "windows_x86_64_gnu 0.34.0", + "windows_x86_64_msvc 0.34.0", ] [[package]] @@ -4376,10 +4511,17 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_msvc" -version = "0.29.0" +name = "windows-sys" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] [[package]] name = "windows_aarch64_msvc" @@ -4388,10 +4530,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" [[package]] -name = "windows_i686_gnu" -version = "0.29.0" +name = "windows_aarch64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_i686_gnu" @@ -4400,10 +4548,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" [[package]] -name = "windows_i686_msvc" -version = "0.29.0" +name = "windows_i686_gnu" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_msvc" @@ -4412,10 +4566,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" [[package]] -name = "windows_x86_64_gnu" -version = "0.29.0" +name = "windows_i686_msvc" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_x86_64_gnu" @@ -4424,10 +4584,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" [[package]] -name = "windows_x86_64_msvc" -version = "0.29.0" +name = "windows_x86_64_gnu" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_msvc" @@ -4435,11 +4601,23 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" +[[package]] +name = "windows_x86_64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "winreg" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" dependencies = [ "winapi", ] diff --git a/Cargo.toml b/Cargo.toml index 1acf9f0..b78cf2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,8 @@ repository = "https://github.com/ipfs-rust/ipfs-embed" [features] default = ["async_global"] -async_global = ["async-global-executor", "libp2p/tcp-async-io", "libp2p/dns-async-std"] -tokio = ["tokio-crate", "libp2p/tcp-tokio", "libp2p/dns-tokio"] +async_global = ["async-global-executor", "libp2p/tcp-async-io", "libp2p/dns-async-std", "libp2p/mdns-async-io"] +tokio = ["tokio-crate", "libp2p/tcp-tokio", "libp2p/dns-tokio", "libp2p/mdns-tokio"] telemetry = ["tide", "async_global"] # Makes it possible to exchange data via Bitswap with a go-ipfs node compat = ["libp2p-bitswap/compat"] @@ -28,11 +28,11 @@ chrono = "0.4.19" fnv = "1.0.7" futures = "0.3.21" futures-timer = "3.0.2" -ipfs-sqlite-block-store = "0.12.0" +ipfs-sqlite-block-store = "0.13.0" lazy_static = "1.4.0" -libipld = { version = "0.12.0", default-features = false } -libp2p-bitswap = "0.22.0" -libp2p-broadcast = "0.9.1" +libipld = { version = "0.14.0", default-features = false } +libp2p-bitswap = "0.23.0" +libp2p-broadcast = "0.10.0" names = "0.13.0" parking_lot = "0.11.2" pin-project = "1.0.10" @@ -42,19 +42,17 @@ thiserror = "1.0.30" tide = { version = "0.16.0", optional = true } tokio-crate = { package = "tokio", version = "1.17.0", features = ["rt"], optional = true } tracing = "0.1.32" -trust-dns-resolver = "0.20" +trust-dns-resolver = "0.21.2" void = "1.0.2" [dependencies.libp2p] -version = "0.43.0" +version = "0.48.0" default-features = false features = [ "gossipsub", "identify", "kad", - "mdns", "ping", - #"relay", "mplex", "noise", "pnet", @@ -62,10 +60,11 @@ features = [ ] [dev-dependencies] +anyhow = { version = "1", features = ["backtrace"] } async-std = { version = "1.11.0", features = ["attributes"] } -libipld = { version = "0.12.0", default-features = false, features = ["dag-cbor", "dag-pb", "derive"] } -libp2p-bitswap = { version = "0.22.0", default-features = false, features = ["compat"] } -multihash = { version = "0.14.0", default-features = false, features = ["blake3"] } +libipld = { version = "0.14.0", default-features = false, features = ["dag-cbor", "dag-pb", "derive"] } +libp2p-bitswap = { version = "0.23.0", default-features = false, features = ["compat"] } +multihash = { version = "0.16.1", default-features = false, features = ["blake3"] } rand = "0.8.5" regex = "1.5.5" tempdir = "0.3.7" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index a5a1a1a..8149053 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -10,6 +10,7 @@ anyhow = "1.0.56" async-process = "1.3.0" async-std = { version = "1.11.0", features = ["attributes"] } chrono = "0.4.19" +futures = "0.3.24" ipfs-embed = { path = ".." } libipld = { version = "0.12.0", default-features = false, features = ["dag-cbor"] } multihash = { version = "0.14.0", default-features = false, features = ["blake3"] } diff --git a/cli/src/main.rs b/cli/src/main.rs index 201e911..763295a 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,5 +1,6 @@ use anyhow::Result; use async_std::stream::StreamExt; +use futures::TryFutureExt; use ipfs_embed::{DefaultParams, Ipfs, NetworkConfig, StorageConfig}; use ipfs_embed_cli::{keypair, Command, Config, Event}; use parking_lot::Mutex; @@ -45,11 +46,11 @@ async fn run() -> Result<()> { }; network.identify.as_mut().unwrap().agent_version = node_name; - let ipfs = Ipfs::::new(ipfs_embed::Config { storage, network }).await?; - let mut events = ipfs.swarm_events(); + let mut ipfs = Ipfs::::new(ipfs_embed::Config { storage, network }).await?; + let mut events = ipfs.swarm_events().await?; for addr in config.listen_on { - let _ = ipfs.listen_on(addr)?; + let _ = ipfs.listen_on(addr); } for addr in config.external { @@ -111,36 +112,45 @@ async fn run() -> Result<()> { loop { line.clear(); stdin.read_line(&mut line)?; - match line.parse()? { - Command::AddAddress(peer, addr) => { - ipfs.lock().add_address(&peer, addr); - } - Command::Dial(peer) => { - ipfs.lock().dial(&peer); - } - Command::PrunePeers => { - ipfs.lock().prune_peers(Duration::ZERO); - } - Command::Get(cid) => { - let block = ipfs.lock().get(&cid)?; - writeln!(stdout, "{}", Event::Block(block))?; - } - Command::Insert(block) => { - ipfs.lock().insert(block)?; - } - Command::Alias(alias, cid) => { - ipfs.lock().alias(&alias, cid.as_ref())?; - } - Command::Flush => { - ipfs.lock().flush().await?; - writeln!(stdout, "{}", Event::Flushed)?; + #[allow(clippy::unit_arg)] + let result = match line.parse()? { + Command::AddAddress(peer, addr) => Ok(ipfs.lock().add_address(peer, addr)), + Command::Dial(peer) => Ok(ipfs.lock().dial(peer)), + Command::PrunePeers => Ok(ipfs.lock().prune_peers(Duration::ZERO)), + Command::Get(cid) => match ipfs.lock().get(&cid) { + Ok(block) => { + writeln!(stdout, "{}", Event::Block(block))?; + Ok(()) + } + Err(err) => Err(err), + }, + Command::Insert(block) => ipfs.lock().insert(block), + Command::Alias(alias, cid) => ipfs.lock().alias(&alias, cid.as_ref()), + Command::Flush => + { + #[allow(clippy::await_holding_lock)] + match ipfs.lock().flush().await { + Ok(_) => { + writeln!(stdout, "{}", Event::Flushed)?; + Ok(()) + } + Err(err) => Err(err), + } } Command::Sync(cid) => { let providers = ipfs.lock().peers(); tracing::debug!("sync {} from {:?}", cid, providers); - ipfs.lock().sync(&cid, providers).await?; - writeln!(stdout, "{}", Event::Synced)?; + match ipfs.lock().sync(&cid, providers).and_then(|f| f).await { + Ok(_) => { + writeln!(stdout, "{}", Event::Synced)?; + Ok(()) + } + Err(err) => Err(err), + } } + }; + if let Err(err) = result { + eprintln!("main loop error (line = {}): {}", line, err); } } } diff --git a/examples/compat.rs b/examples/compat.rs index 855aa88..0091a6b 100644 --- a/examples/compat.rs +++ b/examples/compat.rs @@ -21,10 +21,10 @@ fn tracing_try_init() { async fn main() -> anyhow::Result<()> { tracing_try_init(); let config = Config::default(); - let ipfs = Ipfs::::new(config).await?; + let mut ipfs = Ipfs::::new(config).await?; let peer: PeerId = "QmRSGx67Kq8w7xSBDia7hQfbfuvauMQGgxcwSWw976x4BS".parse()?; let addr: Multiaddr = "/ip4/54.173.33.96/tcp/4001".parse()?; - ipfs.dial_address(&peer, addr); + ipfs.dial_address(peer, addr); // 10 random bytes let _cid_rand10: Cid = "QmXQsqVRpp2W7fbYZHi4aB2Xkqfd3DpwWskZoLVEYigMKC".parse()?; @@ -42,7 +42,7 @@ async fn main() -> anyhow::Result<()> { let block = ipfs.fetch(&cid_simple_dag, vec![peer]).await?; println!("got single block. len = {}", block.data().len()); - let mut updates = ipfs.sync(&cid_simple_dag, vec![peer]); + let mut updates = ipfs.sync(&cid_simple_dag, vec![peer]).await?; println!("starting sync of large file"); while let Some(update) = updates.next().await { println!("{:?}", update); diff --git a/examples/sync.rs b/examples/sync.rs index dafb4f4..8811ce9 100644 --- a/examples/sync.rs +++ b/examples/sync.rs @@ -45,8 +45,8 @@ async fn main() -> Result<()> { .init(); let mut config = Config::new("/tmp/local1".as_ref(), Keypair::generate()); config.network.kad = None; - let a = Ipfs::::new(config).await?; - a.listen_on("/ip4/127.0.0.1/tcp/0".parse()?)? + let mut a = Ipfs::::new(config).await?; + a.listen_on("/ip4/127.0.0.1/tcp/0".parse()?) .next() .await .unwrap(); @@ -76,6 +76,7 @@ async fn main() -> Result<()> { b.alias(ROOT, builder.prev.as_ref())?; b.sync(builder.prev.as_ref().unwrap(), vec![a.local_peer_id()]) + .await? .await?; b.flush().await?; diff --git a/harness/Cargo.toml b/harness/Cargo.toml index 39a8417..3f50551 100644 --- a/harness/Cargo.toml +++ b/harness/Cargo.toml @@ -13,10 +13,10 @@ async-std = "1.11.0" escargot = "0.5.7" futures = "0.3.21" ipfs-embed-cli = { path = "../cli" } -libipld = { version = "0.12.0", default-features = false, features = ["dag-cbor", "dag-pb", "derive"] } -libp2p = { version = "0.43.0", default-features = false } +libipld = { version = "0.14.0", default-features = false, features = ["dag-cbor", "dag-pb", "derive"] } +libp2p = { version = "0.48.0", default-features = false } maplit = "1.0.2" -multihash = { version = "0.14.0", default-features = false, features = ["blake3"] } +multihash = { version = "0.16.1", default-features = false, features = ["blake3"] } netsim-embed = "0.7.1" rand = "0.8.5" structopt = "0.3.26" diff --git a/src/db.rs b/src/db.rs index ea6542b..a4a7206 100644 --- a/src/db.rs +++ b/src/db.rs @@ -347,7 +347,7 @@ where } else { timer.stop_and_discard(); } - Ok(res?) + res } struct SqliteStoreCollector { diff --git a/src/lib.rs b/src/lib.rs index 0c287b5..4985fe3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,8 +5,8 @@ //! # #[async_std::main] //! # async fn main() -> Result<(), Box> { //! # use ipfs_embed::{Config, DefaultParams, Ipfs}; -//! let ipfs = Ipfs::::new(Config::default()).await?; -//! ipfs.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; +//! let mut ipfs = Ipfs::::new(Config::default()).await?; +//! ipfs.listen_on("/ip4/0.0.0.0/tcp/0".parse()?); //! # Ok(()) } //! ``` @@ -17,6 +17,7 @@ mod net; mod telemetry; #[cfg(test)] mod test_util; +mod variable; /// convenience re-export of configuration types from libp2p pub mod config { @@ -45,7 +46,7 @@ pub use crate::{ pub use libipld::{store::DefaultParams, Block, Cid}; pub use libp2p::{ - core::{connection::ListenerId, ConnectedPoint, Multiaddr, PeerId}, + core::{transport::ListenerId, ConnectedPoint, Multiaddr, PeerId}, identity, kad::{kbucket::Key as BucketKey, record::Key, PeerRecord, Quorum, Record}, multiaddr, @@ -55,7 +56,7 @@ pub use libp2p::{ use crate::net::NetworkService; use async_trait::async_trait; use chrono::{DateTime, Utc}; -use futures::stream::Stream; +use futures::{stream::Stream, Future}; use libipld::{ codec::References, error::BlockNotFound, @@ -98,7 +99,7 @@ impl Default for Config { #[derive(Clone)] pub struct Ipfs { storage: StorageService

, - network: NetworkService

, + network: NetworkService, } impl std::fmt::Debug for Ipfs

{ @@ -167,7 +168,7 @@ where } /// Listens on a new `Multiaddr`. - pub fn listen_on(&self, addr: Multiaddr) -> Result> { + pub fn listen_on(&mut self, addr: Multiaddr) -> impl Stream { self.network.listen_on(addr) } @@ -177,7 +178,7 @@ where } /// Adds an external address. - pub fn add_external_address(&self, addr: Multiaddr) { + pub fn add_external_address(&mut self, addr: Multiaddr) { self.network.add_external_address(addr) } @@ -187,39 +188,39 @@ where } /// Adds a known `Multiaddr` for a `PeerId`. - pub fn add_address(&self, peer: &PeerId, addr: Multiaddr) { + pub fn add_address(&mut self, peer: PeerId, addr: Multiaddr) { self.network.add_address(peer, addr) } /// Removes a `Multiaddr` for a `PeerId`. - pub fn remove_address(&self, peer: &PeerId, addr: &Multiaddr) { + pub fn remove_address(&mut self, peer: PeerId, addr: Multiaddr) { self.network.remove_address(peer, addr) } /// Removes all unconnected peers without addresses which have been /// in this state for at least the given duration - pub fn prune_peers(&self, min_age: Duration) { + pub fn prune_peers(&mut self, min_age: Duration) { self.network.prune_peers(min_age); } /// Dials a `PeerId` using a known address. - pub fn dial(&self, peer: &PeerId) { + pub fn dial(&mut self, peer: PeerId) { self.network.dial(peer); } /// Dials a `PeerId` using `Multiaddr`. - pub fn dial_address(&self, peer: &PeerId, addr: Multiaddr) { + pub fn dial_address(&mut self, peer: PeerId, addr: Multiaddr) { self.network.dial_address(peer, addr); } /// Bans a `PeerId` from the swarm, dropping all existing connections and /// preventing new connections from the peer. - pub fn ban(&self, peer: PeerId) { + pub fn ban(&mut self, peer: PeerId) { self.network.ban(peer) } /// Unbans a previously banned `PeerId`. - pub fn unban(&self, peer: PeerId) { + pub fn unban(&mut self, peer: PeerId) { self.network.unban(peer) } @@ -245,9 +246,11 @@ where /// Bootstraps the dht using a set of bootstrap nodes. After bootstrap /// completes it provides all blocks in the block store. - pub async fn bootstrap(&self, nodes: &[(PeerId, Multiaddr)]) -> Result<()> { - self.network.bootstrap(nodes).await?; - Ok(()) + pub fn bootstrap( + &mut self, + nodes: Vec<(PeerId, Multiaddr)>, + ) -> impl Future> { + self.network.bootstrap(nodes) } /// Returns true if the dht was bootstrapped. @@ -257,59 +260,70 @@ where /// Gets the closest peer to a key. Useful for finding the `Multiaddr` of a /// `PeerId`. - pub async fn get_closest_peers(&self, key: K) -> Result<()> - where - K: Into> + Into> + Clone, - { - self.network.get_closest_peers(key).await?; - Ok(()) - } + // pub async fn get_closest_peers(&self, key: K) -> Result<()> + // where + // K: Into> + Into> + Clone, + // { + // self.network.get_closest_peers(key).await?; + // Ok(()) + // } /// Gets providers of a key from the dht. - pub async fn providers(&self, key: Key) -> Result> { - self.network.providers(key).await + pub fn providers(&mut self, key: Key) -> impl Future>> { + self.network.providers(key) } /// Provides a key in the dht. - pub async fn provide(&self, key: Key) -> Result<()> { - self.network.provide(key).await + pub fn provide(&mut self, key: Key) -> impl Future> { + self.network.provide(key) } /// Stops providing a key in the dht. - pub fn unprovide(&self, key: &Key) { + pub fn unprovide(&mut self, key: Key) -> Result<()> { self.network.unprovide(key) } /// Gets a record from the dht. - pub async fn get_record(&self, key: Key, quorum: Quorum) -> Result> { - self.network.get_record(key, quorum).await + pub fn get_record( + &mut self, + key: Key, + quorum: Quorum, + ) -> impl Future>> { + self.network.get_record(key, quorum) } /// Puts a new record in the dht. - pub async fn put_record(&self, record: Record, quorum: Quorum) -> Result<()> { - self.network.put_record(record, quorum).await + pub fn put_record( + &mut self, + record: Record, + quorum: Quorum, + ) -> impl Future> { + self.network.put_record(record, quorum) } /// Removes a record from the dht. - pub fn remove_record(&self, key: &Key) { + pub fn remove_record(&mut self, key: Key) -> Result<()> { self.network.remove_record(key) } /// Subscribes to a `topic` returning a `Stream` of messages. If all /// `Stream`s for a topic are dropped it unsubscribes from the `topic`. - pub fn subscribe(&self, topic: &str) -> Result> { + pub fn subscribe( + &mut self, + topic: String, + ) -> impl Future>> { self.network.subscribe(topic) } /// Publishes a new message in a `topic`, sending the message to all /// subscribed peers. - pub fn publish(&self, topic: &str, msg: Vec) -> Result<()> { + pub fn publish(&mut self, topic: String, msg: Vec) -> impl Future> { self.network.publish(topic, msg) } /// Publishes a new message in a `topic`, sending the message to all /// subscribed connected peers. - pub fn broadcast(&self, topic: &str, msg: Vec) -> Result<()> { + pub fn broadcast(&mut self, topic: String, msg: Vec) -> impl Future> { self.network.broadcast(topic, msg) } @@ -352,7 +366,7 @@ where return Ok(block); } if !providers.is_empty() { - self.network.get(*cid, providers.into_iter()).await?; + self.network.get(*cid, providers).await?.await?; if let Some(data) = self.storage.get(cid)? { let block = Block::new_unchecked(*cid, data); return Ok(block); @@ -375,7 +389,11 @@ where self.storage.evict().await } - pub fn sync(&self, cid: &Cid, providers: Vec) -> SyncQuery

{ + pub fn sync( + &self, + cid: &Cid, + providers: Vec, + ) -> impl Future> { let missing = self.storage.missing_blocks(cid).ok().unwrap_or_default(); tracing::trace!(cid = %cid, missing = %missing.len(), "sync"); self.network.sync(*cid, providers, missing) @@ -419,12 +437,12 @@ where /// Registers prometheus metrics in a registry. pub fn register_metrics(&self, registry: &Registry) -> Result<()> { self.storage.register_metrics(registry)?; - self.network.register_metrics(registry)?; + net::register_metrics(registry)?; Ok(()) } /// Subscribes to the swarm event stream. - pub fn swarm_events(&self) -> SwarmEvents { + pub fn swarm_events(&mut self) -> impl Future> { self.network.swarm_events() } } @@ -479,7 +497,7 @@ where } async fn sync(&self, cid: &Cid) -> Result<()> { - Ipfs::sync(self, cid, self.peers()).await + Ipfs::sync(self, cid, self.peers()).await?.await } } @@ -511,8 +529,8 @@ mod tests { network.mdns = None; } - let ipfs = Ipfs::new(Config { storage, network }).await?; - ipfs.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap())? + let mut ipfs = Ipfs::new(Config { storage, network }).await?; + ipfs.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .next() .await .unwrap(); @@ -561,15 +579,15 @@ mod tests { async fn test_exchange_kad() -> Result<()> { tracing_try_init(); let (store, _tmp) = create_store(false).await?; - let (store1, _tmp) = create_store(false).await?; - let (store2, _tmp) = create_store(false).await?; + let (mut store1, _tmp) = create_store(false).await?; + let (mut store2, _tmp) = create_store(false).await?; let addr = store.listeners()[0].clone(); let peer_id = store.local_peer_id(); let nodes = [(peer_id, addr)]; - let b1 = store1.bootstrap(&nodes); - let b2 = store2.bootstrap(&nodes); + let b1 = store1.bootstrap(nodes[..].into()); + let b2 = store2.bootstrap(nodes[..].into()); let (r1, r2) = join!(b1, b2); r1.unwrap(); r2.unwrap(); @@ -640,10 +658,10 @@ mod tests { #[async_std::test] async fn test_sync() -> Result<()> { tracing_try_init(); - let (local1, _tmp) = create_store(false).await?; - let (local2, _tmp) = create_store(false).await?; - local1.add_address(&local2.local_peer_id(), local2.listeners()[0].clone()); - local2.add_address(&local1.local_peer_id(), local1.listeners()[0].clone()); + let (mut local1, _tmp) = create_store(false).await?; + let (mut local2, _tmp) = create_store(false).await?; + local1.add_address(local2.local_peer_id(), local2.listeners()[0].clone()); + local2.add_address(local1.local_peer_id(), local1.listeners()[0].clone()); let a1 = create_ipld_block(&ipld!({ "a": 0 }))?; let b1 = create_ipld_block(&ipld!({ "b": 0 }))?; @@ -662,7 +680,10 @@ mod tests { assert_pinned!(&local1, &c1); local2.alias(&x, Some(c1.cid()))?; - local2.sync(c1.cid(), vec![local1.local_peer_id()]).await?; + local2 + .sync(c1.cid(), vec![local1.local_peer_id()]) + .await? + .await?; local2.flush().await?; assert_pinned!(&local2, &a1); assert_pinned!(&local2, &b1); @@ -679,7 +700,10 @@ mod tests { assert_pinned!(&local2, &c2); local1.alias(x, Some(c2.cid()))?; - local1.sync(c2.cid(), vec![local2.local_peer_id()]).await?; + local1 + .sync(c2.cid(), vec![local2.local_peer_id()]) + .await? + .await?; local1.flush().await?; assert_pinned!(&local1, &a1); assert_unpinned!(&local1, &b1); @@ -709,22 +733,24 @@ mod tests { #[allow(clippy::eval_order_dependence)] async fn test_dht_record() -> Result<()> { tracing_try_init(); - let stores = [create_store(false).await?, create_store(false).await?]; + let mut stores = [create_store(false).await?, create_store(false).await?]; async_std::task::sleep(Duration::from_millis(100)).await; stores[0] .0 - .bootstrap(&[( + .bootstrap(vec![( stores[1].0.local_peer_id(), stores[1].0.listeners()[0].clone(), )]) .await?; stores[1] .0 - .bootstrap(&[( + .bootstrap(vec![( stores[0].0.local_peer_id(), stores[0].0.listeners()[0].clone(), )]) .await?; + + async_std::task::sleep(Duration::from_millis(500)).await; let key: Key = b"key".to_vec().into(); stores[0] @@ -743,7 +769,7 @@ mod tests { #[allow(clippy::eval_order_dependence)] async fn test_gossip_and_broadcast() -> Result<()> { tracing_try_init(); - let stores = [ + let mut stores = [ create_store(false).await?, create_store(false).await?, create_store(false).await?, @@ -752,27 +778,48 @@ mod tests { create_store(false).await?, ]; let mut subscriptions = vec![]; - let topic = "topic"; - for (store, _) in &stores { - for (other, _) in &stores { - if store.local_peer_id() != other.local_peer_id() { - store.dial_address(&other.local_peer_id(), other.listeners()[0].clone()); + let topic = "topic".to_owned(); + let others = stores + .iter() + .map(|store| { + ( + store.0.local_peer_id(), + store.0.listeners().into_iter().next().unwrap(), + ) + }) + .collect::>(); + for (store, _) in &mut stores { + for (peer, addr) in &others { + if store.local_peer_id() != *peer { + store.dial_address(*peer, addr.clone()); } } } - async_std::task::sleep(Duration::from_millis(500)).await; - // Make sure everyone is peered before subscribing + // TCP sim open redials may take a second + async_std::task::sleep(Duration::from_millis(1500)).await; for (store, _) in &stores { - subscriptions.push(store.subscribe(topic)?); + for (peer, _) in &others { + assert!(store.is_connected(peer)); + } + } + for (store, _) in &mut stores { + subscriptions.push(store.subscribe(topic.clone()).await?); } async_std::task::sleep(Duration::from_millis(500)).await; stores[0] .0 - .publish(topic, b"hello gossip".to_vec()) + .publish(topic.clone(), b"hello gossip".to_vec()) + .await .unwrap(); + /* + * This test used to assume that calling subscribe immediately updates the local subscription + * while sending that subscription over the network takes some time, meaning that all participants + * received all Subscribed messages. With the new asynchronous NetworkCommand this is no longer + * true, so Subscribed messages are sometimes missed. + */ for (idx, subscription) in subscriptions.iter_mut().enumerate() { let mut expected = stores .iter() @@ -798,42 +845,58 @@ mod tests { Box::new(std::iter::empty()) }) .collect::>(); - while !expected.is_empty() { + while expected + .iter() + .any(|msg| matches!(msg, GossipEvent::Message(..))) + { let ev = timeout(Duration::from_millis(100), subscription.next()) .await - .unwrap() + .expect(&*format!("idx {} timeout waiting for {:?}", idx, expected)) .unwrap(); - assert!(expected.contains(&ev)); + assert!(expected.contains(&ev), ", received {:?}", ev); if let Some(idx) = expected.iter().position(|e| e == &ev) { // Can't retain, as there might be multiple messages expected.remove(idx); } } + if idx != 0 { + assert!( + expected.len() < (stores.len() - 1) * 2, + ", idx {} did not receive any Subscribed message", + idx + ); + } } // Check broadcast subscription stores[0] .0 - .broadcast(topic, b"hello broadcast".to_vec()) + .broadcast(topic.clone(), b"hello broadcast".to_vec()) + .await .unwrap(); for subscription in &mut subscriptions[1..] { - if let GossipEvent::Message(p, data) = subscription.next().await.unwrap() { - assert_eq!(p, stores[0].0.local_peer_id()); - assert_eq!(data[..], b"hello broadcast"[..]); - } else { - panic!() + match subscription.next().await.unwrap() { + GossipEvent::Message(p, data) => { + assert_eq!(p, stores[0].0.local_peer_id()); + assert_eq!(data[..], b"hello broadcast"[..]); + } + x => { + panic!("received unexpected message: {:?}", x); + } } } // trigger cleanup + let mut last_sub = subscriptions.drain(..1).next().unwrap(); + drop(subscriptions); + stores[0] .0 .broadcast(topic, b"r u still listening?".to_vec()) + .await .unwrap(); - let mut last_sub = subscriptions.drain(..1).next().unwrap(); - drop(subscriptions); let mut expected = stores[1..] .iter() .map(|s| s.0.local_peer_id()) @@ -847,7 +910,12 @@ mod tests { .await .unwrap() .unwrap(); - assert!(expected.contains(&ev)); + // this is idx==0 which didn’t have a message to receive in the gossipsub round, + // so the Subscribed messages are still lingering in this channel + if let GossipEvent::Subscribed(..) = ev { + continue; + } + assert!(expected.contains(&ev), ", received {:?}", ev); if let Some(idx) = expected.iter().position(|e| e == &ev) { // Can't retain, as there might be multiple messages expected.remove(idx); @@ -920,6 +988,7 @@ mod tests { let t0 = Instant::now(); let _ = b .sync(&cid, vec![a.local_peer_id()]) + .await? .for_each(|x| async move { tracing::debug!("sync progress {:?}", x) }) .await; b.flush().await?; @@ -960,6 +1029,7 @@ mod tests { let t0 = Instant::now(); let _ = b .sync(&cid, vec![a.local_peer_id()]) + .await? .for_each(|x| async move { tracing::debug!("sync progress {:?}", x) }) .await; b.flush().await?; diff --git a/src/net/behaviour.rs b/src/net/behaviour.rs index 636d3f5..f661a16 100644 --- a/src/net/behaviour.rs +++ b/src/net/behaviour.rs @@ -1,25 +1,22 @@ -use super::peer_info::Direction; use crate::{ net::{ config::NetworkConfig, - peers::{AddressBook, Event, SwarmEvents}, + peers::{AddressBook, Event}, }, + variable::Writer, AddressSource, PeerInfo, }; -use chrono::{DateTime, Utc}; -use fnv::FnvHashMap; -use futures::{ - channel::{mpsc, oneshot}, - stream::Stream, +use fnv::{FnvHashMap, FnvHashSet}; +use futures::channel::{ + mpsc::{self, UnboundedSender}, + oneshot, }; use libipld::{store::StoreParams, Cid, DefaultParams, Result}; use libp2p::{ core::ConnectedPoint, gossipsub::{Gossipsub, GossipsubEvent, GossipsubMessage, IdentTopic, MessageAuthenticity}, identify::{Identify, IdentifyEvent}, - identity::ed25519::PublicKey, kad::{ - kbucket::Key as BucketKey, record::{store::MemoryStore, Key, Record}, AddProviderOk, BootstrapOk, GetClosestPeersOk, GetProvidersOk, GetRecordOk, Kademlia, KademliaEvent, PeerRecord, PutRecordOk, QueryResult, Quorum, @@ -27,14 +24,13 @@ use libp2p::{ mdns::{Mdns, MdnsEvent}, ping::{Ping, PingEvent, PingFailure, PingSuccess}, swarm::{ - behaviour::toggle::Toggle, ConnectionError, ConnectionHandler, IntoConnectionHandler, - NetworkBehaviour, NetworkBehaviourEventProcess, + behaviour::toggle::Toggle, AddressRecord, ConnectionError, ConnectionHandler, + IntoConnectionHandler, NetworkBehaviour, }, Multiaddr, NetworkBehaviour, PeerId, }; use libp2p_bitswap::{Bitswap, BitswapEvent, BitswapStore}; use libp2p_broadcast::{Broadcast, BroadcastEvent, Topic}; -use prometheus::Registry; use std::{collections::HashSet, sync::Arc, time::Duration}; use thiserror::Error; @@ -73,17 +69,12 @@ pub enum SyncEvent { pub type GetChannel = oneshot::Receiver>; pub type SyncChannel = mpsc::UnboundedReceiver; -pub type BootstrapChannel = oneshot::Receiver>; -pub type GetClosestPeersChannel = oneshot::Receiver>>; -pub type GetProvidersChannel = oneshot::Receiver>>; -pub type StartProvidingChannel = oneshot::Receiver>; -pub type GetRecordChannel = oneshot::Receiver>>; -pub type PutRecordChannel = oneshot::Receiver>; - -enum QueryChannel { + +pub enum QueryChannel { Get(oneshot::Sender>), Sync(mpsc::UnboundedSender), Bootstrap(oneshot::Sender>), + #[allow(dead_code)] GetClosestPeers(oneshot::Sender>>), GetProviders(oneshot::Sender>>), StartProviding(oneshot::Sender>), @@ -101,7 +92,6 @@ pub(crate) type MyHandlerError = << as Ne ::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::Error; #[derive(NetworkBehaviour)] -#[behaviour(event_process = true)] pub struct NetworkBackendBehaviour { peers: AddressBook, kad: Toggle>, @@ -111,17 +101,10 @@ pub struct NetworkBackendBehaviour { bitswap: Toggle>, gossipsub: Toggle, broadcast: Toggle, - - #[behaviour(ignore)] - bootstrap_complete: bool, - #[behaviour(ignore)] - queries: FnvHashMap, - #[behaviour(ignore)] - subscriptions: FnvHashMap>>, } -impl NetworkBehaviourEventProcess for NetworkBackendBehaviour

{ - fn inject_event(&mut self, event: MdnsEvent) { +impl NetworkBackendBehaviour

{ + pub fn inject_mdns_event(&mut self, event: MdnsEvent) { match event { MdnsEvent::Discovered(list) => { for (peer_id, addr) in list { @@ -171,16 +154,21 @@ pub struct KadGetRecordError(pub libp2p::kad::GetRecordError); #[error("{0:?}")] pub struct KadPutRecordError(pub libp2p::kad::PutRecordError); -impl NetworkBehaviourEventProcess for NetworkBackendBehaviour

{ - fn inject_event(&mut self, event: KademliaEvent) { +impl NetworkBackendBehaviour

{ + pub fn inject_kad_event( + &mut self, + event: KademliaEvent, + bootstrap_complete: &mut bool, + queries: &mut FnvHashMap, + ) { tracing::trace!("kademlia event {:?}", event); if let KademliaEvent::OutboundQueryCompleted { id, result, .. } = event { match result { QueryResult::Bootstrap(Ok(BootstrapOk { num_remaining, .. })) => { tracing::trace!("remaining {}", num_remaining); if num_remaining == 0 { - self.bootstrap_complete = true; - if let Some(QueryChannel::Bootstrap(ch)) = self.queries.remove(&id.into()) { + *bootstrap_complete = true; + if let Some(QueryChannel::Bootstrap(ch)) = queries.remove(&id.into()) { ch.send(Ok(())).ok(); } self.peers.notify(Event::Bootstrapped); @@ -188,44 +176,40 @@ impl NetworkBehaviourEventProcess for NetworkBack } QueryResult::Bootstrap(Err(err)) => { tracing::trace!("{:?}", err); - if let Some(QueryChannel::Bootstrap(ch)) = self.queries.remove(&id.into()) { + if let Some(QueryChannel::Bootstrap(ch)) = queries.remove(&id.into()) { ch.send(Err(KadBootstrapError(err).into())).ok(); } } QueryResult::GetClosestPeers(Ok(GetClosestPeersOk { peers, .. })) => { - if let Some(QueryChannel::GetClosestPeers(ch)) = self.queries.remove(&id.into()) - { + if let Some(QueryChannel::GetClosestPeers(ch)) = queries.remove(&id.into()) { ch.send(Ok(peers)).ok(); } } QueryResult::GetClosestPeers(Err(err)) => { tracing::trace!("{:?}", err); - if let Some(QueryChannel::GetClosestPeers(ch)) = self.queries.remove(&id.into()) - { + if let Some(QueryChannel::GetClosestPeers(ch)) = queries.remove(&id.into()) { ch.send(Err(KadGetClosestPeersError(err).into())).ok(); } } QueryResult::GetProviders(Ok(GetProvidersOk { providers, .. })) => { - if let Some(QueryChannel::GetProviders(ch)) = self.queries.remove(&id.into()) { + if let Some(QueryChannel::GetProviders(ch)) = queries.remove(&id.into()) { ch.send(Ok(providers)).ok(); } } QueryResult::GetProviders(Err(err)) => { tracing::trace!("{:?}", err); - if let Some(QueryChannel::GetProviders(ch)) = self.queries.remove(&id.into()) { + if let Some(QueryChannel::GetProviders(ch)) = queries.remove(&id.into()) { ch.send(Err(KadGetProvidersError(err).into())).ok(); } } QueryResult::StartProviding(Ok(AddProviderOk { .. })) => { - if let Some(QueryChannel::StartProviding(ch)) = self.queries.remove(&id.into()) - { + if let Some(QueryChannel::StartProviding(ch)) = queries.remove(&id.into()) { ch.send(Ok(())).ok(); } } QueryResult::StartProviding(Err(err)) => { tracing::trace!("{:?}", err); - if let Some(QueryChannel::StartProviding(ch)) = self.queries.remove(&id.into()) - { + if let Some(QueryChannel::StartProviding(ch)) = queries.remove(&id.into()) { ch.send(Err(KadAddProviderError(err).into())).ok(); } } @@ -234,24 +218,24 @@ impl NetworkBehaviourEventProcess for NetworkBack tracing::trace!("{:?}", err); } QueryResult::GetRecord(Ok(GetRecordOk { records, .. })) => { - if let Some(QueryChannel::GetRecord(ch)) = self.queries.remove(&id.into()) { + if let Some(QueryChannel::GetRecord(ch)) = queries.remove(&id.into()) { ch.send(Ok(records)).ok(); } } QueryResult::GetRecord(Err(err)) => { tracing::trace!("{:?}", err); - if let Some(QueryChannel::GetRecord(ch)) = self.queries.remove(&id.into()) { + if let Some(QueryChannel::GetRecord(ch)) = queries.remove(&id.into()) { ch.send(Err(KadGetRecordError(err).into())).ok(); } } QueryResult::PutRecord(Ok(PutRecordOk { .. })) => { - if let Some(QueryChannel::PutRecord(ch)) = self.queries.remove(&id.into()) { + if let Some(QueryChannel::PutRecord(ch)) = queries.remove(&id.into()) { ch.send(Ok(())).ok(); } } QueryResult::PutRecord(Err(err)) => { tracing::trace!("{:?}", err); - if let Some(QueryChannel::PutRecord(ch)) = self.queries.remove(&id.into()) { + if let Some(QueryChannel::PutRecord(ch)) = queries.remove(&id.into()) { ch.send(Err(KadPutRecordError(err).into())).ok(); } } @@ -264,15 +248,19 @@ impl NetworkBehaviourEventProcess for NetworkBack } } -impl NetworkBehaviourEventProcess for NetworkBackendBehaviour

{ - fn inject_event(&mut self, event: BitswapEvent) { +impl NetworkBackendBehaviour

{ + pub fn inject_bitswap_event( + &mut self, + event: BitswapEvent, + queries: &mut FnvHashMap, + ) { match event { BitswapEvent::Progress(id, missing) => { - if let Some(QueryChannel::Sync(ch)) = self.queries.get(&id.into()) { + if let Some(QueryChannel::Sync(ch)) = queries.get(&id.into()) { ch.unbounded_send(SyncEvent::Progress { missing }).ok(); } } - BitswapEvent::Complete(id, result) => match self.queries.remove(&id.into()) { + BitswapEvent::Complete(id, result) => match queries.remove(&id.into()) { Some(QueryChannel::Get(ch)) => { ch.send(result).ok(); } @@ -285,8 +273,8 @@ impl NetworkBehaviourEventProcess for NetworkBacke } } -impl NetworkBehaviourEventProcess for NetworkBackendBehaviour

{ - fn inject_event(&mut self, event: PingEvent) { +impl NetworkBackendBehaviour

{ + pub fn inject_ping_event(&mut self, event: PingEvent) { // Don't really need to do anything here as ping handles disconnecting // automatically. let peer = event.peer; @@ -313,8 +301,8 @@ impl NetworkBehaviourEventProcess for NetworkBackendB } } -impl NetworkBehaviourEventProcess for NetworkBackendBehaviour

{ - fn inject_event(&mut self, event: IdentifyEvent) { +impl NetworkBackendBehaviour

{ + pub fn inject_id_event(&mut self, event: IdentifyEvent) { // When a peer opens a connection we only have it's outgoing address. The // identify protocol sends the listening address which needs to be // registered with kademlia. @@ -328,8 +316,12 @@ impl NetworkBehaviourEventProcess for NetworkBack #[error("{0:?}")] pub struct GossipsubPublishError(pub libp2p::gossipsub::error::PublishError); -impl NetworkBehaviourEventProcess for NetworkBackendBehaviour

{ - fn inject_event(&mut self, event: GossipsubEvent) { +impl NetworkBackendBehaviour

{ + pub fn inject_gossip_event( + &mut self, + event: GossipsubEvent, + subscriptions: &mut FnvHashMap>>, + ) { match event { GossipsubEvent::Message { message: @@ -345,59 +337,74 @@ impl NetworkBehaviourEventProcess for NetworkBac self.notify_subscribers( &*topic.to_string(), GossipEvent::Message(source.unwrap_or(propagation_source), data.into()), + subscriptions, ); } GossipsubEvent::Subscribed { peer_id, topic, .. } => { self.peers .notify(Event::Subscribed(peer_id, topic.to_string())); - self.notify_subscribers(&*topic.to_string(), GossipEvent::Subscribed(peer_id)); + self.notify_subscribers( + &*topic.to_string(), + GossipEvent::Subscribed(peer_id), + subscriptions, + ); } GossipsubEvent::Unsubscribed { peer_id, topic, .. } => { self.peers .notify(Event::Unsubscribed(peer_id, topic.to_string())); - self.notify_subscribers(&*topic.to_string(), GossipEvent::Unsubscribed(peer_id)); + self.notify_subscribers( + &*topic.to_string(), + GossipEvent::Unsubscribed(peer_id), + subscriptions, + ); } GossipsubEvent::GossipsubNotSupported { .. } => {} } } } -impl NetworkBehaviourEventProcess for NetworkBackendBehaviour

{ - fn inject_event(&mut self, event: BroadcastEvent) { +impl NetworkBackendBehaviour

{ + pub fn inject_broadcast_event( + &mut self, + event: BroadcastEvent, + subscriptions: &mut FnvHashMap>>, + ) { match event { BroadcastEvent::Received(peer_id, topic, data) => { let topic = std::str::from_utf8(&topic).unwrap(); - self.notify_subscribers(topic, GossipEvent::Message(peer_id, data)); + self.notify_subscribers(topic, GossipEvent::Message(peer_id, data), subscriptions); } BroadcastEvent::Subscribed(peer_id, topic) => { if let Ok(topic) = std::str::from_utf8(&topic) { self.peers.notify(Event::Subscribed(peer_id, topic.into())); - self.notify_subscribers(topic, GossipEvent::Subscribed(peer_id)); + self.notify_subscribers(topic, GossipEvent::Subscribed(peer_id), subscriptions); } } BroadcastEvent::Unsubscribed(peer_id, topic) => { if let Ok(topic) = std::str::from_utf8(&topic) { self.peers .notify(Event::Unsubscribed(peer_id, topic.into())); - self.notify_subscribers(topic, GossipEvent::Unsubscribed(peer_id)); + self.notify_subscribers( + topic, + GossipEvent::Unsubscribed(peer_id), + subscriptions, + ); } } } } } -impl NetworkBehaviourEventProcess for NetworkBackendBehaviour

{ - fn inject_event(&mut self, _event: void::Void) {} -} - impl NetworkBackendBehaviour

{ /// Create a Kademlia behaviour with the IPFS bootstrap nodes. pub async fn new>( config: &mut NetworkConfig, store: S, + listeners: Writer>, + peers: Writer>, + external: Writer>, ) -> Result { - let public = config.node_key.public(); let node_key = libp2p::identity::Keypair::Ed25519(config.node_key.clone()); let node_name = config.node_name.clone(); let peer_id = node_key.public().to_peer_id(); @@ -433,13 +440,13 @@ impl NetworkBackendBehaviour

{ .take() .map(|config| Bitswap::new(config, store)); Ok(Self { - bootstrap_complete: false, peers: AddressBook::new( peer_id, - node_name, - public, config.port_reuse, config.enable_loopback, + listeners, + peers, + external, ), mdns: mdns.into(), kad: kad.into(), @@ -448,19 +455,9 @@ impl NetworkBackendBehaviour

{ bitswap: bitswap.into(), gossipsub: gossipsub.into(), broadcast: broadcast.into(), - queries: Default::default(), - subscriptions: Default::default(), }) } - pub fn local_public_key(&self) -> &PublicKey { - self.peers.local_public_key() - } - - pub fn local_node_name(&self) -> &str { - self.peers.local_node_name() - } - pub fn add_address(&mut self, peer_id: &PeerId, addr: Multiaddr, source: AddressSource) { if let Some(kad) = self.kad.as_mut() { kad.add_address(peer_id, addr.clone()); @@ -498,30 +495,15 @@ impl NetworkBackendBehaviour

{ .connection_closed(peer, cp, num_established, error); } - pub fn peers(&self) -> impl Iterator + '_ { - self.peers.peers() - } - - pub fn info(&self, peer_id: &PeerId) -> Option<&PeerInfo> { - self.peers.info(peer_id) - } - - pub fn connections( - &self, - ) -> impl Iterator, Direction)> { - self.peers.connections() - } - - pub fn is_connected(&self, peer: &PeerId) -> bool { - self.peers.is_connected(peer) - } - - pub fn bootstrap(&mut self) -> BootstrapChannel { - let (tx, rx) = oneshot::channel(); + pub fn bootstrap( + &mut self, + queries: &mut FnvHashMap, + tx: oneshot::Sender>, + ) { if let Some(kad) = self.kad.as_mut() { match kad.bootstrap() { Ok(id) => { - self.queries.insert(id.into(), QueryChannel::Bootstrap(tx)); + queries.insert(id.into(), QueryChannel::Bootstrap(tx)); } Err(err) => { tx.send(Err(err.into())).ok(); @@ -530,38 +512,41 @@ impl NetworkBackendBehaviour

{ } else { tx.send(Err(NotBootstrapped.into())).ok(); } - rx - } - - pub fn is_bootstrapped(&self) -> bool { - self.bootstrap_complete } - pub fn get_closest_peers(&mut self, key: K) -> GetClosestPeersChannel - where - K: Into> + Into> + Clone, - { - let (tx, rx) = oneshot::channel(); - if self.bootstrap_complete { - if let Some(kad) = self.kad.as_mut() { - let id = kad.get_closest_peers(key); - self.queries - .insert(id.into(), QueryChannel::GetClosestPeers(tx)); - } - } else { - tx.send(Err(NotBootstrapped.into())).ok(); - } - rx - } - - pub fn provide(&mut self, key: Key) -> StartProvidingChannel { - let (tx, rx) = oneshot::channel(); - if self.bootstrap_complete { + // pub fn get_closest_peers( + // &mut self, + // key: K, + // bootstrap_complete: bool, + // queries: &mut FnvHashMap, + // ) -> GetClosestPeersChannel + // where + // K: Into> + Into> + Clone, + // { + // let (tx, rx) = oneshot::channel(); + // if bootstrap_complete { + // if let Some(kad) = self.kad.as_mut() { + // let id = kad.get_closest_peers(key); + // queries.insert(id.into(), QueryChannel::GetClosestPeers(tx)); + // } + // } else { + // tx.send(Err(NotBootstrapped.into())).ok(); + // } + // rx + // } + + pub fn provide( + &mut self, + key: Key, + bootstrap_complete: bool, + queries: &mut FnvHashMap, + tx: oneshot::Sender>, + ) { + if bootstrap_complete { if let Some(kad) = self.kad.as_mut() { match kad.start_providing(key) { Ok(id) => { - self.queries - .insert(id.into(), QueryChannel::StartProviding(tx)); + queries.insert(id.into(), QueryChannel::StartProviding(tx)); } Err(err) => { tx.send(Err(KadStoreError(err).into())).ok(); @@ -571,7 +556,6 @@ impl NetworkBackendBehaviour

{ } else { tx.send(Err(NotBootstrapped.into())).ok(); } - rx } pub fn unprovide(&mut self, key: &Key) { @@ -580,40 +564,54 @@ impl NetworkBackendBehaviour

{ } } - pub fn providers(&mut self, key: Key) -> GetProvidersChannel { - let (tx, rx) = oneshot::channel(); - if self.bootstrap_complete { + pub fn providers( + &mut self, + key: Key, + bootstrap_complete: bool, + queries: &mut FnvHashMap, + tx: oneshot::Sender>>, + ) { + if bootstrap_complete { if let Some(kad) = self.kad.as_mut() { let id = kad.get_providers(key); - self.queries - .insert(id.into(), QueryChannel::GetProviders(tx)); + queries.insert(id.into(), QueryChannel::GetProviders(tx)); } } else { tx.send(Err(NotBootstrapped.into())).ok(); } - rx } - pub fn get_record(&mut self, key: Key, quorum: Quorum) -> GetRecordChannel { - let (tx, rx) = oneshot::channel(); - if self.bootstrap_complete { + pub fn get_record( + &mut self, + key: Key, + quorum: Quorum, + bootstrap_complete: bool, + queries: &mut FnvHashMap, + tx: oneshot::Sender>>, + ) { + if bootstrap_complete { if let Some(kad) = self.kad.as_mut() { let id = kad.get_record(key, quorum); - self.queries.insert(id.into(), QueryChannel::GetRecord(tx)); + queries.insert(id.into(), QueryChannel::GetRecord(tx)); } } else { tx.send(Err(NotBootstrapped.into())).ok(); } - rx } - pub fn put_record(&mut self, record: Record, quorum: Quorum) -> PutRecordChannel { - let (tx, rx) = oneshot::channel(); - if self.bootstrap_complete { + pub fn put_record( + &mut self, + record: Record, + quorum: Quorum, + bootstrap_complete: bool, + queries: &mut FnvHashMap, + tx: oneshot::Sender>, + ) { + if bootstrap_complete { if let Some(kad) = self.kad.as_mut() { match kad.put_record(record, quorum) { Ok(id) => { - self.queries.insert(id.into(), QueryChannel::PutRecord(tx)); + queries.insert(id.into(), QueryChannel::PutRecord(tx)); } Err(err) => { tx.send(Err(KadStoreError(err).into())).ok(); @@ -623,7 +621,6 @@ impl NetworkBackendBehaviour

{ } else { tx.send(Err(NotBootstrapped.into())).ok(); } - rx } pub fn remove_record(&mut self, key: &Key) { @@ -632,18 +629,21 @@ impl NetworkBackendBehaviour

{ } } - pub fn subscribe(&mut self, topic: &str) -> Result> { + pub fn subscribe( + &mut self, + topic: &str, + subscriptions: &mut FnvHashMap>>, + ) -> Result> { if self.gossipsub.as_ref().is_none() && self.broadcast.as_ref().is_none() { return Err(DisabledProtocol("gossipsub and broadcast").into()); } let (tx, rx) = mpsc::unbounded(); - if let Some(subscribers) = self.subscriptions.get_mut(topic) { + if let Some(subscribers) = subscriptions.get_mut(topic) { subscribers.push(tx); } else { let gossip_topic = IdentTopic::new(topic); let broadcast_topic = Topic::new(gossip_topic.hash().as_str().as_ref()); - self.subscriptions - .insert(gossip_topic.hash().as_str().to_string(), vec![tx]); + subscriptions.insert(gossip_topic.hash().as_str().to_string(), vec![tx]); if let Some(gossipsub) = self.gossipsub.as_mut() { gossipsub .subscribe(&gossip_topic) @@ -669,12 +669,17 @@ impl NetworkBackendBehaviour

{ } } - fn notify_subscribers(&mut self, topic: &str, event: GossipEvent) { - if let Some(subscribers) = self.subscriptions.get_mut(topic) { + fn notify_subscribers( + &mut self, + topic: &str, + event: GossipEvent, + subscriptions: &mut FnvHashMap>>, + ) { + if let Some(subscribers) = subscriptions.get_mut(topic) { subscribers.retain(|subscriber| subscriber.unbounded_send(event.clone()).is_ok()); if subscribers.is_empty() { self.unsubscribe(topic); - self.subscriptions.remove(topic); + subscriptions.remove(topic); } } } @@ -711,11 +716,12 @@ impl NetworkBackendBehaviour

{ &mut self, cid: Cid, providers: impl Iterator, + queries: &mut FnvHashMap, ) -> (GetChannel, QueryId) { let bitswap = self.bitswap.as_mut().expect("bitswap enabled"); let (tx, rx) = oneshot::channel(); let id = bitswap.get(cid, providers); - self.queries.insert(id.into(), QueryChannel::Get(tx)); + queries.insert(id.into(), QueryChannel::Get(tx)); (rx, id.into()) } @@ -724,30 +730,23 @@ impl NetworkBackendBehaviour

{ cid: Cid, providers: Vec, missing: impl Iterator, + queries: &mut FnvHashMap, ) -> (SyncChannel, QueryId) { let bitswap = self.bitswap.as_mut().expect("bitswap enabled"); let (tx, rx) = mpsc::unbounded(); let id = bitswap.sync(cid, providers, missing); - self.queries.insert(id.into(), QueryChannel::Sync(tx)); + queries.insert(id.into(), QueryChannel::Sync(tx)); (rx, id.into()) } - pub fn cancel(&mut self, id: QueryId) { - self.queries.remove(&id); + pub fn cancel(&mut self, id: QueryId, queries: &mut FnvHashMap) { + queries.remove(&id); if let QueryId(InnerQueryId::Bitswap(id)) = id { self.bitswap.as_mut().unwrap().cancel(id); } } - pub fn register_metrics(&self, registry: &Registry) -> Result<()> { - if let Some(bitswap) = self.bitswap.as_ref() { - bitswap.register_metrics(registry)?; - } - self.peers.register_metrics(registry)?; - Ok(()) - } - - pub fn swarm_events(&mut self) -> SwarmEvents { - self.peers.swarm_events() + pub fn swarm_events(&mut self, tx: UnboundedSender) { + self.peers.swarm_events(tx) } } diff --git a/src/net/mod.rs b/src/net/mod.rs index 4ff792e..6eed941 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -10,17 +10,25 @@ pub use self::{ behaviour::{GossipEvent, QueryId, SyncEvent}, config::{DnsConfig, NetworkConfig}, peer_info::{AddressSource, ConnectionFailure, Direction, PeerInfo, Rtt}, - peers::{Event, SwarmEvents}, + peers::{register_metrics, Event, SwarmEvents}, }; -use self::behaviour::{GetChannel, NetworkBackendBehaviour, SyncChannel}; -use crate::executor::{Executor, JoinHandle}; +use self::behaviour::{GetChannel, NetworkBackendBehaviour, QueryChannel, SyncChannel}; +use crate::{ + executor::{Executor, JoinHandle}, + variable::{Reader, Writer}, +}; +use anyhow::anyhow; use chrono::{DateTime, Utc}; +use fnv::{FnvHashMap, FnvHashSet}; use futures::{ - channel::mpsc, - future, + channel::{ + mpsc::{self, Receiver, Sender, UnboundedReceiver, UnboundedSender}, + oneshot, + }, + future::{self, Either}, stream::{Stream, StreamExt}, - task::AtomicWaker, + FutureExt, }; use libipld::{error::BlockNotFound, store::StoreParams, Cid, Result}; #[cfg(feature = "async_global")] @@ -28,7 +36,7 @@ use libp2p::dns::DnsConfig as Dns; #[cfg(all(feature = "tokio", not(feature = "async_global")))] use libp2p::dns::TokioDnsConfig as Dns; #[cfg(feature = "async_global")] -use libp2p::tcp::TcpConfig; +use libp2p::tcp::GenTcpConfig as TcpConfig; #[cfg(all(feature = "tokio", not(feature = "async_global")))] use libp2p::tcp::TokioTcpConfig as TcpConfig; use libp2p::{ @@ -38,17 +46,16 @@ use libp2p::{ upgrade::{SelectUpgrade, Version}, }, identity::ed25519::PublicKey, - kad::{kbucket::Key as BucketKey, record::Key, PeerRecord, Quorum, Record}, + kad::{record::Key, PeerRecord, Quorum, Record}, mplex::MplexConfig, noise::{self, NoiseConfig, X25519Spec}, pnet::{PnetConfig, PreSharedKey}, swarm::{AddressRecord, AddressScore, Swarm, SwarmBuilder, SwarmEvent}, + tcp::TcpTransport, yamux::YamuxConfig, Multiaddr, PeerId, }; use libp2p_bitswap::BitswapStore; -use parking_lot::Mutex; -use prometheus::Registry; use std::{ collections::HashSet, future::Future, @@ -57,32 +64,88 @@ use std::{ task::{Context, Poll}, time::Duration, }; +use void::unreachable; #[derive(Clone, Debug, Eq, PartialEq)] pub enum ListenerEvent { NewListenAddr(Multiaddr), ExpiredListenAddr(Multiaddr), + ListenFailed(Multiaddr, String), +} + +#[derive(Debug)] +pub enum NetworkCommand { + ListenOn(Multiaddr, UnboundedSender), + AddExternalAddress(Multiaddr), + AddAddress(PeerId, Multiaddr), + RemoveAddress(PeerId, Multiaddr), + PrunePeers(Duration), + Dial(PeerId), + DialAddress(PeerId, Multiaddr), + Ban(PeerId), + Unban(PeerId), + Bootstrap( + Vec<(PeerId, Multiaddr)>, + oneshot::Sender>, + ), + Providers(Key, oneshot::Sender>>), + Provide(Key, oneshot::Sender>), + Unprovide(Key), + GetRecord( + Key, + Quorum, + oneshot::Sender>>, + ), + PutRecord(Record, Quorum, oneshot::Sender>), + RemoveRecord(Key), + Subscribe( + String, + oneshot::Sender>>, + ), + Publish(String, Vec, oneshot::Sender>), + Broadcast(String, Vec, oneshot::Sender>), + Get(Cid, Vec, oneshot::Sender), + Sync(Cid, Vec, Vec, oneshot::Sender), + SwarmEvents(oneshot::Sender), + CancelQuery(QueryId), } #[derive(Clone)] -pub struct NetworkService { - swarm: Arc>>>, - waker: Arc, +pub struct NetworkService { + bootstrapped: Reader, + peers: Reader>, + listeners: Reader>, + external: Reader>, + public_key: PublicKey, + peer_id: PeerId, + node_name: String, + cmd: Sender, _swarm_task: Arc>, } -impl NetworkService

{ - pub async fn new>( +impl NetworkService { + pub async fn new( mut config: NetworkConfig, store: S, executor: Executor, ) -> Result { + let public_key = config.node_key.public(); let peer_id = - PeerId::from_public_key(&libp2p::core::PublicKey::Ed25519(config.node_key.public())); - let behaviour = NetworkBackendBehaviour::

::new(&mut config, store).await?; + PeerId::from_public_key(&libp2p::core::PublicKey::Ed25519(public_key.clone())); + let node_name = config.node_name.clone(); + + let peers = Writer::new(FnvHashMap::default()); + let peers2 = peers.reader(); + let listeners = Writer::new(FnvHashSet::default()); + let listeners2 = listeners.reader(); + let external = Writer::new(vec![]); + let external2 = external.reader(); + let behaviour = + NetworkBackendBehaviour::new(&mut config, store, listeners, peers, external).await?; let tcp = { - let transport = TcpConfig::new().nodelay(true).port_reuse(config.port_reuse); + let transport = + TcpTransport::new(TcpConfig::new().nodelay(true).port_reuse(config.port_reuse)); let transport = if let Some(psk) = config.psk { let psk = PreSharedKey::new(psk); EitherTransport::Left( @@ -173,344 +236,583 @@ impl NetworkService

{ .unwrap(); */ - let swarm = Arc::new(Mutex::new(swarm)); - let swarm2 = swarm.clone(); - let waker = Arc::new(AtomicWaker::new()); - let waker2 = waker.clone(); - let swarm_task = executor.spawn(future::poll_fn(move |cx| { - waker.register(cx.waker()); - let mut swarm = swarm.lock(); - let mut count = 0; - loop { - count += 1; - if count > 20 { - cx.waker().wake_by_ref(); - return Poll::Pending; - } - - let event = match swarm.poll_next_unpin(cx) { - Poll::Ready(Some(e)) => e, - Poll::Ready(None) => return Poll::Ready(()), - Poll::Pending => return Poll::Pending, - }; - - if let SwarmEvent::ConnectionClosed { - peer_id, - endpoint, - num_established, - cause, - } = event - { - swarm.behaviour_mut().connection_closed( - peer_id, - endpoint, - num_established, - cause, - ); - }; - } - })); + let bootstrapped = Writer::new(false); + let bootstrapped2 = bootstrapped.reader(); + let (cmd_tx, cmd_rx) = mpsc::channel(100); + let swarm_task = executor.spawn(poll_swarm( + cmd_rx, + cmd_tx.clone(), + swarm, + executor.clone(), + bootstrapped, + )); Ok(Self { - swarm: swarm2, - waker: waker2, + bootstrapped: bootstrapped2, + peers: peers2, + listeners: listeners2, + external: external2, + public_key, + peer_id, + node_name, + cmd: cmd_tx, _swarm_task: Arc::new(swarm_task), }) } pub fn local_public_key(&self) -> PublicKey { - let swarm = self.swarm.lock(); - swarm.behaviour().local_public_key().clone() + self.public_key.clone() } pub fn local_peer_id(&self) -> PeerId { - let swarm = self.swarm.lock(); - *swarm.local_peer_id() + self.peer_id } pub fn local_node_name(&self) -> String { - let swarm = self.swarm.lock(); - swarm.behaviour().local_node_name().to_string() - } - - pub fn listen_on(&self, addr: Multiaddr) -> Result> { - let mut swarm = self.swarm.lock(); - let stream = swarm.behaviour_mut().swarm_events(); - let listener = swarm.listen_on(addr)?; - self.waker.wake(); - Ok(stream - .take_while(move |event| match event { - Event::ListenerClosed(id) if *id == listener => future::ready(false), - _ => future::ready(true), - }) - .filter_map(move |event| match event { - Event::NewListenAddr(id, addr) if id == listener => { - future::ready(Some(ListenerEvent::NewListenAddr(addr))) - } - Event::ExpiredListenAddr(id, addr) if id == listener => { - future::ready(Some(ListenerEvent::ExpiredListenAddr(addr))) - } - _ => future::ready(None), - })) + self.node_name.clone() + } + + fn cmd(&mut self, msg: NetworkCommand) -> Option<(NetworkCommand, &'static str)> { + match self.cmd.try_send(msg) { + Ok(_) => None, + Err(err) => { + let reason = if err.is_disconnected() { + "receiver went away" + } else { + "channel is full" + }; + let val = err.into_inner(); + tracing::warn!("failed IPFS swarm command {:?}: {}", val, reason); + Some((val, reason)) + } + } + } + + fn cmd_shared(&self, msg: NetworkCommand) -> Option<(NetworkCommand, &'static str)> { + match self.cmd.clone().try_send(msg) { + Ok(_) => None, + Err(err) => { + let reason = if err.is_disconnected() { + "receiver went away" + } else { + "channel is full" + }; + let val = err.into_inner(); + tracing::warn!("failed IPFS swarm command {:?}: {}", val, reason); + Some((val, reason)) + } + } + } + + pub fn listen_on(&mut self, addr: Multiaddr) -> impl Stream { + let (tx, rx) = mpsc::unbounded(); + if let Some((NetworkCommand::ListenOn(addr, tx), reason)) = + self.cmd(NetworkCommand::ListenOn(addr, tx)) + { + tx.unbounded_send(ListenerEvent::ListenFailed( + addr, + format!("cannot send to Swarm: {}", reason), + )) + .ok(); + } + rx } pub fn listeners(&self) -> Vec { - let swarm = self.swarm.lock(); - swarm.listeners().cloned().collect() + self.listeners.project(|l| l.iter().cloned().collect()) } - pub fn add_external_address(&self, mut addr: Multiaddr) { - crate::net::peers::normalize_addr(&mut addr, &self.local_peer_id()); - let mut swarm = self.swarm.lock(); - swarm.add_external_address(addr, AddressScore::Infinite); - self.waker.wake(); + pub fn add_external_address(&mut self, mut addr: Multiaddr) { + peers::normalize_addr(&mut addr, &self.local_peer_id()); + self.cmd(NetworkCommand::AddExternalAddress(addr)); } pub fn external_addresses(&self) -> Vec { - let swarm = self.swarm.lock(); - swarm.external_addresses().cloned().collect() + self.external.cloned() } - pub fn add_address(&self, peer: &PeerId, addr: Multiaddr) { - let mut swarm = self.swarm.lock(); - swarm - .behaviour_mut() - .add_address(peer, addr, AddressSource::User); - self.waker.wake(); + pub fn add_address(&mut self, peer: PeerId, addr: Multiaddr) { + self.cmd(NetworkCommand::AddAddress(peer, addr)); } - pub fn remove_address(&self, peer: &PeerId, addr: &Multiaddr) { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().remove_address(peer, addr); - self.waker.wake(); + pub fn remove_address(&mut self, peer: PeerId, addr: Multiaddr) { + self.cmd(NetworkCommand::RemoveAddress(peer, addr)); } - pub fn prune_peers(&self, min_age: Duration) { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().prune_peers(min_age); + pub fn prune_peers(&mut self, min_age: Duration) { + self.cmd(NetworkCommand::PrunePeers(min_age)); } - pub fn dial(&self, peer: &PeerId) { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().dial(peer); - self.waker.wake(); + pub fn dial(&mut self, peer: PeerId) { + self.cmd(NetworkCommand::Dial(peer)); } - pub fn dial_address(&self, peer: &PeerId, addr: Multiaddr) { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().dial_address(peer, addr); - self.waker.wake(); + pub fn dial_address(&mut self, peer: PeerId, addr: Multiaddr) { + self.cmd(NetworkCommand::DialAddress(peer, addr)); } - pub fn ban(&self, peer: PeerId) { - let mut swarm = self.swarm.lock(); - swarm.ban_peer_id(peer); - self.waker.wake(); + pub fn ban(&mut self, peer: PeerId) { + self.cmd(NetworkCommand::Ban(peer)); } - pub fn unban(&self, peer: PeerId) { - let mut swarm = self.swarm.lock(); - swarm.unban_peer_id(peer); - self.waker.wake(); + pub fn unban(&mut self, peer: PeerId) { + self.cmd(NetworkCommand::Unban(peer)); } pub fn peers(&self) -> Vec { - let swarm = self.swarm.lock(); - swarm.behaviour().peers().copied().collect() + self.peers.project(|peers| peers.keys().copied().collect()) } pub fn connections(&self) -> Vec<(PeerId, Multiaddr, DateTime, Direction)> { - let swarm = self.swarm.lock(); - swarm - .behaviour() - .connections() - .map(|(peer_id, addr, dt, dir)| (peer_id, addr.clone(), dt, dir)) - .collect() + self.peers.project(|peers| { + peers + .iter() + .flat_map(|(peer, info)| { + info.connections + .iter() + .map(move |(a, t)| (*peer, a.clone(), t.0, t.1)) + }) + .collect() + }) } pub fn is_connected(&self, peer: &PeerId) -> bool { - let swarm = self.swarm.lock(); - swarm.behaviour().is_connected(peer) + *peer == self.local_peer_id() + || self.peers.project(|peers| { + peers + .get(peer) + .map(|info| !info.connections.is_empty()) + .unwrap_or(false) + }) } pub fn peer_info(&self, peer: &PeerId) -> Option { - let swarm = self.swarm.lock(); - swarm.behaviour().info(peer).cloned() + self.peers.project(|peers| peers.get(peer).cloned()) } - pub async fn bootstrap(&self, peers: &[(PeerId, Multiaddr)]) -> Result<()> { - for (peer, addr) in peers { - self.add_address(peer, addr.clone()); - self.dial(peer); + pub fn bootstrap( + &mut self, + peers: Vec<(PeerId, Multiaddr)>, + ) -> impl Future> { + let (tx, rx) = oneshot::channel(); + if let Some((_, err)) = self.cmd(NetworkCommand::Bootstrap(peers, tx)) { + return future::ready(Err(anyhow!("{}", err))).left_future(); } - let rx = { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().bootstrap() - }; - tracing::trace!("started bootstrap"); - rx.await??; - tracing::trace!("boostrap complete"); - Ok(()) + tracing::debug!("started bootstrap"); + async { + rx.await??; + tracing::debug!("boostrap complete"); + Ok(()) + } + .right_future() } pub fn is_bootstrapped(&self) -> bool { - let swarm = self.swarm.lock(); - swarm.behaviour().is_bootstrapped() - } - - pub async fn get_closest_peers(&self, key: K) -> Result> - where - K: Into> + Into> + Clone, - { - let rx = { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().get_closest_peers(key) - }; - Ok(rx.await??) + self.bootstrapped.get() + } + + // This weird function signature seems impossible to support. WTF. + // pub async fn get_closest_peers(&self, key: K) -> Result> + // where + // K: Into> + Into> + Clone, + // { + // let rx = { + // let mut swarm = self.swarm.lock(); + // swarm.behaviour_mut().get_closest_peers(key) + // }; + // Ok(rx.await??) + // } + + pub fn providers(&mut self, key: Key) -> impl Future>> { + let (tx, rx) = oneshot::channel(); + if let Some((_, err)) = self.cmd(NetworkCommand::Providers(key, tx)) { + return future::ready(Err(anyhow!("{}", err))).left_future(); + } + async { rx.await? }.right_future() } - pub async fn providers(&self, key: Key) -> Result> { - let rx = { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().providers(key) - }; - Ok(rx.await??) + pub fn provide(&mut self, key: Key) -> impl Future> { + let (tx, rx) = oneshot::channel(); + if let Some((_, err)) = self.cmd(NetworkCommand::Provide(key, tx)) { + return future::ready(Err(anyhow!("{}", err))).left_future(); + } + async { rx.await? }.right_future() } - pub async fn provide(&self, key: Key) -> Result<()> { - let rx = { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().provide(key) - }; - Ok(rx.await??) + pub fn unprovide(&mut self, key: Key) -> Result<()> { + if let Some((_, err)) = self.cmd(NetworkCommand::Unprovide(key)) { + return Err(anyhow!("{}", err)); + } + Ok(()) } - pub fn unprovide(&self, key: &Key) { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().unprovide(key); - self.waker.wake(); + pub fn get_record( + &mut self, + key: Key, + quorum: Quorum, + ) -> impl Future>> { + let (tx, rx) = oneshot::channel(); + if let Some((_, err)) = self.cmd(NetworkCommand::GetRecord(key, quorum, tx)) { + return future::ready(Err(anyhow!("{}", err))).left_future(); + } + async { rx.await? }.right_future() } - pub async fn get_record(&self, key: Key, quorum: Quorum) -> Result> { - let rx = { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().get_record(key, quorum) - }; - Ok(rx.await??) + pub fn put_record( + &mut self, + record: Record, + quorum: Quorum, + ) -> impl Future> { + let (tx, rx) = oneshot::channel(); + if let Some((_, err)) = self.cmd(NetworkCommand::PutRecord(record, quorum, tx)) { + return future::ready(Err(anyhow!("{}", err))).left_future(); + } + async { rx.await? }.right_future() } - pub async fn put_record(&self, record: Record, quorum: Quorum) -> Result<()> { - let rx = { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().put_record(record, quorum) - }; - rx.await??; + pub fn remove_record(&mut self, key: Key) -> Result<()> { + if let Some((_, err)) = self.cmd(NetworkCommand::RemoveRecord(key)) { + return Err(anyhow!("{}", err)); + } Ok(()) } - pub fn remove_record(&self, key: &Key) { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().remove_record(key); - self.waker.wake(); - } - - pub fn subscribe(&self, topic: &str) -> Result> { - let mut swarm = self.swarm.lock(); - let stream = swarm.behaviour_mut().subscribe(topic)?; - self.waker.wake(); - Ok(stream) + pub fn subscribe( + &mut self, + topic: String, + ) -> impl Future>> { + let (tx, rx) = oneshot::channel(); + if let Some((_, err)) = self.cmd(NetworkCommand::Subscribe(topic, tx)) { + return future::ready(Err(anyhow!("{}", err))).left_future(); + } + async { rx.await? }.right_future() } - pub fn publish(&self, topic: &str, msg: Vec) -> Result<()> { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().publish(topic, msg)?; - self.waker.wake(); - Ok(()) + pub fn publish(&mut self, topic: String, msg: Vec) -> impl Future> { + let (tx, rx) = oneshot::channel(); + if let Some((_, err)) = self.cmd(NetworkCommand::Publish(topic, msg, tx)) { + return future::ready(Err(anyhow!("{}", err))).left_future(); + } + async { rx.await? }.right_future() } - pub fn broadcast(&self, topic: &str, msg: Vec) -> Result<()> { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().broadcast(topic, msg)?; - self.waker.wake(); - Ok(()) + pub fn broadcast(&mut self, topic: String, msg: Vec) -> impl Future> { + let (tx, rx) = oneshot::channel(); + if let Some((_, err)) = self.cmd(NetworkCommand::Broadcast(topic, msg, tx)) { + return future::ready(Err(anyhow!("{}", err))).left_future(); + } + async { rx.await? }.right_future() } - pub fn get(&self, cid: Cid, providers: impl Iterator) -> GetQuery

{ - let mut swarm = self.swarm.lock(); - let (rx, id) = swarm.behaviour_mut().get(cid, providers); - self.waker.wake(); - GetQuery { - swarm: Some(self.swarm.clone()), - id, - rx, + pub fn get(&self, cid: Cid, providers: Vec) -> impl Future> { + let (tx, rx) = oneshot::channel(); + if let Some((_, err)) = self.cmd_shared(NetworkCommand::Get(cid, providers, tx)) { + return future::ready(Err(anyhow!("{}", err))).left_future(); } + async { Ok(rx.await?) }.right_future() } - pub fn sync(&self, cid: Cid, providers: Vec, missing: Vec) -> SyncQuery

{ + pub fn sync( + &self, + cid: Cid, + providers: Vec, + missing: Vec, + ) -> impl Future> { if missing.is_empty() { - return SyncQuery::ready(Ok(())); + return future::ready(Ok(SyncQuery::ready(Ok(())))).left_future(); } if providers.is_empty() { - return SyncQuery::ready(Err(BlockNotFound(missing[0]).into())); + return future::ready(Ok(SyncQuery::ready(Err(BlockNotFound(missing[0]).into())))) + .left_future(); } - let mut swarm = self.swarm.lock(); - let (rx, id) = swarm - .behaviour_mut() - .sync(cid, providers, missing.into_iter()); - self.waker.wake(); - drop(swarm); - SyncQuery { - swarm: Some(self.swarm.clone()), - id: Some(id), - rx, + let (tx, rx) = oneshot::channel(); + if let Some((_, err)) = self.cmd_shared(NetworkCommand::Sync(cid, providers, missing, tx)) { + return future::ready(Err(anyhow!("{}", err))).left_future(); } + async { Ok(rx.await?) }.right_future() } - pub fn register_metrics(&self, registry: &Registry) -> Result<()> { - let swarm = self.swarm.lock(); - swarm.behaviour().register_metrics(registry) + pub fn swarm_events(&mut self) -> impl Future> { + let (tx, rx) = oneshot::channel(); + if let Some((_, err)) = self.cmd(NetworkCommand::SwarmEvents(tx)) { + return future::ready(Err(anyhow!("{}", err))).left_future(); + } + async { Ok(rx.await?) }.right_future() } +} - pub fn swarm_events(&self) -> SwarmEvents { - let mut swarm = self.swarm.lock(); - swarm.behaviour_mut().swarm_events() +async fn poll_swarm( + mut cmd_rx: Receiver, + cmd_tx: Sender, + mut swarm: Swarm>, + executor: Executor, + bootstrapped: Writer, +) { + let mut subscriptions = + FnvHashMap::>>::default(); + let mut queries = FnvHashMap::::default(); + loop { + match future::select( + future::poll_fn(|cx| swarm.poll_next_unpin(cx)), + cmd_rx.next(), + ) + .await + { + Either::Left((None, _)) => { + tracing::debug!("poll_swarm: swarm stream ended, terminating"); + return; + } + Either::Left((Some(cmd), _)) => match cmd { + SwarmEvent::ConnectionClosed { + peer_id, + endpoint, + num_established, + cause, + } => swarm.behaviour_mut().connection_closed( + peer_id, + endpoint, + num_established, + cause, + ), + SwarmEvent::Behaviour(event) => { + let swarm = swarm.behaviour_mut(); + match event { + behaviour::NetworkBackendBehaviourEvent::Peers(e) => unreachable(e), + behaviour::NetworkBackendBehaviourEvent::Kad(e) => { + let mut bootstrap_complete = *bootstrapped.read(); + let bootstrap_old = bootstrap_complete; + swarm.inject_kad_event(e, &mut bootstrap_complete, &mut queries); + if bootstrap_complete != bootstrap_old { + *bootstrapped.write() = bootstrap_complete; + } + } + behaviour::NetworkBackendBehaviourEvent::Mdns(e) => { + swarm.inject_mdns_event(e); + } + behaviour::NetworkBackendBehaviourEvent::Ping(e) => { + swarm.inject_ping_event(e); + } + behaviour::NetworkBackendBehaviourEvent::Identify(e) => { + swarm.inject_id_event(e); + } + behaviour::NetworkBackendBehaviourEvent::Bitswap(e) => { + swarm.inject_bitswap_event(e, &mut queries); + } + behaviour::NetworkBackendBehaviourEvent::Gossipsub(e) => { + swarm.inject_gossip_event(e, &mut subscriptions); + } + behaviour::NetworkBackendBehaviourEvent::Broadcast(e) => { + swarm.inject_broadcast_event(e, &mut subscriptions); + } + } + } + _ => {} + }, + Either::Right((None, _)) => { + tracing::debug!("poll_swarm: command sender dropped, terminating"); + return; + } + Either::Right((Some(cmd), _)) => match cmd { + NetworkCommand::ListenOn(addr, response) => { + let (tx, rx) = mpsc::unbounded(); + swarm.behaviour_mut().swarm_events(tx); + match swarm.listen_on(addr.clone()) { + Ok(listener) => executor + .spawn( + rx.take_while(move |event| match event { + Event::ListenerClosed(id) if *id == listener => { + future::ready(false) + } + Event::NewListenAddr(id, addr) if *id == listener => { + future::ready( + response + .unbounded_send(ListenerEvent::NewListenAddr( + addr.clone(), + )) + .is_ok(), + ) + } + Event::ExpiredListenAddr(id, addr) if *id == listener => { + future::ready( + response + .unbounded_send(ListenerEvent::ExpiredListenAddr( + addr.clone(), + )) + .is_ok(), + ) + } + _ => future::ready(true), + }) + .for_each(|_| future::ready(())), + ) + .detach(), + Err(error) => { + response + .unbounded_send(ListenerEvent::ListenFailed( + addr, + error.to_string(), + )) + .ok(); + } + }; + } + NetworkCommand::AddExternalAddress(addr) => { + swarm.add_external_address(addr, AddressScore::Infinite); + } + NetworkCommand::AddAddress(peer, addr) => { + swarm + .behaviour_mut() + .add_address(&peer, addr, AddressSource::User); + } + NetworkCommand::RemoveAddress(peer, addr) => { + swarm.behaviour_mut().remove_address(&peer, &addr); + } + NetworkCommand::PrunePeers(min_age) => { + swarm.behaviour_mut().prune_peers(min_age); + } + NetworkCommand::Dial(peer) => { + swarm.behaviour_mut().dial(&peer); + } + NetworkCommand::DialAddress(peer, addr) => { + swarm.behaviour_mut().dial_address(&peer, addr); + } + NetworkCommand::Ban(peer) => { + swarm.ban_peer_id(peer); + } + NetworkCommand::Unban(peer) => { + swarm.unban_peer_id(peer); + } + NetworkCommand::Bootstrap(initial, tx) => { + let swarm = swarm.behaviour_mut(); + for (peer, addr) in initial { + swarm.add_address(&peer, addr.clone(), AddressSource::User); + swarm.dial(&peer); + } + swarm.bootstrap(&mut queries, tx); + } + NetworkCommand::Providers(key, tx) => { + let bootstrap_complete = *bootstrapped.read(); + swarm + .behaviour_mut() + .providers(key, bootstrap_complete, &mut queries, tx); + } + NetworkCommand::Provide(key, tx) => { + let bootstrap_complete = *bootstrapped.read(); + swarm + .behaviour_mut() + .provide(key, bootstrap_complete, &mut queries, tx); + } + NetworkCommand::Unprovide(key) => { + swarm.behaviour_mut().unprovide(&key); + } + NetworkCommand::GetRecord(key, quorum, tx) => { + let bootstrap_complete = *bootstrapped.read(); + swarm.behaviour_mut().get_record( + key, + quorum, + bootstrap_complete, + &mut queries, + tx, + ); + } + NetworkCommand::PutRecord(record, quorum, tx) => { + let bootstrap_complete = *bootstrapped.read(); + swarm.behaviour_mut().put_record( + record, + quorum, + bootstrap_complete, + &mut queries, + tx, + ); + } + NetworkCommand::RemoveRecord(key) => { + swarm.behaviour_mut().remove_record(&key); + } + NetworkCommand::Subscribe(topic, tx) => { + tx.send(swarm.behaviour_mut().subscribe(&*topic, &mut subscriptions)) + .ok(); + } + NetworkCommand::Publish(topic, msg, tx) => { + tx.send(swarm.behaviour_mut().publish(&*topic, msg)).ok(); + } + NetworkCommand::Broadcast(topic, msg, tx) => { + tx.send(swarm.behaviour_mut().broadcast(&*topic, msg)).ok(); + } + NetworkCommand::Get(cid, providers, tx) => { + let (rx, id) = + swarm + .behaviour_mut() + .get(cid, providers.into_iter(), &mut queries); + tx.send(GetQuery { + swarm: cmd_tx.clone(), + id, + rx, + }) + .ok(); + } + NetworkCommand::Sync(cid, providers, missing, tx) => { + let (rx, id) = swarm.behaviour_mut().sync( + cid, + providers, + missing.into_iter(), + &mut queries, + ); + tx.send(SyncQuery { + swarm: Some(cmd_tx.clone()), + id: Some(id), + rx, + }) + .ok(); + } + NetworkCommand::SwarmEvents(result) => { + let (tx, rx) = mpsc::unbounded(); + swarm.behaviour_mut().swarm_events(tx); + result.send(SwarmEvents::new(rx)).ok(); + } + NetworkCommand::CancelQuery(id) => { + swarm.behaviour_mut().cancel(id, &mut queries); + } + }, + } } } -pub struct GetQuery { - swarm: Option>>>>, +#[derive(Debug)] +pub struct GetQuery { + swarm: Sender, id: QueryId, rx: GetChannel, } -impl Future for GetQuery

{ +impl Future for GetQuery { type Output = Result<()>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { match Pin::new(&mut self.rx).poll(cx) { Poll::Ready(Ok(result)) => Poll::Ready(result), - Poll::Ready(Err(err)) => Poll::Ready(Err(err.into())), + Poll::Ready(Err(err)) => Poll::Ready(Err(anyhow!("{}", err))), Poll::Pending => Poll::Pending, } } } -impl Drop for GetQuery

{ +impl Drop for GetQuery { fn drop(&mut self) { - let swarm = self.swarm.take().unwrap(); - let mut swarm = swarm.lock(); - swarm.behaviour_mut().cancel(self.id); + if let Err(err) = self.swarm.try_send(NetworkCommand::CancelQuery(self.id)) { + tracing::warn!("cannot cancel dropped GetQuery: {}", err.into_send_error()); + } } } /// A `bitswap` sync query. -pub struct SyncQuery { - swarm: Option>>>>, +#[derive(Debug)] +pub struct SyncQuery { + swarm: Option>, id: Option, rx: SyncChannel, } -impl SyncQuery

{ +impl SyncQuery { fn ready(res: Result<()>) -> Self { let (tx, rx) = mpsc::unbounded(); tx.unbounded_send(SyncEvent::Complete(res)).unwrap(); @@ -522,7 +824,7 @@ impl SyncQuery

{ } } -impl Future for SyncQuery

{ +impl Future for SyncQuery { type Output = Result<()>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { @@ -538,7 +840,7 @@ impl Future for SyncQuery

{ } } -impl Stream for SyncQuery

{ +impl Stream for SyncQuery { type Item = SyncEvent; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { @@ -548,12 +850,13 @@ impl Stream for SyncQuery

{ } } -impl Drop for SyncQuery

{ +impl Drop for SyncQuery { fn drop(&mut self) { if let Some(id) = self.id.take() { - let swarm = self.swarm.take().unwrap(); - let mut swarm = swarm.lock(); - swarm.behaviour_mut().cancel(id); + let swarm = self.swarm.as_mut().unwrap(); + if let Err(err) = swarm.try_send(NetworkCommand::CancelQuery(id)) { + tracing::warn!("cannot cancel dropped SyncQuery: {}", err.into_send_error()); + } } } } diff --git a/src/net/peers.rs b/src/net/peers.rs index 10ebbfd..85f439b 100644 --- a/src/net/peers.rs +++ b/src/net/peers.rs @@ -3,12 +3,12 @@ use super::{ behaviour::MyHandlerError, peer_info::{AddressSource, Direction, PeerInfo}, }; -use crate::net::peer_info::ConnectionFailure; +use crate::{net::peer_info::ConnectionFailure, variable::Writer}; use anyhow::Result; use chrono::{DateTime, Utc}; use fnv::{FnvHashMap, FnvHashSet}; use futures::{ - channel::mpsc, + channel::mpsc::{self, UnboundedSender}, future::BoxFuture, stream::{FuturesUnordered, Stream}, FutureExt, StreamExt, @@ -16,13 +16,16 @@ use futures::{ use futures_timer::Delay; use lazy_static::lazy_static; use libp2p::{ - core::connection::{ConnectedPoint, ConnectionId, ListenerId}, + core::{ + connection::{ConnectedPoint, ConnectionId}, + transport::ListenerId, + }, identify::IdentifyInfo, - identity::ed25519::PublicKey, multiaddr::Protocol, swarm::{ dial_opts::{DialOpts, PeerCondition}, - ConnectionError, DialError, NetworkBehaviour, NetworkBehaviourAction, PollParameters, + AddressRecord, ConnectionError, DialError, NetworkBehaviour, NetworkBehaviourAction, + PollParameters, }, Multiaddr, PeerId, }; @@ -186,11 +189,11 @@ impl MultiaddrExt for Multiaddr { pub struct AddressBook { port_reuse: bool, enable_loopback: bool, - local_node_name: String, local_peer_id: PeerId, - local_public_key: PublicKey, - listeners: FnvHashSet, - peers: FnvHashMap, + listeners: Writer>, + peers: Writer>, + external: Writer>, + refresh_external: bool, event_stream: Vec>, pub(crate) actions: VecDeque>, deferred: FuturesUnordered< @@ -201,33 +204,26 @@ pub struct AddressBook { impl AddressBook { pub fn new( local_peer_id: PeerId, - local_node_name: String, - local_public_key: PublicKey, port_reuse: bool, enable_loopback: bool, + listeners: Writer>, + peers: Writer>, + external: Writer>, ) -> Self { Self { port_reuse, enable_loopback, - local_node_name, local_peer_id, - local_public_key, - listeners: Default::default(), - peers: Default::default(), + listeners, + peers, + external, + refresh_external: true, event_stream: Default::default(), actions: Default::default(), deferred: Default::default(), } } - pub fn local_public_key(&self) -> &PublicKey { - &self.local_public_key - } - - pub fn local_node_name(&self) -> &str { - &self.local_node_name - } - pub fn local_peer_id(&self) -> &PeerId { &self.local_peer_id } @@ -251,12 +247,14 @@ impl AddressBook { return; } let target = normalize_addr_ref(&addr, peer); - if let Some(info) = self.peers.get(peer) { - if info.connections.contains_key(target.as_ref()) { - tracing::debug!(peer = %peer, addr = %&addr, + let mut peers = self.peers.write(); + let info = peers.entry(*peer).or_default(); + if info.connections.contains_key(target.as_ref()) { + tracing::debug!(peer = %peer, addr = %&addr, "skipping dial since already connected"); - } + return; } + drop(peers); tracing::debug!(peer = %peer, addr = %&addr, "request dialing"); let handler = IntoAddressHandler(Some((target.into_owned(), SIM_OPEN_RETRIES + 1))); self.actions.push_back(NetworkBehaviourAction::Dial { @@ -274,6 +272,7 @@ impl AddressBook { } let discovered = self .peers + .read() .get(peer) .filter(|info| info.confirmed_addresses().next().is_some()) .is_none(); @@ -285,13 +284,16 @@ impl AddressBook { } Cow::Owned(a) => a, }; - if !self.listeners.contains(&address) { + let is_listener = self.listeners.read().contains(&address); + if !is_listener { // addr_full is with peerId, address is guaranteed without tracing::debug!(peer = %peer, "adding address {} from {:?}", address, source); - let info = self.peers.entry(*peer).or_default(); - if info.ingest_address(addr_full.clone(), source) - && !info.connections.contains_key(&addr_full) - { + let mut peers = self.peers.write(); + let info = peers.entry(*peer).or_default(); + let result = info.ingest_address(addr_full.clone(), source) + && !info.connections.contains_key(&addr_full); + drop(peers); + if result { self.actions.push_back(NetworkBehaviourAction::Dial { opts: DialOpts::peer_id(*peer) .condition(PeerCondition::Always) @@ -311,7 +313,7 @@ impl AddressBook { } pub fn remove_address(&mut self, peer: &PeerId, address: &Multiaddr) { - if let Some(info) = self.peers.get_mut(peer) { + if let Some(info) = self.peers.write().get_mut(peer) { let address = normalize_addr_ref(address, peer); tracing::trace!("removing address {}", address); info.addresses.remove(&address); @@ -322,7 +324,7 @@ impl AddressBook { let _span = tracing::trace_span!("prune_peers").entered(); let now = Utc::now(); let mut remove = Vec::new(); - 'l: for (peer, info) in self.peers.iter() { + 'l: for (peer, info) in self.peers.read().iter() { if info.connections().next().is_some() { tracing::trace!(peer = %peer, "keeping connected"); continue; @@ -350,7 +352,7 @@ impl AddressBook { remove.push(*peer); } for peer in remove { - self.peers.remove(&peer); + self.peers.write().remove(&peer); self.notify(Event::NewInfo(peer)); } } @@ -395,7 +397,8 @@ impl AddressBook { reason ); - let entry = self.peers.entry(peer).or_default(); + let mut peers = self.peers.write(); + let entry = peers.entry(peer).or_default(); entry.connections.remove(addr); let addr_no_peer = without_peer_id(addr); let failure = if peer_closed { @@ -404,6 +407,8 @@ impl AddressBook { ConnectionFailure::us(addr_no_peer, reason, debug) }; entry.push_failure(addr, failure, false); + drop(peers); + self.notify(Event::ConnectionClosed(peer, conn)); if num_established == 0 { self.notify(Event::Disconnected(peer)); @@ -411,42 +416,29 @@ impl AddressBook { self.notify(Event::NewInfo(peer)); } - pub fn peers(&self) -> impl Iterator + '_ { - self.peers.keys() - } - - pub fn connections( - &self, - ) -> impl Iterator, Direction)> { - self.peers.iter().flat_map(|(peer, info)| { - info.connections - .iter() - .map(move |(a, t)| (*peer, a, t.0, t.1)) - }) - } - - pub fn is_connected(&self, peer: &PeerId) -> bool { - self.peers - .get(peer) - .map(|info| !info.connections.is_empty()) - .unwrap_or(false) - || peer == self.local_peer_id() + #[cfg(test)] + pub fn peers(&self) -> Vec { + self.peers.read().keys().copied().collect() } - pub fn info(&self, peer_id: &PeerId) -> Option<&PeerInfo> { - self.peers.get(peer_id) + #[cfg(test)] + pub fn info(&self, peer_id: &PeerId) -> Option { + self.peers.read().get(peer_id).cloned() } pub fn set_rtt(&mut self, peer_id: &PeerId, rtt: Option) { - if let Some(info) = self.peers.get_mut(peer_id) { + let mut peers = self.peers.write(); + if let Some(info) = peers.get_mut(peer_id) { info.set_rtt(rtt); + drop(peers); self.notify(Event::NewInfo(*peer_id)); } } pub fn set_info(&mut self, peer_id: &PeerId, identify: IdentifyInfo) { let _span = tracing::trace_span!("set_info", peer = %peer_id).entered(); - if let Some(info) = self.peers.get_mut(peer_id) { + let mut peers = self.peers.write(); + if let Some(info) = peers.get_mut(peer_id) { info.protocol_version = Some(identify.protocol_version); info.agent_version = Some(identify.agent_version); info.protocols = identify.protocols; @@ -522,7 +514,7 @@ impl AddressBook { for addr in translated { let mut tcp = addr.clone(); tcp.pop(); - if self.listeners.contains(&tcp) { + if self.listeners.read().contains(&tcp) { // diallling our own listener somehow breaks the Swarm tracing::trace!("not adding self-addr {}", tcp); continue; @@ -549,14 +541,13 @@ impl AddressBook { } } } + drop(peers); self.notify(Event::NewInfo(*peer_id)); } } - pub fn swarm_events(&mut self) -> SwarmEvents { - let (tx, rx) = mpsc::unbounded(); + pub fn swarm_events(&mut self, tx: UnboundedSender) { self.event_stream.push(tx); - SwarmEvents(rx) } pub fn notify(&mut self, event: Event) { @@ -564,19 +555,19 @@ impl AddressBook { self.event_stream .retain(|tx| tx.unbounded_send(event.clone()).is_ok()); } +} - pub fn register_metrics(&self, registry: &Registry) -> Result<()> { - registry.register(Box::new(LISTENERS.clone()))?; - registry.register(Box::new(LISTEN_ADDRS.clone()))?; - registry.register(Box::new(EXTERNAL_ADDRS.clone()))?; - registry.register(Box::new(DISCOVERED.clone()))?; - registry.register(Box::new(CONNECTED.clone()))?; - registry.register(Box::new(CONNECTIONS.clone()))?; - registry.register(Box::new(LISTENER_ERROR.clone()))?; - registry.register(Box::new(ADDRESS_REACH_FAILURE.clone()))?; - registry.register(Box::new(DIAL_FAILURE.clone()))?; - Ok(()) - } +pub fn register_metrics(registry: &Registry) -> Result<()> { + registry.register(Box::new(LISTENERS.clone()))?; + registry.register(Box::new(LISTEN_ADDRS.clone()))?; + registry.register(Box::new(EXTERNAL_ADDRS.clone()))?; + registry.register(Box::new(DISCOVERED.clone()))?; + registry.register(Box::new(CONNECTED.clone()))?; + registry.register(Box::new(CONNECTIONS.clone()))?; + registry.register(Box::new(LISTENER_ERROR.clone()))?; + registry.register(Box::new(ADDRESS_REACH_FAILURE.clone()))?; + registry.register(Box::new(DIAL_FAILURE.clone()))?; + Ok(()) } fn ip_port(m: &Multiaddr) -> Option<(IpAddr, u16)> { @@ -600,8 +591,15 @@ fn diff_time(former: DateTime, latter: DateTime) -> Duration { .unwrap_or(Duration::ZERO) } +#[derive(Debug)] pub struct SwarmEvents(mpsc::UnboundedReceiver); +impl SwarmEvents { + pub fn new(channel: mpsc::UnboundedReceiver) -> Self { + Self(channel) + } +} + impl Stream for SwarmEvents { type Item = Event; @@ -619,7 +617,7 @@ impl NetworkBehaviour for AddressBook { } fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { - if let Some(info) = self.peers.get(peer_id) { + if let Some(info) = self.peers.read().get(peer_id) { info.confirmed_addresses().cloned().collect() } else { vec![] @@ -631,8 +629,12 @@ impl NetworkBehaviour for AddressBook { fn poll( &mut self, cx: &mut Context, - _params: &mut impl PollParameters, + params: &mut impl PollParameters, ) -> Poll> { + if self.refresh_external { + self.refresh_external = false; + *self.external.write() = params.external_addresses().collect(); + } if let Some(action) = self.actions.pop_front() { Poll::Ready(action) } else if !self.deferred.is_empty() { @@ -664,6 +666,7 @@ impl NetworkBehaviour for AddressBook { }; self.add_address(peer_id, address.clone(), src); self.peers + .write() .entry(*peer_id) .or_default() .connections @@ -697,11 +700,14 @@ impl NetworkBehaviour for AddressBook { AddressSource::Incoming }; self.add_address(peer_id, new_addr.clone(), src); - let entry = self.peers.entry(*peer_id).or_default(); + let mut peers = self.peers.write(); + let entry = peers.entry(*peer_id).or_default(); entry.connections.remove(old_addr); entry .connections .insert(new_addr.clone(), (Utc::now(), Direction::from(&new))); + drop(peers); + self.notify(Event::AddressChanged(*peer_id, old, new)); } @@ -717,7 +723,8 @@ impl NetworkBehaviour for AddressBook { tracing::debug!("dial failure without peer ID: {}", error); return; }; - if let Some(info) = self.peers.get_mut(&peer_id) { + let mut peer = self.peers.write(); + if let Some(info) = peer.get_mut(&peer_id) { if let IntoAddressHandler(Some((addr, retries))) = handler { // this was our own validation dial let transport = matches!(error, DialError::Transport(_)); @@ -753,6 +760,8 @@ impl NetworkBehaviour for AddressBook { self.deferred .push(Delay::new(delay).map(move |_| action).boxed()); } + drop(peer); + self.notify(Event::DialFailure(peer_id, addr, error)); self.notify(Event::NewInfo(peer_id)); } else if let DialError::Transport(v) = error { @@ -776,6 +785,7 @@ impl NetworkBehaviour for AddressBook { } events.push(Event::DialFailure(peer_id, addr.clone(), error)); } + drop(peer); for event in events { self.notify(event); } @@ -791,6 +801,7 @@ impl NetworkBehaviour for AddressBook { } else if let DialError::DialPeerConditionFalse(d) = error { tracing::trace!(peer = %peer_id, cond = ?d, "dial condition not satisfied"); } else { + drop(peer); tracing::debug!(peer = %peer_id, error = %error, "dial failure"); if !matches!(error, DialError::Banned | DialError::LocalPeerId) { self.notify(Event::Unreachable(peer_id)); @@ -809,15 +820,17 @@ impl NetworkBehaviour for AddressBook { fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { tracing::trace!("listener {:?}: new listen addr {}", id, addr); - LISTEN_ADDRS.inc(); - self.listeners.insert(addr.clone()); + if self.listeners.write().insert(addr.clone()) { + LISTEN_ADDRS.inc(); + } self.notify(Event::NewListenAddr(id, addr.clone())); } fn inject_expired_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { tracing::trace!("listener {:?}: expired listen addr {}", id, addr); - LISTEN_ADDRS.dec(); - self.listeners.remove(addr); + if self.listeners.write().remove(addr) { + LISTEN_ADDRS.dec(); + } self.notify(Event::ExpiredListenAddr(id, addr.clone())); } @@ -835,6 +848,7 @@ impl NetworkBehaviour for AddressBook { } fn inject_new_external_addr(&mut self, addr: &Multiaddr) { + self.refresh_external = true; let mut addr = addr.clone(); normalize_addr(&mut addr, self.local_peer_id()); tracing::trace!("new external addr {}", addr); @@ -843,6 +857,7 @@ impl NetworkBehaviour for AddressBook { } fn inject_expired_external_addr(&mut self, addr: &Multiaddr) { + self.refresh_external = true; let mut addr = addr.clone(); normalize_addr(&mut addr, self.local_peer_id()); tracing::trace!("expired external addr {}", addr); diff --git a/src/net/tests.rs b/src/net/tests.rs index 83d0347..0c284c6 100644 --- a/src/net/tests.rs +++ b/src/net/tests.rs @@ -10,7 +10,7 @@ use libp2p::{ swarm::{DialError, NetworkBehaviour, NetworkBehaviourAction}, TransportError, }; -use std::{cell::RefCell, io::ErrorKind}; +use std::{cell::RefCell, collections::HashMap, io::ErrorKind}; use tracing_subscriber::EnvFilter; use Event::*; @@ -46,14 +46,17 @@ fn test_dial_basic() { let mut book = AddressBook::new( PeerId::random(), - "".into(), - Keypair::generate().public(), false, false, + Writer::new(HashSet::default()), + Writer::new(HashMap::default()), + Writer::new(vec![]), ); let events = Default::default(); - let events = Events::new(book.swarm_events(), &events); + let (tx, rx) = mpsc::unbounded(); + book.swarm_events(tx); + let events = Events::new(SwarmEvents::new(rx), &events); let peer_a = PeerId::random(); let addr_1: Multiaddr = "/ip4/1.1.1.1/tcp/3333".parse().unwrap(); @@ -68,8 +71,8 @@ fn test_dial_basic() { assert_eq!(events.next(), vec!(Discovered(peer_a), NewInfo(peer_a))); book.add_address(&peer_a, addr_2.clone(), AddressSource::Incoming); assert_eq!(events.next(), vec!(NewInfo(peer_a))); - let peers = book.peers().collect::>(); - assert_eq!(peers, vec![&peer_a]); + let peers = book.peers(); + assert_eq!(peers, vec![peer_a]); book.inject_dial_failure( Some(peer_a), IntoAddressHandler(Some((addr_1.clone(), 3))), @@ -106,7 +109,7 @@ fn test_dial_basic() { NewInfo(peer_a) ) ); - assert_eq!(book.peers().next(), Some(&peer_a)); + assert_eq!(book.peers().into_iter().next(), Some(peer_a)); assert_eq!(dials(&mut book), vec![]); assert_eq!( @@ -204,13 +207,16 @@ fn from_docker_host() { let mut book = AddressBook::new( peer_a, - "name".to_owned(), - Keypair::generate().public(), false, false, + Writer::new(HashSet::default()), + Writer::new(HashMap::default()), + Writer::new(vec![]), ); let events = Default::default(); - let events = Events::new(book.swarm_events(), &events); + let (tx, rx) = mpsc::unbounded(); + book.swarm_events(tx); + let events = Events::new(SwarmEvents::new(rx), &events); let key_b = libp2p::identity::PublicKey::Ed25519(Keypair::generate().public()); let peer_b = PeerId::from(&key_b); @@ -324,13 +330,16 @@ fn from_docker_container() { let mut book = AddressBook::new( peer_a, - "name".to_owned(), - Keypair::generate().public(), false, false, + Writer::new(HashSet::default()), + Writer::new(HashMap::default()), + Writer::new(vec![]), ); let events = Default::default(); - let events = Events::new(book.swarm_events(), &events); + let (tx, rx) = mpsc::unbounded(); + book.swarm_events(tx); + let events = Events::new(SwarmEvents::new(rx), &events); let key_b = libp2p::identity::PublicKey::Ed25519(Keypair::generate().public()); let peer_b = PeerId::from(&key_b); diff --git a/src/variable.rs b/src/variable.rs new file mode 100644 index 0000000..761b720 --- /dev/null +++ b/src/variable.rs @@ -0,0 +1,62 @@ +use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use std::sync::Arc; + +struct Inner { + value: RwLock, +} + +/// Write-side of a variable with read capability to use as single source of truth +/// +/// Usage of [`read`] and [`write`] should be non-blocking so that readers can always +/// quickly access the latest value. +#[derive(Clone)] +pub struct Writer(Arc>); + +impl std::fmt::Debug for Writer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("Writer").finish() + } +} + +impl Writer { + pub fn new(value: T) -> Self { + Self(Arc::new(Inner { + value: RwLock::new(value), + })) + } + + pub fn write(&self) -> RwLockWriteGuard<'_, T> { + self.0.value.write() + } + + pub fn read(&self) -> RwLockReadGuard<'_, T> { + self.0.value.read() + } + + pub fn reader(&self) -> Reader { + Reader(self.0.clone()) + } +} + +/// Read-side of a variable, intentionally limited to avoid blocking the writer +#[derive(Clone)] +pub struct Reader(Arc>); + +impl Reader { + pub fn project(&self, f: impl Fn(&T) -> U) -> U { + let value = self.0.value.read(); + f(&*value) + } +} + +impl Reader { + pub fn get(&self) -> T { + *self.0.value.read() + } +} + +impl Reader { + pub fn cloned(&self) -> T { + self.0.value.read().clone() + } +} From 9a882d5353eb86876dd7ac8ad4c7299723e0cfb9 Mon Sep 17 00:00:00 2001 From: Roland Kuhn Date: Mon, 17 Oct 2022 12:07:25 +0200 Subject: [PATCH 2/4] fix warnings and cli features not updating the explicit dependency on multihash meant that 0.16.1 was used without the `blake3` feature, breaking the tests --- Cargo.lock | 156 ++++++++---------------------------------------- cli/Cargo.toml | 4 +- cli/src/main.rs | 55 ++++++++--------- src/db.rs | 32 +++++----- src/lib.rs | 8 +-- 5 files changed, 71 insertions(+), 184 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10683fd..a38405d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -610,23 +610,13 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" -[[package]] -name = "cached" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e2afe73808fbaac302e39c9754bfc3c4b4d0f99c9c240b9f4e4efc841ad1b74" -dependencies = [ - "hashbrown 0.9.1", - "once_cell", -] - [[package]] name = "cached" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af4dfac631a8e77b2f327f7852bb6172771f5279c4512efe79fad6067b37be3d" dependencies = [ - "hashbrown 0.11.2", + "hashbrown", "once_cell", ] @@ -687,17 +677,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "cid" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6b8976b33648136e969aafa6eb33d58ff0d301fa0b4e8d513db58fd32cd81aa" -dependencies = [ - "multibase", - "multihash 0.14.0", - "unsigned-varint", -] - [[package]] name = "cid" version = "0.8.3" @@ -706,7 +685,7 @@ checksum = "dd5d90881dc52bb7867dd4341dfe6836077370f879df51cee353daa74e035a13" dependencies = [ "core2", "multibase", - "multihash 0.16.1", + "multihash", "unsigned-varint", ] @@ -1395,10 +1374,10 @@ dependencies = [ "escargot", "futures", "ipfs-embed-cli", - "libipld 0.14.0", + "libipld", "libp2p", "maplit", - "multihash 0.16.1", + "multihash", "netsim-embed", "predicates", "rand 0.8.5", @@ -1408,12 +1387,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "hashbrown" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" - [[package]] name = "hashbrown" version = "0.11.2" @@ -1429,7 +1402,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" dependencies = [ - "hashbrown 0.11.2", + "hashbrown", ] [[package]] @@ -1596,7 +1569,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg", - "hashbrown 0.11.2", + "hashbrown", ] [[package]] @@ -1648,11 +1621,11 @@ dependencies = [ "futures-timer", "ipfs-sqlite-block-store", "lazy_static", - "libipld 0.14.0", + "libipld", "libp2p", "libp2p-bitswap", "libp2p-broadcast", - "multihash 0.16.1", + "multihash", "names", "parking_lot 0.11.2", "pin-project", @@ -1679,8 +1652,8 @@ dependencies = [ "chrono", "futures", "ipfs-embed", - "libipld 0.12.0", - "multihash 0.14.0", + "libipld", + "multihash", "parking_lot 0.11.2", "serde", "serde_json", @@ -1700,7 +1673,7 @@ dependencies = [ "fnv", "futures", "itertools", - "libipld 0.14.0", + "libipld", "parking_lot 0.11.2", "rusqlite", "tracing", @@ -1763,24 +1736,6 @@ version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" -[[package]] -name = "libipld" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373a32b8d77bf13d6d5552b068e55991cc26f6f43edae25409fec5f555494438" -dependencies = [ - "async-trait", - "cached 0.23.0", - "fnv", - "libipld-cbor 0.12.1", - "libipld-core 0.12.0", - "libipld-macro 0.12.0", - "log", - "multihash 0.14.0", - "parking_lot 0.11.2", - "thiserror", -] - [[package]] name = "libipld" version = "0.14.0" @@ -1788,30 +1743,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac9c3aa309c260aa2f174bac968901eddc546e9d85950c28eae6a7bec402f926" dependencies = [ "async-trait", - "cached 0.30.0", + "cached", "fnv", - "libipld-cbor 0.14.0", + "libipld-cbor", "libipld-cbor-derive", - "libipld-core 0.14.0", - "libipld-macro 0.14.0", + "libipld-core", + "libipld-macro", "libipld-pb", "log", - "multihash 0.16.1", + "multihash", "parking_lot 0.12.0", "thiserror", ] -[[package]] -name = "libipld-cbor" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51882ee3a6ebc8b770b507558b8bc993659d7e96e160fb796bc1fc7c290d74c4" -dependencies = [ - "byteorder", - "libipld-core 0.12.0", - "thiserror", -] - [[package]] name = "libipld-cbor" version = "0.14.0" @@ -1819,7 +1763,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dd1ab68c9d26f20c7d0dfea6eecbae8c00359875210001b33ca27d4a02f3d09" dependencies = [ "byteorder", - "libipld-core 0.14.0", + "libipld-core", "thiserror", ] @@ -1836,19 +1780,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "libipld-core" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29a8a4ac024d51f15cc7b71d888b51bf3ab5d26a502e3f48fc9df33d7fd02ac" -dependencies = [ - "anyhow", - "cid 0.7.0", - "multibase", - "multihash 0.14.0", - "thiserror", -] - [[package]] name = "libipld-core" version = "0.14.0" @@ -1856,29 +1787,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d44790246ec6b7314cba745992c23d479d018073e66d49ae40ae1b64e5dd8eb5" dependencies = [ "anyhow", - "cid 0.8.3", + "cid", "core2", "multibase", - "multihash 0.16.1", + "multihash", "thiserror", ] -[[package]] -name = "libipld-macro" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d553f07747f7cb5e62d15de5fb416bf0e22968b2ee685226e91faaffd43a464" -dependencies = [ - "libipld-core 0.12.0", -] - [[package]] name = "libipld-macro" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852c011562ae5059b67c3a917f9f5945af5a68df8e39ede4444fff33274d25e2" dependencies = [ - "libipld-core 0.14.0", + "libipld-core", ] [[package]] @@ -1887,7 +1809,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c003be513496578115256a1b4ac7b80d4ece2462c9869dfb736fd30d8bb1d1c0" dependencies = [ - "libipld-core 0.14.0", + "libipld-core", "prost 0.10.4", "prost-build 0.10.4", "thiserror", @@ -1938,7 +1860,7 @@ dependencies = [ "fnv", "futures", "lazy_static", - "libipld 0.14.0", + "libipld", "libp2p", "prometheus", "prost 0.9.0", @@ -1976,7 +1898,7 @@ dependencies = [ "lazy_static", "log", "multiaddr", - "multihash 0.16.1", + "multihash", "multistream-select", "parking_lot 0.12.0", "pin-project", @@ -2342,7 +2264,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb87f3080f6d1d69e8c564c0fcfde1d7aa8cc451ce40cae89479111f03bc0eb" dependencies = [ - "hashbrown 0.11.2", + "hashbrown", ] [[package]] @@ -2418,7 +2340,7 @@ dependencies = [ "bs58", "byteorder", "data-encoding", - "multihash 0.16.1", + "multihash", "percent-encoding", "serde", "static_assertions", @@ -2437,18 +2359,6 @@ dependencies = [ "data-encoding-macro", ] -[[package]] -name = "multihash" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "752a61cd890ff691b4411423d23816d5866dd5621e4d1c5687a53b94b5a979d8" -dependencies = [ - "blake3 0.3.8", - "generic-array", - "multihash-derive 0.7.2", - "unsigned-varint", -] - [[package]] name = "multihash" version = "0.16.1" @@ -2458,25 +2368,11 @@ dependencies = [ "blake3 1.3.1", "core2", "digest 0.10.3", - "multihash-derive 0.8.0", + "multihash-derive", "sha2 0.10.2", "unsigned-varint", ] -[[package]] -name = "multihash-derive" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "424f6e86263cd5294cbd7f1e95746b95aca0e0d66bff31e5a40d6baa87b4aa99" -dependencies = [ - "proc-macro-crate", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", - "synstructure", -] - [[package]] name = "multihash-derive" version = "0.8.0" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 8149053..66a4fa1 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -12,8 +12,8 @@ async-std = { version = "1.11.0", features = ["attributes"] } chrono = "0.4.19" futures = "0.3.24" ipfs-embed = { path = ".." } -libipld = { version = "0.12.0", default-features = false, features = ["dag-cbor"] } -multihash = { version = "0.14.0", default-features = false, features = ["blake3"] } +libipld = { version = "0.14.0", default-features = false, features = ["dag-cbor"] } +multihash = { version = "0.16.1", default-features = false, features = ["blake3"] } parking_lot = "0.11.2" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" diff --git a/cli/src/main.rs b/cli/src/main.rs index 763295a..6ac7d6e 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -113,41 +113,34 @@ async fn run() -> Result<()> { line.clear(); stdin.read_line(&mut line)?; #[allow(clippy::unit_arg)] - let result = match line.parse()? { - Command::AddAddress(peer, addr) => Ok(ipfs.lock().add_address(peer, addr)), - Command::Dial(peer) => Ok(ipfs.lock().dial(peer)), - Command::PrunePeers => Ok(ipfs.lock().prune_peers(Duration::ZERO)), - Command::Get(cid) => match ipfs.lock().get(&cid) { - Ok(block) => { - writeln!(stdout, "{}", Event::Block(block))?; - Ok(()) - } - Err(err) => Err(err), - }, - Command::Insert(block) => ipfs.lock().insert(block), - Command::Alias(alias, cid) => ipfs.lock().alias(&alias, cid.as_ref()), - Command::Flush => - { - #[allow(clippy::await_holding_lock)] - match ipfs.lock().flush().await { - Ok(_) => { - writeln!(stdout, "{}", Event::Flushed)?; - Ok(()) - } - Err(err) => Err(err), - } + let result = match line.parse() { + Ok(Command::AddAddress(peer, addr)) => Ok(ipfs.lock().add_address(peer, addr)), + Ok(Command::Dial(peer)) => Ok(ipfs.lock().dial(peer)), + Ok(Command::PrunePeers) => Ok(ipfs.lock().prune_peers(Duration::ZERO)), + Ok(Command::Get(cid)) => ipfs + .lock() + .get(&cid) + .map(|block| writeln!(stdout, "{}", Event::Block(block)).expect("print")), + Ok(Command::Insert(block)) => ipfs.lock().insert(block), + Ok(Command::Alias(alias, cid)) => ipfs.lock().alias(&alias, cid.as_ref()), + Ok(Command::Flush) => { + let f = ipfs + .lock() + .flush() + .inspect_ok(|_| writeln!(stdout, "{}", Event::Flushed).expect("print")); + f.await } - Command::Sync(cid) => { + Ok(Command::Sync(cid)) => { let providers = ipfs.lock().peers(); tracing::debug!("sync {} from {:?}", cid, providers); - match ipfs.lock().sync(&cid, providers).and_then(|f| f).await { - Ok(_) => { - writeln!(stdout, "{}", Event::Synced)?; - Ok(()) - } - Err(err) => Err(err), - } + let f = ipfs + .lock() + .sync(&cid, providers) + .and_then(|f| f) + .inspect_ok(|_| writeln!(stdout, "{}", Event::Synced).expect("print")); + f.await } + Err(err) => Err(err), }; if let Err(err) = result { eprintln!("main loop error (line = {}): {}", line, err); diff --git a/src/db.rs b/src/db.rs index a4a7206..0446e76 100644 --- a/src/db.rs +++ b/src/db.rs @@ -275,31 +275,29 @@ where self.rw("missing_blocks", |x| x.missing_blocks(cid)) } - pub async fn evict(&self) -> Result<()> { + pub fn evict(&self) -> impl Future> { let store = self.inner.store.clone(); let gc_min_blocks = self.inner.gc_min_blocks; let gc_target_duration = self.inner.gc_target_duration; - self.inner - .executor - .spawn_blocking(move || { - while !store - .lock() - .incremental_gc(gc_min_blocks, gc_target_duration)? - { - tracing::trace!("x"); - } - Ok(()) - }) - .await? - } - - pub async fn flush(&self) -> Result<()> { + let evict = self.inner.executor.spawn_blocking(move || { + while !store + .lock() + .incremental_gc(gc_min_blocks, gc_target_duration)? + { + tracing::trace!("x"); + } + Ok(()) + }); + async { evict.await? } + } + + pub fn flush(&self) -> impl Future> { let store = self.inner.store.clone(); let flush = self .inner .executor .spawn_blocking(move || store.lock().flush()); - Ok(observe_future("flush", flush).await??) + async { Ok(observe_future("flush", flush).await??) } } pub fn register_metrics(&self, registry: &Registry) -> Result<()> { diff --git a/src/lib.rs b/src/lib.rs index 4985fe3..8864cee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -385,8 +385,8 @@ where /// Manually runs garbage collection to completion. This is mainly useful /// for testing and administrative interfaces. During normal operation, /// the garbage collector automatically runs in the background. - pub async fn evict(&self) -> Result<()> { - self.storage.evict().await + pub fn evict(&self) -> impl Future> { + self.storage.evict() } pub fn sync( @@ -422,8 +422,8 @@ where /// Flushes the block store. After `flush` completes successfully it is /// guaranteed that all writes have been persisted to disk. - pub async fn flush(&self) -> Result<()> { - self.storage.flush().await + pub fn flush(&self) -> impl Future> { + self.storage.flush() } /// Perform a set of storage operations in a batch From 29873e167cef7ae3a93cdceb92bc5dcf1ad7f38a Mon Sep 17 00:00:00 2001 From: Roland Kuhn Date: Mon, 17 Oct 2022 17:39:13 +0200 Subject: [PATCH 3/4] fix wrong assumptions in some tests --- harness/src/bin/discover_nat.rs | 37 ++++++++++++++++--------- harness/src/bin/discover_nat_forward.rs | 27 +++++++++++++----- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/harness/src/bin/discover_nat.rs b/harness/src/bin/discover_nat.rs index ebf23fc..177dce1 100644 --- a/harness/src/bin/discover_nat.rs +++ b/harness/src/bin/discover_nat.rs @@ -110,8 +110,11 @@ fn main() -> anyhow::Result<()> { // we can’t attempt to dial while the connection exists i.addresses.get(&i.connections[0]).map(|s| s.as_str()) == Some("Candidate") - // can’t check for full hashmap equality since the state where only the - // Candidate is present may be lost to output race conditions + // can’t check for full hashmap equality since the state where only the + // Candidate is present may be lost to output race conditions + || i.addresses.is_empty() + // if consumer sent identify first, then the NAT address wasn’t known + // and only falsifiable listen addresses are left )) .then(|| ()) }) @@ -137,22 +140,30 @@ fn main() -> anyhow::Result<()> { .deadline(started, 30) .await .unwrap(); - m.drain_matching(|e| matches!(e, Event::DialFailure(p, ..) if p == peer)); + m.drain_matching(|e| matches!(e, Event::DialFailure(p, ..) | Event::Unreachable(p) if p == peer)); tracing::info!("provider {} saw close from {}", id, m_id); m.send(Command::Dial(*peer)); - m.select(|e| matches!(e, Event::DialFailure(p, ..) if p == peer).then(|| ())) + let alive = m + .select(|e| match e { + Event::DialFailure(p, ..) | Event::Unreachable(p) if p == peer => Some(true), + Event::PeerRemoved(p) if p == peer => Some(false), + _ => None, + }) .timeout(10) .await + .unwrap() .unwrap(); - m.send(Command::PrunePeers); - m.select(|e| { - // prune_peers will remove the peer when a failure happens while not - // connected - matches!(e, Event::PeerRemoved(p) if p == peer).then(|| ()) - }) - .timeout(10) - .await - .unwrap(); + if alive { + m.send(Command::PrunePeers); + m.select(|e| { + // prune_peers will remove the peer when a failure happens while not + // connected + matches!(e, Event::PeerRemoved(p) if p == peer).then(|| ()) + }) + .timeout(10) + .await + .unwrap(); + } tracing::info!("provider {} done with {}", id, m_id); } } diff --git a/harness/src/bin/discover_nat_forward.rs b/harness/src/bin/discover_nat_forward.rs index f0ba1d8..e2950f8 100644 --- a/harness/src/bin/discover_nat_forward.rs +++ b/harness/src/bin/discover_nat_forward.rs @@ -141,12 +141,12 @@ fn main() -> anyhow::Result<()> { Event::PeerInfo(p, i) if p == peer => Some(i.connections[0].clone()), _ => None }).timeout(1).await.unwrap().unwrap(); - tracing::info!("first address is {}", a_1); // the NAT may give us the correct port in a_1 already, so no second entry to // check let a_nat = a_1 .replace(1, |_| Some(Protocol::Tcp(30000))) .filter(|a| *m_id == m_nat && *a != a_1); + tracing::info!("first address is {}, a_nat={:?}", a_1, a_nat); m.select(|e| { matches!(e, Event::PeerInfo(p, i) if p == peer && ( // port_reuse unfortunately means that the NATed port is added to @@ -156,10 +156,13 @@ fn main() -> anyhow::Result<()> { a_nat.iter().all(|a_nat| { i.addresses.get(a_nat).map(|x| x.as_str()) == Some("Dial") })) + // if consumer sent identify first, then the NAT address wasn’t known + // and only falsifiable listen addresses are left + || i.addresses.is_empty() ) .then(|| ()) }) - .deadline(started, 5).await.unwrap(); + .deadline(started, 10).await.unwrap(); tracing::info!("provider {} identified {}", id, m_id); } m.drain(); @@ -190,11 +193,21 @@ fn main() -> anyhow::Result<()> { let m = sim.machine(*id); for (m_id, (peer, _addr)) in consumers.iter() { m.send(Command::Dial(*peer)); - m.select(|e| matches!(e, Event::DialFailure(p, ..) if p == peer).then(|| ())) - .timeout(10).await.unwrap(); - m.send(Command::PrunePeers); - m.select(|e| matches!(e, Event::PeerRemoved(p) if p == peer).then(|| ())) - .timeout(10).await.unwrap(); + let alive = m + .select(|e| match e { + Event::DialFailure(p, ..) | Event::Unreachable(p) if p == peer => Some(true), + Event::PeerRemoved(p) if p == peer => Some(false), + _ => None, + }) + .timeout(10) + .await + .unwrap() + .unwrap(); + if alive { + m.send(Command::PrunePeers); + m.select(|e| matches!(e, Event::PeerRemoved(p) if p == peer).then(|| ())) + .timeout(10).await.unwrap(); + } tracing::info!("provider {} done with {}", id, m_id); } } From 1b385e971465851fde9bc8a06d6c4bc98bff63ab Mon Sep 17 00:00:00 2001 From: Roland Kuhn Date: Tue, 18 Oct 2022 11:55:57 +0200 Subject: [PATCH 4/4] fixes after PR review --- Cargo.lock | 1 + Cargo.toml | 3 +- src/net/mod.rs | 94 +++++++++++++++++++++++-------------------------- src/variable.rs | 2 +- 4 files changed, 49 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a38405d..7c22843 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1905,6 +1905,7 @@ dependencies = [ "prost 0.11.0", "prost-build 0.11.1", "rand 0.8.5", + "ring", "rw-stream-sink", "sha2 0.10.2", "smallvec", diff --git a/Cargo.toml b/Cargo.toml index b78cf2e..63912e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,8 @@ description = "small embeddable ipfs implementation" repository = "https://github.com/ipfs-rust/ipfs-embed" [features] -default = ["async_global"] +default = ["async_global", "rsa"] +rsa = ["libp2p/rsa"] async_global = ["async-global-executor", "libp2p/tcp-async-io", "libp2p/dns-async-std", "libp2p/mdns-async-io"] tokio = ["tokio-crate", "libp2p/tcp-tokio", "libp2p/dns-tokio", "libp2p/mdns-tokio"] telemetry = ["tide", "async_global"] diff --git a/src/net/mod.rs b/src/net/mod.rs index 6eed941..47458f9 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -23,7 +23,7 @@ use chrono::{DateTime, Utc}; use fnv::{FnvHashMap, FnvHashSet}; use futures::{ channel::{ - mpsc::{self, Receiver, Sender, UnboundedReceiver, UnboundedSender}, + mpsc::{self, Receiver, Sender, TrySendError, UnboundedReceiver, UnboundedSender}, oneshot, }, future::{self, Either}, @@ -42,7 +42,7 @@ use libp2p::tcp::TokioTcpConfig as TcpConfig; use libp2p::{ core::{ either::EitherTransport, - transport::Transport, + transport::{ListenerId, Transport}, upgrade::{SelectUpgrade, Version}, }, identity::ed25519::PublicKey, @@ -273,23 +273,17 @@ impl NetworkService { } fn cmd(&mut self, msg: NetworkCommand) -> Option<(NetworkCommand, &'static str)> { - match self.cmd.try_send(msg) { - Ok(_) => None, - Err(err) => { - let reason = if err.is_disconnected() { - "receiver went away" - } else { - "channel is full" - }; - let val = err.into_inner(); - tracing::warn!("failed IPFS swarm command {:?}: {}", val, reason); - Some((val, reason)) - } - } + Self::handle_send_result(self.cmd.try_send(msg)) } fn cmd_shared(&self, msg: NetworkCommand) -> Option<(NetworkCommand, &'static str)> { - match self.cmd.clone().try_send(msg) { + Self::handle_send_result(self.cmd.clone().try_send(msg)) + } + + fn handle_send_result( + res: Result<(), TrySendError>, + ) -> Option<(NetworkCommand, &'static str)> { + match res { Ok(_) => None, Err(err) => { let reason = if err.is_disconnected() { @@ -328,7 +322,7 @@ impl NetworkService { } pub fn external_addresses(&self) -> Vec { - self.external.cloned() + self.external.get_cloned() } pub fn add_address(&mut self, peer: PeerId, addr: Multiaddr) { @@ -504,6 +498,7 @@ impl NetworkService { async { rx.await? }.right_future() } + // This cannot take `&mut self` due to trait constraints, so it needs to use the less efficient cmd_shared. pub fn get(&self, cid: Cid, providers: Vec) -> impl Future> { let (tx, rx) = oneshot::channel(); if let Some((_, err)) = self.cmd_shared(NetworkCommand::Get(cid, providers, tx)) { @@ -512,6 +507,7 @@ impl NetworkService { async { Ok(rx.await?) }.right_future() } + // This cannot take `&mut self` due to trait constraints, so it needs to use the less efficient cmd_shared. pub fn sync( &self, cid: Cid, @@ -581,6 +577,7 @@ async fn poll_swarm( behaviour::NetworkBackendBehaviourEvent::Kad(e) => { let mut bootstrap_complete = *bootstrapped.read(); let bootstrap_old = bootstrap_complete; + // DO NOT HOLD bootstrapped LOCK ACROSS ARBITRARY CODE swarm.inject_kad_event(e, &mut bootstrap_complete, &mut queries); if bootstrap_complete != bootstrap_old { *bootstrapped.write() = bootstrap_complete; @@ -618,33 +615,7 @@ async fn poll_swarm( swarm.behaviour_mut().swarm_events(tx); match swarm.listen_on(addr.clone()) { Ok(listener) => executor - .spawn( - rx.take_while(move |event| match event { - Event::ListenerClosed(id) if *id == listener => { - future::ready(false) - } - Event::NewListenAddr(id, addr) if *id == listener => { - future::ready( - response - .unbounded_send(ListenerEvent::NewListenAddr( - addr.clone(), - )) - .is_ok(), - ) - } - Event::ExpiredListenAddr(id, addr) if *id == listener => { - future::ready( - response - .unbounded_send(ListenerEvent::ExpiredListenAddr( - addr.clone(), - )) - .is_ok(), - ) - } - _ => future::ready(true), - }) - .for_each(|_| future::ready(())), - ) + .spawn(forward_listener_events(listener, response, rx)) .detach(), Err(error) => { response @@ -777,6 +748,28 @@ async fn poll_swarm( } } +fn forward_listener_events( + listener: ListenerId, + response: UnboundedSender, + rx: UnboundedReceiver, +) -> impl Future { + rx.take_while(move |event| match event { + Event::ListenerClosed(id) if *id == listener => future::ready(false), + Event::NewListenAddr(id, addr) if *id == listener => future::ready( + response + .unbounded_send(ListenerEvent::NewListenAddr(addr.clone())) + .is_ok(), + ), + Event::ExpiredListenAddr(id, addr) if *id == listener => future::ready( + response + .unbounded_send(ListenerEvent::ExpiredListenAddr(addr.clone())) + .is_ok(), + ), + _ => future::ready(true), + }) + .for_each(|_| future::ready(())) +} + #[derive(Debug)] pub struct GetQuery { swarm: Sender, @@ -790,7 +783,7 @@ impl Future for GetQuery { fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { match Pin::new(&mut self.rx).poll(cx) { Poll::Ready(Ok(result)) => Poll::Ready(result), - Poll::Ready(Err(err)) => Poll::Ready(Err(anyhow!("{}", err))), + Poll::Ready(Err(err)) => Poll::Ready(Err(err.into())), Poll::Pending => Poll::Pending, } } @@ -799,7 +792,9 @@ impl Future for GetQuery { impl Drop for GetQuery { fn drop(&mut self) { if let Err(err) = self.swarm.try_send(NetworkCommand::CancelQuery(self.id)) { - tracing::warn!("cannot cancel dropped GetQuery: {}", err.into_send_error()); + if !err.is_disconnected() { + tracing::warn!("cannot cancel dropped GetQuery: {}", err.into_send_error()); + } } } } @@ -852,10 +847,11 @@ impl Stream for SyncQuery { impl Drop for SyncQuery { fn drop(&mut self) { - if let Some(id) = self.id.take() { - let swarm = self.swarm.as_mut().unwrap(); + if let (Some(id), Some(mut swarm)) = (self.id.take(), self.swarm.take()) { if let Err(err) = swarm.try_send(NetworkCommand::CancelQuery(id)) { - tracing::warn!("cannot cancel dropped SyncQuery: {}", err.into_send_error()); + if !err.is_disconnected() { + tracing::warn!("cannot cancel dropped SyncQuery: {}", err.into_send_error()); + } } } } diff --git a/src/variable.rs b/src/variable.rs index 761b720..dadf615 100644 --- a/src/variable.rs +++ b/src/variable.rs @@ -56,7 +56,7 @@ impl Reader { } impl Reader { - pub fn cloned(&self) -> T { + pub fn get_cloned(&self) -> T { self.0.value.read().clone() } }