diff --git a/Cargo.lock b/Cargo.lock index 408849d69..a0a7eb93b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -196,45 +196,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" -[[package]] -name = "asn1-rs" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" -dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror", - "time", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure", -] - -[[package]] -name = "asn1-rs-impl" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "async-channel" version = "1.9.0" @@ -322,19 +283,6 @@ dependencies = [ "syn 2.0.60", ] -[[package]] -name = "asynchronous-codec" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057f2c32adbb2fc158e22fb38433c8e9bbf76b75a4732c7c0cbaf695fb65568" -dependencies = [ - "bytes", - "futures-sink", - "futures-util", - "memchr", - "pin-project-lite", -] - [[package]] name = "asynchronous-codec" version = "0.7.0" @@ -366,17 +314,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "attohttpc" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" -dependencies = [ - "http 0.2.12", - "log", - "url", -] - [[package]] name = "autocfg" version = "1.2.0" @@ -441,7 +378,7 @@ dependencies = [ "sha1", "sync_wrapper 1.0.1", "tokio", - "tokio-tungstenite", + "tokio-tungstenite 0.21.0", "tower", "tower-layer", "tower-service", @@ -499,18 +436,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -565,15 +490,6 @@ dependencies = [ "wyz", ] -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - [[package]] name = "blake3" version = "1.5.1" @@ -875,15 +791,6 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" -[[package]] -name = "core2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" -dependencies = [ - "memchr", -] - [[package]] name = "corosensei" version = "0.1.4" @@ -1092,7 +999,7 @@ version = "3.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" dependencies = [ - "nix 0.28.0", + "nix", "windows-sys 0.52.0", ] @@ -1107,7 +1014,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "socket2 0.5.6", + "socket2", "windows-sys 0.52.0", ] @@ -1126,34 +1033,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "curve25519-dalek" -version = "4.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "platforms", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - [[package]] name = "darling" version = "0.20.8" @@ -1208,26 +1087,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" -[[package]] -name = "data-encoding-macro" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20c01c06f5f429efdf2bae21eb67c28b3df3cf85b7dd2d8ef09c0838dac5d33e" -dependencies = [ - "data-encoding", - "data-encoding-macro-internal", -] - -[[package]] -name = "data-encoding-macro-internal" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0047d07f2c89b17dd631c80450d69841a6b5d7fb17278cbc43d7e4cfcf2576f3" -dependencies = [ - "data-encoding", - "syn 1.0.109", -] - [[package]] name = "delegate" version = "0.12.0" @@ -1250,20 +1109,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "der-parser" -version = "8.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] - [[package]] name = "deranged" version = "0.3.11" @@ -1329,17 +1174,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "displaydoc" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - [[package]] name = "dlv-list" version = "0.5.2" @@ -1355,37 +1189,6 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" -[[package]] -name = "dtoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core", - "serde", - "sha2", - "subtle", - "zeroize", -] - [[package]] name = "either" version = "1.11.0" @@ -1404,30 +1207,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "enum-as-inner" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "enum-as-inner" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.60", -] - [[package]] name = "enum-iterator" version = "0.7.0" @@ -1582,7 +1361,6 @@ dependencies = [ "futures", "glob", "http 1.1.0", - "libp2p-identity", "pico-args", "rand", "reqwest", @@ -1593,19 +1371,13 @@ dependencies = [ "tar", "thiserror", "tokio", - "tokio-tungstenite", + "tokio-tungstenite 0.21.0", "toml", "tracing", "tracing-subscriber", "xz2", ] -[[package]] -name = "fiat-crypto" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38793c55593b33412e3ae40c2c9781ffaa6f438f6f8c10f24e71846fbd7ae01e" - [[package]] name = "filetime" version = "0.2.23" @@ -1624,6 +1396,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +[[package]] +name = "flatbuffers" +version = "23.5.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dac53e22462d78c16d64a1cd22371b54cc3fe94aa15e7886a2fa6e5d1ab8640" +dependencies = [ + "bitflags 1.3.2", + "rustc_version", +] + [[package]] name = "flatbuffers" version = "24.3.25" @@ -1683,7 +1465,7 @@ dependencies = [ "anyhow", "arbitrary", "arc-swap", - "asynchronous-codec 0.7.0", + "asynchronous-codec", "axum 0.7.5", "bincode", "blake3", @@ -1702,13 +1484,11 @@ dependencies = [ "delegate", "directories", "either", - "flatbuffers", + "flatbuffers 24.3.25", "freenet-stdlib", "futures", "headers", "itertools", - "libp2p", - "libp2p-identity", "notify", "once_cell", "opentelemetry", @@ -1722,6 +1502,7 @@ dependencies = [ "redb", "reqwest", "rsa", + "semver", "serde", "serde_json", "serde_with", @@ -1733,13 +1514,13 @@ dependencies = [ "thiserror", "time", "tokio", - "tokio-tungstenite", + "tokio-tungstenite 0.21.0", "tower-http", "tracing", "tracing-opentelemetry", "tracing-subscriber", "ulid", - "unsigned-varint 0.8.0", + "unsigned-varint", "wasmer", "xz2", ] @@ -1763,7 +1544,7 @@ dependencies = [ "bs58", "byteorder", "chrono", - "flatbuffers", + "flatbuffers 23.5.26", "freenet-macros", "futures", "js-sys", @@ -1777,7 +1558,7 @@ dependencies = [ "serde_with", "thiserror", "tokio", - "tokio-tungstenite", + "tokio-tungstenite 0.20.1", "tracing", "tracing-subscriber", "wasm-bindgen", @@ -1815,16 +1596,6 @@ dependencies = [ "futures-util", ] -[[package]] -name = "futures-bounded" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b07bbbe7d7e78809544c6f718d875627addc73a7c3582447abc052cd3dc67e0" -dependencies = [ - "futures-timer", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.30" @@ -1850,7 +1621,6 @@ dependencies = [ "futures-core", "futures-task", "futures-util", - "num_cpus", ] [[package]] @@ -1906,16 +1676,6 @@ dependencies = [ "syn 2.0.60", ] -[[package]] -name = "futures-rustls" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd3cf68c183738046838e300353e4716c674dc5e56890de4826801a6622a28" -dependencies = [ - "futures-io", - "rustls", -] - [[package]] name = "futures-sink" version = "0.3.30" @@ -1928,12 +1688,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" - [[package]] name = "futures-util" version = "0.3.30" @@ -2167,17 +1921,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi", -] - [[package]] name = "http" version = "0.2.12" @@ -2269,7 +2012,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.6", + "socket2", "tokio", "tower-service", "tracing", @@ -2338,7 +2081,7 @@ dependencies = [ "http-body 1.0.0", "hyper 1.3.1", "pin-project-lite", - "socket2 0.5.6", + "socket2", "tokio", "tower", "tower-service", @@ -2356,7 +2099,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core", ] [[package]] @@ -2374,27 +2117,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.5.0" @@ -2405,54 +2127,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "if-addrs" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "if-watch" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" -dependencies = [ - "async-io", - "core-foundation", - "fnv", - "futures", - "if-addrs", - "ipnet", - "log", - "rtnetlink", - "system-configuration", - "tokio", - "windows", -] - -[[package]] -name = "igd-next" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064d90fec10d541084e7b39ead8875a5a80d9114a2b18791565253bae25f49e4" -dependencies = [ - "async-trait", - "attohttpc", - "bytes", - "futures", - "http 0.2.12", - "hyper 0.14.28", - "log", - "rand", - "tokio", - "url", - "xmltree", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -2520,20 +2194,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" [[package]] -name = "ipconfig" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" -dependencies = [ - "socket2 0.5.6", - "widestring", - "windows-sys 0.48.0", - "winreg 0.50.0", -] - -[[package]] -name = "ipnet" -version = "2.9.0" +name = "ipnet" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" @@ -2644,391 +2306,6 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" -[[package]] -name = "libp2p" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94495eb319a85b70a68b85e2389a95bb3555c71c49025b78c691a854a7e6464" -dependencies = [ - "bytes", - "either", - "futures", - "futures-timer", - "getrandom", - "instant", - "libp2p-allow-block-list", - "libp2p-autonat", - "libp2p-connection-limits", - "libp2p-core", - "libp2p-dns", - "libp2p-identify", - "libp2p-identity", - "libp2p-mdns", - "libp2p-metrics", - "libp2p-noise", - "libp2p-ping", - "libp2p-quic", - "libp2p-swarm", - "libp2p-tcp", - "libp2p-upnp", - "libp2p-yamux", - "multiaddr", - "pin-project", - "rw-stream-sink", - "thiserror", -] - -[[package]] -name = "libp2p-allow-block-list" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55b46558c5c0bf99d3e2a1a38fd54ff5476ca66dd1737b12466a1824dd219311" -dependencies = [ - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "void", -] - -[[package]] -name = "libp2p-autonat" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e907be08be5e4152317a79d310a6f501a1b5c02a81dcb065dc865475bbae9498" -dependencies = [ - "async-trait", - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-identity", - "libp2p-request-response", - "libp2p-swarm", - "log", - "quick-protobuf", - "rand", -] - -[[package]] -name = "libp2p-connection-limits" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f5107ad45cb20b2f6c3628c7b6014b996fcb13a88053f4569c872c6e30abf58" -dependencies = [ - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "void", -] - -[[package]] -name = "libp2p-core" -version = "0.40.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd44289ab25e4c9230d9246c475a22241e301b23e8f4061d3bdef304a1a99713" -dependencies = [ - "either", - "fnv", - "futures", - "futures-timer", - "instant", - "libp2p-identity", - "log", - "multiaddr", - "multihash", - "multistream-select", - "once_cell", - "parking_lot", - "pin-project", - "quick-protobuf", - "rand", - "rw-stream-sink", - "smallvec", - "thiserror", - "unsigned-varint 0.7.2", - "void", -] - -[[package]] -name = "libp2p-dns" -version = "0.40.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a18db73084b4da2871438f6239fef35190b05023de7656e877c18a00541a3b" -dependencies = [ - "async-trait", - "futures", - "libp2p-core", - "libp2p-identity", - "log", - "parking_lot", - "smallvec", - "trust-dns-resolver", -] - -[[package]] -name = "libp2p-identify" -version = "0.43.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a96638a0a176bec0a4bcaebc1afa8cf909b114477209d7456ade52c61cd9cd" -dependencies = [ - "asynchronous-codec 0.6.2", - "either", - "futures", - "futures-bounded", - "futures-timer", - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "log", - "lru", - "quick-protobuf", - "quick-protobuf-codec", - "smallvec", - "thiserror", - "void", -] - -[[package]] -name = "libp2p-identity" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999ec70441b2fb35355076726a6bc466c932e9bdc66f6a11c6c0aa17c7ab9be0" -dependencies = [ - "bs58", - "ed25519-dalek", - "hkdf", - "multihash", - "quick-protobuf", - "rand", - "sha2", - "thiserror", - "tracing", - "zeroize", -] - -[[package]] -name = "libp2p-mdns" -version = "0.44.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a2567c305232f5ef54185e9604579a894fd0674819402bb0ac0246da82f52a" -dependencies = [ - "data-encoding", - "futures", - "if-watch", - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "log", - "rand", - "smallvec", - "socket2 0.5.6", - "tokio", - "trust-dns-proto 0.22.0", - "void", -] - -[[package]] -name = "libp2p-metrics" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239ba7d28f8d0b5d77760dc6619c05c7e88e74ec8fbbe97f856f20a56745e620" -dependencies = [ - "instant", - "libp2p-core", - "libp2p-identify", - "libp2p-identity", - "libp2p-ping", - "libp2p-swarm", - "once_cell", - "prometheus-client", -] - -[[package]] -name = "libp2p-noise" -version = "0.43.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2eeec39ad3ad0677551907dd304b2f13f17208ccebe333bef194076cd2e8921" -dependencies = [ - "bytes", - "curve25519-dalek", - "futures", - "libp2p-core", - "libp2p-identity", - "log", - "multiaddr", - "multihash", - "once_cell", - "quick-protobuf", - "rand", - "sha2", - "snow", - "static_assertions", - "thiserror", - "x25519-dalek", - "zeroize", -] - -[[package]] -name = "libp2p-ping" -version = "0.43.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e702d75cd0827dfa15f8fd92d15b9932abe38d10d21f47c50438c71dd1b5dae3" -dependencies = [ - "either", - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "log", - "rand", - "void", -] - -[[package]] -name = "libp2p-quic" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "130d451d83f21b81eb7b35b360bc7972aeafb15177784adc56528db082e6b927" -dependencies = [ - "bytes", - "futures", - "futures-timer", - "if-watch", - "libp2p-core", - "libp2p-identity", - "libp2p-tls", - "log", - "parking_lot", - "quinn", - "rand", - "ring 0.16.20", - "rustls", - "socket2 0.5.6", - "thiserror", - "tokio", -] - -[[package]] -name = "libp2p-request-response" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e3b4d67870478db72bac87bfc260ee6641d0734e0e3e275798f089c3fecfd4" -dependencies = [ - "async-trait", - "futures", - "instant", - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "log", - "rand", - "smallvec", - "void", -] - -[[package]] -name = "libp2p-swarm" -version = "0.43.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "580189e0074af847df90e75ef54f3f30059aedda37ea5a1659e8b9fca05c0141" -dependencies = [ - "either", - "fnv", - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-identity", - "libp2p-swarm-derive", - "log", - "multistream-select", - "once_cell", - "rand", - "smallvec", - "tokio", - "void", -] - -[[package]] -name = "libp2p-swarm-derive" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4d5ec2a3df00c7836d7696c136274c9c59705bac69133253696a6c932cd1d74" -dependencies = [ - "heck 0.4.1", - "proc-macro-warning", - "proc-macro2", - "quote", - "syn 2.0.60", -] - -[[package]] -name = "libp2p-tcp" -version = "0.40.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b558dd40d1bcd1aaaed9de898e9ec6a436019ecc2420dd0016e712fbb61c5508" -dependencies = [ - "futures", - "futures-timer", - "if-watch", - "libc", - "libp2p-core", - "libp2p-identity", - "log", - "socket2 0.5.6", - "tokio", -] - -[[package]] -name = "libp2p-tls" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8218d1d5482b122ccae396bbf38abdcb283ecc96fa54760e1dfd251f0546ac61" -dependencies = [ - "futures", - "futures-rustls", - "libp2p-core", - "libp2p-identity", - "rcgen", - "ring 0.16.20", - "rustls", - "rustls-webpki", - "thiserror", - "x509-parser", - "yasna", -] - -[[package]] -name = "libp2p-upnp" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82775a47b34f10f787ad3e2a22e2c1541e6ebef4fe9f28f3ac553921554c94c1" -dependencies = [ - "futures", - "futures-timer", - "igd-next", - "libp2p-core", - "libp2p-swarm", - "log", - "tokio", - "void", -] - -[[package]] -name = "libp2p-yamux" -version = "0.44.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eedcb62824c4300efb9cfd4e2a6edaf3ca097b9e68b36dabe45a44469fd6a85" -dependencies = [ - "futures", - "libp2p-core", - "log", - "thiserror", - "yamux", -] - [[package]] name = "libredox" version = "0.1.3" @@ -3090,24 +2367,6 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" -[[package]] -name = "lru" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" -dependencies = [ - "hashbrown 0.14.3", -] - -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] - [[package]] name = "lzma-sys" version = "0.1.20" @@ -3137,12 +2396,6 @@ dependencies = [ "libc", ] -[[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" - [[package]] name = "matchers" version = "0.1.0" @@ -3152,12 +2405,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "matchit" version = "0.7.3" @@ -3266,60 +2513,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" -[[package]] -name = "multiaddr" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" -dependencies = [ - "arrayref", - "byteorder", - "data-encoding", - "libp2p-identity", - "multibase", - "multihash", - "percent-encoding", - "serde", - "static_assertions", - "unsigned-varint 0.7.2", - "url", -] - -[[package]] -name = "multibase" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" -dependencies = [ - "base-x", - "data-encoding", - "data-encoding-macro", -] - -[[package]] -name = "multihash" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" -dependencies = [ - "core2", - "unsigned-varint 0.7.2", -] - -[[package]] -name = "multistream-select" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" -dependencies = [ - "bytes", - "futures", - "log", - "pin-project", - "smallvec", - "unsigned-varint 0.7.2", -] - [[package]] name = "nalgebra" version = "0.29.0" @@ -3367,83 +2560,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "netlink-packet-core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" -dependencies = [ - "anyhow", - "byteorder", - "libc", - "netlink-packet-utils", -] - -[[package]] -name = "netlink-packet-route" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" -dependencies = [ - "anyhow", - "bitflags 1.3.2", - "byteorder", - "libc", - "netlink-packet-core", - "netlink-packet-utils", -] - -[[package]] -name = "netlink-packet-utils" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" -dependencies = [ - "anyhow", - "byteorder", - "paste", - "thiserror", -] - -[[package]] -name = "netlink-proto" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" -dependencies = [ - "bytes", - "futures", - "log", - "netlink-packet-core", - "netlink-sys", - "thiserror", - "tokio", -] - -[[package]] -name = "netlink-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" -dependencies = [ - "bytes", - "futures", - "libc", - "log", - "tokio", -] - -[[package]] -name = "nix" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", -] - [[package]] name = "nix" version = "0.28.0" @@ -3456,12 +2572,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nohash-hasher" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" - [[package]] name = "nom" version = "7.1.3" @@ -3501,17 +2611,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-bigint" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -3605,15 +2704,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "oid-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" -dependencies = [ - "asn1-rs", -] - [[package]] name = "once_cell" version = "1.19.0" @@ -3875,15 +2965,6 @@ dependencies = [ "serde", ] -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -4009,12 +3090,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "platforms" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" - [[package]] name = "polling" version = "2.8.0" @@ -4105,17 +3180,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-warning" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - [[package]] name = "proc-macro2" version = "1.0.81" @@ -4125,29 +3189,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prometheus-client" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c99afa9a01501019ac3a14d71d9f94050346f55ca471ce90c799a15c58f61e2" -dependencies = [ - "dtoa", - "itoa", - "parking_lot", - "prometheus-client-derive-encode", -] - -[[package]] -name = "prometheus-client-derive-encode" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - [[package]] name = "prost" version = "0.12.4" @@ -4191,82 +3232,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quick-protobuf" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" -dependencies = [ - "byteorder", -] - -[[package]] -name = "quick-protobuf-codec" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ededb1cd78531627244d51dd0c7139fbe736c7d57af0092a76f0ffb2f56e98" -dependencies = [ - "asynchronous-codec 0.6.2", - "bytes", - "quick-protobuf", - "thiserror", - "unsigned-varint 0.7.2", -] - -[[package]] -name = "quinn" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" -dependencies = [ - "bytes", - "futures-io", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "thiserror", - "tokio", - "tracing", -] - -[[package]] -name = "quinn-proto" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" -dependencies = [ - "bytes", - "rand", - "ring 0.16.20", - "rustc-hash", - "rustls", - "slab", - "thiserror", - "tinyvec", - "tracing", -] - -[[package]] -name = "quinn-udp" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" -dependencies = [ - "bytes", - "libc", - "socket2 0.5.6", - "tracing", - "windows-sys 0.48.0", -] - [[package]] name = "quote" version = "1.0.36" @@ -4339,25 +3304,13 @@ dependencies = [ ] [[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "rcgen" -version = "0.10.0" +name = "rayon-core" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "pem", - "ring 0.16.20", - "time", - "yasna", + "crossbeam-deque", + "crossbeam-utils", ] [[package]] @@ -4505,32 +3458,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg 0.52.0", -] - -[[package]] -name = "resolv-conf" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" -dependencies = [ - "hostname", - "quick-error", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", + "winreg", ] [[package]] @@ -4544,7 +3472,7 @@ dependencies = [ "getrandom", "libc", "spin 0.9.8", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.52.0", ] @@ -4611,21 +3539,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rtnetlink" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" -dependencies = [ - "futures", - "log", - "netlink-packet-route", - "netlink-proto", - "nix 0.24.3", - "thiserror", - "tokio", -] - [[package]] name = "rust-ini" version = "0.19.0" @@ -4642,12 +3555,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc_version" version = "0.4.0" @@ -4657,15 +3564,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rusticata-macros" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" -dependencies = [ - "nom", -] - [[package]] name = "rustix" version = "0.38.34" @@ -4685,8 +3583,7 @@ version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" dependencies = [ - "log", - "ring 0.17.8", + "ring", "rustls-webpki", "sct", ] @@ -4722,8 +3619,8 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] @@ -4732,17 +3629,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" -[[package]] -name = "rw-stream-sink" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" -dependencies = [ - "futures", - "pin-project", - "static_assertions", -] - [[package]] name = "ryu" version = "1.0.17" @@ -4788,8 +3674,8 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] @@ -5070,33 +3956,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "snow" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" -dependencies = [ - "aes-gcm", - "blake2", - "chacha20poly1305", - "curve25519-dalek", - "rand_core", - "ring 0.17.8", - "rustc_version", - "sha2", - "subtle", -] - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.6" @@ -5345,12 +4204,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "statrs" version = "0.16.0" @@ -5448,18 +4301,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - [[package]] name = "system-configuration" version = "0.5.1" @@ -5637,7 +4478,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.6", + "socket2", "tokio-macros", "windows-sys 0.48.0", ] @@ -5684,6 +4525,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.20.1", +] + [[package]] name = "tokio-tungstenite" version = "0.21.0" @@ -5693,7 +4546,7 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite", + "tungstenite 0.21.0", ] [[package]] @@ -5920,83 +4773,30 @@ dependencies = [ ] [[package]] -name = "trust-dns-proto" -version = "0.22.0" +name = "try-lock" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner 0.5.1", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.2.3", - "ipnet", - "lazy_static", - "rand", - "smallvec", - "socket2 0.4.10", - "thiserror", - "tinyvec", - "tokio", - "tracing", - "url", -] +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] -name = "trust-dns-proto" -version = "0.23.2" +name = "tungstenite" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3119112651c157f4488931a01e586aa459736e9d6046d3bd9105ffb69352d374" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ - "async-trait", - "cfg-if", + "byteorder", + "bytes", "data-encoding", - "enum-as-inner 0.6.0", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.4.0", - "ipnet", - "once_cell", + "http 0.2.12", + "httparse", + "log", "rand", - "smallvec", + "sha1", "thiserror", - "tinyvec", - "tokio", - "tracing", "url", + "utf-8", ] -[[package]] -name = "trust-dns-resolver" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a3e6c3aff1718b3c73e395d1f35202ba2ffa847c6a62eea0db8fb4cfe30be6" -dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lru-cache", - "once_cell", - "parking_lot", - "rand", - "resolv-conf", - "smallvec", - "thiserror", - "tokio", - "tracing", - "trust-dns-proto 0.23.2", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "tungstenite" version = "0.21.0" @@ -6082,12 +4882,6 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - [[package]] name = "unicode_categories" version = "0.1.1" @@ -6104,33 +4898,17 @@ dependencies = [ "subtle", ] -[[package]] -name = "unsigned-varint" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" -dependencies = [ - "asynchronous-codec 0.6.2", - "bytes", -] - [[package]] name = "unsigned-varint" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" dependencies = [ - "asynchronous-codec 0.7.0", + "asynchronous-codec", "bytes", "tokio-util", ] -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -6144,7 +4922,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna", "percent-encoding", ] @@ -6190,12 +4968,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - [[package]] name = "waker-fn" version = "1.1.1" @@ -6530,12 +5302,6 @@ dependencies = [ "safe_arch", ] -[[package]] -name = "widestring" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" - [[package]] name = "winapi" version = "0.3.9" @@ -6567,25 +5333,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" -dependencies = [ - "windows-core 0.51.1", - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-core" -version = "0.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-core" version = "0.52.0" @@ -6786,16 +5533,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "winreg" version = "0.52.0" @@ -6815,35 +5552,6 @@ dependencies = [ "tap", ] -[[package]] -name = "x25519-dalek" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" -dependencies = [ - "curve25519-dalek", - "rand_core", - "serde", - "zeroize", -] - -[[package]] -name = "x509-parser" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" -dependencies = [ - "asn1-rs", - "data-encoding", - "der-parser", - "lazy_static", - "nom", - "oid-registry", - "rusticata-macros", - "thiserror", - "time", -] - [[package]] name = "xattr" version = "1.3.1" @@ -6855,21 +5563,6 @@ dependencies = [ "rustix", ] -[[package]] -name = "xml-rs" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" - -[[package]] -name = "xmltree" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" -dependencies = [ - "xml-rs", -] - [[package]] name = "xxhash-rust" version = "0.8.10" @@ -6894,30 +5587,6 @@ dependencies = [ "linked-hash-map", ] -[[package]] -name = "yamux" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed0164ae619f2dc144909a9f082187ebb5893693d8c0196e8085283ccd4b776" -dependencies = [ - "futures", - "log", - "nohash-hasher", - "parking_lot", - "pin-project", - "rand", - "static_assertions", -] - -[[package]] -name = "yasna" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" -dependencies = [ - "time", -] - [[package]] name = "zerocopy" version = "0.7.32" @@ -6943,17 +5612,3 @@ name = "zeroize" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63381fa6624bf92130a6b87c0d07380116f80b565c42cf0d754136f0238359ef" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index feb6def1e..16ad68193 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -37,10 +37,9 @@ directories = "5" either = { features = ["serde"], workspace = true } flatbuffers = "24.3" futures = "0.3" +semver = { version = "1.0.14", features = ["serde"] } headers = "0.4" itertools = "0.12" -libp2p = { default-features = false, features = ["autonat", "dns", "ed25519", "identify", "macros", "noise", "ping", "tcp", "tokio", "yamux"], version = "0.52.3" } -libp2p-identity = { features = ["ed25519", "rand"], version = "0.2.7" } notify = "6" once_cell = "1" ordered-float = "4.2" diff --git a/crates/core/src/client_events.rs b/crates/core/src/client_events.rs index 6489eb87a..bea9bf9d4 100644 --- a/crates/core/src/client_events.rs +++ b/crates/core/src/client_events.rs @@ -266,7 +266,7 @@ pub(crate) mod test { async { loop { if self.signal.changed().await.is_ok() { - let (ev_id, pk) = *self.signal.borrow(); + let (ev_id, pk) = self.signal.borrow().clone(); if self.rng.is_some() && pk == self.id { let res = OpenRequest { client_id: ClientId::FIRST, diff --git a/crates/core/src/client_events/combinator.rs b/crates/core/src/client_events/combinator.rs index e679f4796..0430fab3b 100644 --- a/crates/core/src/client_events/combinator.rs +++ b/crates/core/src/client_events/combinator.rs @@ -60,10 +60,6 @@ impl super::ClientEventsProxy for ClientEventsCombinator { Box::pin(async { let mut futs_opt = [(); N].map(|_| None); let pend_futs = &mut self.pend_futs; - eprintln!( - "pending futs: {}", - pend_futs.iter().filter(|a| a.is_some()).count() - ); for (i, pend) in pend_futs.iter_mut().enumerate() { let fut = &mut futs_opt[i]; if let Some(pend_fut) = pend.take() { @@ -216,9 +212,7 @@ impl Future for SelectAll { let rest = std::mem::replace(&mut self.inner, [(); N].map(|_| None)); return Poll::Ready((res, idx, rest)); } - None => { - eprintln!("not found"); - } + None => {} } }; } diff --git a/crates/core/src/config.rs b/crates/core/src/config.rs index a6bdada66..e86d241b5 100644 --- a/crates/core/src/config.rs +++ b/crates/core/src/config.rs @@ -4,18 +4,16 @@ use std::{ io::Read, net::{IpAddr, Ipv4Addr, SocketAddr}, path::PathBuf, - pin::Pin, str::FromStr, sync::atomic::AtomicBool, time::Duration, }; use directories::ProjectDirs; -use libp2p::{identity, PeerId}; use once_cell::sync::Lazy; use tokio::runtime::Runtime; -use crate::local_node::OperationMode; +use crate::{local_node::OperationMode, transport::TransportKeypair}; /// Default maximum number of connections for the peer. pub const DEFAULT_MAX_CONNECTIONS: usize = 20; @@ -31,12 +29,10 @@ pub const DEFAULT_RANDOM_PEER_CONN_THRESHOLD: usize = 7; /// Default maximum number of hops to live for any operation /// (if it applies, e.g. connect requests). pub const DEFAULT_MAX_HOPS_TO_LIVE: usize = 10; -const DEFAULT_BOOTSTRAP_PORT: u16 = 7800; const DEFAULT_WEBSOCKET_API_PORT: u16 = 55008; static CONFIG: std::sync::OnceLock = std::sync::OnceLock::new(); -pub(crate) const PEER_TIMEOUT: Duration = Duration::from_secs(60); pub(crate) const OPERATION_TTL: Duration = Duration::from_secs(60); // Initialize the executor once. @@ -47,10 +43,7 @@ const ORGANIZATION: &str = "The Freenet Project Inc"; const APPLICATION: &str = "Freenet"; pub struct Config { - pub bootstrap_ip: IpAddr, - pub bootstrap_port: u16, - pub bootstrap_id: Option, - pub local_peer_keypair: identity::Keypair, + pub transport_keypair: TransportKeypair, pub log_level: tracing::log::LevelFilter, config_paths: ConfigPaths, local_mode: AtomicBool, @@ -221,12 +214,13 @@ impl Config { }) } - fn load_conf() -> std::io::Result { + fn load_conf() -> anyhow::Result { let settings: config::Config = config::Config::builder() .add_source(config::Environment::with_prefix("FREENET")) .build() .unwrap(); - let local_peer_keypair = if let Ok(path_to_key) = settings + + let transport_keypair: Option = if let Ok(path_to_key) = settings .get_string("local_peer_key_file") .map(PathBuf::from) { @@ -238,20 +232,17 @@ impl Config { }); let mut buf = Vec::new(); key_file.read_to_end(&mut buf).unwrap(); - Some( - identity::Keypair::from_protobuf_encoding(&buf) - .map_err(|_| std::io::ErrorKind::InvalidData)?, - ) + todo!("get an rsa private key from the file and create a TransportKeypair") } else { None }; + let log_level = settings .get_string("log") .map(|lvl| lvl.parse().ok()) .ok() .flatten() .unwrap_or(tracing::log::LevelFilter::Info); - let (bootstrap_ip, bootstrap_port, bootstrap_id) = Config::get_bootstrap_host(&settings)?; let data_dir = settings.get_string("data_dir").ok().map(PathBuf::from); let config_paths = ConfigPaths::new(data_dir)?; @@ -259,11 +250,7 @@ impl Config { let local_mode = settings.get_string("network_mode").is_err(); Ok(Config { - bootstrap_ip, - bootstrap_port, - bootstrap_id, - local_peer_keypair: local_peer_keypair - .unwrap_or_else(identity::Keypair::generate_ed25519), + transport_keypair: transport_keypair.unwrap_or_else(|| TransportKeypair::new()), log_level, config_paths, local_mode: AtomicBool::new(local_mode), @@ -271,36 +258,6 @@ impl Config { ws: WebSocketApiConfig::from_config(&settings), }) } - - fn get_bootstrap_host( - settings: &config::Config, - ) -> std::io::Result<(IpAddr, u16, Option)> { - let bootstrap_ip = IpAddr::from_str( - &settings - .get_string("bootstrap_host") - .unwrap_or_else(|_| format!("{}", Ipv4Addr::LOCALHOST)), - ) - .map_err(|_err| std::io::ErrorKind::InvalidInput)?; - - let bootstrap_port = settings - .get_int("bootstrap_port") - .ok() - .map(u16::try_from) - .unwrap_or(Ok(DEFAULT_BOOTSTRAP_PORT)) - .map_err(|_err| std::io::ErrorKind::InvalidInput)?; - - let id_str = if let Some(id_str) = settings - .get_string("bootstrap_id") - .ok() - .map(|id| id.parse().map_err(|_err| std::io::ErrorKind::InvalidInput)) - { - Some(id_str?) - } else { - None - }; - - Ok((bootstrap_ip, bootstrap_port, id_str)) - } } pub(crate) struct GlobalExecutor; @@ -335,12 +292,6 @@ impl GlobalExecutor { } } -impl libp2p::swarm::Executor for GlobalExecutor { - fn exec(&self, future: Pin + 'static + Send>>) { - GlobalExecutor::spawn(future); - } -} - pub fn set_logger(level: Option) { #[cfg(feature = "trace")] { diff --git a/crates/core/src/contract/executor/mock_runtime.rs b/crates/core/src/contract/executor/mock_runtime.rs index 7173214be..84406479b 100644 --- a/crates/core/src/contract/executor/mock_runtime.rs +++ b/crates/core/src/contract/executor/mock_runtime.rs @@ -15,9 +15,13 @@ impl Executor { std::fs::create_dir_all(&contracts_data_dir).expect("directory created"); let contract_store = ContractStore::new(contracts_data_dir, u16::MAX as i64)?; - let db_path = data_dir.join("db"); - std::fs::create_dir_all(&db_path).expect("directory created"); - let state_store = StateStore::new(Storage::new(&db_path).await?, u16::MAX as u32).unwrap(); + // FIXME: if is sqlite it should be a dir, named /db + // let db_path = data_dir.join("db"); + // let state_store = StateStore::new(Storage::new(&db_path).await?, u16::MAX as u32).unwrap(); + tracing::debug!("creating state store at path: {data_dir:?}"); + std::fs::create_dir_all(&data_dir).expect("directory created"); + let state_store = StateStore::new(Storage::new(&data_dir).await?, u16::MAX as u32).unwrap(); + tracing::debug!("state store created"); let executor = Executor::new( state_store, diff --git a/crates/core/src/contract/handler.rs b/crates/core/src/contract/handler.rs index b49ce1fbe..e4869a3dc 100644 --- a/crates/core/src/contract/handler.rs +++ b/crates/core/src/contract/handler.rs @@ -498,7 +498,7 @@ pub(super) mod in_memory { channel, runtime: Executor::new_mock(identifier, executor_request_sender) .await - .unwrap(), + .expect("should start mock executor"), } } } diff --git a/crates/core/src/contract/storages/redb.rs b/crates/core/src/contract/storages/redb.rs index fc67530f4..16d03c03e 100644 --- a/crates/core/src/contract/storages/redb.rs +++ b/crates/core/src/contract/storages/redb.rs @@ -12,9 +12,9 @@ const STATE_TABLE: TableDefinition<&[u8], &[u8]> = TableDefinition::new("state") pub struct ReDb(Database); impl ReDb { - pub async fn new(db_path: &Path) -> Result { + pub async fn new(data_dir: &Path) -> Result { + let db_path = data_dir.join("db"); tracing::info!("loading contract store from {db_path:?}"); - Database::create(db_path).map(Self).map_err(Into::into) } } diff --git a/crates/core/src/generated/mod.rs b/crates/core/src/generated/mod.rs index 52efedad5..ae2fa5753 100644 --- a/crates/core/src/generated/mod.rs +++ b/crates/core/src/generated/mod.rs @@ -134,10 +134,10 @@ impl PeerChange<'_> { connections: impl Iterator, ) -> Vec { let mut buf = flatbuffers::FlatBufferBuilder::new(); - let to = buf.create_string(to.to_string().as_str()); + let to = buf.create_vector(&bincode::serialize(&to).unwrap()); let connections = connections .map(|(from, from_location)| { - let from = Some(buf.create_string(from.to_string().as_str())); + let from = Some(buf.create_vector(&bincode::serialize(from).unwrap())); topology::AddedConnection::create( &mut buf, &topology::AddedConnectionArgs { @@ -169,16 +169,16 @@ impl PeerChange<'_> { (to, to_location): (PeerId, f64), ) -> Vec { let mut buf = flatbuffers::FlatBufferBuilder::new(); - let from = Some(buf.create_string(from.to_string().as_str())); - let to = Some(buf.create_string(to.to_string().as_str())); + let from = buf.create_vector(&bincode::serialize(&from).unwrap()); + let to = buf.create_vector(&bincode::serialize(&to).unwrap()); let transaction = transaction.map(|t| buf.create_string(t.as_ref())); let add_conn = topology::AddedConnection::create( &mut buf, &topology::AddedConnectionArgs { transaction, - from, + from: Some(from), from_location, - to, + to: Some(to), to_location, }, ); @@ -196,11 +196,14 @@ impl PeerChange<'_> { pub fn removed_connection_msg(at: PeerId, from: PeerId) -> Vec { let mut buf = flatbuffers::FlatBufferBuilder::new(); - let at = Some(buf.create_string(at.to_string().as_str())); - let from = Some(buf.create_string(from.to_string().as_str())); + let at = buf.create_vector(&bincode::serialize(&at).unwrap()); + let from = buf.create_vector(&bincode::serialize(&from).unwrap()); let remove_conn = topology::RemovedConnection::create( &mut buf, - &topology::RemovedConnectionArgs { at, from }, + &topology::RemovedConnectionArgs { + at: Some(at), + from: Some(from), + }, ); let msg = topology::PeerChange::create( &mut buf, diff --git a/crates/core/src/generated/topology_generated.rs b/crates/core/src/generated/topology_generated.rs index ecea1b1c7..a0ad83526 100644 --- a/crates/core/src/generated/topology_generated.rs +++ b/crates/core/src/generated/topology_generated.rs @@ -393,13 +393,16 @@ pub mod topology { } } #[inline] - pub fn from(&self) -> &'a str { + pub fn from(&self) -> flatbuffers::Vector<'a, u8> { // Safety: // Created from valid Table for this object // which contains a valid value in this slot unsafe { self._tab - .get::>(AddedConnection::VT_FROM, None) + .get::>>( + AddedConnection::VT_FROM, + None, + ) .unwrap() } } @@ -415,13 +418,16 @@ pub mod topology { } } #[inline] - pub fn to(&self) -> &'a str { + pub fn to(&self) -> flatbuffers::Vector<'a, u8> { // Safety: // Created from valid Table for this object // which contains a valid value in this slot unsafe { self._tab - .get::>(AddedConnection::VT_TO, None) + .get::>>( + AddedConnection::VT_TO, + None, + ) .unwrap() } } @@ -451,9 +457,17 @@ pub mod topology { Self::VT_TRANSACTION, false, )? - .visit_field::>("from", Self::VT_FROM, true)? + .visit_field::>>( + "from", + Self::VT_FROM, + true, + )? .visit_field::("from_location", Self::VT_FROM_LOCATION, false)? - .visit_field::>("to", Self::VT_TO, true)? + .visit_field::>>( + "to", + Self::VT_TO, + true, + )? .visit_field::("to_location", Self::VT_TO_LOCATION, false)? .finish(); Ok(()) @@ -461,9 +475,9 @@ pub mod topology { } pub struct AddedConnectionArgs<'a> { pub transaction: Option>, - pub from: Option>, + pub from: Option>>, pub from_location: f64, - pub to: Option>, + pub to: Option>>, pub to_location: f64, } impl<'a> Default for AddedConnectionArgs<'a> { @@ -492,7 +506,7 @@ pub mod topology { ); } #[inline] - pub fn add_from(&mut self, from: flatbuffers::WIPOffset<&'b str>) { + pub fn add_from(&mut self, from: flatbuffers::WIPOffset>) { self.fbb_ .push_slot_always::>(AddedConnection::VT_FROM, from); } @@ -502,7 +516,7 @@ pub mod topology { .push_slot::(AddedConnection::VT_FROM_LOCATION, from_location, 0.0); } #[inline] - pub fn add_to(&mut self, to: flatbuffers::WIPOffset<&'b str>) { + pub fn add_to(&mut self, to: flatbuffers::WIPOffset>) { self.fbb_ .push_slot_always::>(AddedConnection::VT_TO, to); } @@ -582,24 +596,30 @@ pub mod topology { } #[inline] - pub fn at(&self) -> &'a str { + pub fn at(&self) -> flatbuffers::Vector<'a, u8> { // Safety: // Created from valid Table for this object // which contains a valid value in this slot unsafe { self._tab - .get::>(RemovedConnection::VT_AT, None) + .get::>>( + RemovedConnection::VT_AT, + None, + ) .unwrap() } } #[inline] - pub fn from(&self) -> &'a str { + pub fn from(&self) -> flatbuffers::Vector<'a, u8> { // Safety: // Created from valid Table for this object // which contains a valid value in this slot unsafe { self._tab - .get::>(RemovedConnection::VT_FROM, None) + .get::>>( + RemovedConnection::VT_FROM, + None, + ) .unwrap() } } @@ -613,15 +633,23 @@ pub mod topology { ) -> Result<(), flatbuffers::InvalidFlatbuffer> { use self::flatbuffers::Verifiable; v.visit_table(pos)? - .visit_field::>("at", Self::VT_AT, true)? - .visit_field::>("from", Self::VT_FROM, true)? + .visit_field::>>( + "at", + Self::VT_AT, + true, + )? + .visit_field::>>( + "from", + Self::VT_FROM, + true, + )? .finish(); Ok(()) } } pub struct RemovedConnectionArgs<'a> { - pub at: Option>, - pub from: Option>, + pub at: Option>>, + pub from: Option>>, } impl<'a> Default for RemovedConnectionArgs<'a> { #[inline] @@ -639,12 +667,12 @@ pub mod topology { } impl<'a: 'b, 'b> RemovedConnectionBuilder<'a, 'b> { #[inline] - pub fn add_at(&mut self, at: flatbuffers::WIPOffset<&'b str>) { + pub fn add_at(&mut self, at: flatbuffers::WIPOffset>) { self.fbb_ .push_slot_always::>(RemovedConnection::VT_AT, at); } #[inline] - pub fn add_from(&mut self, from: flatbuffers::WIPOffset<&'b str>) { + pub fn add_from(&mut self, from: flatbuffers::WIPOffset>) { self.fbb_ .push_slot_always::>(RemovedConnection::VT_FROM, from); } diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index a59e10165..623309fe9 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -57,6 +57,7 @@ pub mod dev_tool { InitPeerNode, InterProcessConnManager, NodeConfig, PeerCliConfig, PeerId, }; pub use ring::Location; + pub use transport::TransportKeypair; pub use wasm_runtime::{ContractStore, DelegateStore, Runtime, SecretsStore, StateStore}; } diff --git a/crates/core/src/message.rs b/crates/core/src/message.rs index ed7a293ba..62c6ea04c 100644 --- a/crates/core/src/message.rs +++ b/crates/core/src/message.rs @@ -1,7 +1,7 @@ //! Network messaging between peers. use std::{ - borrow::Cow, + borrow::{Borrow, Cow}, fmt::Display, time::{Duration, SystemTime}, }; @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use ulid::Ulid; use crate::{ - node::{ConnectionError, PeerId}, + node::PeerId, operations::{ connect::ConnectMsg, get::GetMsg, put::PutMsg, subscribe::SubscribeMsg, update::UpdateMsg, }, @@ -30,7 +30,7 @@ pub(crate) use sealed_msg_type::{TransactionType, TransactionTypeId}; /// to sweep any garbage left by a finished (or timed out) transaction. /// /// A transaction may span different messages sent across the network. -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Clone, Copy)] +#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Clone, Copy)] pub struct Transaction { id: Ulid, } @@ -128,6 +128,12 @@ impl Display for Transaction { } } +impl std::fmt::Debug for Transaction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.id) + } +} + impl PartialOrd for Transaction { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) @@ -195,11 +201,11 @@ mod sealed_msg_type { } macro_rules! transaction_type_enumeration { - (decl struct { $( $var:tt -> $ty:tt),+ }) => { + ($variant:ident, $enum_type:ident, decl struct { $( $var:ident -> $ty:ty ),+ }) => { $( impl From<$ty> for NetMessage { fn from(msg: $ty) -> Self { - Self::$var(msg) + Self::$variant($enum_type::$var(msg)) } } @@ -212,7 +218,7 @@ mod sealed_msg_type { }; } - transaction_type_enumeration!(decl struct { + transaction_type_enumeration!(V1, NetMessageV1, decl struct { Connect -> ConnectMsg, Put -> PutMsg, Get -> GetMsg, @@ -221,8 +227,25 @@ mod sealed_msg_type { }); } +pub(crate) trait MessageStats { + fn id(&self) -> &Transaction; + + fn target(&self) -> Option; + + fn terminal(&self) -> bool; + + fn requested_location(&self) -> Option; + + fn track_stats(&self) -> bool; +} + #[derive(Debug, Serialize, Deserialize)] pub(crate) enum NetMessage { + V1(NetMessageV1), +} + +#[derive(Debug, Serialize, Deserialize)] +pub(crate) enum NetMessageV1 { Connect(ConnectMsg), Put(PutMsg), Get(GetMsg), @@ -233,14 +256,45 @@ pub(crate) enum NetMessage { from: PeerId, }, Update(UpdateMsg), - /// Failed a transaction, informing of abortion. Aborted(Transaction), } +trait Versioned { + fn version(&self) -> semver::Version; +} + +impl Versioned for NetMessage { + fn version(&self) -> semver::Version { + match self { + NetMessage::V1(inner) => inner.version(), + } + } +} + +impl Versioned for NetMessageV1 { + fn version(&self) -> semver::Version { + match self { + NetMessageV1::Connect(_) => semver::Version::new(1, 0, 0), + NetMessageV1::Put(_) => semver::Version::new(1, 0, 0), + NetMessageV1::Get(_) => semver::Version::new(1, 0, 0), + NetMessageV1::Subscribe(_) => semver::Version::new(1, 0, 0), + NetMessageV1::Unsubscribed { .. } => semver::Version::new(1, 0, 0), + NetMessageV1::Update(_) => semver::Version::new(1, 0, 0), + NetMessageV1::Aborted(_) => semver::Version::new(1, 0, 0), + } + } +} + +impl From for semver::Version { + fn from(msg: NetMessage) -> Self { + msg.version() + } +} + pub(crate) trait InnerMessage: Into { fn id(&self) -> &Transaction; - fn target(&self) -> Option<&PeerKeyLocation>; + fn target(&self) -> Option>; fn terminal(&self) -> bool; @@ -252,15 +306,8 @@ pub(crate) trait InnerMessage: Into { pub(crate) enum NodeEvent { /// For unspecified reasons the node is gracefully shutting down. ShutdownNode, - /// Received a confirmation from a peer that a physical connection was established. - ConfirmedInbound, /// Drop the given peer connection. DropConnection(PeerId), - /// Accept the connections from the given peer. - AcceptConnection(PeerId), - /// Error while sending a message by the connection bridge from within the ops. - #[serde(skip)] - Error(ConnectionError), Disconnect { cause: Option>, }, @@ -270,14 +317,9 @@ impl Display for NodeEvent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { NodeEvent::ShutdownNode => f.write_str("ShutdownNode"), - NodeEvent::ConfirmedInbound => f.write_str("ConfirmedInbound"), NodeEvent::DropConnection(peer) => { write!(f, "DropConnection (from {peer})") } - NodeEvent::AcceptConnection(peer) => { - write!(f, "AcceptConnection (from {peer})") - } - NodeEvent::Error(err) => write!(f, "{err}"), NodeEvent::Disconnect { cause: Some(cause) } => { write!(f, "Disconnect node, reason: {cause}") } @@ -288,85 +330,127 @@ impl Display for NodeEvent { } } -impl NetMessage { - pub fn id(&self) -> &Transaction { - use NetMessage::*; +impl MessageStats for NetMessage { + fn id(&self) -> &Transaction { match self { - Connect(op) => op.id(), - Put(op) => op.id(), - Get(op) => op.id(), - Subscribe(op) => op.id(), - Update(op) => op.id(), - Aborted(tx) => tx, - Unsubscribed { transaction, .. } => transaction, + NetMessage::V1(msg) => msg.id(), } } - pub fn target(&self) -> Option<&PeerKeyLocation> { - use NetMessage::*; + fn target(&self) -> Option { match self { - Connect(op) => op.target(), - Put(op) => op.target(), - Get(op) => op.target(), - Subscribe(op) => op.target(), - Update(op) => op.target(), - Aborted(_) => None, - Unsubscribed { .. } => None, + NetMessage::V1(msg) => msg.target(), } } - /// Is the last expected message for this chain of messages. - pub fn terminal(&self) -> bool { - use NetMessage::*; + fn terminal(&self) -> bool { match self { - Connect(op) => op.terminal(), - Put(op) => op.terminal(), - Get(op) => op.terminal(), - Subscribe(op) => op.terminal(), - Update(op) => op.terminal(), - Aborted(_) => true, - Unsubscribed { .. } => true, + NetMessage::V1(msg) => msg.terminal(), } } - pub fn requested_location(&self) -> Option { - use NetMessage::*; + fn requested_location(&self) -> Option { match self { - Connect(op) => op.requested_location(), - Put(op) => op.requested_location(), - Get(op) => op.requested_location(), - Subscribe(op) => op.requested_location(), - Update(op) => op.requested_location(), - Aborted(_) => None, - Unsubscribed { .. } => None, + NetMessage::V1(msg) => msg.requested_location(), } } - pub fn track_stats(&self) -> bool { - use NetMessage::*; - !matches!(self, Connect(_) | Subscribe(_) | Aborted(_)) + fn track_stats(&self) -> bool { + match self { + NetMessage::V1(msg) => msg.track_stats(), + } + } +} + +impl MessageStats for NetMessageV1 { + fn id(&self) -> &Transaction { + match self { + NetMessageV1::Connect(op) => op.id(), + NetMessageV1::Put(op) => op.id(), + NetMessageV1::Get(op) => op.id(), + NetMessageV1::Subscribe(op) => op.id(), + NetMessageV1::Update(op) => op.id(), + NetMessageV1::Aborted(tx) => tx, + NetMessageV1::Unsubscribed { transaction, .. } => transaction, + } + } + + fn target(&self) -> Option { + match self { + NetMessageV1::Connect(op) => op.target(), + NetMessageV1::Put(op) => op.target().cloned(), + NetMessageV1::Get(op) => op.target().cloned(), + NetMessageV1::Subscribe(op) => op.target().cloned(), + NetMessageV1::Update(op) => op.target().cloned(), + NetMessageV1::Aborted(_) => None, + NetMessageV1::Unsubscribed { .. } => None, + } + } + + fn terminal(&self) -> bool { + match self { + NetMessageV1::Connect(op) => op.terminal(), + NetMessageV1::Put(op) => op.terminal(), + NetMessageV1::Get(op) => op.terminal(), + NetMessageV1::Subscribe(op) => op.terminal(), + NetMessageV1::Update(op) => op.terminal(), + NetMessageV1::Aborted(_) => true, + NetMessageV1::Unsubscribed { .. } => true, + } + } + + fn requested_location(&self) -> Option { + match self { + NetMessageV1::Connect(op) => op.requested_location(), + NetMessageV1::Put(op) => op.requested_location(), + NetMessageV1::Get(op) => op.requested_location(), + NetMessageV1::Subscribe(op) => op.requested_location(), + NetMessageV1::Update(op) => op.requested_location(), + NetMessageV1::Aborted(_) => None, + NetMessageV1::Unsubscribed { .. } => None, + } + } + + fn track_stats(&self) -> bool { + match self { + NetMessageV1::Connect(_) | NetMessageV1::Subscribe(_) | NetMessageV1::Aborted(_) => { + false + } + _ => true, + } } } impl Display for NetMessage { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use NetMessage::*; + use NetMessageV1::*; write!(f, "Message {{")?; match self { - Connect(msg) => msg.fmt(f)?, - Put(msg) => msg.fmt(f)?, - Get(msg) => msg.fmt(f)?, - Subscribe(msg) => msg.fmt(f)?, - Update(msg) => msg.fmt(f)?, - Aborted(msg) => msg.fmt(f)?, - Unsubscribed { key, from, .. } => { - write!(f, "Unsubscribed {{ key: {}, from: {} }}", key, from)?; - } + NetMessage::V1(msg) => match msg { + Connect(msg) => msg.fmt(f)?, + Put(msg) => msg.fmt(f)?, + Get(msg) => msg.fmt(f)?, + Subscribe(msg) => msg.fmt(f)?, + Update(msg) => msg.fmt(f)?, + Aborted(msg) => msg.fmt(f)?, + Unsubscribed { key, from, .. } => { + write!(f, "Unsubscribed {{ key: {}, from: {} }}", key, from)?; + } + }, }; write!(f, "}}") } } +/// The result of a connection attempt. +#[derive(Debug, Serialize, Deserialize)] +pub(crate) enum ConnectionResult { + /// The target node for connection is valid + Accepted, + /// The target node for connection is not valid + Connection, +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/core/src/node.rs b/crates/core/src/node.rs index 196a600eb..3571eea67 100644 --- a/crates/core/src/node.rs +++ b/crates/core/src/node.rs @@ -8,12 +8,12 @@ //! - in-memory: a simplifying node used for emulation purposes mainly. //! - inter-process: similar to in-memory, but can be rana cross multiple processes, closer to the real p2p impl +use std::net::SocketAddr; use std::{ fmt::Display, io::Write, net::{IpAddr, Ipv4Addr}, path::PathBuf, - str::FromStr, sync::Arc, time::Duration, }; @@ -23,15 +23,14 @@ use freenet_stdlib::{ client_api::{ClientRequest, ContractRequest, ErrorKind}, prelude::{ContractKey, RelatedContracts, WrappedState}, }; -use libp2p::{identity, multiaddr::Protocol, Multiaddr, PeerId as Libp2pPeerId}; use serde::{Deserialize, Serialize}; use tracing::Instrument; use self::p2p_impl::NodeP2P; +use crate::message::{MessageStats, NetMessageV1}; use crate::{ client_events::{BoxedClient, ClientEventsProxy, ClientId, OpenRequest}, - config::Config, config::GlobalExecutor, contract::{ Callback, ClientResponsesReceiver, ClientResponsesSender, ContractError, @@ -53,6 +52,7 @@ pub use network_bridge::inter_process::InterProcessConnManager; pub(crate) use network_bridge::{ConnectionError, EventLoopNotificationsSender, NetworkBridge}; use crate::topology::rate::Rate; +use crate::transport::{TransportKeypair, TransportPublicKey}; pub(crate) use op_state_manager::{OpManager, OpNotAvailable}; mod network_bridge; @@ -72,7 +72,7 @@ pub struct PeerCliConfig { #[arg(long, short, default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))] pub address: IpAddr, - /// Port to expose api on + /// Port to expose the websocket API on #[arg(long, short, default_value_t = 50509)] pub port: u16, } @@ -98,16 +98,20 @@ impl Node { /// be listening but also try to connect to an existing peer. #[derive(Serialize, Deserialize, Clone, Debug)] pub struct NodeConfig { - /// public identifier for the peer - pub peer_id: PeerId, + /// Determines if an initial connection should be attempted. + /// Only true for an initial gateway/node. If false, the gateway will be disconnected unless other peers connect through it. + pub should_connect: bool, + pub is_gateway: bool, + /// If not specified, a key is generated and used when creating the node. + pub key_pair: Option, // optional local info, in case this is an initial bootstrap node - /// IP to bind to the listener + /// IP to bind to the network listener. pub local_ip: Option, - /// socket port to bind to the listener + /// socket port to bind to the network listener. pub local_port: Option, - /// IP dialers should connect to + /// IP dialers should connect to, only set on gateways pub(crate) public_ip: Option, - /// socket port dialers should connect to + /// socket port dialers should connect to, only set on gateways pub(crate) public_port: Option, /// At least an other running listener node is required for joining the network. /// Not necessary if this is an initial node. @@ -124,9 +128,10 @@ pub struct NodeConfig { impl NodeConfig { pub fn new() -> NodeConfig { - let local_key = Config::conf().local_peer_keypair.public().into(); NodeConfig { - peer_id: local_key, + should_connect: true, + is_gateway: false, + key_pair: None, remote_nodes: Vec::with_capacity(1), local_ip: None, local_port: None, @@ -142,6 +147,25 @@ impl NodeConfig { } } + pub fn is_gateway(&mut self) -> &mut Self { + self.is_gateway = true; + self + } + + pub fn first_gateway(&mut self) { + self.should_connect = false; + } + + pub fn with_key_pair(&mut self, key_pair: TransportKeypair) -> &mut Self { + self.key_pair = Some(key_pair); + self + } + + pub fn with_should_connect(&mut self, should_connect: bool) -> &mut Self { + self.should_connect = should_connect; + self + } + pub fn max_hops_to_live(&mut self, num_hops: usize) -> &mut Self { self.max_hops_to_live = Some(num_hops); self @@ -172,13 +196,6 @@ impl NodeConfig { self } - /// Optional identity key of this node. - /// If not provided it will be either obtained from the configuration or freshly generated. - pub fn with_key(&mut self, key: PeerId) -> &mut Self { - self.peer_id = key; - self - } - pub fn with_location(&mut self, loc: Location) -> &mut Self { self.location = Some(loc); self @@ -195,7 +212,7 @@ impl NodeConfig { self, config: PeerCliConfig, clients: [BoxedClient; CLIENTS], - private_key: identity::Keypair, + private_key: TransportKeypair, ) -> Result { let event_register = { #[cfg(feature = "trace-ot")] @@ -224,33 +241,33 @@ impl NodeConfig { Ok(Node(node)) } - pub fn is_gateway(&self) -> bool { - self.local_ip.is_some() && self.local_port.is_some() && self.location.is_some() + pub fn get_peer_id(&self) -> Option { + match (self.key_pair.as_ref(), self.local_ip, self.local_port) { + (Some(kp), Some(ip), Some(port)) => { + Some(PeerId::new(SocketAddr::new(ip, port), kp.public.clone())) + } + _ => None, + } } /// Returns all specified gateways for this peer. Returns an error if the peer is not a gateway /// and no gateways are specified. fn get_gateways(&self) -> Result, anyhow::Error> { - let peer = self.peer_id; - let gateways: Vec<_> = self + let gateways: Vec = self .remote_nodes .iter() .filter_map(|node| { - if node.addr.is_some() { - Some(PeerKeyLocation { - peer: node.identifier, - location: Some(node.location), - }) - } else { - None - } + Some(PeerKeyLocation { + peer: node.peer_id.clone(), + location: Some(node.location), + }) }) - .filter(|pkloc| pkloc.peer != peer) .collect(); + if (self.local_ip.is_none() || self.local_port.is_none()) && gateways.is_empty() { anyhow::bail!( - "At least one remote gateway is required to join an existing network for non-gateway nodes." - ) + "At least one remote gateway is required to join an existing network for non-gateway nodes." + ) } else { Ok(gateways) } @@ -263,55 +280,16 @@ impl Default for NodeConfig { } } -/// Gateway node to bootstrap the network. +/// Gateway node to use for joining the network. #[derive(Clone, Serialize, Deserialize, Debug)] pub struct InitPeerNode { - addr: Option, - identifier: PeerId, + peer_id: PeerId, location: Location, } impl InitPeerNode { - pub fn new(identifier: Libp2pPeerId, location: Location) -> Self { - Self { - addr: None, - identifier: PeerId(identifier), - location, - } - } - - /// Given a byte array decode into a PeerId data type. - /// - /// # Panic - /// Will panic if is not a valid representation. - pub fn decode_peer_id>(mut bytes: T) -> Libp2pPeerId { - Libp2pPeerId::from_public_key( - &identity::Keypair::from( - identity::ed25519::Keypair::try_from_bytes(bytes.as_mut()).unwrap(), - ) - .public(), - ) - } - - /// IP which will be assigned to this node. - pub fn listening_ip>(mut self, ip: T) -> Self { - if let Some(addr) = &mut self.addr { - addr.push(Protocol::from(ip.into())); - } else { - self.addr = Some(Multiaddr::from(ip.into())); - } - self - } - - /// TCP listening port (only required in case of using TCP as transport). - /// If not specified port 7800 will be used as default. - pub fn listening_port(mut self, port: u16) -> Self { - if let Some(addr) = &mut self.addr { - addr.push(Protocol::Tcp(port)); - } else { - self.addr = Some(Multiaddr::from(Protocol::Tcp(port))); - } - self + pub fn new(peer_id: PeerId, location: Location) -> Self { + Self { peer_id, location } } } @@ -377,9 +355,13 @@ async fn process_open_request(request: OpenRequest<'static>, op_manager: Arc { + let peer_id = op_manager + .ring + .get_peer_key() + .expect("Peer id not found at put op, it should be set"); // Initialize a put op. tracing::debug!( - this_peer = %op_manager.ring.peer_key, + this_peer = %peer_id, "Received put from user event", ); let op = put::start_op( @@ -397,9 +379,12 @@ async fn process_open_request(request: OpenRequest<'static>, op_manager: Arc { - // FIXME: perform updates + let peer_id = op_manager + .ring + .get_peer_key() + .expect("Peer id not found at update op, it should be set"); tracing::debug!( - this_peer = %op_manager.ring.peer_key, + this_peer = %peer_id, "Received update from user event", ); let state = match data { @@ -428,9 +413,13 @@ async fn process_open_request(request: OpenRequest<'static>, op_manager: Arc { + let peer_id = op_manager + .ring + .get_peer_key() + .expect("Peer id not found at get op, it should be set"); // Initialize a get op. tracing::debug!( - this_peer = %op_manager.ring.peer_key, + this_peer = %peer_id, "Received get from user event", ); let op = get::start_op(key, contract); @@ -497,7 +486,7 @@ async fn report_result( payload_transfer_time, } => { let event = RouteEvent { - peer: *target_peer, + peer: target_peer.clone(), contract_location, outcome: RouteOutcome::Success { time_to_response_start: first_response_time, @@ -531,7 +520,9 @@ async fn report_result( cb.response(op_res).await; } } - Ok(None) => {} + Ok(None) => { + tracing::debug!(?tx, "No operation result found, not sending response"); + } Err(err) => { // just mark the operation as completed so no redundant messages are processed for this transaction anymore if let Some(tx) = tx { @@ -554,7 +545,7 @@ async fn report_result( second_trace_lines.join("\n") }) .unwrap_or_default(); - let peer = &op_manager.ring.peer_key; + let peer = &op_manager.ring.get_peer_key().expect("Peer key not found"); let log = format!( "Transaction ({tx} @ {peer}) error trace:\n {trace} \nstate:\n {state:?}\n" ); @@ -573,10 +564,14 @@ macro_rules! handle_op_not_available { if let Err(OpError::OpNotAvailable(state)) = &$op_result { match state { OpNotAvailable::Running => { + tracing::debug!("Operation still running"); tokio::time::sleep(Duration::from_micros(1_000)).await; continue; } - OpNotAvailable::Completed => return, + OpNotAvailable::Completed => { + tracing::debug!("Operation already completed"); + return; + } } } }; @@ -585,6 +580,36 @@ macro_rules! handle_op_not_available { async fn process_message( msg: NetMessage, op_manager: Arc, + conn_manager: CB, + event_listener: Box, + executor_callback: Option>, + client_req_handler_callback: Option, + client_id: Option, +) where + CB: NetworkBridge, +{ + let tx = Some(*msg.id()); + match msg { + NetMessage::V1(msg_v1) => { + process_message_v1( + tx, + msg_v1, + op_manager, + conn_manager, + event_listener, + executor_callback, + client_req_handler_callback, + client_id, + ) + .await + } + } +} + +async fn process_message_v1( + tx: Option, + msg: NetMessageV1, + op_manager: Arc, mut conn_manager: CB, mut event_listener: Box, executor_callback: Option>, @@ -594,20 +619,40 @@ async fn process_message( CB: NetworkBridge, { let cli_req = client_id.zip(client_req_handler_callback); - - let tx = Some(*msg.id()); event_listener - .register_events(NetEventLog::from_inbound_msg(&msg, &op_manager)) + .register_events(NetEventLog::from_inbound_msg_v1(&msg, &op_manager)) .await; - loop { - match &msg { - NetMessage::Connect(op) => { - // log_handling_msg!("join", op.id(), op_manager); + + for i in 0.. { + tracing::debug!(?tx, "Processing operation, iteration: {i}"); + match msg { + NetMessageV1::Connect(ref op) => { + let parent_span = tracing::Span::current(); + let span = tracing::info_span!( + parent: parent_span, + "handle_connect_op_request", + peer = ?op_manager.ring.get_peer_key(), + transaction = %msg.id(), + tx_type = %msg.id().transaction_type() + ); let op_result = handle_op_request::(&op_manager, &mut conn_manager, op) + .instrument(span) .await; handle_op_not_available!(op_result); - break report_result( + match &op_result { + Ok(Some(OpEnum::Connect(op))) => { + tracing::info!(?op, "Connect operation started"); + } + Ok(None) => { + tracing::info!("Connect operation not started"); + } + Err(err) => { + tracing::error!(%err, "Connect operation failed"); + } + _ => {} + } + return report_result( tx, op_result, &op_manager, @@ -617,12 +662,11 @@ async fn process_message( ) .await; } - NetMessage::Put(op) => { - // log_handling_msg!("put", *op.id(), op_manager); + NetMessageV1::Put(ref op) => { let op_result = handle_op_request::(&op_manager, &mut conn_manager, op).await; handle_op_not_available!(op_result); - break report_result( + return report_result( tx, op_result, &op_manager, @@ -632,12 +676,11 @@ async fn process_message( ) .await; } - NetMessage::Get(op) => { - // log_handling_msg!("get", op.id(), op_manager); + NetMessageV1::Get(ref op) => { let op_result = handle_op_request::(&op_manager, &mut conn_manager, op).await; handle_op_not_available!(op_result); - break report_result( + return report_result( tx, op_result, &op_manager, @@ -647,8 +690,7 @@ async fn process_message( ) .await; } - NetMessage::Subscribe(op) => { - // log_handling_msg!("subscribe", op.id(), op_manager); + NetMessageV1::Subscribe(ref op) => { let op_result = handle_op_request::( &op_manager, &mut conn_manager, @@ -656,7 +698,7 @@ async fn process_message( ) .await; handle_op_not_available!(op_result); - break report_result( + return report_result( tx, op_result, &op_manager, @@ -666,12 +708,12 @@ async fn process_message( ) .await; } - NetMessage::Update(op) => { + NetMessageV1::Update(ref op) => { let op_result = handle_op_request::(&op_manager, &mut conn_manager, op) .await; handle_op_not_available!(op_result); - break report_result( + return report_result( tx, op_result, &op_manager, @@ -681,12 +723,11 @@ async fn process_message( ) .await; } - - NetMessage::Unsubscribed { key, .. } => { + NetMessageV1::Unsubscribed { ref key, .. } => { subscribe(op_manager, key.clone(), None).await; break; } - _ => break, + _ => break, // Exit the loop if no applicable message type is found } } } @@ -753,7 +794,7 @@ async fn subscribe(op_manager: Arc, key: ContractKey, client_id: Opti async fn handle_aborted_op( tx: Transaction, - this_peer: PeerId, + this_peer_pub_key: TransportPublicKey, op_manager: &OpManager, conn_manager: &mut CM, gateways: &[PeerKeyLocation], @@ -779,7 +820,7 @@ where tracing::warn!("Retry connecting to gateway {}", gateway.peer); connect::join_ring_request( backoff, - this_peer, + this_peer_pub_key, &gateway, op_manager, conn_manager, @@ -789,17 +830,12 @@ where } Ok(Some(OpEnum::Connect(_))) => { // if no connections were achieved just fail - if op_manager.ring.open_connections() == 0 { + if op_manager.ring.open_connections() == 0 && op_manager.ring.is_gateway() { tracing::warn!("Retrying joining the ring with an other gateway"); - if let Some(gateway) = gateways - .iter() - .shuffle() - .next() - .filter(|p| p.peer != this_peer) - { + if let Some(gateway) = gateways.iter().shuffle().next() { connect::join_ring_request( None, - this_peer, + this_peer_pub_key, gateway, op_manager, conn_manager, @@ -814,30 +850,80 @@ where Ok(()) } -#[derive(PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)] -pub struct PeerId(Libp2pPeerId); +/* +- Cuando es un gateway: se define desde el inicio del nodo +- Cuando es un peer regular: se define en el momento de la conexión con el gateway +*/ +#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Clone)] +pub struct PeerId { + pub addr: SocketAddr, + pub pub_key: TransportPublicKey, +} + +impl Ord for PeerId { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.addr.cmp(&other.addr) + } +} + +impl PartialOrd for PeerId { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +// impl FromStr for PeerId { +// type Err = anyhow::Error; +// fn from_str(s: &str) -> Result { +// Ok(Self { +// addr: s.parse()?, +// pub_key: TransportKeypair::new().public, +// }) +// } +// } + +impl PeerId { + pub fn new(addr: SocketAddr, pub_key: TransportPublicKey) -> Self { + Self { addr, pub_key } + } + + pub fn addr(&self) -> SocketAddr { + self.addr + } + + pub fn pub_key(&self) -> &TransportPublicKey { + &self.pub_key + } +} #[cfg(test)] impl<'a> arbitrary::Arbitrary<'a> for PeerId { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - let data: [u8; 32] = u.arbitrary()?; - let id = Libp2pPeerId::from_multihash( - libp2p::multihash::Multihash::wrap(0, data.as_slice()).unwrap(), - ) - .unwrap(); - Ok(Self(id)) + let addr: ([u8; 4], u16) = u.arbitrary()?; + let pub_key = TransportKeypair::new().public; // FIXME: impl arbitrary for TransportPublicKey + Ok(Self { + addr: addr.into(), + pub_key, + }) } } impl PeerId { pub fn random() -> Self { - use libp2p::identity::Keypair; - PeerId::from(Keypair::generate_ed25519().public()) + use rand::Rng; + let mut addr = [0; 4]; + rand::thread_rng().fill(&mut addr[..]); + let port = crate::util::get_free_port().unwrap(); + let pub_key = TransportKeypair::new().public; + Self { + addr: (addr, port).into(), + pub_key, + } } #[cfg(test)] pub fn to_bytes(self) -> Vec { - self.0.to_bytes() + bincode::serialize(&self).unwrap() } } @@ -849,54 +935,6 @@ impl std::fmt::Debug for PeerId { impl Display for PeerId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for PeerId { - fn from(val: identity::PublicKey) -> Self { - PeerId(Libp2pPeerId::from(val)) - } -} - -impl From for PeerId { - fn from(val: Libp2pPeerId) -> Self { - PeerId(val) - } -} - -impl FromStr for PeerId { - type Err = libp2p_identity::ParseError; - - fn from_str(s: &str) -> Result { - Ok(Self(Libp2pPeerId::from_str(s)?)) - } -} - -mod serialization { - use libp2p::PeerId as Libp2pPeerId; - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - - use super::PeerId; - - impl Serialize for PeerId { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_bytes(&self.0.to_bytes()) - } - } - - impl<'de> Deserialize<'de> for PeerId { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let bytes: Vec = Deserialize::deserialize(deserializer)?; - Ok(PeerId( - Libp2pPeerId::from_bytes(&bytes).expect("failed deserialization of PeerKey"), - )) - } + write!(f, "{:?}", self.addr) } } diff --git a/crates/core/src/node/network_bridge.rs b/crates/core/src/node/network_bridge.rs index 0d27ce18b..07ed3289e 100644 --- a/crates/core/src/node/network_bridge.rs +++ b/crates/core/src/node/network_bridge.rs @@ -4,7 +4,6 @@ use std::future::Future; use std::ops::{Deref, DerefMut}; use either::Either; -use libp2p::swarm::StreamUpgradeError; use serde::{Deserialize, Serialize}; use tokio::sync::mpsc::{self, Receiver, Sender}; @@ -24,8 +23,6 @@ pub(crate) type ConnResult = std::result::Result; /// Allows handling of connections to the network as well as sending messages /// to other peers in the network with whom connection has been established. pub(crate) trait NetworkBridge: Send + Sync { - fn add_connection(&mut self, peer: PeerId) -> impl Future> + Send; - fn drop_connection(&mut self, peer: &PeerId) -> impl Future> + Send; fn send(&self, target: &PeerId, msg: NetMessage) @@ -38,19 +35,21 @@ pub(crate) enum ConnectionError { LocationUnknown, #[error("unable to send message")] SendNotCompleted, + #[error("Unexpected connection req")] + UnexpectedReq, #[error("error while de/serializing message")] #[serde(skip)] Serialization(#[from] Option>), + #[error("{0}")] + TransportError(String), + #[error("unwanted connection")] + FailedConnectOp, // errors produced while handling the connection: #[error("IO error: {0}")] IOError(String), - #[error("timeout error while opening a connectio.")] + #[error("timeout error while waiting for a message")] Timeout, - #[error("no protocols could be agreed upon")] - NegotiationFailed, - #[error("protocol upgrade error: {0}")] - Upgrade(String), } impl From for ConnectionError { @@ -59,14 +58,9 @@ impl From for ConnectionError { } } -impl From> for ConnectionError { - fn from(err: StreamUpgradeError) -> Self { - match err { - StreamUpgradeError::Timeout => Self::Timeout, - StreamUpgradeError::Apply(err) => Self::Upgrade(format!("{err}")), - StreamUpgradeError::NegotiationFailed => Self::NegotiationFailed, - StreamUpgradeError::Io(err) => Self::IOError(format!("{err}")), - } +impl From for ConnectionError { + fn from(err: crate::transport::TransportError) -> Self { + Self::TransportError(err.to_string()) } } @@ -78,8 +72,9 @@ impl Clone for ConnectionError { Self::SendNotCompleted => Self::SendNotCompleted, Self::IOError(err) => Self::IOError(err.clone()), Self::Timeout => Self::Timeout, - Self::Upgrade(err) => Self::Upgrade(err.clone()), - Self::NegotiationFailed => Self::NegotiationFailed, + Self::UnexpectedReq => Self::UnexpectedReq, + Self::TransportError(err) => Self::TransportError(err.clone()), + Self::FailedConnectOp => Self::FailedConnectOp, } } } diff --git a/crates/core/src/node/network_bridge/in_memory.rs b/crates/core/src/node/network_bridge/in_memory.rs index 90405dcd8..5f2ae8706 100644 --- a/crates/core/src/node/network_bridge/in_memory.rs +++ b/crates/core/src/node/network_bridge/in_memory.rs @@ -67,11 +67,7 @@ impl NetworkBridge for MemoryConnManager { .await; self.op_manager.sending_transaction(target, &msg); let msg = bincode::serialize(&msg)?; - self.transport.send(*target, msg); - Ok(()) - } - - async fn add_connection(&mut self, _peer: PeerId) -> super::ConnResult<()> { + self.transport.send(target.clone(), msg); Ok(()) } @@ -121,6 +117,7 @@ impl InMemoryTransport { // store messages incoming from the network in the msg stack let msg_stack_queue_cp = msg_stack_queue.clone(); let network_tx_cp = network_tx.clone(); + let ip = interface_peer.clone(); GlobalExecutor::spawn(async move { const MAX_DELAYED_MSG: usize = 10; let mut rng = StdRng::from_entropy(); @@ -129,14 +126,17 @@ impl InMemoryTransport { let last_drain = Instant::now(); loop { match network_rx.try_recv() { - Ok(msg) if msg.target == interface_peer => { + Ok(msg) if msg.target == ip => { tracing::trace!( "Inbound message received for peer {} from {}", - interface_peer, + ip, msg.origin ); if rng.gen_bool(0.5) && delayed.len() < MAX_DELAYED_MSG && add_noise { - delayed.entry(msg.target).or_default().push(msg); + delayed + .entry(msg.target.clone()) + .or_default() + .push(msg.clone()); tokio::time::sleep(Duration::from_millis(10)).await; } else { let mut queue = msg_stack_queue_cp.lock().await; @@ -170,7 +170,7 @@ impl InMemoryTransport { queue.shuffle(&mut rng); } } - tracing::error!("Stopped receiving messages in {}", interface_peer); + tracing::error!("Stopped receiving messages in {ip}"); }); Self { @@ -182,7 +182,7 @@ impl InMemoryTransport { fn send(&self, peer: PeerId, message: Vec) { let send_res = self.network.send(MessageOnTransit { - origin: self.interface_peer, + origin: self.interface_peer.clone(), target: peer, data: message, }); diff --git a/crates/core/src/node/network_bridge/inter_process.rs b/crates/core/src/node/network_bridge/inter_process.rs index f50c0244b..5c2bdb34b 100644 --- a/crates/core/src/node/network_bridge/inter_process.rs +++ b/crates/core/src/node/network_bridge/inter_process.rs @@ -87,7 +87,7 @@ impl NetworkBridge for InterProcessConnManager { self.log_register .register_events(NetEventLog::from_outbound_msg(&msg, &self.op_manager.ring)) .await; - let data = bincode::serialize(&(*target, msg))?; + let data = bincode::serialize(&(target, msg))?; let output = &mut *self.output.lock().await; output.write_all(&(data.len() as u32).to_le_bytes()).await?; output.write_all(&data).await?; @@ -96,10 +96,6 @@ impl NetworkBridge for InterProcessConnManager { Ok(()) } - async fn add_connection(&mut self, _peer: PeerId) -> super::ConnResult<()> { - Ok(()) - } - async fn drop_connection(&mut self, _peer: &PeerId) -> super::ConnResult<()> { Ok(()) } diff --git a/crates/core/src/node/network_bridge/p2p_protoc.rs b/crates/core/src/node/network_bridge/p2p_protoc.rs index 56efa2ff3..f18926afc 100644 --- a/crates/core/src/node/network_bridge/p2p_protoc.rs +++ b/crates/core/src/node/network_bridge/p2p_protoc.rs @@ -1,126 +1,47 @@ +use std::net::{IpAddr, SocketAddr}; use std::{ - collections::{HashMap, HashSet, VecDeque}, - io, - net::IpAddr, - pin::Pin, + collections::{HashMap, HashSet}, sync::Arc, - task::Poll, }; -use asynchronous_codec::{BytesMut, Framed}; -use dashmap::{DashMap, DashSet}; +use anyhow::anyhow; +use dashmap::DashSet; use either::{Either, Left, Right}; -use futures::{ - future::{self}, - sink, stream, AsyncRead, AsyncWrite, FutureExt, Sink, SinkExt, Stream, StreamExt, TryStreamExt, -}; -use libp2p::{ - autonat, - core::{muxing, transport, UpgradeInfo}, - identify, - identity::Keypair, - multiaddr::Protocol, - swarm::{ - self, - dial_opts::DialOpts, - handler::{DialUpgradeError, FullyNegotiatedInbound, FullyNegotiatedOutbound}, - Config as SwarmConfig, ConnectionHandler, ConnectionHandlerEvent, ConnectionId, FromSwarm, - KeepAlive, NetworkBehaviour, NotifyHandler, Stream as NegotiatedSubstream, - SubstreamProtocol, SwarmEvent, ToSwarm, - }, - InboundUpgrade, Multiaddr, OutboundUpgrade, PeerId as Libp2pPeerId, Swarm, -}; +use futures::stream::FuturesUnordered; +use futures::{FutureExt, StreamExt}; +use tokio::net::UdpSocket; use tokio::sync::mpsc::{self, Receiver, Sender}; use tracing::Instrument; -use unsigned_varint::codec::UviBytes; use super::{ConnectionError, EventLoopNotificationsReceiver, NetworkBridge}; +use crate::message::NetMessageV1; + +use crate::node::PeerId; +use crate::operations::connect::{self, ConnectMsg, ConnectRequest, ConnectResponse}; +use crate::transport::{ + create_connection_handler, OutboundConnectionHandler, PeerConnection, TransportError, + TransportKeypair, +}; use crate::{ client_events::ClientId, - config::{self, GlobalExecutor}, + config::GlobalExecutor, contract::{ ClientResponsesSender, ContractHandlerChannel, ExecutorToEventLoopChannel, NetworkEventListenerHalve, WaitingResolution, }, - message::{NetMessage, NodeEvent, Transaction}, + message::{MessageStats, NetMessage, NodeEvent, Transaction}, node::{ - handle_aborted_op, process_message, InitPeerNode, NetEventRegister, NodeConfig, OpManager, + handle_aborted_op, process_message, NetEventRegister, NodeConfig, OpManager, PeerId as FreenetPeerId, }, ring::PeerKeyLocation, tracing::NetEventLog, }; -/// The default maximum size for a varint length-delimited packet. -pub const DEFAULT_MAX_PACKET_SIZE: usize = 16 * 1024; - -const CURRENT_AGENT_VER: &str = "/freenet/agent/0.1.0"; -const CURRENT_PROTOC_VER: &str = "/freenet/0.1.0"; -const CURRENT_PROTOC_VER_STR: &str = "/freenet/0.1.0"; -const CURRENT_IDENTIFY_PROTOC_VER: &str = "/id/1.0.0"; - -fn config_behaviour( - private_key: &Keypair, - gateways: &[InitPeerNode], - _private_addr: &Option, - op_manager: Arc, -) -> NetBehaviour { - let routing_table: HashMap<_, _> = gateways - .iter() - .filter_map(|p| { - p.addr - .as_ref() - .map(|addr| (p.identifier.0, HashSet::from_iter([addr.clone()]))) - }) - .collect(); - - let ident_config = identify::Config::new( - CURRENT_IDENTIFY_PROTOC_VER.to_string(), - private_key.public(), - ) - .with_agent_version(CURRENT_AGENT_VER.to_string()); - - let peer_id = private_key.public().to_peer_id(); - let auto_nat = { - let config = autonat::Config { - ..Default::default() - }; - let mut behaviour = autonat::Behaviour::new(peer_id, config); - - for (peer, addr) in gateways.iter().map(|p| (&p.identifier, &p.addr)) { - behaviour.add_server(peer.0, addr.clone()); - } - behaviour - }; - - NetBehaviour { - identify: identify::Behaviour::new(ident_config), - auto_nat, - freenet: FreenetBehaviour { - outbound: VecDeque::new(), - routing_table, - connected: HashMap::new(), - openning_connection: HashSet::new(), - inbound: VecDeque::new(), - op_manager, - }, - } -} - -/// Small helper function to convert a tuple composed of an IP address and a port -/// to a libp2p Multiaddr type. -fn multiaddr_from_connection(conn: (IpAddr, u16)) -> Multiaddr { - let mut addr = Multiaddr::with_capacity(2); - addr.push(Protocol::from(conn.0)); - addr.push(Protocol::Tcp(conn.1)); - addr -} - type P2pBridgeEvent = Either<(FreenetPeerId, Box), NodeEvent>; #[derive(Clone)] pub(crate) struct P2pBridge { - active_net_connections: Arc>, accepted_peers: Arc>, ev_listener_tx: Sender, op_manager: Arc, @@ -137,7 +58,6 @@ impl P2pBridge { EL: NetEventRegister, { Self { - active_net_connections: Arc::new(DashMap::new()), accepted_peers: Arc::new(DashSet::new()), ev_listener_tx: sender, op_manager, @@ -147,21 +67,10 @@ impl P2pBridge { } impl NetworkBridge for P2pBridge { - async fn add_connection(&mut self, peer: FreenetPeerId) -> super::ConnResult<()> { - if self.active_net_connections.contains_key(&peer) { - self.accepted_peers.insert(peer); - } - self.ev_listener_tx - .send(Right(NodeEvent::AcceptConnection(peer))) - .await - .map_err(|_| ConnectionError::SendNotCompleted)?; - Ok(()) - } - async fn drop_connection(&mut self, peer: &FreenetPeerId) -> super::ConnResult<()> { self.accepted_peers.remove(peer); self.ev_listener_tx - .send(Right(NodeEvent::DropConnection(*peer))) + .send(Right(NodeEvent::DropConnection(peer.clone()))) .await .map_err(|_| ConnectionError::SendNotCompleted)?; self.log_register @@ -179,91 +88,71 @@ impl NetworkBridge for P2pBridge { .await; self.op_manager.sending_transaction(target, &msg); self.ev_listener_tx - .send(Left((*target, Box::new(msg)))) + .send(Left((target.clone(), Box::new(msg)))) .await .map_err(|_| ConnectionError::SendNotCompleted)?; Ok(()) } } +type PeerConnChannelSender = Sender>; +type PeerConnChannelRecv = Receiver>; + pub(in crate::node) struct P2pConnManager { - pub(in crate::node) swarm: Swarm, pub(in crate::node) gateways: Vec, pub(in crate::node) bridge: P2pBridge, conn_bridge_rx: Receiver, - /// last valid observed public address - public_addr: Option, - listening_addr: Option, event_listener: Box, + connection: HashMap, + key_pair: TransportKeypair, + listening_ip: IpAddr, + listening_port: u16, + is_gateway: bool, +} + +impl Drop for P2pConnManager { + fn drop(&mut self) { + tracing::info!( + "This peer {:?} has active connections with peers: {:?}", + self.bridge.op_manager.ring.get_peer_key().unwrap(), + self.connection.keys().map(|p| &p.addr) + ); + } } impl P2pConnManager { - pub fn build( - transport: transport::Boxed<(Libp2pPeerId, muxing::StreamMuxerBox)>, + pub async fn build( config: &NodeConfig, op_manager: Arc, event_listener: impl NetEventRegister + Clone, - private_key: Keypair, + private_key: TransportKeypair, ) -> Result { - // We set a global executor which is virtually the Tokio multi-threaded executor - // to reuse it's thread pool and scheduler in order to drive futures. - let global_executor = GlobalExecutor; - - let private_addr = if let Some(conn) = config.local_ip.zip(config.local_port) { - let public_addr = multiaddr_from_connection(conn); - Some(public_addr) - } else { - None - }; - - let public_addr = if let Some(conn) = config.public_ip.zip(config.public_port) { - let public_addr = multiaddr_from_connection(conn); - Some(public_addr) - } else { - None - }; + let listen_port = config + .local_port + .ok_or_else(|| anyhow::anyhow!("network listener port does not contain a port"))?; - let behaviour = config_behaviour( - &private_key, - &config.remote_nodes, - &private_addr, - op_manager.clone(), - ); - let mut swarm = Swarm::new( - transport, - behaviour, - config.peer_id.0, - SwarmConfig::with_executor(global_executor) - .with_idle_connection_timeout(config::PEER_TIMEOUT), - ); - - for remote_addr in config.remote_nodes.iter().filter_map(|r| r.addr.clone()) { - swarm.add_external_address(remote_addr); - } + let listener_ip = config + .local_ip + .ok_or(anyhow!("network listener IP not set"))?; let (tx_bridge_cmd, rx_bridge_cmd) = mpsc::channel(100); let bridge = P2pBridge::new(tx_bridge_cmd, op_manager, event_listener.clone()); let gateways = config.get_gateways()?; Ok(P2pConnManager { - swarm, gateways, bridge, conn_bridge_rx: rx_bridge_cmd, - public_addr, - listening_addr: private_addr, event_listener: Box::new(event_listener), + connection: HashMap::new(), + key_pair: private_key, + listening_ip: listener_ip, + listening_port: listen_port, + is_gateway: config.is_gateway, }) } - pub fn listen_on(&mut self) -> Result<(), anyhow::Error> { - if let Some(listening_addr) = &self.listening_addr { - self.swarm.listen_on(listening_addr.clone())?; - } - Ok(()) - } - - #[tracing::instrument(name = "network_event_listener", fields(peer = %self.bridge.op_manager.ring.peer_key), skip_all)] + #[tracing::instrument(name = "network_event_listener", fields(peer = ?self.bridge.op_manager.ring.get_peer_key()), skip_all)] pub async fn run_event_listener( mut self, op_manager: Arc, @@ -275,109 +164,168 @@ impl P2pConnManager { ) -> Result<(), anyhow::Error> { use ConnMngrActions::*; + let (mut outbound_conn_handler, mut inbound_conn_handler) = + create_connection_handler::( + self.key_pair.clone(), + self.listening_ip, + self.listening_port, + self.is_gateway, + ) + .await?; + // FIXME: this two containers need to be clean up on transaction time-out let mut pending_from_executor = HashSet::new(); let mut tx_to_client: HashMap = HashMap::new(); - let this_peer = FreenetPeerId::from( - crate::config::Config::conf() - .local_peer_keypair - .public() - .to_peer_id(), - ); + let mut peer_connections = FuturesUnordered::new(); + let mut outbound_conn_handler_2 = outbound_conn_handler.clone(); + let mut pending_outbound_conns = FuturesUnordered::new(); + let mut pending_inbound_gw_conns = HashMap::new(); + let mut pending_listening_gw_conns = FuturesUnordered::new(); + let mut gw_inbound_pending_connections = HashSet::new(); loop { - let network_msg = self.swarm.select_next_some().map(|event| match event { - SwarmEvent::Behaviour(NetEvent::Freenet(msg)) => { - tracing::debug!("Message inbound: {:?}", msg); - Ok(Left(*msg)) - } - SwarmEvent::ConnectionClosed { peer_id, .. } => { - Ok(Right(ConnMngrActions::ConnectionClosed { - peer: FreenetPeerId::from(peer_id), - })) - } - SwarmEvent::Dialing { peer_id, .. } => { - if let Some(peer_id) = peer_id { - tracing::debug!("Attempting connection to {}", peer_id); - } - Ok(Right(ConnMngrActions::NoAction)) - } - SwarmEvent::Behaviour(NetEvent::Identify(id)) => { - if let identify::Event::Received { peer_id, info } = *id { - if Self::is_compatible_peer(&info) { - Ok(Right(ConnMngrActions::ConnectionEstablished { - peer: FreenetPeerId::from(peer_id), - address: info.observed_addr, - })) - } else { - tracing::warn!("Incompatible peer: {}, disconnecting", peer_id); - Ok(Right(ConnMngrActions::ConnectionClosed { - peer: FreenetPeerId::from(peer_id), - })) - } - } else { - Ok(Right(ConnMngrActions::NoAction)) + tracing::info!( + "This peer {:?} has active connections with peers: {:?}", + self.bridge.op_manager.ring.get_peer_key().unwrap(), + gw_inbound_pending_connections + .iter() + .chain(self.connection.keys().map(|p| &p.addr)) + .collect::>() + ); + + let notification_msg = notification_channel.0.recv().map(|m| match m { + None => Ok(Right(ClosedChannel)), + Some(Left(msg)) => Ok(Left((msg, None))), + Some(Right(action)) => Ok(Right(NodeAction(action))), + }); + + let bridge_msg = async { + loop { + match self.conn_bridge_rx.recv().await { + Some(msg) => match msg { + Left((peer, msg)) => { + if let Right(new_conn) = self + .handle_bridge_connection_message( + peer, + msg, + &mut outbound_conn_handler, + &mut pending_inbound_gw_conns, + ) + .await? + { + break Ok::<_, anyhow::Error>(Left(new_conn)); + } + } + Right(action) => break Ok(Right(NodeAction(action))), + }, + None => break Ok(Right(ClosedChannel)), } } - SwarmEvent::Behaviour(NetEvent::Autonat(event)) => match event { - autonat::Event::InboundProbe(autonat::InboundProbeEvent::Response { - address, - peer, - .. - }) => { + }; + + let new_inbound_connection = async { + match inbound_conn_handler.next_connection().await { + Some(peer_conn) => { tracing::debug!( - "Successful autonat probe, established conn with {peer} @ {address}" + remote = %peer_conn.remote_addr(), + "New inbound connection at gateway" ); - Ok(Right(ConnMngrActions::ConnectionEstablished { - peer: FreenetPeerId::from(peer), - address, + Ok(Right(GatewayConnection { + remote_addr: peer_conn.remote_addr(), + peer_conn, })) } - autonat::Event::InboundProbe(autonat::InboundProbeEvent::Error { - peer, - error: autonat::InboundProbeError::Response(err), - .. - }) => match err { - autonat::ResponseError::DialError | autonat::ResponseError::DialRefused => { - Ok(Right(ConnMngrActions::IsPrivatePeer(peer))) - } - _ => Ok(Right(ConnMngrActions::NoAction)), - }, - autonat::Event::StatusChanged { - new: autonat::NatStatus::Public(address), - .. - } => { - tracing::debug!("NAT status: public @ {address}"); - Ok(Right(ConnMngrActions::UpdatePublicAddr(address))) - } - _ => Ok(Right(ConnMngrActions::NoAction)), - }, - other_event => { - tracing::debug!("Received other swarm event: {:?}", other_event); - Ok(Right(ConnMngrActions::NoAction)) + None => Ok(Right(ClosedChannel)), } - }); - - let notification_msg = notification_channel.0.recv().map(|m| match m { - None => Ok(Right(ClosedChannel)), - Some(Left(msg)) => Ok(Left(msg)), - Some(Right(action)) => Ok(Right(NodeAction(action))), - }); + }; - let bridge_msg = self.conn_bridge_rx.recv().map(|msg| match msg { - Some(Left((peer, msg))) => { - tracing::debug!("Message outbound: {:?}", msg); - Ok(Right(SendMessage { peer, msg })) + let msg: Result<_, ConnectionError> = tokio::select! { + msg = peer_connections.next(), if !peer_connections.is_empty() => { + let PeerConnectionInbound { conn, rx, msg } = match msg { + Some(Ok(peer_conn)) => peer_conn, + Some(Err(err)) => { + tracing::error!("Error in peer connection: {err}"); + // FIXME: clean up the remote connection from everywhere + continue; + } + None => { + tracing::error!("All peer connections closed"); + continue; + } + }; + let remote_addr = conn.remote_addr(); + let task = peer_connection_listener(rx, conn).boxed(); + peer_connections.push(task); + Ok(Left((msg, Some(remote_addr)))) } - Some(Right(action)) => Ok(Right(NodeAction(action))), - None => Ok(Right(ClosedChannel)), - }); + msg = pending_listening_gw_conns.next(), if !pending_listening_gw_conns.is_empty() => { + let PeerConnectionInbound { conn, rx, msg } = match msg { + Some(Ok(gw_conn)) => gw_conn, + Some(Err(err)) => { + tracing::error!("Error in gateway connection: {err}"); + continue; + } + None => { + tracing::error!("All gateway connections closed"); + continue; + } + }; + let remote_addr = conn.remote_addr(); - let msg: Result<_, ConnectionError> = tokio::select! { - msg = network_msg => { msg } - msg = notification_msg => { msg } - msg = bridge_msg => { msg } + if !pending_inbound_gw_conns.contains_key(&remote_addr) { + tracing::error!("Connection not found in pending gateway connections"); + continue; + } + let remote_addr = conn.remote_addr(); + let task = peer_connection_listener(rx, conn).boxed(); + peer_connections.push(task); + Ok(Left((msg, Some(remote_addr)))) + } + msg = pending_outbound_conns.next(), if !pending_outbound_conns.is_empty() => { + match msg { + Some((peer_conn, peer_id)) => { + match peer_conn { + Ok(peer_conn) => Ok(Right(ConnectionEstablished { + peer: peer_id, + peer_conn, + })), + Err(err) => { + tracing::error!(remote = %peer_id, "Error while attempting connection: {err}"); + // in this case although theoretically the Connect request would have added a new connection + // it failed, so we must free a spot reserved for this connection + op_manager.ring.prune_connection(peer_id.clone()).await; + continue; + } + } + }, + None => { + tracing::error!("All outbound peer connections closed"); + continue; + } + } + } + msg = notification_msg => { + msg.map(|maybe_net_msg| maybe_net_msg.map_left(|(msg, o)| (Some(msg), o))) + } + msg = bridge_msg => { + let msg = match msg { + Ok(msg) => msg, + Err(err) => { + tracing::error!("Error in bridge message: {err}"); + continue; + } + }; + match msg { + Left((peer, peer_conn)) => { + Ok(Right(ConnectionEstablished { + peer, + peer_conn, + })) + } + Right(action) => Ok(Right(action)), + } + } msg = node_controller.recv() => { if let Some(msg) = msg { Ok(Right(NodeAction(msg))) @@ -385,26 +333,31 @@ impl P2pConnManager { Ok(Right(ClosedChannel)) } } + msg = new_inbound_connection => { + // this is an inbound message at the gateway + msg + } event_id = client_wait_for_transaction.relay_transaction_result_to_client() => { - let (client_id, transaction) = event_id.map_err(|err| anyhow::anyhow!(err))?; + let (client_id, transaction) = event_id.map_err(|err| anyhow::Error::msg(err))?; tx_to_client.insert(transaction, client_id); continue; } id = executor_listener.transaction_from_executor() => { - let id = id.map_err(|err| anyhow::anyhow!(err))?; + let id = id.map_err(|err| anyhow::Error::msg(err))?; pending_from_executor.insert(id); continue; } }; match msg { - Ok(Left(msg)) => { + // This are either inbound messages or fast tracked by the event notifier + Ok(Left((Some(msg), maybe_socket))) => { let cb = self.bridge.clone(); match msg { - NetMessage::Aborted(tx) => { + NetMessage::V1(NetMessageV1::Aborted(tx)) => { handle_aborted_op( tx, - op_manager.ring.peer_key, + op_manager.ring.get_peer_pub_key(), &op_manager, &mut self.bridge, &self.gateways, @@ -412,7 +365,92 @@ impl P2pConnManager { .await?; continue; } - msg => { + mut msg => { + if let NetMessage::V1(NetMessageV1::Connect(ConnectMsg::Response { + msg: + ConnectResponse::AcceptedBy { + accepted, + acceptor, + joiner, + }, + .. + })) = &msg + { + // this is the inbound response from the peer we want to connect to + // for the other peer returning this response, check handle_bridge_connection_message + let this_peer_id = op_manager + .ring + .set_peer_key(joiner.clone()) + .unwrap_or_else(|| joiner.clone()); + if *accepted && &this_peer_id == joiner { + tracing::debug!(remote = %acceptor.peer, "Connection accepted by target, attempting connection"); + // we need to start the process of connecting to the other peer + let remote_peer = acceptor.peer.clone(); + let conn_fut = outbound_conn_handler_2 + .connect(acceptor.peer.pub_key.clone(), acceptor.peer.addr) + .await + .map(|peer_conn| (peer_conn, remote_peer)); + pending_outbound_conns.push(conn_fut); + } else if &this_peer_id == joiner { + tracing::debug!(remote = %acceptor.peer, "Connection rejected by target"); + gw_inbound_pending_connections.remove(&acceptor.peer.addr()); + } + } + + if let NetMessage::V1(NetMessageV1::Connect(ConnectMsg::Request { + msg: + ConnectRequest::StartJoinReq { + joiner, + joiner_key, + hops_to_live, + max_hops_to_live, + .. + }, + .. + })) = &mut msg + { + tracing::debug!(?joiner, "Received connection request from peer",); + // this is a gateway forwarding a connection request + // in this case a real connection already exists and we just need to maintain it alive + // long enough so the request is forwarded + // this should be the first hop: + debug_assert_eq!(hops_to_live, max_hops_to_live); + // at this point the joiner is probably not yet set, so we need to update it + if let Some(remote_addr) = maybe_socket { + if let Some(msg_sender) = + pending_inbound_gw_conns.remove(&remote_addr) + { + let peer_id = PeerId::new(remote_addr, joiner_key.clone()); + + tracing::debug!( + %remote_addr, + "Established connection with peer", + ); + gw_inbound_pending_connections.insert(remote_addr); + + self.connection.insert(peer_id.clone(), msg_sender); + } else if joiner.is_none() { + tracing::error!( + "Joiner unexpectedly not set for connection request." + ); + } + } + } + + if let NetMessage::V1(NetMessageV1::Connect(ConnectMsg::Request { + msg: ConnectRequest::CleanConnection { joiner }, + .. + })) = &msg + { + tracing::debug!(remote = %joiner, this_peer = ?op_manager.ring.get_peer_key().unwrap(), "Received clean connection message"); + // this is the clean up message for a gw connection that was not accepted + // in this case the joiner is connected to another peers, so we don't need to maintain the + // connection with the rejected gateway + gw_inbound_pending_connections.remove(&joiner.peer.addr()); + self.connection.remove(&joiner.peer); + op_manager.ring.prune_connection(joiner.peer.clone()).await; + } + let executor_callback = pending_from_executor .remove(msg.id()) .then(|| executor_listener.callback()); @@ -426,7 +464,8 @@ impl P2pConnManager { let span = tracing::info_span!( parent: parent_span, "process_network_message", - peer = %this_peer, transaction = %msg.id(), + peer = ?self.bridge.op_manager.ring.get_peer_key(), + transaction = %msg.id(), tx_type = %msg.id().transaction_type() ); GlobalExecutor::spawn( @@ -444,29 +483,10 @@ impl P2pConnManager { } } } - Ok(Right(SendMessage { peer, msg })) => { - tracing::debug!( - "Sending swarm message from {} to {}", - op_manager.ring.peer_key, - peer - ); - self.swarm - .behaviour_mut() - .freenet - .outbound - .push_front((peer.0, Left(*msg))); - } Ok(Right(NodeAction(NodeEvent::ShutdownNode))) => { tracing::info!("Shutting down message loop gracefully"); break; } - Ok(Right(NodeAction(NodeEvent::Error(err)))) => { - tracing::error!("Bridge conn error: {err}"); - } - Ok(Right(NodeAction(NodeEvent::AcceptConnection(_key)))) => { - // todo: if we prefilter connections, should only accept ones informed this way - // (except 'join ring' requests) - } Ok(Right(NodeAction(NodeEvent::Disconnect { cause }))) => { match cause { Some(cause) => tracing::warn!("Shutting down node: {cause}"), @@ -474,31 +494,42 @@ impl P2pConnManager { } return Ok(()); } - Ok(Right(ConnectionEstablished { - address: addr, - peer, - })) => { - tracing::debug!("Established connection with peer {} @ {}", peer, addr); - self.bridge.active_net_connections.insert(peer, addr); - } - Ok(Right(ConnectionClosed { peer: peer_id })) - | Ok(Right(NodeAction(NodeEvent::DropConnection(peer_id)))) => { - self.bridge.active_net_connections.remove(&peer_id); - op_manager.ring.prune_connection(peer_id).await; - // todo: notify the handler, read `disconnect_peer_id` doc - let _ = self.swarm.disconnect_peer_id(peer_id.0); + Ok(Right(NodeAction(NodeEvent::DropConnection(peer_id)))) => { + tracing::info!(remote = %peer_id, this_peer = ?op_manager.ring.get_peer_key().unwrap(), "Dropping connection"); + gw_inbound_pending_connections.remove(&peer_id.addr()); + op_manager.ring.prune_connection(peer_id.clone()).await; + self.connection.remove(&peer_id); tracing::info!("Dropped connection with peer {}", peer_id); } - Ok(Right(UpdatePublicAddr(address))) => { - self.public_addr = Some(address); + Ok(Right(GatewayConnection { + remote_addr, + peer_conn, + })) => { + gw_inbound_pending_connections.insert(remote_addr); + let (tx, rx) = mpsc::channel(10); + pending_inbound_gw_conns.insert(remote_addr, tx); + let task = peer_connection_listener(rx, peer_conn).boxed(); + pending_listening_gw_conns.push(task); } - Ok(Right(IsPrivatePeer(_peer))) => { - todo!("this peer is private, attempt hole punching") + Ok(Right(ConnectionEstablished { peer, peer_conn })) => { + let (tx, rx) = mpsc::channel(10); + self.connection.insert(peer.clone(), tx); + + // Spawn a task to handle the connection messages (inbound and outbound) + let task = peer_connection_listener(rx, peer_conn).boxed(); + peer_connections.push(task); } Ok(Right(ClosedChannel)) => { tracing::info!("Notification channel closed"); break; } + Ok(Left((None, _))) => { + // the conn to the gw has been accepted, we can dismiss this + tracing::debug!("Connection accepted by gateway"); + } + Ok(Right(AcceptConnection)) => { + unreachable!() + } Err(err) => { super::super::report_result( None, @@ -510,185 +541,172 @@ impl P2pConnManager { ) .await; } - Ok(Right(NoAction)) | Ok(Right(NodeAction(NodeEvent::ConfirmedInbound))) => {} } } Ok(()) } - fn is_compatible_peer(info: &identify::Info) -> bool { - let compatible_agent = info.agent_version == CURRENT_AGENT_VER; - let compatible_protoc = info - .protocols - .iter() - .any(|s| s.as_ref() == CURRENT_PROTOC_VER_STR); - compatible_agent && compatible_protoc - } -} - -enum ConnMngrActions { - /// Received a new connection - ConnectionEstablished { - peer: FreenetPeerId, - address: Multiaddr, - }, - /// Closed a connection with the peer - ConnectionClosed { - peer: FreenetPeerId, - }, - /// Outbound message - SendMessage { - peer: FreenetPeerId, - msg: Box, - }, - /// Update self own public address, useful when communicating for first time - UpdatePublicAddr(Multiaddr), - /// This is private, so when establishing connections hole-punching should be performed - IsPrivatePeer(Libp2pPeerId), - NodeAction(NodeEvent), - ClosedChannel, - NoAction, -} - -/// Manages network connections with different peers and event routing within the swarm. -pub(in crate::node) struct FreenetBehaviour { - // FIFO queue for outbound messages - outbound: VecDeque<(Libp2pPeerId, Either)>, - // FIFO queue for inbound messages - inbound: VecDeque>, - routing_table: HashMap>, - connected: HashMap, - openning_connection: HashSet, - op_manager: Arc, -} - -impl NetworkBehaviour for FreenetBehaviour { - type ConnectionHandler = Handler; - - type ToSwarm = NetMessage; - - fn handle_established_inbound_connection( - &mut self, - connection_id: ConnectionId, - peer_id: Libp2pPeerId, - _local_addr: &Multiaddr, - remote_addr: &Multiaddr, - ) -> Result, libp2p::swarm::ConnectionDenied> { - self.openning_connection.remove(&peer_id); - self.openning_connection.shrink_to_fit(); - self.connected.insert(peer_id, connection_id); - self.routing_table - .entry(peer_id) - .or_default() - .insert(remote_addr.clone()); - Ok(Handler::new(self.op_manager.clone())) - } - - fn handle_established_outbound_connection( - &mut self, - connection_id: ConnectionId, - peer_id: Libp2pPeerId, - addr: &Multiaddr, - _role_override: libp2p::core::Endpoint, - ) -> Result, libp2p::swarm::ConnectionDenied> { - self.openning_connection.remove(&peer_id); - self.openning_connection.shrink_to_fit(); - self.connected.insert(peer_id, connection_id); - self.routing_table - .entry(peer_id) - .or_default() - .insert(addr.clone()); - Ok(Handler::new(self.op_manager.clone())) + async fn establish_connection( + outbound_conn_handler: &mut OutboundConnectionHandler, + peer: &PeerId, + ) -> Result { + let peer_conn = outbound_conn_handler + .connect(peer.pub_key.clone(), peer.addr) + .await + .await?; + tracing::debug!("Connection established with peer {}", peer.addr); + Ok(peer_conn) } - fn on_connection_handler_event( + /// Outbound message from bridge handler + async fn handle_bridge_connection_message( &mut self, - peer_id: Libp2pPeerId, - _connection: ConnectionId, - event: ::ToBehaviour, - ) { - match event { - HandlerEvent::Outbound(msg) => { - self.outbound.push_front((peer_id, msg)); + peer: PeerId, + mut net_msg: Box, + outbound_conn_handler: &mut OutboundConnectionHandler, + pending_inbound_gw_conns: &mut HashMap, + ) -> Result, ConnectionError> { + let mut connection = None; + let mut closing_gw_conn = None; + + tracing::debug!(target_peer = %peer, %net_msg, "Handling bridge connection message"); + match &mut *net_msg { + NetMessage::V1(NetMessageV1::Connect(ConnectMsg::Request { + msg: + connect::ConnectRequest::StartJoinReq { + joiner, + joiner_key, + skip_list, + .. + }, + .. + })) => { + if !self.connection.contains_key(&peer) { + // Establish a new connection with the peer + let peer_conn = + Self::establish_connection(outbound_conn_handler, &peer).await?; + + // Set the local peer ID using the connection information + if self.bridge.op_manager.ring.get_peer_key().is_none() { + tracing::debug!("Setting peer key for the first time"); + let my_address: SocketAddr = peer_conn.my_address().unwrap(); + let own_peer_id = PeerId::new(my_address, joiner_key.clone()); + self.bridge.op_manager.ring.set_peer_key(own_peer_id); + } + *joiner = self.bridge.op_manager.ring.get_peer_key(); + *skip_list = self.connection.keys().cloned().collect(); + connection = Some((peer.clone(), peer_conn)); + } else { + tracing::warn!("Connection already exists with gateway {}", peer.addr); + return Ok(Either::Left(())); + } } - HandlerEvent::Inbound(msg) => { - self.inbound.push_front(msg); + NetMessage::V1(NetMessageV1::Connect(ConnectMsg::Request { + msg: connect::ConnectRequest::FindOptimalPeer { skip_list, .. }, + .. + })) => { + *skip_list = self.connection.keys().cloned().collect(); } - } - } - - fn on_swarm_event(&mut self, event: libp2p::swarm::FromSwarm) { - if let FromSwarm::ConnectionClosed(swarm::ConnectionClosed { peer_id, .. }) = event { - self.connected.remove(&peer_id); - } - } - - fn poll( - &mut self, - _: &mut std::task::Context<'_>, - _: &mut impl libp2p::swarm::PollParameters, - ) -> std::task::Poll< - ToSwarm::FromBehaviour>, - > { - if let Some(Left(msg)) = self.inbound.pop_back() { - let send_to_ev_listener = ToSwarm::GenerateEvent(msg); - return Poll::Ready(send_to_ev_listener); + NetMessage::V1(NetMessageV1::Connect(ConnectMsg::Response { + msg: + ConnectResponse::AcceptedBy { + accepted, + acceptor, + joiner, + }, + .. + })) => { + if acceptor.peer + == self + .bridge + .op_manager + .ring + .get_peer_key() + .expect("should be set at this point") + { + if *accepted { + // In this case we are the acceptor, we need to establish a connection with the joiner + // this should only happen for the non-first peers in a Connect request, the first one + // should already be connected at this point, so check just in case + if !self.is_gateway && !self.connection.contains_key(&acceptor.peer) { + let peer_conn = + Self::establish_connection(outbound_conn_handler, joiner).await?; + connection = Some((joiner.clone(), peer_conn)); + } + tracing::debug!(this = %acceptor.peer, %joiner, "Connection accepted"); + if let Some(tx) = pending_inbound_gw_conns.get(&peer.addr) { + // if this node is a gateway we need to signal that we accepted the connection + let _ = tx.send(Right(ConnMngrActions::AcceptConnection)).await.map_err(|_| { + tracing::debug!(remote = %peer.addr, "Couldn't signal to the connection that is accepted, likely dropped"); + }); + } + pending_inbound_gw_conns.remove(&peer.addr); + } else { + closing_gw_conn = pending_inbound_gw_conns.remove(&joiner.addr()); + } + } + } + _ => {} } - if let Some((peer_id, msg)) = self.outbound.pop_back() { - if let Right(NodeEvent::Error(err)) = msg { - tracing::warn!("Connection error: {}", err); - return Poll::Pending; + if let Some(tx) = closing_gw_conn + .as_ref() + .map(Some) + .unwrap_or_else(|| pending_inbound_gw_conns.get(&peer.addr())) + { + tx.send(Either::Left(*net_msg)) + .await + .map_err(|_| ConnectionError::SendNotCompleted)?; + if closing_gw_conn.is_some() { + let _ = tx + .send(Either::Right(ConnMngrActions::ClosedChannel)) + .await + .map_err(|_| { + tracing::warn!("failed to send closed action"); + }); } + return Ok(connection + .map(|conn| Either::Right(conn)) + .unwrap_or(Either::Left(()))); + } - if let Some(id) = self.connected.get(&peer_id) { - let send_to_handler = ToSwarm::NotifyHandler { - peer_id, - handler: NotifyHandler::One(*id), - event: HandlerEvent::Outbound(msg), - }; - Poll::Ready(send_to_handler) - } else if self.openning_connection.contains(&peer_id) { - // waiting to have an open connection - self.outbound.push_front((peer_id, msg)); - Poll::Pending - } else if let Some(conn) = self.routing_table.get(&peer_id) { - // initiate a connection if one does not exist - // FIXME: we dial as listener to perform NAT hole-punching though the `override_role` method, - // if this is required because the other peer - let peer_opts = DialOpts::peer_id(peer_id) - .addresses(conn.iter().cloned().collect()) - .extend_addresses_through_behaviour(); - let initiate_conn = ToSwarm::Dial { - opts: peer_opts.build(), - }; - self.outbound.push_front((peer_id, msg)); - self.openning_connection.insert(peer_id); - Poll::Ready(initiate_conn) + if let Some((_, conn)) = &mut connection { + conn.send(net_msg) + .await + .map_err(|_| ConnectionError::SendNotCompleted)?; + } else { + if let Some(conn) = self.connection.get(&peer) { + tracing::debug!(target = %peer, "Connection status: {}", conn.is_closed().then(|| "closed").unwrap_or("open")); + conn.send(Either::Left(*net_msg)) + .await + .map_err(|_| ConnectionError::SendNotCompleted)?; } else { - Poll::Pending + tracing::error!(target = %peer, "Connection likely dropped"); + return Err(ConnectionError::SendNotCompleted); } - } else { - Poll::Pending } - } -} -type UniqConnId = usize; - -#[derive(Debug)] -pub(in crate::node) enum HandlerEvent { - Inbound(Either), - Outbound(Either), + Ok(connection + .map(|conn| Either::Right(conn)) + .unwrap_or(Either::Left(()))) + } } -/// Handles the connection with a given peer. -pub(in crate::node) struct Handler { - substreams: Vec, - uniq_conn_id: UniqConnId, - protocol_status: ProtocolStatus, - pending: Vec, - op_manager: Arc, +enum ConnMngrActions { + /// Gateway connection + GatewayConnection { + remote_addr: SocketAddr, + peer_conn: PeerConnection, + }, + /// Received a new connection + ConnectionEstablished { + peer: FreenetPeerId, + peer_conn: PeerConnection, + }, + /// Accept connection + AcceptConnection, + NodeAction(NodeEvent), + ClosedChannel, } #[allow(dead_code)] @@ -699,519 +717,58 @@ enum ProtocolStatus { Failed, } -#[allow(dead_code)] -enum SubstreamState { - /// We haven't started opening the outgoing substream yet. - /// Contains the initial request we want to send. - OutPendingOpen { - msg: Box, - conn_id: UniqConnId, - }, - /// Waiting for the first message after requesting an outbound open connection. - AwaitingFirst { conn_id: UniqConnId }, - FreeStream { - conn_id: UniqConnId, - substream: FreenetStream, - }, - /// Waiting to send a message to the remote. - PendingSend { - conn_id: UniqConnId, - substream: FreenetStream, - msg: Box>, - }, - /// Waiting to flush the substream so that the data arrives to the remote. - PendingFlush { - conn_id: UniqConnId, - substream: FreenetStream, - op_id: Option, - }, - /// Waiting for an answer back from the remote. - WaitingMsg { - conn_id: UniqConnId, - substream: FreenetStream, - }, - /// An error happened on the substream and we should report the error to the user. - ReportError { error: ConnectionError }, +struct PeerConnectionInbound { + conn: PeerConnection, + /// Receiver for inbound messages for the peer connection + rx: Receiver>, + msg: Option, } -impl Handler { - fn new(op_manager: Arc) -> Self { - Self { - substreams: vec![], - uniq_conn_id: 0, - protocol_status: ProtocolStatus::Unconfirmed, - pending: Vec::new(), - op_manager, - } - } - - #[inline] - fn send_to_free_substream(&mut self, msg: NetMessage) -> Option { - let pos = self - .substreams - .iter() - .position(|state| matches!(state, SubstreamState::FreeStream { .. })); - - if let Some(pos) = pos { - let (conn_id, substream) = match self.substreams.swap_remove(pos) { - SubstreamState::FreeStream { - substream: stream, - conn_id, - } => (conn_id, stream), - _ => unreachable!(), - }; - - self.substreams.push(SubstreamState::PendingSend { - msg: Box::new(Left(msg)), - conn_id, - substream, - }); - None - } else { - Some(msg) - } - } -} - -type HandlePollingEv = ConnectionHandlerEvent; - -impl ConnectionHandler for Handler { - /// Event received from the network by the handler - type FromBehaviour = HandlerEvent; - - /// Event producer by the handler and processed by the swarm - type ToBehaviour = HandlerEvent; - - type Error = ConnectionError; - - type InboundProtocol = FreenetProtocol; - - type OutboundProtocol = FreenetProtocol; - - type InboundOpenInfo = (); - - type OutboundOpenInfo = (); - - fn listen_protocol(&self) -> SubstreamProtocol { - SubstreamProtocol::new(FreenetProtocol, ()) - } - - fn on_behaviour_event(&mut self, msg: Self::FromBehaviour) { - match msg { - HandlerEvent::Outbound(Left(msg)) => { - if let Some(msg) = self.send_to_free_substream(msg) { - let conn_id = self.uniq_conn_id; - self.uniq_conn_id += 1; - // is the first request initiated and/or there are no free substreams, open a new one - self.substreams.push(SubstreamState::OutPendingOpen { - msg: Box::new(msg), - conn_id, - }); - } - } - HandlerEvent::Outbound(Right(node_ev)) => { - tracing::debug!("Received node event at connection handler: {node_ev}"); - } - HandlerEvent::Inbound(_) => unreachable!(), - } - } - - fn connection_keep_alive(&self) -> KeepAlive { - KeepAlive::Yes - } - - fn poll(&mut self, cx: &mut std::task::Context<'_>) -> std::task::Poll { - if self.substreams.is_empty() { - return Poll::Pending; - } - - if let ProtocolStatus::Confirmed = self.protocol_status { - self.protocol_status = ProtocolStatus::Reported; - return Poll::Ready(ConnectionHandlerEvent::NotifyBehaviour( - HandlerEvent::Outbound(Right(NodeEvent::ConfirmedInbound)), - )); - } - - for n in (0..self.substreams.len()).rev() { - let mut stream = self.substreams.swap_remove(n); - loop { - match stream { - SubstreamState::OutPendingOpen { msg, conn_id } => { - let event = ConnectionHandlerEvent::OutboundSubstreamRequest { - protocol: SubstreamProtocol::new(FreenetProtocol, ()), - }; - self.substreams - .push(SubstreamState::AwaitingFirst { conn_id }); - self.pending.push(*msg); - return Poll::Ready(event); - } - SubstreamState::AwaitingFirst { conn_id } => { - self.substreams - .push(SubstreamState::AwaitingFirst { conn_id }); - break; - } - SubstreamState::FreeStream { substream, conn_id } => { - if let Some(msg) = self.pending.pop() { - stream = SubstreamState::PendingSend { - substream, - conn_id, - msg: Box::new(Left(msg)), - }; - continue; - } else { - self.substreams - .push(SubstreamState::WaitingMsg { substream, conn_id }); - break; - } +async fn peer_connection_listener( + mut rx: PeerConnChannelRecv, + mut conn: PeerConnection, +) -> Result { + loop { + tokio::select! { + msg = rx.recv() => { + tracing::debug!(at=?conn.my_address(), from=%conn.remote_addr(), "Received message from channel"); + let Some(msg) = msg else { break Err(TransportError::ConnectionClosed); }; + match msg { + Left(msg) => { + tracing::debug!(at=?conn.my_address(), from=%conn.remote_addr() ,"Sending message to peer. Msg: {msg}"); + conn + .send(msg) + .await?; } - SubstreamState::PendingSend { - mut substream, - msg, - conn_id, - } => match Sink::poll_ready(Pin::new(&mut substream), cx) { - Poll::Ready(Ok(())) => match *msg { - Right(action) => match action { - NodeEvent::ConfirmedInbound => { - stream = SubstreamState::FreeStream { substream, conn_id }; - continue; - } - _ => break, - }, - Left(msg) => { - let op_id = msg.id(); - if msg.track_stats() { - if let Ok(Some(mut op)) = self.op_manager.pop(op_id) { - op.record_transfer(); - let fut = self.op_manager.push(*op_id, op); - futures::pin_mut!(fut); - match fut.poll_unpin(cx) { - Poll::Ready(_) => {} - Poll::Pending => return Poll::Pending, - } - } - } - let op_id = *op_id; - match Sink::start_send(Pin::new(&mut substream), msg) { - Ok(()) => { - stream = SubstreamState::PendingFlush { - substream, - conn_id, - op_id: Some(op_id), - }; - } - Err(err) => { - let event = ConnectionHandlerEvent::NotifyBehaviour( - HandlerEvent::Inbound(Right(NodeEvent::Error(err))), - ); - return Poll::Ready(event); - } - } - } - }, - Poll::Pending => { - stream = SubstreamState::PendingSend { - substream, - msg, - conn_id, - }; - continue; - } - Poll::Ready(Err(err)) => { - let event = ConnectionHandlerEvent::NotifyBehaviour( - HandlerEvent::Inbound(Right(NodeEvent::Error(err))), - ); - return Poll::Ready(event); - } - }, - SubstreamState::PendingFlush { - mut substream, - conn_id, - op_id, - } => match Sink::poll_flush(Pin::new(&mut substream), cx) { - Poll::Ready(Ok(())) => { - if let Some(op_id) = op_id { - if let Ok(Some(mut op)) = self.op_manager.pop(&op_id) { - op.record_transfer(); - let fut = self.op_manager.push(op_id, op); - futures::pin_mut!(fut); - match fut.poll_unpin(cx) { - Poll::Ready(_) => {} - Poll::Pending => return Poll::Pending, - } - } + Right(action) => { + tracing::debug!(at=?conn.my_address(), from=%conn.remote_addr(), "Received action from channel"); + match action { + ConnMngrActions::NodeAction(NodeEvent::DropConnection(_)) | ConnMngrActions::ClosedChannel => { + break Err(TransportError::ConnectionClosed); } - stream = SubstreamState::WaitingMsg { substream, conn_id }; - continue; - } - Poll::Pending => { - self.substreams.push(SubstreamState::PendingFlush { - substream, - conn_id, - op_id, - }); - break; - } - Poll::Ready(Err(err)) => { - let event = ConnectionHandlerEvent::NotifyBehaviour( - HandlerEvent::Inbound(Right(NodeEvent::Error(err))), - ); - return Poll::Ready(event); - } - }, - SubstreamState::WaitingMsg { - mut substream, - conn_id, - } => match Stream::poll_next(Pin::new(&mut substream), cx) { - Poll::Ready(Some(Ok(msg))) => { - let op_id = msg.id(); - if let Ok(Some(mut op)) = self.op_manager.pop(op_id) { - op.record_transfer(); - let fut = self.op_manager.push(*op_id, op); - futures::pin_mut!(fut); - match fut.poll_unpin(cx) { - Poll::Ready(_) => {} - Poll::Pending => return Poll::Pending, - } - } - if !msg.terminal() { - // received a message, the other peer is waiting for an answer - self.substreams - .push(SubstreamState::FreeStream { substream, conn_id }); + ConnMngrActions::AcceptConnection => { + return Ok(PeerConnectionInbound { conn, rx, msg: None }); } - let event = ConnectionHandlerEvent::NotifyBehaviour( - HandlerEvent::Inbound(Left(msg)), - ); - return Poll::Ready(event); - } - Poll::Pending => { - self.substreams - .push(SubstreamState::WaitingMsg { substream, conn_id }); - break; + _ => {} } - Poll::Ready(Some(Err(err))) => { - let event = ConnectionHandlerEvent::NotifyBehaviour( - HandlerEvent::Inbound(Right(NodeEvent::Error(err))), - ); - return Poll::Ready(event); - } - Poll::Ready(None) => { - let event = ConnectionHandlerEvent::NotifyBehaviour( - HandlerEvent::Inbound(Right(NodeEvent::Error( - std::io::Error::from(io::ErrorKind::UnexpectedEof).into(), - ))), - ); - return Poll::Ready(event); - } - }, - SubstreamState::ReportError { error, .. } => { - let event = ConnectionHandlerEvent::NotifyBehaviour(HandlerEvent::Inbound( - Right(NodeEvent::Error(error)), - )); - return Poll::Ready(event); - } - } - } - } - - Poll::Pending - } - - fn on_connection_event( - &mut self, - event: libp2p::swarm::handler::ConnectionEvent< - Self::InboundProtocol, - Self::OutboundProtocol, - Self::InboundOpenInfo, - Self::OutboundOpenInfo, - >, - ) { - match event { - swarm::handler::ConnectionEvent::FullyNegotiatedInbound(FullyNegotiatedInbound { - protocol: stream, - .. - }) => { - if let Some(prev_stream) = self - .substreams - .iter() - .position(|state| matches!(state, SubstreamState::AwaitingFirst { .. })) - { - match self.substreams.swap_remove(prev_stream) { - SubstreamState::AwaitingFirst { conn_id } => { - self.substreams.push(SubstreamState::FreeStream { - conn_id, - substream: stream, - }); - } - _ => unreachable!(), } - } else { - self.substreams.push(SubstreamState::WaitingMsg { - conn_id: self.uniq_conn_id, - substream: stream, - }); - self.uniq_conn_id += 1; - } - - if let ProtocolStatus::Unconfirmed = self.protocol_status { - self.protocol_status = ProtocolStatus::Confirmed; } } - swarm::handler::ConnectionEvent::FullyNegotiatedOutbound(FullyNegotiatedOutbound { - protocol: stream, - .. - }) => { - if let Some(pos) = self - .substreams - .iter() - .position(|state| matches!(state, SubstreamState::AwaitingFirst { .. })) - { - let conn_id = match self.substreams.swap_remove(pos) { - SubstreamState::AwaitingFirst { conn_id } => conn_id, - _ => unreachable!(), - }; - self.substreams.push(SubstreamState::FreeStream { - conn_id, - substream: stream, - }); - } else { - unreachable!(); - } - } - swarm::handler::ConnectionEvent::AddressChange(_) => {} - swarm::handler::ConnectionEvent::DialUpgradeError(DialUpgradeError { - error, .. - }) => { - self.protocol_status = ProtocolStatus::Failed; - self.substreams.push(SubstreamState::ReportError { - error: error.into(), - }); - self.uniq_conn_id += 1; - } - swarm::handler::ConnectionEvent::ListenUpgradeError( - swarm::handler::ListenUpgradeError { error, .. }, - ) => { - self.protocol_status = ProtocolStatus::Failed; - self.substreams.push(SubstreamState::ReportError { error }); - self.uniq_conn_id += 1; + msg = conn.recv() => { + let Ok(msg) = msg.map_err(|error| { + tracing::error!(at=?conn.my_address(), from=%conn.remote_addr(), "Error while receiving message: {error}"); + }) else { + break Err(TransportError::ConnectionClosed); + }; + let net_message = decode_msg(&msg).unwrap(); + tracing::debug!(at=?conn.my_address(), from=%conn.remote_addr() ,"Received message from peer. Msg: {net_message}"); + break Ok(PeerConnectionInbound { conn, rx, msg: Some(net_message) }); } - swarm::handler::ConnectionEvent::LocalProtocolsChange(_) => {} - swarm::handler::ConnectionEvent::RemoteProtocolsChange(_) => {} } } } -pub(crate) struct FreenetProtocol; - -impl UpgradeInfo for FreenetProtocol { - type Info = &'static str; - type InfoIter = std::iter::Once; - - fn protocol_info(&self) -> Self::InfoIter { - std::iter::once(CURRENT_PROTOC_VER) - } -} - -pub(crate) type FreenetStream = stream::AndThen< - sink::With< - stream::ErrInto>>>, ConnectionError>, - io::Cursor>, - NetMessage, - future::Ready>, ConnectionError>>, - fn(NetMessage) -> future::Ready>, ConnectionError>>, - >, - future::Ready>, - fn(BytesMut) -> future::Ready>, ->; - -impl InboundUpgrade for FreenetProtocol -where - S: AsyncRead + AsyncWrite + Unpin, -{ - type Output = FreenetStream; - type Error = ConnectionError; - type Future = future::Ready>; - - fn upgrade_inbound(self, incoming: S, _: Self::Info) -> Self::Future { - frame_stream(incoming) - } -} - -impl OutboundUpgrade for FreenetProtocol -where - S: AsyncRead + AsyncWrite + Unpin, -{ - type Output = FreenetStream; - type Error = ConnectionError; - type Future = future::Ready>; - - fn upgrade_outbound(self, incoming: S, _: Self::Info) -> Self::Future { - frame_stream(incoming) - } -} - -fn frame_stream(incoming: S) -> future::Ready, ConnectionError>> -where - S: AsyncRead + AsyncWrite + Unpin, -{ - let mut codec = UviBytes::default(); - codec.set_max_len(DEFAULT_MAX_PACKET_SIZE); - let framed = Framed::new(incoming, codec) - .err_into() - .with::<_, _, fn(_) -> _, _>(|response| match encode_msg(response) { - Ok(msg) => future::ready(Ok(io::Cursor::new(msg))), - Err(err) => future::ready(Err(err)), - }) - .and_then::<_, fn(_) -> _>(|bytes| future::ready(decode_msg(bytes))); - future::ok(framed) -} - #[inline(always)] -fn encode_msg(msg: NetMessage) -> Result, ConnectionError> { - bincode::serialize(&msg).map_err(|err| ConnectionError::Serialization(Some(err))) -} - -#[inline(always)] -fn decode_msg(buf: BytesMut) -> Result { - let cursor = std::io::Cursor::new(buf); - bincode::deserialize_from(cursor).map_err(|err| ConnectionError::Serialization(Some(err))) -} - -/// The network behaviour implements the following capabilities: -/// -/// - [Identify](https://github.com/libp2p/specs/tree/master/identify) libp2p protocol. -/// - [Ping](https://docs.rs/libp2p/latest/libp2p/ping/index.html) `/ipfs/ping/1.0.0` protocol. -/// - Freenet ring protocol, which handles the messages. -/// - [AutoNAT](https://github.com/libp2p/specs/tree/master/autonat) libp2p protocol. -#[derive(libp2p::swarm::NetworkBehaviour)] -#[behaviour(event_process = false)] -#[behaviour(to_swarm = "NetEvent")] -pub(in crate::node) struct NetBehaviour { - identify: identify::Behaviour, - freenet: FreenetBehaviour, - auto_nat: autonat::Behaviour, -} - -#[derive(Debug)] -pub(in crate::node) enum NetEvent { - Freenet(Box), - Identify(Box), - Autonat(autonat::Event), -} - -impl From for NetEvent { - fn from(event: autonat::Event) -> NetEvent { - Self::Autonat(event) - } -} - -impl From for NetEvent { - fn from(event: identify::Event) -> NetEvent { - Self::Identify(Box::new(event)) - } -} - -impl From for NetEvent { - fn from(event: NetMessage) -> NetEvent { - Self::Freenet(Box::new(event)) - } +fn decode_msg(data: &[u8]) -> Result { + bincode::deserialize(data).map_err(|err| ConnectionError::Serialization(Some(err))) } diff --git a/crates/core/src/node/op_state_manager.rs b/crates/core/src/node/op_state_manager.rs index 01abf3fe8..84640025b 100644 --- a/crates/core/src/node/op_state_manager.rs +++ b/crates/core/src/node/op_state_manager.rs @@ -7,7 +7,7 @@ use tracing::Instrument; use crate::{ config::GlobalExecutor, contract::{ContractError, ContractHandlerChannel, ContractHandlerEvent, SenderHalve}, - message::{NetMessage, Transaction, TransactionType}, + message::{MessageStats, NetMessage, Transaction, TransactionType}, operations::{ connect::ConnectOp, get::GetOp, put::PutOp, subscribe::SubscribeOp, update::UpdateOp, OpEnum, OpError, @@ -66,7 +66,7 @@ impl OpManager { config, notification_channel.clone(), event_register.clone(), - config.is_gateway(), + config.is_gateway, )?; let ops = Arc::new(Ops::default()); @@ -203,11 +203,11 @@ impl OpManager { let transaction = msg.id(); if let (Some(recipient), Some(target)) = (msg.target(), msg.requested_location()) { self.ring - .record_request(*recipient, target, transaction.transaction_type()); + .record_request(recipient.clone(), target, transaction.transaction_type()); } self.ring .live_tx_tracker - .add_transaction(*peer, *transaction); + .add_transaction(peer.clone(), *transaction); } } diff --git a/crates/core/src/node/p2p_impl.rs b/crates/core/src/node/p2p_impl.rs index 6069f218f..4a5f8b96f 100644 --- a/crates/core/src/node/p2p_impl.rs +++ b/crates/core/src/node/p2p_impl.rs @@ -1,14 +1,5 @@ use std::sync::Arc; -use libp2p::{ - core::{ - muxing, - transport::{self, upgrade}, - }, - dns, - identity::Keypair, - noise, tcp, yamux, PeerId as Libp2pPeerId, Transport, -}; use tracing::Instrument; use super::{ @@ -16,11 +7,12 @@ use super::{ network_bridge::{ event_loop_notification_channel, p2p_protoc::P2pConnManager, EventLoopNotificationsReceiver, }, - NetEventRegister, PeerId as FreenetPeerId, + NetEventRegister, }; +use crate::transport::{TransportKeypair, TransportPublicKey}; use crate::{ client_events::{combinator::ClientEventsCombinator, BoxedClient}, - config::{self, GlobalExecutor}, + config::GlobalExecutor, contract::{ self, ClientResponsesSender, ContractHandler, ContractHandlerChannel, ExecutorToEventLoopChannel, NetworkEventListenerHalve, WaitingResolution, @@ -33,7 +25,7 @@ use crate::{ use super::OpManager; pub(super) struct NodeP2P { - pub(crate) peer_key: FreenetPeerId, + pub(crate) peer_pub_key: TransportPublicKey, pub(crate) op_manager: Arc, notification_channel: EventLoopNotificationsReceiver, client_wait_for_transaction: ContractHandlerChannel, @@ -41,24 +33,21 @@ pub(super) struct NodeP2P { executor_listener: ExecutorToEventLoopChannel, cli_response_sender: ClientResponsesSender, node_controller: tokio::sync::mpsc::Receiver, - is_gateway: bool, + should_try_connect: bool, } impl NodeP2P { - pub(super) async fn run_node(mut self) -> Result<(), anyhow::Error> { - // start listening in case this is a listening node (gateway) and join the ring - if self.is_gateway { - self.conn_manager.listen_on()?; + pub(super) async fn run_node(self) -> Result<(), anyhow::Error> { + if self.should_try_connect { + connect::initial_join_procedure( + self.op_manager.clone(), + self.conn_manager.bridge.clone(), + self.peer_pub_key, + &self.conn_manager.gateways, + ) + .await?; } - connect::initial_join_procedure( - &self.op_manager, - &mut self.conn_manager.bridge, - self.peer_key, - &self.conn_manager.gateways, - ) - .await?; - // start the p2p event loop self.conn_manager .run_event_listener( @@ -74,7 +63,7 @@ impl NodeP2P { pub(crate) async fn build( config: NodeConfig, - private_key: Keypair, + private_key: TransportKeypair, clients: [BoxedClient; CLIENTS], event_register: ER, ch_builder: CH::Builder, @@ -83,7 +72,12 @@ impl NodeP2P { CH: ContractHandler + Send + 'static, ER: NetEventRegister + Clone, { - let peer_key = config.peer_id; + let keypair = config + .key_pair + .clone() + .unwrap_or_else(|| TransportKeypair::new()); + // FIXME: pass downn this keypair to the network listener + let peer_pub_key = keypair.public.clone(); let (notification_channel, notification_tx) = event_loop_notification_channel(); let (ch_outbound, ch_inbound, wait_for_event) = contract::contract_handler_channel(); @@ -100,16 +94,8 @@ impl NodeP2P { .await .map_err(|e| anyhow::anyhow!(e))?; - let conn_manager = { - let transport = Self::config_transport(&private_key)?; - P2pConnManager::build( - transport, - &config, - op_manager.clone(), - event_register, - private_key, - )? - }; + let conn_manager = + P2pConnManager::build(&config, op_manager.clone(), event_register, private_key).await?; let parent_span = tracing::Span::current(); GlobalExecutor::spawn( @@ -129,7 +115,7 @@ impl NodeP2P { ); Ok(NodeP2P { - peer_key, + peer_pub_key, conn_manager, notification_channel, client_wait_for_transaction: wait_for_event, @@ -137,130 +123,7 @@ impl NodeP2P { executor_listener, cli_response_sender, node_controller: node_controller_rx, - is_gateway: config.is_gateway(), + should_try_connect: config.should_connect, }) } - - /// Capabilities built into the transport by default: - /// - /// - TCP/IP handling over Tokio streams. - /// - DNS when dialing peers. - /// - Authentication and encryption via [Noise](https://github.com/libp2p/specs/tree/master/noise) protocol. - /// - Compression using Deflate. - /// - Multiplexing using [Yamux](https://github.com/hashicorp/yamux/blob/master/spec.md). - fn config_transport( - local_key: &Keypair, - ) -> std::io::Result> { - let tcp = tcp::tokio::Transport::new(tcp::Config::new().nodelay(true).port_reuse(true)); - let with_dns = dns::tokio::Transport::system(tcp)?; - Ok(with_dns - .upgrade(upgrade::Version::V1) - .authenticate(noise::Config::new(local_key).unwrap()) - .multiplex(yamux::Config::default()) - .timeout(config::PEER_TIMEOUT) - .map(|(peer, muxer), _| (peer, muxing::StreamMuxerBox::new(muxer))) - .boxed()) - } -} - -#[cfg(test)] -mod test { - use std::{net::Ipv4Addr, time::Duration}; - - use super::*; - use crate::{ - client_events::test::MemoryEventsGen, - contract::MemoryContractHandler, - node::{testing_impl::get_free_port, InitPeerNode}, - ring::Location, - }; - - use futures::StreamExt; - use tokio::sync::watch::channel; - - /// Ping test event loop - async fn ping_ev_loop(peer: &mut NodeP2P) -> Result<(), ()> { - loop { - let ev = tokio::time::timeout( - Duration::from_secs(30), - peer.conn_manager.swarm.select_next_some(), - ); - match ev.await { - Ok(other) => { - tracing::debug!("{:?}", other) - } - Err(_) => { - return Err(()); - } - } - } - } - - #[ignore] - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn ping() -> Result<(), ()> { - let peer1_port = get_free_port().unwrap(); - let peer1_key = Keypair::generate_ed25519(); - let peer1_id: Libp2pPeerId = peer1_key.public().into(); - let peer1_config = InitPeerNode::new(peer1_id, Location::random()) - .listening_ip(Ipv4Addr::LOCALHOST) - .listening_port(peer1_port); - - let peer2_key = Keypair::generate_ed25519(); - let peer2_id: Libp2pPeerId = peer2_key.public().into(); - - let (_, receiver1) = channel((0, FreenetPeerId::from(peer1_id))); - let (_, receiver2) = channel((0, FreenetPeerId::from(peer2_id))); - - // Start up the initial node. - GlobalExecutor::spawn(async move { - let user_events = MemoryEventsGen::new(receiver1, FreenetPeerId::from(peer1_id)); - let mut config = NodeConfig::new(); - config - .with_ip(Ipv4Addr::LOCALHOST) - .with_port(peer1_port) - .with_key(peer1_key.public().into()); - let mut peer1 = Box::new( - NodeP2P::build::( - config, - peer1_key, - [Box::new(user_events)], - crate::tracing::TestEventListener::new().await, - "ping-listener".into(), - ) - .await?, - ); - peer1.conn_manager.listen_on()?; - ping_ev_loop(&mut peer1).await.unwrap(); - Ok::<_, anyhow::Error>(()) - }); - - // Start up the dialing node - let dialer = GlobalExecutor::spawn(async move { - let user_events = MemoryEventsGen::new(receiver2, FreenetPeerId::from(peer2_id)); - let mut config = NodeConfig::new(); - config - .add_gateway(peer1_config.clone()) - .with_key(peer2_key.public().into()); - let mut peer2 = NodeP2P::build::( - config, - peer2_key, - [Box::new(user_events)], - crate::tracing::TestEventListener::new().await, - "ping-dialer".into(), - ) - .await - .unwrap(); - // wait a bit to make sure the first peer is up and listening - tokio::time::sleep(Duration::from_millis(10)).await; - peer2 - .conn_manager - .swarm - .dial(peer1_config.addr.unwrap()) - .map_err(|_| ())?; - ping_ev_loop(&mut peer2).await - }); - - dialer.await.map_err(|_| ())? - } } diff --git a/crates/core/src/node/testing_impl.rs b/crates/core/src/node/testing_impl.rs index 0bb70aa21..183763575 100644 --- a/crates/core/src/node/testing_impl.rs +++ b/crates/core/src/node/testing_impl.rs @@ -1,7 +1,8 @@ use std::{ collections::{HashMap, HashSet}, fmt::Write, - net::{Ipv4Addr, Ipv6Addr, SocketAddr, TcpListener}, + net::Ipv6Addr, + num::NonZeroUsize, pin::Pin, sync::Arc, time::{Duration, Instant}, @@ -11,8 +12,7 @@ use either::Either; use freenet_stdlib::prelude::*; use futures::Future; use itertools::Itertools; -use libp2p::{identity, PeerId as Libp2pPeerId}; -use rand::{seq::SliceRandom, Rng}; +use rand::seq::SliceRandom; use tokio::sync::{mpsc, watch}; use tracing::{info, Instrument}; @@ -25,7 +25,7 @@ use crate::{ self, ContractHandlerChannel, ExecutorToEventLoopChannel, NetworkEventListenerHalve, WaitingResolution, }, - message::{NetMessage, NodeEvent, Transaction}, + message::{MessageStats, NetMessage, NetMessageV1, NodeEvent, Transaction}, node::{InitPeerNode, NetEventRegister, NodeConfig}, operations::connect, ring::{Distance, Location, PeerKeyLocation}, @@ -43,25 +43,6 @@ use super::{ network_bridge::EventLoopNotificationsReceiver, ConnectionError, NetworkBridge, PeerId, }; -pub fn get_free_port() -> Result { - let mut port; - for _ in 0..100 { - port = get_dynamic_port(); - let bind_addr = SocketAddr::from((Ipv4Addr::LOCALHOST, port)); - if let Ok(conn) = TcpListener::bind(bind_addr) { - std::mem::drop(conn); - return Ok(port); - } - } - Err(()) -} - -fn get_dynamic_port() -> u16 { - const FIRST_DYNAMIC_PORT: u16 = 49152; - const LAST_DYNAMIC_PORT: u16 = 65535; - rand::thread_rng().gen_range(FIRST_DYNAMIC_PORT..LAST_DYNAMIC_PORT) -} - pub(crate) type EventId = u32; #[derive(PartialEq, Eq, Hash, Clone, PartialOrd, Ord, Debug)] @@ -137,8 +118,7 @@ pub(crate) struct NodeSpecification { #[derive(Clone)] struct GatewayConfig { label: NodeLabel, - port: u16, - id: Libp2pPeerId, + id: PeerId, location: Location, } @@ -191,7 +171,7 @@ impl EventChain { let rng = &mut this.rng; let labels = &mut this.labels; let (_, id) = labels.choose(rng).expect("not empty"); - *id + id.clone() } fn set_choice(self: Pin<&mut Self>, id: PeerId) { @@ -247,7 +227,7 @@ impl futures::stream::Stream for EventChain { let id = self.as_mut().choose_peer(); match self .user_ev_controller - .send(cx, (self.count, id)) + .send(cx, (self.count, id.clone())) .map_err(|_| { tracing::error!("peer controller should be alive, finishing event chain") }) { @@ -297,10 +277,10 @@ impl Builder { contract_handler_name: String, add_noise: bool, ) -> Builder { - let peer_key = builder.peer_id; + let peer_key = builder.get_peer_id().unwrap(); Builder { peer_key, - config: builder, + config: builder.clone(), contract_handler_name, add_noise, event_register, @@ -340,7 +320,7 @@ impl SimNetwork { max_connections: usize, min_connections: usize, ) -> Self { - assert!(gateways > 0 && nodes > 0); + assert!(nodes > 0); let (user_ev_controller, mut receiver_ch) = watch::channel((0, PeerId::random())); receiver_ch.borrow_and_update(); let mut net = Self { @@ -361,7 +341,12 @@ impl SimNetwork { start_backoff: Duration::from_millis(1), add_noise: false, }; - net.config_gateways(gateways).await; + net.config_gateways( + gateways + .try_into() + .expect("should have at least one gateway"), + ) + .await; net.config_nodes(nodes).await; net } @@ -383,53 +368,47 @@ impl SimNetwork { self.clean_up_tmp_dirs = false; } - async fn config_gateways(&mut self, num: usize) { + async fn config_gateways(&mut self, num: NonZeroUsize) { info!("Building {} gateways", num); - let mut configs = Vec::with_capacity(num); - for node_no in 0..num { + let mut configs = Vec::with_capacity(num.into()); + for node_no in 0..num.into() { let label = NodeLabel::gateway(node_no); - let pair = identity::Keypair::generate_ed25519(); - let id = pair.public().to_peer_id(); - let port = get_free_port().unwrap(); + let port = crate::util::get_free_port().unwrap(); + let keypair = crate::transport::TransportKeypair::new(); + let id = PeerId::new((Ipv6Addr::LOCALHOST, port).into(), keypair.public.clone()); let location = Location::random(); let mut config = NodeConfig::new(); config + .with_key_pair(keypair) .with_ip(Ipv6Addr::LOCALHOST) .with_port(port) - .with_key(pair.public().into()) .with_location(location) .max_hops_to_live(self.ring_max_htl) .max_number_of_connections(self.max_connections) .min_number_of_connections(self.min_connections) + .is_gateway() .rnd_if_htl_above(self.rnd_if_htl_above); - self.event_listener - .add_node(label.clone(), PeerId::from(id)); + self.event_listener.add_node(label.clone(), id.clone()); configs.push(( config, GatewayConfig { label, id, - port, location, }, )); } + configs[0].0.should_connect = false; let gateways: Vec<_> = configs.iter().map(|(_, gw)| gw.clone()).collect(); for (mut this_node, this_config) in configs { - for GatewayConfig { - port, id, location, .. - } in gateways + for GatewayConfig { id, location, .. } in gateways .iter() .filter(|config| this_config.label != config.label) { - this_node.add_gateway( - InitPeerNode::new(*id, *location) - .listening_ip(Ipv6Addr::LOCALHOST) - .listening_port(*port), - ); + this_node.add_gateway(InitPeerNode::new(id.clone(), *location)); } let event_listener = { #[cfg(feature = "trace-ot")] @@ -466,29 +445,22 @@ impl SimNetwork { for node_no in self.number_of_gateways..num + self.number_of_gateways { let label = NodeLabel::node(node_no); - let pair = identity::Keypair::generate_ed25519(); - let id = pair.public().to_peer_id(); + let peer = PeerId::random(); + let keypair: crate::dev_tool::TransportKeypair = + crate::transport::TransportKeypair::new(); let mut config = NodeConfig::new(); - for GatewayConfig { - port, id, location, .. - } in &gateways - { - config.add_gateway( - InitPeerNode::new(*id, *location) - .listening_ip(Ipv6Addr::LOCALHOST) - .listening_port(*port), - ); + for GatewayConfig { id, location, .. } in &gateways { + config.add_gateway(InitPeerNode::new(id.clone(), *location)); } config .max_hops_to_live(self.ring_max_htl) .rnd_if_htl_above(self.rnd_if_htl_above) .max_number_of_connections(self.max_connections) - .with_key(pair.public().into()) + .with_key_pair(keypair) .with_ip(Ipv6Addr::LOCALHOST) - .with_port(get_free_port().unwrap()); + .with_port(crate::util::get_free_port().unwrap()); - let peer = PeerId::from(id); self.event_listener.add_node(label.clone(), peer); let event_listener = { @@ -529,7 +501,8 @@ impl SimNetwork { for (mut node, label) in gw.chain(self.nodes.drain(..)).collect::>() { tracing::debug!(peer = %label, "initializing"); let node_spec = specs.remove(&label); - let mut user_events = MemoryEventsGen::new(self.receiver_ch.clone(), node.peer_key); + let mut user_events = + MemoryEventsGen::new(self.receiver_ch.clone(), node.peer_key.clone()); if let Some(specs) = node_spec.clone() { user_events.generate_events(specs.events_to_generate); } @@ -541,7 +514,7 @@ impl SimNetwork { if let Some(specs) = node_spec { node.append_contracts(specs.owned_contracts, specs.contract_subscribers); } - self.labels.push((label, node.peer_key)); + self.labels.push((label, node.peer_key.clone())); let node_task = async move { node.run_node(user_events, span).await }; GlobalExecutor::spawn(node_task); @@ -565,15 +538,18 @@ impl SimNetwork { let mut peers = vec![]; for (node, label) in gw.chain(self.nodes.drain(..)).collect::>() { tracing::debug!(peer = %label, "initializing"); - let mut user_events = - MemoryEventsGen::::new_with_seed(self.receiver_ch.clone(), node.peer_key, seed); + let mut user_events = MemoryEventsGen::::new_with_seed( + self.receiver_ch.clone(), + node.peer_key.clone(), + seed, + ); user_events.rng_params(label.number(), total_peer_num, max_contract_num, iterations); let span = if label.is_gateway() { tracing::info_span!("in_mem_gateway", %node.peer_key) } else { tracing::info_span!("in_mem_node", %node.peer_key) }; - self.labels.push((label, node.peer_key)); + self.labels.push((label, node.peer_key.clone())); let node_task = async move { node.run_node(user_events, span).await }; let handle = GlobalExecutor::spawn(node_task); @@ -606,7 +582,7 @@ impl SimNetwork { locations_by_node.insert( label.clone(), PeerKeyLocation { - peer: node.peer_key, + peer: node.peer_key.clone(), location: None, }, ); @@ -615,7 +591,7 @@ impl SimNetwork { locations_by_node.insert( config.label.clone(), PeerKeyLocation { - peer: node.peer_key, + peer: node.peer_key.clone(), location: config.location.into(), }, ); @@ -665,7 +641,7 @@ impl SimNetwork { pub fn ring_distribution(&self, scale: i32) -> Vec<(f64, usize)> { let mut all_dists = Vec::with_capacity(self.labels.len()); for (.., key) in &self.labels { - all_dists.push(self.event_listener.connections(*key)); + all_dists.push(self.event_listener.connections(key.clone())); } let mut dist_buckets = group_locations_in_buckets( all_dists.into_iter().flatten().map(|(_, l)| l.as_f64()), @@ -685,10 +661,10 @@ impl SimNetwork { for (label, key) in &self.labels { let conns = self .event_listener - .connections(*key) + .connections(key.clone()) .map(|(k, d)| (key_to_label[&k].clone(), d)) .collect::>(); - peers_connections.insert(label.clone(), (*key, conns)); + peers_connections.insert(label.clone(), (key.clone(), conns)); } peers_connections } @@ -714,7 +690,7 @@ impl SimNetwork { self.user_ev_controller .as_ref() .expect("should be set") - .send((event_id, *peer)) + .send((event_id, peer.clone())) .expect("node listeners disconnected"); if let Some(sleep_time) = await_for { tokio::time::sleep(sleep_time).await; @@ -992,9 +968,9 @@ where UsrEv: ClientEventsProxy + Send + 'static, { connect::initial_join_procedure( - &config.op_manager, - &mut config.conn_manager, - config.peer_key, + config.op_manager.clone(), + config.conn_manager.clone(), + config.peer_key.pub_key.clone(), &config.gateways, ) .await?; @@ -1007,7 +983,7 @@ where tracing::info_span!( parent: parent_span, "client_event_handling", - peer = %config.peer_key + peer = %config.peer_key.clone() ) }) .unwrap_or_else( @@ -1088,9 +1064,15 @@ where } }; - if let Ok(Either::Left(NetMessage::Aborted(tx))) = msg { - super::handle_aborted_op(tx, peer_key, &op_manager, &mut conn_manager, &gateways) - .await?; + if let Ok(Either::Left(NetMessage::V1(NetMessageV1::Aborted(tx)))) = msg { + super::handle_aborted_op( + tx, + peer_key.pub_key.clone(), + &op_manager, + &mut conn_manager, + &gateways, + ) + .await?; } let msg = match msg { @@ -1116,9 +1098,6 @@ where tracing::info!(peer = %peer_key, "Shutting down node"); return Ok(()); } - other => { - unreachable!("event {other:?}, shouldn't happen in the in-memory impl") - } }, Err(err) => { super::report_result( diff --git a/crates/core/src/node/testing_impl/in_memory.rs b/crates/core/src/node/testing_impl/in_memory.rs index 2b81e8130..c5c3a766f 100644 --- a/crates/core/src/node/testing_impl/in_memory.rs +++ b/crates/core/src/node/testing_impl/in_memory.rs @@ -47,7 +47,7 @@ impl Builder { .map_err(|e| anyhow::anyhow!(e))?; let conn_manager = MemoryConnManager::new( - self.peer_key, + self.peer_key.clone(), self.event_register.clone(), op_manager.clone(), self.add_noise, @@ -111,7 +111,7 @@ where tracing::debug!( "Appended contract {} to peer {}", key, - self.op_manager.ring.peer_key + self.op_manager.ring.get_peer_key().unwrap() ); if subscription { self.op_manager.ring.seed_contract(key.clone()); @@ -122,7 +122,7 @@ where if self .op_manager .ring - .add_subscriber(&key, *subscriber) + .add_subscriber(&key, subscriber.clone()) .is_err() { tracing::warn!("Max subscribers for contract {} reached", key); diff --git a/crates/core/src/node/testing_impl/inter_process.rs b/crates/core/src/node/testing_impl/inter_process.rs index c682e93b9..308a733a0 100644 --- a/crates/core/src/node/testing_impl/inter_process.rs +++ b/crates/core/src/node/testing_impl/inter_process.rs @@ -68,20 +68,19 @@ impl SimPeer { let contract_handler = MemoryContractHandler::build( ch_channel, executor_sender, - self.config.peer_id.to_string(), + self.config.get_peer_id().unwrap().to_string(), ) .await .map_err(|e| anyhow::anyhow!(e))?; let conn_manager = InterProcessConnManager::new(event_register.clone(), op_manager.clone()); - GlobalExecutor::spawn( - contract::contract_handling(contract_handler) - .instrument(tracing::info_span!("contract_handling", peer = %self.config.peer_id)), - ); + GlobalExecutor::spawn(contract::contract_handling(contract_handler).instrument( + tracing::info_span!("contract_handling", peer = %self.config.get_peer_id().unwrap()), + )); let running_node = super::RunnerConfig { - peer_key: self.config.peer_id, + peer_key: self.config.get_peer_id().unwrap(), op_manager, notification_channel, conn_manager, diff --git a/crates/core/src/node/testing_impl/network.rs b/crates/core/src/node/testing_impl/network.rs index 3619263a7..61b51bb7e 100644 --- a/crates/core/src/node/testing_impl/network.rs +++ b/crates/core/src/node/testing_impl/network.rs @@ -3,9 +3,9 @@ use crate::contract::MemoryContractHandler; use crate::node::p2p_impl::NodeP2P; use crate::node::Node; use crate::tracing::EventRegister; +use crate::transport::TransportKeypair; use anyhow::Error; use futures::SinkExt; -use libp2p_identity::Keypair; use serde::{Deserialize, Serialize}; use std::sync::Arc; use tokio::net::TcpStream; @@ -48,10 +48,10 @@ impl NetworkPeer { let response = reqwest::get(&config_url).await?; let peer_config = response.json::().await?; - tracing::debug!(peer_config = ?peer_config, "Received peer config"); + tracing::debug!("Received peer config"); let (user_ev_controller, receiver_ch): (PeerEventSender, PeerEventReceiver) = - tokio::sync::watch::channel((0, peer_config.peer_id)); + tokio::sync::watch::channel((0, peer_config.get_peer_id().unwrap())); Ok(NetworkPeer { id: peer_id, @@ -67,7 +67,7 @@ impl NetworkPeer { &self, identifier: String, clients: [BoxedClient; CLIENTS], - private_key: Keypair, + private_key: TransportKeypair, ) -> Result { let event_register = { #[cfg(feature = "trace-ot")] diff --git a/crates/core/src/operations.rs b/crates/core/src/operations.rs index 0e0dfe517..99efd3e18 100644 --- a/crates/core/src/operations.rs +++ b/crates/core/src/operations.rs @@ -9,7 +9,7 @@ use tokio::sync::mpsc::error::SendError; use crate::{ client_events::HostResult, contract::{ContractError, ExecutorError}, - message::{InnerMessage, NetMessage, Transaction, TransactionType}, + message::{InnerMessage, MessageStats, NetMessage, NetMessageV1, Transaction, TransactionType}, node::{ConnectionError, NetworkBridge, OpManager, OpNotAvailable, PeerId}, ring::{Location, PeerKeyLocation, RingError}, }; @@ -22,7 +22,7 @@ pub(crate) mod update; pub(crate) trait Operation where - Self: Sized + TryInto, + Self: Sized, { type Message: InnerMessage + std::fmt::Display; @@ -97,31 +97,33 @@ where Err(err) => { if let Some(sender) = sender { network_bridge - .send(&sender, NetMessage::Aborted(tx_id)) + .send(&sender, NetMessage::V1(NetMessageV1::Aborted(tx_id))) .await?; } return Err(err); } + Ok(OperationResult { + return_msg: None, + state: Some(final_state), + }) if final_state.finalized() => { + // operation finished_completely with result + op_manager.completed(tx_id); + return Ok(Some(final_state)); + } Ok(OperationResult { return_msg: Some(msg), state: Some(updated_state), }) => { // updated op let id = *msg.id(); - if let Some(target) = msg.target().cloned() { + tracing::debug!(%id, "updated op state"); + if let Some(target) = msg.target() { + tracing::debug!(%id, "sending updated op state"); network_bridge.send(&target.peer, msg).await?; } op_manager.push(id, updated_state).await?; } - Ok(OperationResult { - return_msg: None, - state: Some(final_state), - }) if final_state.finalized() => { - // operation finished_completely with result - op_manager.completed(tx_id); - return Ok(Some(final_state)); - } Ok(OperationResult { return_msg: None, state: Some(updated_state), @@ -137,7 +139,7 @@ where op_manager.completed(tx_id); // finished the operation at this node, informing back - if let Some(target) = msg.target().cloned() { + if let Some(target) = msg.target() { network_bridge.send(&target.peer, msg).await?; } } @@ -172,7 +174,6 @@ impl OpEnum { pub fn id(&self) -> &Transaction; pub fn outcome(&self) -> OpOutcome; pub fn finalized(&self) -> bool; - pub fn record_transfer(&mut self); pub fn to_host_result(&self) -> HostResult; } } diff --git a/crates/core/src/operations/connect.rs b/crates/core/src/operations/connect.rs index fa9a380f9..10ae7c0f7 100644 --- a/crates/core/src/operations/connect.rs +++ b/crates/core/src/operations/connect.rs @@ -1,21 +1,30 @@ //! Operation which seeks new connections in the ring. +use std::collections::HashSet; +use std::pin::Pin; +use std::sync::Arc; +use std::time::Duration; + use freenet_stdlib::client_api::HostResponse; use futures::Future; -use std::pin::Pin; -use std::{collections::HashSet, time::Duration}; use super::{OpError, OpInitialization, OpOutcome, Operation, OperationResult}; use crate::client_events::HostResult; +use crate::dev_tool::Location; +use crate::message::NetMessageV1; +use crate::node::ConnectionError; +use crate::ring::Ring; +use crate::transport::TransportPublicKey; use crate::{ message::{InnerMessage, NetMessage, Transaction}, - node::{ConnectionError, NetworkBridge, OpManager, PeerId}, + node::{NetworkBridge, OpManager, PeerId}, operations::OpEnum, - ring::{Location, PeerKeyLocation, Ring}, + ring::PeerKeyLocation, util::ExponentialBackoff, }; pub(crate) use self::messages::{ConnectMsg, ConnectRequest, ConnectResponse}; +#[derive(Debug)] pub(crate) struct ConnectOp { id: Transaction, state: Option, @@ -37,8 +46,6 @@ impl ConnectOp { matches!(self.state, Some(ConnectState::Connected)) } - pub(super) fn record_transfer(&mut self) {} - pub(super) fn to_host_result(&self) -> HostResult { // this should't ever be called since clients can't request explicit connects Ok(HostResponse::Ok) @@ -118,14 +125,14 @@ impl Operation for ConnectOp { } fn process_message<'a, NB: NetworkBridge>( - self, + mut self, network_bridge: &'a mut NB, op_manager: &'a OpManager, input: &'a Self::Message, ) -> Pin> + Send + 'a>> { Box::pin(async move { let return_msg; - let mut new_state; + let new_state; match input { ConnectMsg::Request { @@ -135,6 +142,7 @@ impl Operation for ConnectOp { ideal_location, joiner, max_hops_to_live, + skip_list, }, id, } => { @@ -146,6 +154,8 @@ impl Operation for ConnectOp { else { return Err(OpError::RingError(crate::ring::RingError::NoLocation)); }; + let mut skip_list = skip_list.clone(); + skip_list.push(query_target.peer.clone()); if this_peer == &query_target.peer { // this peer should be the original target queries tracing::debug!( @@ -156,35 +166,38 @@ impl Operation for ConnectOp { ); if let Some(desirable_peer) = op_manager .ring - .closest_to_location(*ideal_location, &[joiner.peer]) + .closest_to_location(*ideal_location, &[joiner.peer.clone()]) { + tracing::debug!( + tx = %id, + query_target = %query_target.peer, + joiner = %joiner.peer, + desirable_peer = %desirable_peer.peer, + "Found a desirable peer to connect to", + ); let msg = ConnectMsg::Request { id: *id, - msg: ConnectRequest::Proxy { - sender: own_loc, - joiner: *joiner, + msg: ConnectRequest::CheckConnectivity { + sender: own_loc.clone(), + joiner: joiner.clone(), hops_to_live: *max_hops_to_live, - skip_list: vec![*this_peer, joiner.peer], - accepted_by: HashSet::new(), + max_hops_to_live: *max_hops_to_live, + skip_list, }, }; network_bridge .send(&desirable_peer.peer, msg.into()) .await?; return_msg = None; - new_state = Some(ConnectState::AwaitingConnectionAcquisition { - joiner: *joiner, - }); + new_state = Some(ConnectState::AwaitingConnectionAcquisition {}); } else { - return_msg = Some(ConnectMsg::Response { - id: *id, - sender: *query_target, - target: *joiner, - msg: ConnectResponse::Proxy { - accepted_by: HashSet::new(), - joiner: joiner.peer, - }, - }); + tracing::debug!( + tx = %id, + query_target = %query_target.peer, + joiner = %joiner.peer, + "No desirable peer found to connect to", + ); + return_msg = None; new_state = None; } } else { @@ -196,16 +209,17 @@ impl Operation for ConnectOp { "Querying the query target for new connections", ); debug_assert_eq!(this_peer, &joiner.peer); - new_state = Some(ConnectState::AwaitingNewConnection { - query_target: query_target.peer, - }); + new_state = Some(ConnectState::AwaitingNewConnection(NewConnectionInfo { + remaining_connetions: *max_hops_to_live, + })); let msg = ConnectMsg::Request { id: *id, msg: ConnectRequest::FindOptimalPeer { - query_target: *query_target, + query_target: query_target.clone(), ideal_location: *ideal_location, - joiner: *joiner, + joiner: joiner.clone(), max_hops_to_live: *max_hops_to_live, + skip_list, }, }; network_bridge.send(&query_target.peer, msg.into()).await?; @@ -215,159 +229,134 @@ impl Operation for ConnectOp { ConnectMsg::Request { id, msg: - ConnectRequest::StartReq { - target: this_peer, + ConnectRequest::StartJoinReq { joiner, hops_to_live, - assigned_location, + skip_list, // .. }, } => { - // likely a gateway which accepts connections - tracing::debug!( - tx = %id, - at = %this_peer.peer, - from = %joiner, - %hops_to_live, - "Connection request received", - ); - - // todo: location should be based on your public IP - let new_location = assigned_location.unwrap_or_else(Location::random); - let accepted_by = if op_manager.ring.should_accept(new_location, joiner) { - tracing::debug!(tx = %id, %joiner, "Accepting connection from"); - HashSet::from_iter([*this_peer]) - } else { - tracing::debug!(tx = %id, at = %this_peer.peer, from = %joiner, "Rejecting connection"); - HashSet::new() - }; + let joiner: PeerId = joiner + .clone() + .expect("should be already set at the p2p bridge level"); + let this_peer = op_manager.ring.own_location(); + let assigned_location = Location::random(); let new_peer_loc = PeerKeyLocation { - location: Some(new_location), - peer: *joiner, + location: Some(assigned_location), + peer: joiner.clone(), }; - if let Some(mut updated_state) = forward_conn( + + let accepted = op_manager + .ring + .should_accept(assigned_location, Some(&joiner)); + + if let Some(updated_state) = forward_conn( *id, &op_manager.ring, network_bridge, - (new_peer_loc, new_peer_loc), + (new_peer_loc.clone(), new_peer_loc.clone()), *hops_to_live, - accepted_by.clone(), - vec![this_peer.peer, *joiner], + accepted, // gateway always accept the first connection + skip_list.clone(), ) .await? { - tracing::debug!( - tx = %id, - at = %this_peer.peer, - "Awaiting proxy response", - ); - updated_state.add_new_proxy(accepted_by.iter().copied())?; - // awaiting responses from proxies new_state = Some(updated_state); - return_msg = None; } else { - if !accepted_by.is_empty() { - tracing::debug!( - tx = %id, - at = %this_peer.peer, - %joiner, - "Open connection received at gateway", - ); - new_state = Some(ConnectState::OCReceived); - } else { - new_state = None - } - return_msg = Some(ConnectMsg::Response { - id: *id, - sender: *this_peer, - msg: ConnectResponse::AcceptedBy { - peers: accepted_by, - your_location: new_location, - your_peer_id: *joiner, - }, - target: PeerKeyLocation { - peer: *joiner, - location: Some(new_location), - }, - }); + new_state = None; + } + + if accepted { + op_manager + .ring + .add_connection(assigned_location, joiner.clone()) + .await; + tracing::debug!(tx = %id, at = %this_peer.peer, %joiner, "Accepting connection"); + } else { + tracing::debug!(tx = %id, at = %this_peer.peer, %joiner, "Rejecting connection"); } + + return_msg = Some(ConnectMsg::Response { + id: *id, + sender: this_peer.clone(), + target: new_peer_loc.clone(), + msg: ConnectResponse::AcceptedBy { + accepted, + acceptor: this_peer.clone(), + joiner: joiner.clone(), + }, + }); } ConnectMsg::Request { id, msg: - ConnectRequest::Proxy { + ConnectRequest::CheckConnectivity { sender, joiner, hops_to_live, skip_list, - accepted_by, + .. }, } => { - let own_loc = op_manager.ring.own_location(); - let mut accepted_by = accepted_by.clone(); + let this_peer = op_manager.ring.own_location(); + let joiner_loc = joiner + .location + .expect("should be already set at the p2p bridge level"); + tracing::debug!( tx = %id, - from = %sender.peer, - joiner = %joiner.peer, - at = %own_loc.peer, - %hops_to_live, - "Proxy connect request received to connect with peer", + at = %this_peer.peer, + hops_to_live = %hops_to_live, + joiner = %joiner, + "Checking connectivity request received" ); - if op_manager.ring.should_accept( - joiner.location.ok_or(ConnectionError::LocationUnknown)?, - &joiner.peer, - ) { - tracing::debug!(tx = %id, "Accepting proxy connection from {}", joiner.peer); - accepted_by.insert(own_loc); + + let should_accept = if op_manager + .ring + .should_accept(joiner_loc, Some(&joiner.peer)) + { + tracing::debug!(tx = %id, %joiner, "Accepting connection from"); + op_manager + .ring + .add_connection(joiner_loc, joiner.peer.clone()) + .await; + + true } else { - tracing::debug!( - tx = %id, - joiner = %joiner.peer, - at = %own_loc.peer, - "Not accepting new proxy connection", - ); - } + tracing::debug!(tx = %id, at = %this_peer.peer, from = %joiner, "Rejecting connection"); + false + }; - let mut skip_list = skip_list.clone(); - skip_list.push(own_loc.peer); - if let Some(mut updated_state) = forward_conn( + if let Some(updated_state) = forward_conn( *id, &op_manager.ring, network_bridge, - (*sender, *joiner), + (sender.clone(), joiner.clone()), *hops_to_live, - accepted_by.clone(), - skip_list, + should_accept, + skip_list.clone(), ) .await? { - updated_state.add_new_proxy(accepted_by.iter().copied())?; - // awaiting responses from proxies new_state = Some(updated_state); - return_msg = None; } else { - match self.state { - Some(ConnectState::Initializing) => { - let (state, msg) = try_returning_proxy_connection( - id, - sender, - &own_loc, - accepted_by, - joiner.peer, - ); - new_state = state; - return_msg = msg; - } - Some(other_state) => { - return Err(OpError::invalid_transition_with_state( - self.id, - Box::new(other_state), - )) - } - None => return Err(OpError::invalid_transition(self.id)), - }; + tracing::debug!(tx = %id, at = %this_peer.peer, "Rejecting connection from {:?}", joiner); + new_state = None } + + let response = ConnectResponse::AcceptedBy { + accepted: should_accept, + acceptor: this_peer.clone(), + joiner: joiner.peer.clone(), + }; + + return_msg = Some(ConnectMsg::Response { + id: *id, + sender: this_peer.clone(), + msg: response, + target: sender.clone(), + }); } ConnectMsg::Response { id, @@ -375,9 +364,9 @@ impl Operation for ConnectOp { target, msg: ConnectResponse::AcceptedBy { - peers: accepted_by, - your_location, - your_peer_id, + accepted, + acceptor, + joiner, }, } => { tracing::debug!( @@ -387,281 +376,181 @@ impl Operation for ConnectOp { "Connect response received", ); - // Set the given location - let pk_loc = PeerKeyLocation { - location: Some(*your_location), - peer: *your_peer_id, - }; + let this_peer_id = op_manager.ring.get_peer_key().expect("peer id not found"); - let Some(ConnectState::Connecting(ConnectionInfo { gateway, .. })) = self.state - else { - return Err(OpError::invalid_transition(self.id)); - }; - if !accepted_by.is_empty() { - tracing::debug!( - tx = %id, - at = %your_peer_id, - from = %sender.peer, - "Open connections acknowledged at requesting peer", - ); - new_state = Some(ConnectState::OCReceived); - if accepted_by.contains(&gateway) { - // just send back a message in case the gw accepteds the connection - // otherwise skip sending anything back - return_msg = Some(ConnectMsg::Response { - id: *id, - msg: ConnectResponse::ReceivedOC { - by_peer: pk_loc, - gateway, - }, - sender: pk_loc, - target: gateway, - }); - } else { - return_msg = None; - } - tracing::debug!( - tx = %id, - at = %your_peer_id, - location = %your_location, - "Updating assigned location" - ); - op_manager.ring.update_location(Some(*your_location)); - - for other_peer in accepted_by.iter().filter(|pl| pl.peer != target.peer) { - let _ = propagate_oc_to_responding_peers( - network_bridge, - op_manager, - gateway, - other_peer, - ConnectMsg::Response { - id: *id, - target: *other_peer, - sender: pk_loc, - msg: ConnectResponse::ReceivedOC { - by_peer: pk_loc, - gateway, - }, - }, - ) - .await; - } - } else { - // no connections accepted, failed - tracing::debug!( - tx = %id, - peer = %your_peer_id, - "Failed to establish any connections, aborting" - ); - let op = ConnectOp { - id: *id, - state: None, - gateway: self.gateway, - backoff: self.backoff, - }; - op_manager - .notify_op_change(NetMessage::Aborted(*id), OpEnum::Connect(op.into())) - .await?; - return Err(OpError::StatePushed); - } - } - ConnectMsg::Response { - id, - target, - sender, - msg: - ConnectResponse::Proxy { - accepted_by, - joiner, - }, - } => { - tracing::debug!(tx = %id, at = %target.peer, "Received proxy connect response"); - match self.state { - Some(ConnectState::AwaitingProxyResponse { - accepted_by: mut previously_accepted, - new_peer_id, - target: original_target, - new_location, - }) => { - let own_loc = op_manager.ring.own_location(); - let target_is_joiner = new_peer_id == original_target.peer; - - previously_accepted.extend(accepted_by.iter().copied()); - let is_accepted: bool = previously_accepted.contains(&own_loc); - if is_accepted { - new_state = Some(ConnectState::OCReceived); - } else { - new_state = None; - } + match self.state.as_mut() { + Some(ConnectState::ConnectingToNode(info)) => { + assert!(info.remaining_connetions > 0); + let remaining_connetions = info.remaining_connetions.saturating_sub(1); - if target_is_joiner { + if *accepted { tracing::debug!( tx = %id, - original_receiver = %target.peer, - original_target = %original_target.peer, - "Sending response to connect request with all the peers that accepted \ - connection from original target", + at = %this_peer_id, + from = %sender.peer, + connectect_to = %acceptor.peer, + "Open connection acknowledged at requesting joiner peer", ); - return_msg = Some(ConnectMsg::Response { - id: *id, - target: original_target, - sender: *target, - msg: ConnectResponse::AcceptedBy { - peers: previously_accepted, - your_location: new_location, - your_peer_id: new_peer_id, - }, - }); + info.accepted_by.insert(acceptor.clone()); + op_manager + .ring + .add_connection( + acceptor.location.expect("location not found"), + acceptor.peer.clone(), + ) + .await; } else { tracing::debug!( tx = %id, - at = %target.peer, - to = %original_target.peer, - "Sending response to connect request with all the peers that accepted \ - connection from proxy peer", + at = %this_peer_id, + from = %sender.peer, + rejected_peer = %acceptor.peer, + "Connection rejected", + ); + } + + let your_location: Location = + target.location.expect("location not found"); + tracing::debug!( + tx = %id, + at = %this_peer_id, + location = %your_location, + "Updating assigned location" + ); + op_manager.ring.update_location(target.location); + + if remaining_connetions == 0 { + tracing::debug!( + tx = %id, + at = %this_peer_id, + from = %sender.peer, + "All available connections established", ); - return_msg = Some(ConnectMsg::Response { - id: *id, - target: original_target, - sender: *target, - msg: ConnectResponse::Proxy { - accepted_by: previously_accepted, - joiner: *joiner, - }, - }); + try_clean_gw_connection( + id.clone(), + network_bridge, + info, + target.clone(), + ) + .await?; + + new_state = Some(ConnectState::Connected); + } else { + new_state = Some(ConnectState::ConnectingToNode(info.clone())); } + return_msg = None; } - Some(ConnectState::AwaitingConnectionAcquisition { joiner }) => { + Some(ConnectState::AwaitingConnectivity(ConnectivityInfo { + remaining_checks, + requester, + })) => { + assert!(*remaining_checks > 0); + let remaining_checks = remaining_checks.saturating_sub(1); + + if *accepted { + tracing::debug!( + tx = %id, + at = %this_peer_id, + from = %sender.peer, + accecpted_by = %acceptor.peer, + "Connectivity check accepted", + ); + let acceptor_loc = + acceptor.location.expect("location not found for acceptor"); + op_manager + .ring + .add_connection(acceptor_loc, acceptor.peer.clone()) + .await; + } else { + tracing::debug!( + tx = %id, + at = %this_peer_id, + from = %sender.peer, + rejected_by = %acceptor.peer, + "Connectivity check rejected", + ); + } + if remaining_checks == 0 { + tracing::debug!( + tx = %id, + at = %this_peer_id, + from = %sender.peer, + "All connectivity checks done", + ); + new_state = None; + } else { + new_state = + Some(ConnectState::AwaitingConnectivity(ConnectivityInfo { + remaining_checks, + requester: requester.clone(), + })); + } + let response = ConnectResponse::AcceptedBy { + accepted: *accepted, + acceptor: acceptor.clone(), + joiner: joiner.clone(), + }; return_msg = Some(ConnectMsg::Response { id: *id, - target: joiner, - sender: *target, - msg: ConnectResponse::Proxy { - accepted_by: accepted_by.clone(), - joiner: joiner.peer, - }, + sender: target.clone(), + msg: response, + target: requester.clone(), }); - new_state = None; } - Some(ConnectState::AwaitingNewConnection { query_target }) => { - let joiner = *target; - if accepted_by.is_empty() { + Some(ConnectState::AwaitingNewConnection(info)) => { + tracing::debug!( + tx = %id, + at = %this_peer_id, + from = %sender.peer, + "Connection request forwarded", + ); + assert!(info.remaining_connetions > 0); + let remaining_connetions = info.remaining_connetions.saturating_sub(1); + + if remaining_connetions == 0 { + tracing::debug!( + tx = %id, + at = %this_peer_id, + from = %sender.peer, + "All available connections established", + ); op_manager .ring .live_tx_tracker - .missing_candidate_peers(query_target) + .missing_candidate_peers(this_peer_id) .await; - return_msg = None; new_state = None; } else { - for peer in accepted_by { - propagate_oc_to_responding_peers( - network_bridge, - op_manager, - *sender, - peer, - ConnectMsg::Response { - id: *id, - sender: joiner, - target: *peer, - msg: ConnectResponse::ReceivedOC { - by_peer: joiner, - gateway: *sender, // irrelevant in this case - }, - }, - ) - .await?; - } - return_msg = None; - new_state = None; - } - } - Some(other_state) => { - return Err(OpError::invalid_transition_with_state( - self.id, - Box::new(other_state), - )) - } - None => return Err(OpError::invalid_transition(self.id)), - } - } - ConnectMsg::Response { - id, - sender, - target, - msg: ConnectResponse::ReceivedOC { by_peer, gateway }, - } => { - match self.state { - Some(ConnectState::OCReceived) => { - if target == gateway { - tracing::debug!(tx = %id, from = %by_peer.peer, at = %target.peer, "Acknowledge connected at gateway"); - return_msg = Some(ConnectMsg::Connected { - id: *id, - sender: *target, - target: *sender, - }); - new_state = Some(ConnectState::Connected); - } else { - tracing::debug!(tx = %id, from = %by_peer.peer, at = %target.peer, "Acknowledge connected at peer"); - return_msg = None; - new_state = None; + new_state = + Some(ConnectState::AwaitingNewConnection(NewConnectionInfo { + remaining_connetions, + })); } - } - Some(other_state) => { - return Err(OpError::invalid_transition_with_state( - self.id, - Box::new(other_state), - )) - } - None => { - tracing::error!(tx = %self.id, at = %target.peer, "completed"); - return Err(OpError::invalid_transition(self.id)); - } - } - network_bridge.add_connection(sender.peer).await?; - op_manager - .ring - .add_connection( - sender.location.ok_or(ConnectionError::LocationUnknown)?, - sender.peer, - ) - .await; - tracing::debug!(tx = %id, from = %by_peer.peer, "Opened connection with peer"); - if target != gateway { - new_state = None; - } - } - ConnectMsg::Connected { target, sender, id } => { - match self.state { - Some(ConnectState::OCReceived) => { - tracing::debug!(tx = %id, at = %target.peer, "Acknowledge connected at peer"); return_msg = None; } - Some(other_state) => { - return Err(OpError::invalid_transition_with_state( - self.id, - Box::new(other_state), - )) + _ => { + tracing::debug!( + tx = %id, + peer = %this_peer_id, + "Failed to establish any connections, aborting" + ); + let op = ConnectOp { + id: *id, + state: None, + gateway: self.gateway, + backoff: self.backoff, + }; + op_manager + .notify_op_change( + NetMessage::V1(NetMessageV1::Aborted(*id)), + OpEnum::Connect(op.into()), + ) + .await?; + return Err(OpError::StatePushed); } - None => return Err(OpError::invalid_transition(self.id)), - }; - tracing::info!( - tx = %id, - at = %target.peer, - assigned_location = ?op_manager.ring.own_location().location, - "Successfully completed connection", - ); - network_bridge.add_connection(sender.peer).await?; - op_manager - .ring - .add_connection( - sender.location.ok_or(ConnectionError::LocationUnknown)?, - sender.peer, - ) - .await; - new_state = None; + } } _ => return Err(OpError::UnexpectedOpState), } @@ -678,134 +567,92 @@ fn build_op_result( gateway: Option>, backoff: Option, ) -> Result { - let output_op = Some(ConnectOp { + tracing::debug!(tx = %id, ?msg, "Connect operation result"); + let output_op = Some(OpEnum::Connect(Box::new(ConnectOp { id, state, gateway, backoff, - }); + }))); Ok(OperationResult { return_msg: msg.map(NetMessage::from), - state: output_op.map(|op| OpEnum::Connect(Box::new(op))), + state: output_op, }) } -fn try_returning_proxy_connection( - id: &Transaction, - sender: &PeerKeyLocation, - own_loc: &PeerKeyLocation, - accepted_by: HashSet, - joiner: PeerId, -) -> (Option, Option) { - let new_state = if accepted_by.contains(own_loc) { - tracing::debug!( - tx = %id, - to = % sender.peer, - proxy = %own_loc.peer, - "Return message, connected at proxy", - ); - Some(ConnectState::OCReceived) - } else { - tracing::debug!(tx = %id, proxy = % sender.peer, "Failed to connect at proxy"); - None - }; - let return_msg = Some(ConnectMsg::Response { - msg: ConnectResponse::Proxy { - accepted_by, - joiner, - }, - sender: *own_loc, - id: *id, - target: *sender, - }); - (new_state, return_msg) -} +async fn try_clean_gw_connection( + id: Transaction, + conn_bridge: &mut NB, + state: &mut ConnectionInfo, + joiner: PeerKeyLocation, +) -> Result<(), OpError> +where + NB: NetworkBridge, +{ + let need_to_clean_gw_conn = state + .accepted_by + .iter() + .all(|pkloc| pkloc.peer != state.gateway.peer); -async fn propagate_oc_to_responding_peers( - network_bridge: &mut NB, - op_manager: &OpManager, - sender: PeerKeyLocation, - other_peer: &PeerKeyLocation, - msg: ConnectMsg, -) -> Result<(), OpError> { - let id = msg.id(); - if op_manager.ring.should_accept( - other_peer - .location - .ok_or(ConnectionError::LocationUnknown)?, - &other_peer.peer, - ) { - tracing::info!(tx = %id, from = %sender.peer, to = %other_peer.peer, "Established connection"); - network_bridge.add_connection(other_peer.peer).await?; - op_manager - .ring - .add_connection( - other_peer - .location - .ok_or(ConnectionError::LocationUnknown)?, - other_peer.peer, - ) - .await; - if other_peer.peer != sender.peer { - // notify all the additional peers which accepted a request; - // the gateway will be notified in the last message - let _ = network_bridge.send(&other_peer.peer, msg.into()).await; - } - } else { - tracing::debug!(tx = %id, from = %sender.peer, to = %other_peer.peer, "Not accepting connection to"); + if need_to_clean_gw_conn { + let msg = ConnectMsg::Request { + id, + msg: ConnectRequest::CleanConnection { joiner }, + }; + conn_bridge.send(&state.gateway.peer, msg.into()).await?; } - Ok(()) } +type Requester = PeerKeyLocation; + #[derive(Debug)] enum ConnectState { Initializing, - Connecting(ConnectionInfo), - AwaitingProxyResponse { - /// Could be either the joiner or nodes which have been previously forwarded to - target: PeerKeyLocation, - accepted_by: HashSet, - new_location: Location, - new_peer_id: PeerId, - }, - AwaitingConnectionAcquisition { - joiner: PeerKeyLocation, - }, - AwaitingNewConnection { - query_target: PeerId, - }, - OCReceived, + ConnectingToNode(ConnectionInfo), + AwaitingConnectivity(ConnectivityInfo), + AwaitingConnectionAcquisition, + AwaitingNewConnection(NewConnectionInfo), Connected, } +#[derive(Debug, Clone)] +struct ConnectivityInfo { + remaining_checks: usize, + requester: Requester, +} + +impl ConnectivityInfo { + fn new(requester: Requester, remaining_checks: usize) -> Self { + Self { + requester, + remaining_checks, + } + } +} + #[derive(Debug, Clone)] struct ConnectionInfo { gateway: PeerKeyLocation, - this_peer: PeerId, + peer_pub_key: TransportPublicKey, max_hops_to_live: usize, + accepted_by: HashSet, + remaining_connetions: usize, +} + +#[derive(Debug, Clone)] +struct NewConnectionInfo { + remaining_connetions: usize, } impl ConnectState { fn try_unwrap_connecting(self) -> Result { - if let Self::Connecting(conn_info) = self { + if let Self::ConnectingToNode(conn_info) = self { Ok(conn_info) } else { Err(OpError::UnexpectedOpState) } } - - fn add_new_proxy( - &mut self, - proxies: impl IntoIterator, - ) -> Result<(), OpError> { - if let Self::AwaitingProxyResponse { accepted_by, .. } = self { - accepted_by.extend(proxies); - Ok(()) - } else { - Err(OpError::UnexpectedOpState) - } - } } /// # Arguments @@ -816,43 +663,66 @@ impl ConnectState { /// /// - is_gateway: Whether this peer is a gateway or not. pub(crate) async fn initial_join_procedure( - op_manager: &OpManager, - conn_manager: &mut CM, - this_peer: PeerId, + op_manager: Arc, + mut conn_manager: CM, + peer_pub_key: TransportPublicKey, gateways: &[PeerKeyLocation], ) -> Result<(), OpError> where - CM: NetworkBridge + Send, + CM: NetworkBridge + Send + 'static, { use crate::util::IterExt; let number_of_parallel_connections = { let max_potential_conns_per_gw = op_manager.ring.max_hops_to_live; // e.g. 10 gateways and htl 5 -> only need 2 connections in parallel - let needed_to_cover_max = gateways - .iter() - .filter(|conn| conn.peer != this_peer) - .count() - / max_potential_conns_per_gw; - needed_to_cover_max.max(1) + let needed_to_cover_max = op_manager.ring.max_connections / max_potential_conns_per_gw; + gateways.iter().take(needed_to_cover_max).count().max(1) }; - tracing::info!( - "Attempting to connect to {} gateways in parallel", - number_of_parallel_connections - ); - for gateway in gateways - .iter() - .shuffle() - .filter(|conn| conn.peer != this_peer) - .take(number_of_parallel_connections) - { - join_ring_request(None, this_peer, gateway, op_manager, conn_manager).await?; - } + let gateways = gateways.to_vec(); + tokio::task::spawn(async move { + loop { + if op_manager.ring.open_connections() == 0 { + tracing::info!( + "Attempting to connect to {} gateways in parallel", + number_of_parallel_connections + ); + for gateway in gateways + .iter() + .shuffle() + .take(number_of_parallel_connections) + { + tracing::info!(%gateway, "Attempting connection to gateway"); + // FIXME: because it stays connected after first attempt, even if it fails, + // we won't be ever retrying with the same gateway + // for gateway in op_manager + // .ring + // .is_connected(gateways.iter()) + // .shuffle() + // .take(number_of_parallel_connections) + // { + if let Err(error) = join_ring_request( + None, + peer_pub_key.clone(), + gateway, + &*op_manager, + &mut conn_manager, + ) + .await + { + tracing::error!(%error, "Failed while attempting connection to gateway"); + } + } + } + tokio::time::sleep(Duration::from_secs(15)).await; + } + }); Ok(()) } +#[tracing::instrument(fields(peer = ?op_manager.ring.get_peer_key()), skip_all)] pub(crate) async fn join_ring_request( backoff: Option, - peer_key: PeerId, + peer_pub_key: TransportPublicKey, gateway: &PeerKeyLocation, op_manager: &OpManager, conn_manager: &mut CM, @@ -860,8 +730,20 @@ pub(crate) async fn join_ring_request( where CM: NetworkBridge + Send, { + if !op_manager.ring.should_accept( + gateway.location.unwrap_or_else(|| Location::random()), + Some(&gateway.peer), + ) { + // ensure that we still want to connect AND reserve an spot implicitly + return Err(OpError::ConnError(ConnectionError::FailedConnectOp)); + } let tx_id = Transaction::new::(); - let mut op = initial_request(peer_key, *gateway, op_manager.ring.max_hops_to_live, tx_id); + let mut op = initial_request( + peer_pub_key, + gateway.clone(), + op_manager.ring.max_hops_to_live, + tx_id, + ); if let Some(mut backoff) = backoff { // backoff to retry later in case it failed tracing::warn!("Performing a new join, attempt {}", backoff.retries() + 1); @@ -885,16 +767,18 @@ where } fn initial_request( - this_peer: PeerId, + peer_pub_key: TransportPublicKey, gateway: PeerKeyLocation, max_hops_to_live: usize, id: Transaction, ) -> ConnectOp { const MAX_JOIN_RETRIES: usize = usize::MAX; - let state = ConnectState::Connecting(ConnectionInfo { - gateway, - this_peer, + let state = ConnectState::ConnectingToNode(ConnectionInfo { + gateway: gateway.clone(), + peer_pub_key: peer_pub_key.clone(), max_hops_to_live, + accepted_by: HashSet::new(), + remaining_connetions: max_hops_to_live, }); let ceiling = if cfg!(test) { Duration::from_secs(1) @@ -928,27 +812,25 @@ where } = join_op; let ConnectionInfo { gateway, - this_peer, + peer_pub_key, max_hops_to_live, + .. } = state.expect("infallible").try_unwrap_connecting()?; tracing::info!( tx = %id, - %this_peer, gateway = %gateway, "Connecting to gateway", ); - conn_bridge.add_connection(gateway.peer).await?; - let assigned_location = op_manager.ring.own_location().location; let join_req = NetMessage::from(messages::ConnectMsg::Request { id: tx, - msg: messages::ConnectRequest::StartReq { - target: gateway, - joiner: this_peer, - assigned_location, + msg: ConnectRequest::StartJoinReq { + joiner: None, + joiner_key: peer_pub_key.clone(), hops_to_live: max_hops_to_live, max_hops_to_live, + skip_list: vec![], }, }); conn_bridge.send(&gateway.peer, join_req).await?; @@ -957,10 +839,12 @@ where tx, OpEnum::Connect(Box::new(ConnectOp { id, - state: Some(ConnectState::Connecting(ConnectionInfo { - gateway, - this_peer, + state: Some(ConnectState::ConnectingToNode(ConnectionInfo { + gateway: gateway.clone(), + peer_pub_key, max_hops_to_live, + accepted_by: HashSet::new(), + remaining_connetions: max_hops_to_live, })), gateway: Some(Box::new(gateway)), backoff, @@ -976,7 +860,7 @@ async fn forward_conn( network_bridge: &mut NB, (req_peer, joiner): (PeerKeyLocation, PeerKeyLocation), left_htl: usize, - accepted_by: HashSet, + accepted: bool, skip_list: Vec, ) -> Result, OpError> where @@ -1000,7 +884,28 @@ where return Ok(None); } - let forward_to = if left_htl >= ring.rnd_if_htl_above { + let target_peer = select_forward_target(id, ring, &req_peer, &joiner, left_htl, &skip_list); + match target_peer { + Some(target_peer) => { + let forward_msg = + create_forward_message(id, &req_peer, &joiner, left_htl, &[req_peer.peer.clone()]); + tracing::debug!(target: "network", "Forwarding connection request to {:?}", target_peer); + network_bridge.send(&target_peer.peer, forward_msg).await?; + update_state_with_forward_info(&req_peer, left_htl) + } + None => handle_unforwardable_connection(id, accepted), + } +} + +fn select_forward_target( + id: Transaction, + ring: &Ring, + request_peer: &PeerKeyLocation, + joiner: &PeerKeyLocation, + left_htl: usize, + skip_list: &[PeerId], +) -> Option { + if left_htl >= ring.rnd_if_htl_above { tracing::debug!( tx = %id, joiner = %joiner.peer, @@ -1013,49 +918,56 @@ where joiner = %joiner.peer, "Selecting close peer to forward request", ); - // FIXME: target the `desired_location` - let desired_location = joiner.location.unwrap(); - ring.routing(desired_location, Some(&req_peer.peer), skip_list.as_slice()) - .and_then(|pkl| (pkl.peer != joiner.peer).then_some(pkl)) - }; + ring.routing( + joiner.location.unwrap(), + Some(&request_peer.peer), + skip_list, + ) + .and_then(|pkl| (pkl.peer != joiner.peer).then_some(pkl)) + } +} - if let Some(forward_to) = forward_to { - let forwarded = NetMessage::from(ConnectMsg::Request { - id, - msg: ConnectRequest::Proxy { - joiner, - hops_to_live: left_htl.saturating_sub(1), - sender: ring.own_location(), - skip_list, - accepted_by: accepted_by.clone(), - }, - }); - tracing::debug!( +fn create_forward_message( + id: Transaction, + request_peer: &PeerKeyLocation, + joiner: &PeerKeyLocation, + hops_to_live: usize, + skip_list: &[PeerId], +) -> NetMessage { + NetMessage::from(ConnectMsg::Request { + id, + msg: ConnectRequest::CheckConnectivity { + sender: request_peer.clone(), + joiner: joiner.clone(), + hops_to_live, + max_hops_to_live: hops_to_live, + skip_list: skip_list.to_vec(), + }, + }) +} + +fn update_state_with_forward_info( + requester: &PeerKeyLocation, + left_htl: usize, +) -> Result, OpError> { + let connecivity_info = ConnectivityInfo::new(requester.clone(), left_htl); + let new_state = ConnectState::AwaitingConnectivity(connecivity_info); + Ok(Some(new_state)) +} + +fn handle_unforwardable_connection( + id: Transaction, + accepted: bool, +) -> Result, OpError> { + if accepted { + tracing::warn!( tx = %id, - sender = %req_peer.peer, - forward_target = %forward_to.peer, - "Forwarding connect request from sender to other peer", + "Unable to forward, will only be connecting to one peer", ); - network_bridge.send(&forward_to.peer, forwarded).await?; - // awaiting for responses from forward nodes - let new_state = ConnectState::AwaitingProxyResponse { - target: req_peer, - accepted_by, - new_location: joiner.location.unwrap(), - new_peer_id: joiner.peer, - }; - Ok(Some(new_state)) } else { - if !accepted_by.is_empty() { - tracing::warn!( - tx = %id, - "Unable to forward, will only be connecting to one peer", - ); - } else { - tracing::warn!(tx = %id, "Unable to forward or accept any connections"); - } - Ok(None) + tracing::warn!(tx = %id, "Unable to forward or accept any connections"); } + Ok(None) } mod messages { @@ -1065,7 +977,7 @@ mod messages { use serde::{Deserialize, Serialize}; - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug, Serialize, Deserialize, Clone)] pub(crate) enum ConnectMsg { Request { id: Transaction, @@ -1093,15 +1005,11 @@ mod messages { } } - fn target(&self) -> Option<&PeerKeyLocation> { + fn target(&self) -> Option { use ConnectMsg::*; match self { - Response { target, .. } => Some(target), - Request { - msg: ConnectRequest::StartReq { target, .. }, - .. - } => Some(target), - Connected { target, .. } => Some(target), + Response { target, .. } => Some(target.clone()), + Connected { target, .. } => Some(target.clone()), _ => None, } } @@ -1111,7 +1019,7 @@ mod messages { matches!( self, Response { - msg: ConnectResponse::Proxy { .. }, + msg: ConnectResponse::AcceptedBy { .. }, .. } | Connected { .. } ) @@ -1128,14 +1036,7 @@ mod messages { match self { Response { sender, .. } => Some(&sender.peer), Connected { sender, .. } => Some(&sender.peer), - Request { - msg: - ConnectRequest::StartReq { - joiner: req_peer, .. - }, - .. - } => Some(req_peer), - _ => None, + Request { .. } => None, } } } @@ -1145,39 +1046,29 @@ mod messages { let id = self.id(); match self { Self::Request { - msg: ConnectRequest::StartReq { .. }, + msg: ConnectRequest::StartJoinReq { .. }, .. } => write!(f, "StartRequest(id: {id})"), - Self::Request { - msg: ConnectRequest::Proxy { .. }, - .. - } => write!(f, "ProxyRequest(id: {id})"), Self::Response { msg: ConnectResponse::AcceptedBy { .. }, .. - } => write!(f, "RouteValue(id: {id})"), - Self::Response { - msg: ConnectResponse::ReceivedOC { .. }, - .. - } => write!(f, "RouteValue(id: {id})"), - Self::Response { - msg: ConnectResponse::Proxy { .. }, - .. - } => write!(f, "RouteValue(id: {id})"), + } => write!(f, "AcceptedBy(id: {id})"), Self::Connected { .. } => write!(f, "Connected(id: {id})"), - _ => unimplemented!(), + ConnectMsg::Request { id, .. } => write!(f, "Request(id: {id})"), } } } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub(crate) enum ConnectRequest { - StartReq { - target: PeerKeyLocation, - joiner: PeerId, - assigned_location: Option, + StartJoinReq { + // The peer who is trying to join, should be set when PeerConnection is established + joiner: Option, + joiner_key: TransportPublicKey, hops_to_live: usize, max_hops_to_live: usize, + // The list of peers to skip when forwarding the connection request, avoiding loops + skip_list: Vec, }, /// Query target should find a good candidate for joiner to join. FindOptimalPeer { @@ -1187,30 +1078,26 @@ mod messages { ideal_location: Location, joiner: PeerKeyLocation, max_hops_to_live: usize, + skip_list: Vec, }, - Proxy { + CheckConnectivity { sender: PeerKeyLocation, joiner: PeerKeyLocation, hops_to_live: usize, + max_hops_to_live: usize, + // The list of peers to skip when forwarding the connection request, avoiding loops skip_list: Vec, - accepted_by: HashSet, }, - ReceivedOC, + CleanConnection { + joiner: PeerKeyLocation, + }, } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub(crate) enum ConnectResponse { AcceptedBy { - peers: HashSet, - your_location: Location, - your_peer_id: PeerId, - }, - ReceivedOC { - by_peer: PeerKeyLocation, - gateway: PeerKeyLocation, - }, - Proxy { - accepted_by: HashSet, + accepted: bool, + acceptor: PeerKeyLocation, joiner: PeerId, }, } diff --git a/crates/core/src/operations/get.rs b/crates/core/src/operations/get.rs index 412f99e13..f64d78c61 100644 --- a/crates/core/src/operations/get.rs +++ b/crates/core/src/operations/get.rs @@ -38,7 +38,6 @@ pub(crate) fn start_op(key: ContractKey, fetch_contract: bool) -> GetOp { next_peer: None, transfer_time: None, first_response_time: None, - step: Default::default(), }), } } @@ -85,7 +84,7 @@ pub(crate) async fn request_get(op_manager: &OpManager, get_op: GetOp) -> Result let msg = GetMsg::RequestGet { id, key, - target, + target: target.clone(), fetch_contract, }; @@ -136,18 +135,6 @@ struct GetStats { first_response_time: Option<(Instant, Option)>, /// (start, end) transfer_time: Option<(Instant, Option)>, - step: RecordingStats, -} - -/// While timing, at what particular step we are now. -#[derive(Clone, Copy, Default)] -enum RecordingStats { - #[default] - Uninitialized, - InitGet, - TransferNotStarted, - TransferStarted, - Completed, } pub(crate) struct GetResult { @@ -210,34 +197,6 @@ impl GetOp { self.result.is_some() } - pub(super) fn record_transfer(&mut self) { - if let Some(stats) = self.stats.as_mut() { - match stats.step { - RecordingStats::Uninitialized => { - stats.first_response_time = Some((Instant::now(), None)); - stats.step = RecordingStats::InitGet; - } - RecordingStats::InitGet => { - if let Some((_, e)) = stats.first_response_time.as_mut() { - *e = Some(Instant::now()); - } - stats.step = RecordingStats::TransferNotStarted; - } - RecordingStats::TransferNotStarted => { - stats.transfer_time = Some((Instant::now(), None)); - stats.step = RecordingStats::TransferStarted; - } - RecordingStats::TransferStarted => { - if let Some((_, e)) = stats.transfer_time.as_mut() { - *e = Some(Instant::now()); - } - stats.step = RecordingStats::Completed; - } - RecordingStats::Completed => {} - } - } - } - pub(super) fn to_host_result(&self) -> HostResult { match &self.result { Some(GetResult { @@ -332,14 +291,13 @@ impl Operation for GetOp { next_peer: None, transfer_time: None, first_response_time: None, - step: Default::default(), }); let own_loc = op_manager.ring.own_location(); return_msg = Some(GetMsg::SeekNode { key: key.clone(), id: *id, - target: *target, - sender: own_loc, + target: target.clone(), + sender: own_loc.clone(), fetch_contract: *fetch_contract, htl: op_manager.ring.max_hops_to_live, skip_list: vec![own_loc.peer], @@ -358,10 +316,10 @@ impl Operation for GetOp { let id = *id; let key: ContractKey = key.clone(); let fetch_contract = *fetch_contract; - let this_peer = *target; + let this_peer = target.clone(); if let Some(s) = stats.as_mut() { - s.next_peer = Some(this_peer); + s.next_peer = Some(this_peer.clone()); } let get_result = op_manager @@ -385,7 +343,7 @@ impl Operation for GetOp { id, key, (htl, fetch_contract), - (this_peer, *sender), + (this_peer, sender.clone()), skip_list, op_manager, stats, @@ -408,7 +366,7 @@ impl Operation for GetOp { state: Some(state), contract, }, - sender: *target, + sender: target.clone(), target: requester, skip_list: skip_list.clone(), }); @@ -432,8 +390,8 @@ impl Operation for GetOp { state: Some(state), contract, }, - sender: *target, - target: *sender, + sender: target.clone(), + target: sender.clone(), skip_list: skip_list.clone(), }); } @@ -469,7 +427,7 @@ impl Operation for GetOp { if retries < MAX_RETRIES { // no response received from this peer, so skip it in the next iteration let mut new_skip_list = skip_list.clone(); - new_skip_list.push(target.peer); + new_skip_list.push(target.peer.clone()); if let Some(target) = op_manager .ring .closest_potentially_caching(key, new_skip_list.as_slice()) @@ -480,7 +438,7 @@ impl Operation for GetOp { id: *id, key: key.clone(), target, - sender: *this_peer, + sender: this_peer.clone(), fetch_contract, htl: current_hop, skip_list: new_skip_list.clone(), @@ -516,8 +474,8 @@ impl Operation for GetOp { state: None, contract: None, }, - sender: *sender, - target: *target, + sender: sender.clone(), + target: target.clone(), skip_list: skip_list.clone(), }); } @@ -556,7 +514,7 @@ impl Operation for GetOp { ); let mut new_skip_list = skip_list.clone(); - new_skip_list.push(sender.peer); + new_skip_list.push(sender.peer.clone()); op_manager .notify_op_change( NetMessage::from(GetMsg::ReturnGet { @@ -566,8 +524,8 @@ impl Operation for GetOp { state: None, contract: None, }, - sender: *sender, - target: *target, + sender: sender.clone(), + target: target.clone(), skip_list: new_skip_list, }), OpEnum::Get(GetOp { @@ -605,7 +563,7 @@ impl Operation for GetOp { let is_subscribed_contract = op_manager.ring.is_seeding_contract(&key); if !is_subscribed_contract && should_subscribe { - tracing::debug!(tx = %id, %key, peer = %op_manager.ring.peer_key, "Contract not cached @ peer, caching"); + tracing::debug!(tx = %id, %key, peer = %op_manager.ring.get_peer_key().unwrap(), "Contract not cached @ peer, caching"); super::start_subscription_request( op_manager, key.clone(), @@ -622,7 +580,7 @@ impl Operation for GetOp { return Err(OpError::ExecutorError(err)); } else { let mut new_skip_list = skip_list.clone(); - new_skip_list.push(sender.peer); + new_skip_list.push(sender.peer.clone()); op_manager .notify_op_change( @@ -633,8 +591,8 @@ impl Operation for GetOp { state: None, contract: None, }, - sender: *sender, - target: *target, + sender: sender.clone(), + target: target.clone(), skip_list: new_skip_list, }), OpEnum::Get(GetOp { @@ -678,7 +636,7 @@ impl Operation for GetOp { state: Some(value.clone()), contract: contract.clone(), }, - sender: *target, + sender: target.clone(), target: requester, skip_list: skip_list.clone(), }); @@ -698,8 +656,8 @@ impl Operation for GetOp { state: Some(value.clone()), contract: contract.clone(), }, - sender: *target, - target: *sender, + sender: target.clone(), + target: sender.clone(), skip_list: skip_list.clone(), }); } @@ -755,7 +713,7 @@ async fn try_forward_or_return( ); let mut new_skip_list = skip_list.to_vec(); - new_skip_list.push(this_peer.peer); + new_skip_list.push(this_peer.peer.clone()); let new_htl = htl - 1; if new_htl == 0 { diff --git a/crates/core/src/operations/put.rs b/crates/core/src/operations/put.rs index 520a1fa96..766bc54cc 100644 --- a/crates/core/src/operations/put.rs +++ b/crates/core/src/operations/put.rs @@ -4,7 +4,6 @@ use std::future::Future; use std::pin::Pin; -use std::time::Instant; pub(crate) use self::messages::PutMsg; use freenet_stdlib::{ @@ -16,7 +15,7 @@ use super::{OpEnum, OpError, OpInitialization, OpOutcome, Operation, OperationRe use crate::{ client_events::HostResult, contract::ContractHandlerEvent, - message::{InnerMessage, NetMessage, Transaction}, + message::{InnerMessage, NetMessage, NetMessageV1, Transaction}, node::{NetworkBridge, OpManager, PeerId}, ring::{Location, PeerKeyLocation, RingError}, }; @@ -58,29 +57,7 @@ impl PutOp { } pub(super) fn finalized(&self) -> bool { - self.stats - .as_ref() - .map(|s| matches!(s.step, RecordingStats::Completed)) - .unwrap_or(false) - || matches!(self.state, Some(PutState::Finished { .. })) - } - - pub(super) fn record_transfer(&mut self) { - if let Some(stats) = self.stats.as_mut() { - match stats.step { - RecordingStats::Uninitialized => { - stats.transfer_time = Some((Instant::now(), None)); - stats.step = RecordingStats::InitPut; - } - RecordingStats::InitPut => { - if let Some((_, e)) = stats.transfer_time.as_mut() { - *e = Some(Instant::now()); - } - stats.step = RecordingStats::Completed; - } - RecordingStats::Completed => {} - } - } + self.state.is_none() } pub(super) fn to_host_result(&self) -> HostResult { @@ -98,42 +75,11 @@ impl PutOp { } struct PutStats { - // contract_location: Location, - // payload_size: usize, - // /// (start, end) - // first_response_time: Option<(Instant, Option)>, - /// (start, end) - transfer_time: Option<(Instant, Option)>, target: Option, - step: RecordingStats, -} - -/// While timing, at what particular step we are now. -#[derive(Clone, Copy, Default)] -enum RecordingStats { - #[default] - Uninitialized, - InitPut, - Completed, } pub(crate) struct PutResult {} -impl TryFrom for PutResult { - type Error = OpError; - - fn try_from(op: PutOp) -> Result { - if let Some(true) = op - .stats - .map(|s| matches!(s.step, RecordingStats::Completed)) - { - Ok(PutResult {}) - } else { - Err(OpError::UnexpectedOpState) - } - } -} - impl Operation for PutOp { type Message = PutMsg; type Result = PutResult; @@ -210,7 +156,7 @@ impl Operation for PutOp { return_msg = Some(PutMsg::SeekNode { id: *id, sender, - target: *target, + target: target.clone(), value: value.clone(), contract: contract.clone(), related_contracts: related_contracts.clone(), @@ -266,7 +212,7 @@ impl Operation for PutOp { value.clone(), *id, new_htl, - vec![sender.peer], + vec![sender.peer.clone()], ) .await; if put_here && !is_subscribed_contract { @@ -301,7 +247,7 @@ impl Operation for PutOp { last_hop, op_manager, self.state, - (broadcast_to, *sender), + (broadcast_to, sender.clone()), key.clone(), (contract.clone(), value.clone()), ) @@ -346,7 +292,7 @@ impl Operation for PutOp { false, op_manager, self.state, - (broadcast_to, *sender), + (broadcast_to, sender.clone()), key.clone(), (contract.clone(), new_value), ) @@ -377,7 +323,7 @@ impl Operation for PutOp { id: *id, key: key.clone(), new_value: new_value.clone(), - sender, + sender: sender.clone(), contract: contract.clone(), }; let f = conn_manager.send(&peer.peer, msg.into()); @@ -417,7 +363,7 @@ impl Operation for PutOp { // Subscriber nodes have been notified of the change, the operation is completed return_msg = Some(PutMsg::SuccessfulPut { id: *id, - target: *upstream, + target: upstream.clone(), key: key.clone(), }); new_state = None; @@ -427,14 +373,14 @@ impl Operation for PutOp { Some(PutState::AwaitingResponse { key, upstream }) => { let is_subscribed_contract = op_manager.ring.is_seeding_contract(&key); if !is_subscribed_contract && op_manager.ring.should_seed(&key) { - tracing::debug!(tx = %id, %key, peer = %op_manager.ring.peer_key, "Contract not cached @ peer, caching"); + tracing::debug!(tx = %id, %key, peer = %op_manager.ring.get_peer_key().unwrap(), "Contract not cached @ peer, caching"); super::start_subscription_request(op_manager, key.clone(), true) .await; } tracing::info!( tx = %id, %key, - this_peer = %op_manager.ring.peer_key, + this_peer = %op_manager.ring.get_peer_key().unwrap(), "Peer completed contract value put", ); new_state = Some(PutState::Finished { key: key.clone() }); @@ -484,7 +430,7 @@ impl Operation for PutOp { // if successful, forward to the next closest peers (if any) let last_hop = if let Some(new_htl) = htl.checked_sub(1) { let mut new_skip_list = skip_list.clone(); - new_skip_list.push(sender.peer); + new_skip_list.push(sender.peer.clone()); // only hop forward if there are closer peers let put_here = forward_put( op_manager, @@ -514,11 +460,11 @@ impl Operation for PutOp { conn_manager .send( &subscriber.peer, - NetMessage::Unsubscribed { + NetMessage::V1(NetMessageV1::Unsubscribed { transaction: Transaction::new::(), key: key.clone(), - from: op_manager.ring.peer_key, - }, + from: op_manager.ring.get_peer_key().unwrap(), + }), ) .await?; } @@ -544,7 +490,7 @@ impl Operation for PutOp { last_hop, op_manager, self.state, - (broadcast_to, *sender), + (broadcast_to, sender.clone()), key.clone(), (contract.clone(), new_value.clone()), ) @@ -574,7 +520,7 @@ impl OpManager { subs.value() .iter() .filter(|pk| &pk.peer != sender) - .copied() + .cloned() .collect::>() }) .unwrap_or_default(); @@ -680,14 +626,7 @@ pub(crate) fn start_op( PutOp { id, state, - stats: Some(PutStats { - // contract_location, - // payload_size, - target: None, - // first_response_time: None, - transfer_time: None, - step: Default::default(), - }), + stats: Some(PutStats { target: None }), } } @@ -731,7 +670,7 @@ pub(crate) async fn request_put(op_manager: &OpManager, mut put_op: PutOp) -> Re let id = put_op.id; if let Some(stats) = &mut put_op.stats { - stats.target = Some(target); + stats.target = Some(target.clone()); } match put_op.state { @@ -752,7 +691,7 @@ pub(crate) async fn request_put(op_manager: &OpManager, mut put_op: PutOp) -> Re related_contracts, value, htl, - target, + target: target.clone(), }; let op = PutOp { diff --git a/crates/core/src/operations/subscribe.rs b/crates/core/src/operations/subscribe.rs index 8ed832ca7..494365b92 100644 --- a/crates/core/src/operations/subscribe.rs +++ b/crates/core/src/operations/subscribe.rs @@ -121,8 +121,6 @@ impl SubscribeOp { matches!(self.state, Some(SubscribeState::Completed { .. })) } - pub(super) fn record_transfer(&mut self) {} - pub(super) fn to_host_result(&self) -> HostResult { if let Some(SubscribeState::Completed {}) = self.state { Ok(HostResponse::Ok) @@ -201,8 +199,8 @@ impl Operation for SubscribeOp { return_msg = Some(SubscribeMsg::SeekNode { id: *id, key: key.clone(), - target: *target, - subscriber: sender, + target: target.clone(), + subscriber: sender.clone(), skip_list: vec![sender.peer], htl: op_manager.ring.max_hops_to_live, retries: 0, @@ -224,8 +222,8 @@ impl Operation for SubscribeOp { key: key.clone(), id: *id, subscribed: false, - sender: this_peer, - target: *subscriber, + sender: this_peer.clone(), + target: subscriber.clone(), })), state: None, } @@ -249,7 +247,7 @@ impl Operation for SubscribeOp { } let mut new_skip_list = skip_list.clone(); - new_skip_list.push(target.peer); + new_skip_list.push(target.peer.clone()); tracing::debug!(tx = %id, new_target = %new_target.peer, "Forward request to peer"); // Retry seek node when the contract to subscribe has not been found in this node @@ -259,7 +257,7 @@ impl Operation for SubscribeOp { skip_list: new_skip_list.clone(), retries: *retries, current_hop: new_htl, - upstream_subscriber: Some(*subscriber), + upstream_subscriber: Some(subscriber.clone()), }), (SubscribeMsg::SeekNode { id: *id, @@ -274,7 +272,11 @@ impl Operation for SubscribeOp { ); } - if op_manager.ring.add_subscriber(key, *subscriber).is_err() { + if op_manager + .ring + .add_subscriber(key, subscriber.clone()) + .is_err() + { tracing::debug!(tx = %id, %key, "Max number of subscribers reached for contract"); // max number of subscribers for this contract reached return Ok(return_not_subbed()); @@ -290,8 +292,8 @@ impl Operation for SubscribeOp { ); new_state = None; return_msg = Some(SubscribeMsg::ReturnSub { - sender: *target, - target: *subscriber, + sender: target.clone(), + target: subscriber.clone(), id: *id, key: key.clone(), subscribed: true, @@ -322,7 +324,7 @@ impl Operation for SubscribeOp { current_hop, }) => { if retries < MAX_RETRIES { - skip_list.push(sender.peer); + skip_list.push(sender.peer.clone()); if let Some(target) = op_manager .ring .closest_potentially_caching(key, skip_list.as_slice()) @@ -377,14 +379,14 @@ impl Operation for SubscribeOp { provider = %sender.peer, "Subscribed to contract" ); - op_manager.ring.register_subscription(key, *sender); + op_manager.ring.register_subscription(key, sender.clone()); new_state = Some(SubscribeState::Completed {}); if let Some(upstream_subscriber) = upstream_subscriber { return_msg = Some(SubscribeMsg::ReturnSub { id: *id, key: key.clone(), - sender: *target, + sender: target.clone(), target: upstream_subscriber, subscribed: true, }); diff --git a/crates/core/src/operations/update.rs b/crates/core/src/operations/update.rs index d52db37df..622db7e61 100644 --- a/crates/core/src/operations/update.rs +++ b/crates/core/src/operations/update.rs @@ -1,5 +1,4 @@ use freenet_stdlib::client_api::{ErrorKind, HostResponse}; -use std::time::Instant; // TODO: complete update logic in the network use freenet_stdlib::prelude::*; @@ -26,30 +25,26 @@ impl UpdateOp { } pub fn finalized(&self) -> bool { - self.stats - .as_ref() - .map(|s| matches!(s.step, RecordingStats::Completed)) - .unwrap_or(false) - || matches!(self.state, Some(UpdateState::Finished { .. })) + matches!(self.state, None | Some(UpdateState::Finished { .. })) } - pub(super) fn record_transfer(&mut self) { - if let Some(stats) = self.stats.as_mut() { - match stats.step { - RecordingStats::Uninitialized => { - stats.transfer_time = Some((Instant::now(), None)); - stats.step = RecordingStats::InitUpdate; - } - RecordingStats::InitUpdate => { - if let Some((_, e)) = stats.transfer_time.as_mut() { - *e = Some(Instant::now()); - } - stats.step = RecordingStats::Completed; - } - RecordingStats::Completed => {} - } - } - } + // pub(super) fn record_transfer(&mut self) { + // if let Some(stats) = self.stats.as_mut() { + // match stats.step { + // RecordingStats::Uninitialized => { + // stats.transfer_time = Some((Instant::now(), None)); + // stats.step = RecordingStats::InitUpdate; + // } + // RecordingStats::InitUpdate => { + // if let Some((_, e)) = stats.transfer_time.as_mut() { + // *e = Some(Instant::now()); + // } + // stats.step = RecordingStats::Completed; + // } + // RecordingStats::Completed => {} + // } + // } + // } pub(super) fn to_host_result(&self) -> HostResult { if let Some(UpdateState::Finished { key, summary }) = &self.state { @@ -69,24 +64,17 @@ impl UpdateOp { } struct UpdateStats { - // contract_location: Location, - // payload_size: usize, - // /// (start, end) - // first_response_time: Option<(Instant, Option)>, - /// (start, end) - transfer_time: Option<(Instant, Option)>, target: Option, - step: RecordingStats, + // step: RecordingStats, } -/// While timing, at what particular step we are now. -#[derive(Clone, Copy, Default)] -enum RecordingStats { - #[default] - Uninitialized, - InitUpdate, - Completed, -} +// /// While timing, at what particular step we are now. +// #[derive(Clone, Copy, Default)] +// enum RecordingStats { +// #[default] +// Uninitialized, +// Completed, +// } pub(crate) struct UpdateResult {} @@ -94,10 +82,7 @@ impl TryFrom for UpdateResult { type Error = OpError; fn try_from(op: UpdateOp) -> Result { - if let Some(true) = op - .stats - .map(|s| matches!(s.step, RecordingStats::Completed)) - { + if matches!(op.state, None | Some(UpdateState::Finished { .. })) { Ok(UpdateResult {}) } else { Err(OpError::UnexpectedOpState) @@ -184,7 +169,7 @@ impl Operation for UpdateOp { return_msg = Some(UpdateMsg::SeekNode { id: *id, sender, - target: *target, + target: target.clone(), value: value.clone(), key: key.clone(), related_contracts: related_contracts.clone(), @@ -237,7 +222,7 @@ impl Operation for UpdateOp { true, op_manager, self.state, - (broadcast_to, *sender), + (broadcast_to, sender.clone()), key.clone(), value.clone(), false, @@ -287,7 +272,7 @@ impl Operation for UpdateOp { false, op_manager, self.state, - (broadcast_to, *sender), + (broadcast_to, sender.clone()), key.clone(), new_value, true, @@ -319,7 +304,7 @@ impl Operation for UpdateOp { id: *id, key: key.clone(), new_value: new_value.clone(), - sender, + sender: sender.clone(), }; let f = conn_manager.send(&peer.peer, msg.into()); broadcasting.push(f); @@ -362,7 +347,7 @@ impl Operation for UpdateOp { // Subscriber nodes have been notified of the change, the operation is complete return_msg = Some(UpdateMsg::SuccessfulUpdate { id: *id, - target: *upstream, + target: upstream.clone(), summary, }); @@ -374,7 +359,7 @@ impl Operation for UpdateOp { tracing::debug!( tx = %id, %key, - this_peer = %op_manager.ring.peer_key, + this_peer = ?op_manager.ring.get_peer_key(), "Peer completed contract value update - SuccessfulUpdate", ); @@ -503,7 +488,7 @@ impl OpManager { subs.value() .iter() .filter(|pk| &pk.peer != sender) - .copied() + .cloned() .collect::>() }) .unwrap_or_default(); @@ -588,14 +573,7 @@ pub(crate) fn start_op( UpdateOp { id, state, - stats: Some(UpdateStats { - // contract_location, - // payload_size, - target: None, - // first_response_time: None, - transfer_time: None, - step: Default::default(), - }), + stats: Some(UpdateStats { target: None }), } } @@ -623,7 +601,7 @@ pub(crate) async fn request_update( } else { let closest = op_manager .ring - .closest_potentially_caching(key, [sender.peer].as_slice()) + .closest_potentially_caching(key, [sender.peer.clone()].as_slice()) .into_iter() .next() .ok_or_else(|| RingError::EmptyRing)?; @@ -638,7 +616,7 @@ pub(crate) async fn request_update( let id = update_op.id; if let Some(stats) = &mut update_op.stats { - stats.target = Some(target); + stats.target = Some(target.clone()); } match update_op.state { diff --git a/crates/core/src/ring.rs b/crates/core/src/ring.rs index b2fbb1f0f..89d75c480 100644 --- a/crates/core/src/ring.rs +++ b/crates/core/src/ring.rs @@ -22,7 +22,8 @@ use anyhow::bail; use dashmap::{mapref::one::Ref as DmRef, DashMap}; use either::Either; use freenet_stdlib::prelude::{ContractInstanceId, ContractKey}; -use parking_lot::RwLock; +use itertools::Itertools; +use parking_lot::{Mutex, RwLock}; use rand::seq::SliceRandom; use rand::Rng; use serde::{Deserialize, Serialize}; @@ -33,6 +34,7 @@ use crate::message::TransactionType; use crate::topology::rate::Rate; use crate::topology::{Limits, TopologyAdjustment, TopologyManager}; use crate::tracing::{NetEventLog, NetEventRegister}; +use crate::transport::TransportPublicKey; use crate::util::Contains; use crate::{ config::GlobalExecutor, @@ -43,7 +45,7 @@ use crate::{ DynError, }; -#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[cfg_attr(test, derive(arbitrary::Arbitrary))] /// The location of a peer in the ring. This location allows routing towards the peer. pub struct PeerKeyLocation { @@ -86,7 +88,7 @@ impl Display for PeerKeyLocation { } } -#[derive(Clone, Copy)] +#[derive(Clone, Debug)] pub(crate) struct Connection { location: PeerKeyLocation, open_at: Instant, @@ -120,7 +122,7 @@ impl LiveTransactionTracker { .tx_per_peer .iter() .filter(|entry| entry.value().iter().any(|otx| otx == &tx)) - .map(|entry| *entry.key()) + .map(|entry| entry.key().clone()) .collect(); for k in keys_to_remove { @@ -181,7 +183,8 @@ impl Eq for Score {} pub(crate) struct Ring { pub rnd_if_htl_above: usize, pub max_hops_to_live: usize, - pub peer_key: PeerId, + peer_key: Mutex>, + peer_pub_key: TransportPublicKey, pub max_connections: usize, pub min_connections: usize, router: Arc>, @@ -254,7 +257,12 @@ impl Ring { ) -> Result, anyhow::Error> { let (live_tx_tracker, missing_candidate_rx) = LiveTransactionTracker::new(); - let peer_key = config.peer_id; + let peer_pub_key = config + .key_pair + .as_ref() + .map(|kp| kp.public.clone()) + .ok_or(anyhow::anyhow!("Key pair should be set at this point"))?; + let peer_key = config.get_peer_id(); // for location here consider -1 == None let own_location = AtomicU64::new(u64::from_le_bytes((-1f64).to_le_bytes())); @@ -316,7 +324,8 @@ impl Ring { connections_by_location: RwLock::new(BTreeMap::new()), location_for_peer: RwLock::new(BTreeMap::new()), own_location, - peer_key, + peer_key: Mutex::new(peer_key), + peer_pub_key, subscribers: DashMap::new(), seeding_contract: DashMap::new(), open_connections: AtomicUsize::new(0), @@ -349,6 +358,29 @@ impl Ring { Ok(ring) } + pub fn get_peer_key(&self) -> Option { + self.peer_key.lock().clone() + } + + /// Sets the peer id if is not already set, or returns the current peer id. + pub fn set_peer_key(&self, peer_key: PeerId) -> Option { + let mut this_peer = self.peer_key.lock(); + if this_peer.is_none() { + *this_peer = Some(peer_key); + None + } else { + this_peer.clone() + } + } + + pub fn get_peer_pub_key(&self) -> TransportPublicKey { + self.peer_pub_key.clone() + } + + pub fn is_gateway(&self) -> bool { + self.is_gateway + } + pub fn open_connections(&self) -> usize { self.open_connections .load(std::sync::atomic::Ordering::Acquire) @@ -463,10 +495,8 @@ impl Ring { } else { Some(Location(location)) }; - PeerKeyLocation { - peer: self.peer_key, - location, - } + let peer = self.get_peer_key().expect("peer key not set"); + PeerKeyLocation { peer, location } } /// Whether a node should accept a new node connection or not based @@ -474,37 +504,54 @@ impl Ring { /// /// # Panic /// Will panic if the node checking for this condition has no location assigned. - pub fn should_accept(&self, location: Location, peer: &PeerId) -> bool { + pub fn should_accept(&self, location: Location, peer: Option<&PeerId>) -> bool { + tracing::debug!("Checking if should accept connection"); let open_conn = self .open_connections .fetch_add(1, std::sync::atomic::Ordering::SeqCst); - if self.location_for_peer.read().get(peer).is_some() { - // avoid connecting mroe than once to the same peer - self.open_connections - .fetch_sub(1, std::sync::atomic::Ordering::SeqCst); - return false; + + if let Some(peer_id) = peer { + if self.location_for_peer.read().get(peer_id).is_some() { + // avoid connecting more than once to the same peer + self.open_connections + .fetch_sub(1, std::sync::atomic::Ordering::SeqCst); + tracing::debug!(%peer_id, "Peer already connected"); + return false; + } } + let my_location = self .own_location() .location - .expect("this node has no location assigned!"); + .unwrap_or_else(|| /* havent joined the ring yet */ Location::random()); let accepted = if location == my_location || self.connections_by_location.read().contains_key(&location) { + tracing::debug!( + "Ring connections {:?}", + &*self.connections_by_location.read() + ); false } else if open_conn < self.min_connections { true } else if open_conn >= self.max_connections { false } else { + tracing::debug!("Evaluating new connection"); self.topology_manager .write() .evaluate_new_connection(location, Instant::now()) - .unwrap_or(false) + .unwrap_or(true) }; if !accepted { self.open_connections .fetch_sub(1, std::sync::atomic::Ordering::SeqCst); + } else { + if let Some(peer_id) = peer { + self.location_for_peer + .write() + .insert(peer_id.clone(), location); + } } accepted } @@ -521,18 +568,23 @@ impl Ring { } pub async fn add_connection(&self, loc: Location, peer: PeerId) { + tracing::info!(%peer, "Adding connection to peer"); self.event_register - .register_events(Either::Left(NetEventLog::connected(self, peer, loc))) + .register_events(Either::Left(NetEventLog::connected( + self, + peer.clone(), + loc, + ))) .await; let mut cbl = self.connections_by_location.write(); cbl.entry(loc).or_default().push(Connection { location: PeerKeyLocation { - peer, + peer: peer.clone(), location: Some(loc), }, open_at: Instant::now(), }); - self.location_for_peer.write().insert(peer, loc); + self.location_for_peer.write().insert(peer.clone(), loc); std::mem::drop(cbl); self.refresh_density_request_cache() } @@ -543,6 +595,20 @@ impl Ring { let _ = topology_manager.refresh_cache(&cbl); } + pub fn is_connected<'a>( + &self, + peers: impl Iterator, + ) -> impl Iterator + Send { + let locs = &*self.location_for_peer.read(); + let mut filtered = Vec::new(); + for peer in peers { + if !locs.contains_key(&peer.peer) { + filtered.push(peer); + } + } + filtered.into_iter() + } + /// Return the most optimal peer caching a given contract. #[inline] pub fn closest_potentially_caching( @@ -577,7 +643,7 @@ impl Ring { pub fn routing_finished(&self, event: crate::router::RouteEvent) { self.topology_manager .write() - .report_outbound_request(event.peer, event.contract_location); + .report_outbound_request(event.peer.clone(), event.contract_location.clone()); self.router.write().add_event(event); } @@ -604,7 +670,7 @@ impl Ring { continue; } else { return Some(PeerKeyLocation { - peer: *peer, + peer: peer.clone(), location: Some(*loc), }); } @@ -692,12 +758,21 @@ impl Ring { ) -> Option { self.connections_by_location .read() - .range(..location) - .filter_map(|(_, conns)| { - let conn = conns.choose(&mut rand::thread_rng()).unwrap(); - (!skip_list.contains(&conn.location.peer)).then_some(conn.location) + .iter() + .sorted_by(|(loc_a, _), (loc_b, _)| { + loc_a.distance(location).cmp(&loc_b.distance(location)) + }) + .find_map(|(_, conns)| { + for _ in 0..conns.len() { + let conn = conns.choose(&mut rand::thread_rng()).unwrap(); + let selected = + (!skip_list.contains(&conn.location.peer)).then_some(conn.location.clone()); + if selected.is_some() { + return selected; + } + } + None }) - .next_back() } async fn connection_maintenance( @@ -801,7 +876,6 @@ impl Ring { match adjustment { TopologyAdjustment::AddConnections(target_locs) => { pending_conn_adds.extend(target_locs); - continue; } TopologyAdjustment::RemoveConnections(mut should_disconnect_peers) => { for peer in should_disconnect_peers.drain(..) { @@ -857,6 +931,7 @@ impl Ring { ideal_location, joiner, max_hops_to_live: missing_connections, + skip_list: skip_list.iter().map(|p| (*p).clone()).collect(), }, }; let id = *msg.id(); diff --git a/crates/core/src/router.rs b/crates/core/src/router.rs index 4c706e025..4c26ebaaa 100644 --- a/crates/core/src/router.rs +++ b/crates/core/src/router.rs @@ -24,7 +24,7 @@ impl Router { let failure_outcomes: Vec = history .iter() .map(|re| IsotonicEvent { - peer: re.peer, + peer: re.peer.clone(), contract_location: re.contract_location, result: match re.outcome { RouteOutcome::Success { @@ -47,7 +47,7 @@ impl Router { } = re.outcome { Some(IsotonicEvent { - peer: re.peer, + peer: re.peer.clone(), contract_location: re.contract_location, result: time_to_response_start.as_secs_f64(), }) @@ -67,7 +67,7 @@ impl Router { } = re.outcome { Some(IsotonicEvent { - peer: re.peer, + peer: re.peer.clone(), contract_location: re.contract_location, result: payload_size as f64 / payload_transfer_time.as_secs_f64(), }) @@ -125,18 +125,18 @@ impl Router { payload_transfer_time, } => { self.response_start_time_estimator.add_event(IsotonicEvent { - peer: event.peer, + peer: event.peer.clone(), contract_location: event.contract_location, result: time_to_response_start.as_secs_f64(), }); self.failure_estimator.add_event(IsotonicEvent { - peer: event.peer, + peer: event.peer.clone(), contract_location: event.contract_location, result: 0.0, }); let transfer_rate_event = IsotonicEvent { - peer: event.peer, contract_location: event.contract_location, + peer: event.peer, result: payload_size as f64 / payload_transfer_time.as_secs_f64(), }; self.mean_transfer_size.add(payload_size as f64); @@ -359,9 +359,10 @@ mod tests { let mut events = vec![]; let mut rng = rand::thread_rng(); for _ in 0..NUM_EVENTS { - let peer = peers[rng.gen_range(0..NUM_PEERS)]; + let peer = peers[rng.gen_range(0..NUM_PEERS)].clone(); let contract_location = Location::random(); - let simulated_prediction = simulate_prediction(&mut rng, peer, contract_location); + let simulated_prediction = + simulate_prediction(&mut rng, peer.clone(), contract_location); let event = RouteEvent { peer, contract_location, @@ -390,7 +391,7 @@ mod tests { // Test the router with the testing events. for event in testing_events { - let truth = simulate_prediction(&mut rng, event.peer, event.contract_location); + let truth = simulate_prediction(&mut rng, event.peer.clone(), event.contract_location); let prediction = router .predict_routing_outcome(&event.peer, event.contract_location) diff --git a/crates/core/src/router/isotonic_estimator.rs b/crates/core/src/router/isotonic_estimator.rs index 24ca45bc9..874ecd425 100644 --- a/crates/core/src/router/isotonic_estimator.rs +++ b/crates/core/src/router/isotonic_estimator.rs @@ -32,10 +32,13 @@ impl IsotonicEstimator { let mut peer_events: HashMap> = HashMap::new(); for event in history { - let point = Point::new(event.route_distance().as_f64(), event.result); + let point = Point::new(event.route_distance().as_f64(), event.result.clone()); all_points.push(point); - peer_events.entry(event.peer).or_default().push(event); + peer_events + .entry(event.peer.clone()) + .or_default() + .push(event); } let global_regression = match estimator_type { @@ -67,7 +70,7 @@ impl IsotonicEstimator { total_adjustment += peer_adjustment; } peer_adjustments.insert( - *peer_location, + peer_location.clone(), Adjustment { sum: total_adjustment, count: event_count, @@ -305,9 +308,14 @@ mod tests { peer: PeerKeyLocation, contract_location: Location, ) -> IsotonicEvent { - let distance: f64 = peer.location.unwrap().distance(contract_location).as_f64(); - - let result = distance.powf(0.5) + peer.peer.to_bytes()[0] as f64; + let distance: f64 = peer + .location + .clone() + .unwrap() + .distance(contract_location) + .as_f64(); + + let result = distance.powf(0.5) + peer.peer.clone().to_bytes()[0] as f64; IsotonicEvent { peer, contract_location, @@ -319,9 +327,14 @@ mod tests { peer: PeerKeyLocation, contract_location: Location, ) -> IsotonicEvent { - let distance: f64 = peer.location.unwrap().distance(contract_location).as_f64(); - - let result = (100.0 - distance).powf(0.5) + peer.peer.to_bytes()[0] as f64; + let distance: f64 = peer + .location + .clone() + .unwrap() + .distance(contract_location) + .as_f64(); + + let result = (100.0 - distance).powf(0.5) + peer.peer.clone().to_bytes()[0] as f64; IsotonicEvent { peer, contract_location, diff --git a/crates/core/src/server.rs b/crates/core/src/server.rs index 59f4fa639..dd61522c6 100644 --- a/crates/core/src/server.rs +++ b/crates/core/src/server.rs @@ -182,12 +182,11 @@ pub mod local_node { pub mod network_node { use std::net::SocketAddr; - use libp2p_identity::Keypair; use tower_http::trace::TraceLayer; use crate::{ client_events::websocket::WebSocketProxy, dev_tool::NodeConfig, local_node::PeerCliConfig, - DynError, + transport::TransportKeypair, DynError, }; use super::{http_gateway::HttpGateway, serve}; @@ -203,9 +202,9 @@ pub mod network_node { let mut node_config = NodeConfig::new(); node_config.with_ip(socket.ip()).with_port(socket.port()); - let private_key = Keypair::generate_ed25519(); + let private_key = TransportKeypair::new(); - let is_gateway = node_config.is_gateway(); + let is_gateway = node_config.is_gateway; let node = node_config .build(config, [Box::new(gw), Box::new(ws_proxy)], private_key) .await?; diff --git a/crates/core/src/topology.rs b/crates/core/src/topology.rs index 5ff34d28e..c9316c55a 100644 --- a/crates/core/src/topology.rs +++ b/crates/core/src/topology.rs @@ -284,11 +284,24 @@ impl TopologyManager { my_location: &Option, at_time: Instant, ) -> TopologyAdjustment { - debug!( - "Adjusting topology at {:?}. Current neighbors: {:?}", - at_time, - neighbor_locations.len() - ); + #[cfg(debug_assertions)] + { + thread_local! { + static LAST_LOG: std::cell::RefCell = std::cell::RefCell::new(Instant::now()); + } + if LAST_LOG + .with(|last_log| last_log.borrow().elapsed() > std::time::Duration::from_secs(10)) + { + LAST_LOG.with(|last_log| { + tracing::trace!( + "Adjusting topology at {:?}. Current neighbors: {:?}", + at_time, + neighbor_locations.len() + ); + *last_log.borrow_mut() = Instant::now(); + }); + } + } if neighbor_locations.len() < self.limits.min_connections { let mut locations = Vec::new(); @@ -307,12 +320,25 @@ impl TopologyManager { } } } - info!( - minimum_num_peers_hard_limit = self.limits.min_connections, - num_peers = neighbor_locations.len(), - to_add = below_threshold, - "Adding peers at random locations to reach minimum number of peers" - ); + #[cfg(debug_assertions)] + { + thread_local! { + static LAST_LOG: std::cell::RefCell = std::cell::RefCell::new(Instant::now()); + } + if LAST_LOG.with(|last_log| { + last_log.borrow().elapsed() > std::time::Duration::from_secs(10) + }) { + LAST_LOG.with(|last_log| { + tracing::trace!( + minimum_num_peers_hard_limit = self.limits.min_connections, + num_peers = neighbor_locations.len(), + to_add = below_threshold, + "Adding peers at random locations to reach minimum number of peers" + ); + *last_log.borrow_mut() = Instant::now(); + }); + } + } } return TopologyAdjustment::AddConnections(locations); } @@ -839,7 +865,7 @@ mod tests { report_time ); resource_manager.report_resource_usage( - &AttributionSource::Peer(*peer), + &AttributionSource::Peer(peer.clone()), ResourceType::InboundBandwidthBytes, bw_usage_by_peer[i] as f64, report_time, @@ -857,7 +883,8 @@ mod tests { for _ in 0..*requests { // For simplicity we'll just assume that the target location of the request is the // neighboring peer's own location - resource_manager.report_outbound_request(peers[i], peers[i].location.unwrap()); + resource_manager + .report_outbound_request(peers[i].clone(), peers[i].location.unwrap()); } } } @@ -869,7 +896,7 @@ mod tests { ) -> usize { let mut values = vec![]; for ix in 0..peers.len() { - let peer = peers[ix]; + let peer = peers[ix].clone(); let value = requests_per_peer[ix] as f64 / bw_usage_by_peer[ix] as f64; values.push(value); debug!( diff --git a/crates/core/src/topology/outbound_request_counter.rs b/crates/core/src/topology/outbound_request_counter.rs index adc73fef1..336e55602 100644 --- a/crates/core/src/topology/outbound_request_counter.rs +++ b/crates/core/src/topology/outbound_request_counter.rs @@ -19,7 +19,7 @@ impl OutboundRequestCounter { } pub(crate) fn record_request(&mut self, peer: PeerKeyLocation) { - self.request_window.push_back(peer); + self.request_window.push_back(peer.clone()); self.counts_by_peer .entry(peer) .and_modify(|count| *count += 1) diff --git a/crates/core/src/tracing.rs b/crates/core/src/tracing.rs index 902703f6a..23f12aff2 100644 --- a/crates/core/src/tracing.rs +++ b/crates/core/src/tracing.rs @@ -24,7 +24,7 @@ use crate::{ config::GlobalExecutor, contract::StoreResponse, generated::ContractChange, - message::{NetMessage, Transaction}, + message::{MessageStats, NetMessage, NetMessageV1, Transaction}, node::PeerId, operations::{connect, get::GetMsg, put::PutMsg, subscribe::SubscribeMsg}, ring::{Location, PeerKeyLocation, Ring}, @@ -120,23 +120,25 @@ impl Clone for CombinedRegister { #[derive(Clone)] pub(crate) struct NetEventLog<'a> { tx: &'a Transaction, - peer_id: &'a PeerId, + peer_id: PeerId, kind: EventKind, } impl<'a> NetEventLog<'a> { pub fn route_event(tx: &'a Transaction, ring: &'a Ring, route_event: &RouteEvent) -> Self { + let peer_id = ring.get_peer_key().unwrap().clone(); NetEventLog { tx, - peer_id: &ring.peer_key, + peer_id, kind: EventKind::Route(route_event.clone()), } } pub fn connected(ring: &'a Ring, peer: PeerId, location: Location) -> Self { + let peer_id = ring.get_peer_key().unwrap().clone(); NetEventLog { tx: Transaction::NULL, - peer_id: &ring.peer_key, + peer_id, kind: EventKind::Connect(ConnectEvent::Connected { this: ring.own_location(), connected: PeerKeyLocation { @@ -148,52 +150,31 @@ impl<'a> NetEventLog<'a> { } pub fn disconnected(ring: &'a Ring, from: &'a PeerId) -> Self { + let peer_id = ring.get_peer_key().unwrap().clone(); NetEventLog { tx: Transaction::NULL, - peer_id: &ring.peer_key, - kind: EventKind::Disconnected { from: *from }, + peer_id, + kind: EventKind::Disconnected { from: from.clone() }, } } pub fn from_outbound_msg(msg: &'a NetMessage, ring: &'a Ring) -> Either> { + let peer_id = ring.get_peer_key().unwrap(); let kind = match msg { - NetMessage::Connect(connect::ConnectMsg::Response { + NetMessage::V1(NetMessageV1::Connect(connect::ConnectMsg::Response { msg: connect::ConnectResponse::AcceptedBy { - peers, - your_location, - your_peer_id, - }, - .. - }) => { - let this_peer = ring.own_location(); - if peers.contains(&this_peer) { - EventKind::Connect(ConnectEvent::Connected { - this: this_peer, - connected: PeerKeyLocation { - peer: *your_peer_id, - location: Some(*your_location), - }, - }) - } else { - EventKind::Ignored - } - } - NetMessage::Connect(connect::ConnectMsg::Response { - msg: - connect::ConnectResponse::Proxy { - accepted_by, - joiner, + accepted, acceptor, .. }, .. - }) => { + })) => { let this_peer = ring.own_location(); - if accepted_by.contains(&this_peer) { + if *accepted { EventKind::Connect(ConnectEvent::Connected { this: this_peer, connected: PeerKeyLocation { - peer: *joiner, - location: None, + peer: acceptor.peer.clone(), + location: acceptor.location.clone(), }, }) } else { @@ -204,79 +185,61 @@ impl<'a> NetEventLog<'a> { }; Either::Left(NetEventLog { tx: msg.id(), - peer_id: &ring.peer_key, + peer_id, kind, }) } - pub fn from_inbound_msg( - msg: &'a NetMessage, + pub fn from_inbound_msg_v1( + msg: &'a NetMessageV1, op_manager: &'a OpManager, ) -> Either> { let kind = match msg { - NetMessage::Connect(connect::ConnectMsg::Response { + NetMessageV1::Connect(connect::ConnectMsg::Response { msg: connect::ConnectResponse::AcceptedBy { - peers, - your_location, - your_peer_id, + acceptor, accepted, .. }, .. }) => { - let this_peer = &op_manager.ring.peer_key; - let mut events = peers - .iter() - .map(|peer| { - let kind: EventKind = EventKind::Connect(ConnectEvent::Connected { - this: PeerKeyLocation { - peer: *your_peer_id, - location: Some(*your_location), - }, - connected: *peer, - }); - NetEventLog { - tx: msg.id(), - peer_id: this_peer, - kind, - } - }) - .collect::>(); - if this_peer == your_peer_id { + let this_peer = &op_manager.ring.get_peer_key().unwrap(); + let mut events = vec![]; + if *accepted { events.push(NetEventLog { tx: msg.id(), - peer_id: this_peer, + peer_id: this_peer.clone(), kind: EventKind::Connect(ConnectEvent::Finished { - initiator: *your_peer_id, - location: *your_location, + initiator: acceptor.peer.clone(), // FIXME + location: acceptor.location.unwrap(), }), }); } return Either::Right(events); } - NetMessage::Put(PutMsg::RequestPut { + NetMessageV1::Put(PutMsg::RequestPut { contract, target, id, .. }) => { - let this_peer = &op_manager.ring.peer_key; + let this_peer = &op_manager.ring.get_peer_key().unwrap(); let key = contract.key(); EventKind::Put(PutEvent::Request { - requester: *this_peer, - target: *target, + requester: this_peer.clone(), + target: target.clone(), key, id: *id, }) } - NetMessage::Put(PutMsg::SuccessfulPut { id, target, key }) => { + NetMessageV1::Put(PutMsg::SuccessfulPut { id, target, key }) => { EventKind::Put(PutEvent::PutSuccess { id: *id, - requester: op_manager.ring.peer_key, - target: *target, + requester: op_manager.ring.get_peer_key().unwrap(), + target: target.clone(), key: key.clone(), }) } - NetMessage::Put(PutMsg::Broadcasting { + NetMessageV1::Put(PutMsg::Broadcasting { new_value, broadcast_to, key, @@ -286,35 +249,35 @@ impl<'a> NetEventLog<'a> { key: key.clone(), value: new_value.clone(), }), - NetMessage::Put(PutMsg::BroadcastTo { + NetMessageV1::Put(PutMsg::BroadcastTo { sender, new_value, key, .. }) => EventKind::Put(PutEvent::BroadcastReceived { - requester: sender.peer, + requester: sender.peer.clone(), key: key.clone(), value: new_value.clone(), }), - NetMessage::Get(GetMsg::ReturnGet { + NetMessageV1::Get(GetMsg::ReturnGet { key, value: StoreResponse { state: Some(_), .. }, .. }) => EventKind::Get { key: key.clone() }, - NetMessage::Subscribe(SubscribeMsg::ReturnSub { + NetMessageV1::Subscribe(SubscribeMsg::ReturnSub { subscribed: true, key, sender, .. }) => EventKind::Subscribed { key: key.clone(), - at: *sender, + at: sender.clone(), }, _ => EventKind::Ignored, }; Either::Left(NetEventLog { tx: msg.id(), - peer_id: &op_manager.ring.peer_key, + peer_id: op_manager.ring.get_peer_key().unwrap().clone(), kind, }) } @@ -363,7 +326,7 @@ impl<'a> From> for NetLogMessage { datetime: Utc::now(), tx: *log.tx, kind: log.kind, - peer_id: *log.peer_id, + peer_id: log.peer_id.clone(), } } } @@ -701,6 +664,10 @@ impl EventRegister { } } + if records.is_empty() { + return Ok(vec![]); + } + let deserialized_records = tokio::task::spawn_blocking(move || { let mut filtered = vec![]; for buf in records { @@ -788,13 +755,13 @@ async fn send_to_metrics_server( }) => { let msg = PeerChange::added_connection_msg( (&send_msg.tx != Transaction::NULL).then(|| send_msg.tx.to_string()), - (*from_peer, from_loc.as_f64()), - (*to_peer, to_loc.as_f64()), + (from_peer.clone(), from_loc.as_f64()), + (to_peer.clone(), to_loc.as_f64()), ); ws_stream.send(Message::Binary(msg)).await } EventKind::Disconnected { from } => { - let msg = PeerChange::removed_connection_msg(*from, send_msg.peer_id); + let msg = PeerChange::removed_connection_msg(from.clone(), send_msg.peer_id.clone()); ws_stream.send(Message::Binary(msg)).await } EventKind::Put(PutEvent::Request { @@ -1237,8 +1204,11 @@ pub(crate) mod tracer { } else { "freenet-core".to_string() }; + println!("setting OT collector with identifier: {identifier}"); let tracing_ot_layer = { // Connect the Jaeger OT tracer with the tracing middleware + // FIXME: remove + #[allow(deprecated)] let ot_jaeger_tracer = opentelemetry_jaeger::config::agent::AgentPipeline::default() .with_service_name(identifier) @@ -1313,7 +1283,7 @@ pub(super) mod test { } events.push(NetEventLog { tx: &transactions[i], - peer_id: &peers[i], + peer_id: peers[i].clone(), kind, }); } @@ -1464,14 +1434,16 @@ pub(super) mod test { .iter() .filter(|l| matches!(l.kind, EventKind::Disconnected { .. })) .fold(HashMap::<_, Vec<_>>::new(), |mut map, log| { - map.entry(log.peer_id).or_default().push(log.datetime); + map.entry(log.peer_id.clone()) + .or_default() + .push(log.datetime); map }); let iter = logs .iter() .filter_map(|l| { - if let EventKind::Connect(ConnectEvent::Connected { this, connected }) = l.kind + if let EventKind::Connect(ConnectEvent::Connected { this, connected }) = &l.kind { let disconnected = disconnects .get(&connected.peer) @@ -1480,7 +1452,7 @@ pub(super) mod test { .any(|dc| dc > &l.datetime); if let Some((this_loc, conn_loc)) = this.location.zip(connected.location) { if this.peer == peer && !disconnected { - return Some((connected.peer, conn_loc.distance(this_loc))); + return Some((connected.peer.clone(), conn_loc.distance(this_loc))); } } } @@ -1497,7 +1469,7 @@ pub(super) mod test { let msg_log = NetLogMessage { datetime: Utc::now(), tx: *log.tx, - peer_id: *peer_id, + peer_id: peer_id.clone(), kind, }; (msg_log, log_id) @@ -1571,14 +1543,14 @@ pub(super) mod test { |(other, location)| { listener.register_events(Either::Left(NetEventLog { tx: &tx, - peer_id: &peer_id, + peer_id: peer_id.clone(), kind: EventKind::Connect(ConnectEvent::Connected { this: PeerKeyLocation { - peer: peer_id, + peer: peer_id.clone(), location: Some(loc), }, connected: PeerKeyLocation { - peer: *other, + peer: other.clone(), location: Some(*location), }, }), diff --git a/crates/core/src/transport.rs b/crates/core/src/transport.rs index 81cfb5d88..196dee9da 100644 --- a/crates/core/src/transport.rs +++ b/crates/core/src/transport.rs @@ -24,6 +24,13 @@ type PacketId = u32; use self::{packet_data::PacketData, peer_connection::StreamId}; +pub use self::crypto::TransportKeypair; +pub(crate) use self::{ + connection_handler::{create_connection_handler, OutboundConnectionHandler}, + crypto::TransportPublicKey, + peer_connection::PeerConnection, +}; + #[derive(Debug, thiserror::Error)] pub(crate) enum TransportError { #[error("transport handler channel closed, socket likely closed")] @@ -49,7 +56,7 @@ pub(crate) enum TransportError { } /// Make connection handler more testable -trait Socket: Sized + Send + Sync + 'static { +pub(crate) trait Socket: Sized + Send + Sync + 'static { fn bind(addr: SocketAddr) -> impl Future> + Send; fn recv_from( &self, diff --git a/crates/core/src/transport/connection_handler.rs b/crates/core/src/transport/connection_handler.rs index 3e3010667..5ec980494 100644 --- a/crates/core/src/transport/connection_handler.rs +++ b/crates/core/src/transport/connection_handler.rs @@ -1,5 +1,5 @@ use std::collections::BTreeMap; -use std::net::{Ipv4Addr, SocketAddr}; +use std::net::{IpAddr, SocketAddr}; use std::pin::Pin; use std::sync::atomic::AtomicU32; use std::sync::Arc; @@ -57,34 +57,51 @@ struct GatewayMessage { resp_tx: oneshot::Sender, } -pub(crate) struct ConnectionHandler { - send_queue: mpsc::Sender<(SocketAddr, ConnectionEvent)>, +pub(crate) async fn create_connection_handler( + keypair: TransportKeypair, + listen_host: IpAddr, + listen_port: u16, + is_gateway: bool, +) -> Result<(OutboundConnectionHandler, InboundConnectionHandler), TransportError> { + // Bind the UDP socket to the specified port + let socket = S::bind((listen_host, listen_port).into()).await?; + let (och, new_connection_notifier) = OutboundConnectionHandler::config_listener( + Arc::new(socket), + keypair, + is_gateway, + (listen_host, listen_port).into(), + )?; + Ok(( + och, + InboundConnectionHandler { + new_connection_notifier, + }, + )) +} + +pub(crate) struct InboundConnectionHandler { new_connection_notifier: mpsc::Receiver, } -impl ConnectionHandler { - pub async fn new( - keypair: TransportKeypair, - listen_port: u16, - is_gateway: bool, - ) -> Result { - // Bind the UDP socket to the specified port - let socket = Arc::new(S::bind((Ipv4Addr::UNSPECIFIED, listen_port).into()).await?); - Self::config_listener( - socket, - keypair, - is_gateway, - #[cfg(test)] - (Ipv4Addr::UNSPECIFIED, listen_port).into(), - ) +impl InboundConnectionHandler { + pub async fn next_connection(&mut self) -> Option { + self.new_connection_notifier.recv().await } +} +#[derive(Clone)] +pub(crate) struct OutboundConnectionHandler { + send_queue: mpsc::Sender<(SocketAddr, ConnectionEvent)>, +} + +impl OutboundConnectionHandler { fn config_listener( socket: Arc, keypair: TransportKeypair, is_gateway: bool, - #[cfg(test)] socket_addr: SocketAddr, - ) -> Result { + socket_addr: SocketAddr, + ) -> Result<(Self, mpsc::Receiver), TransportError> { + // Channel buffer is one so senders will await until the receiver is ready, important for bandwidth limiting let (conn_handler_sender, conn_handler_receiver) = mpsc::channel(100); let (new_connection_sender, new_connection_notifier) = mpsc::channel(100); @@ -98,22 +115,20 @@ impl ConnectionHandler { connection_handler: conn_handler_receiver, new_connection_notifier: new_connection_sender, outbound_packets: outbound_sender, - #[cfg(test)] this_addr: socket_addr, }; let bw_tracker = super::rate_limiter::PacketRateLimiter::new( DEFAULT_BW_TRACKER_WINDOW_SIZE, outbound_recv, ); - let connection_handler = ConnectionHandler { + let connection_handler = OutboundConnectionHandler { send_queue: conn_handler_sender, - new_connection_notifier, }; task::spawn(bw_tracker.rate_limiter(BANDWITH_LIMIT, socket)); task::spawn(transport.listen()); - Ok(connection_handler) + Ok((connection_handler, new_connection_notifier)) } #[cfg(test)] @@ -122,7 +137,7 @@ impl ConnectionHandler { socket: Arc, keypair: TransportKeypair, is_gateway: bool, - ) -> Result { + ) -> Result<(Self, mpsc::Receiver), TransportError> { Self::config_listener(socket, keypair, is_gateway, socket_addr) } @@ -156,10 +171,6 @@ impl ConnectionHandler { }) .boxed() } - - pub async fn next_connection(&mut self) -> Option { - self.new_connection_notifier.recv().await - } } pub enum Message { @@ -181,7 +192,6 @@ struct UdpPacketsListener { is_gateway: bool, new_connection_notifier: mpsc::Sender, outbound_packets: mpsc::Sender<(SocketAddr, Arc<[u8]>)>, - #[cfg(test)] this_addr: SocketAddr, } @@ -242,7 +252,7 @@ impl UdpPacketsListener { if let Some((packets_sender, open_connection)) = ongoing_connections.remove(&remote_addr) { if packets_sender.send(packet_data).await.is_err() { // it can happen that the connection is established but the channel is closed because the task completed - // but we still ahven't polled the result future + // but we still haven't polled the result future tracing::debug!(%remote_addr, "failed to send packet to remote"); } ongoing_connections.insert(remote_addr, (packets_sender, open_connection)); @@ -319,7 +329,9 @@ impl UdpPacketsListener { if let Some((_, result_sender)) = ongoing_connections.remove(&outbound_remote_conn.remote_addr) { tracing::debug!(%outbound_remote_conn.remote_addr, "connection established"); self.remote_connections.insert(outbound_remote_conn.remote_addr, inbound_remote_connection); - let _ = result_sender.send(Ok(outbound_remote_conn)); + let _ = result_sender.send(Ok(outbound_remote_conn)).map_err(|_| { + tracing::error!("failed sending back peer connection"); + }); } else { tracing::error!(%outbound_remote_conn.remote_addr, "connection established but no ongoing connection found"); } @@ -366,13 +378,16 @@ impl UdpPacketsListener { >, > + Send + 'static { - tracing::debug!(%remote_addr, "new connection to gateway"); let secret = self.this_peer_keypair.secret.clone(); let outbound_packets = self.outbound_packets.clone(); let socket_listener = self.socket_listener.clone(); async move { - let decrypted_intro_packet = secret.decrypt(remote_intro_packet.data())?; + let decrypted_intro_packet = + secret.decrypt(remote_intro_packet.data()).map_err(|err| { + tracing::debug!(%remote_addr, %err, "Failed to decrypt intro packet"); + err + })?; let protoc = &decrypted_intro_packet[..PROTOC_VERSION.len()]; let outbound_key_bytes = &decrypted_intro_packet[PROTOC_VERSION.len()..PROTOC_VERSION.len() + 16]; @@ -488,6 +503,7 @@ impl UdpPacketsListener { inbound_checked_times: 0, }; + tracing::debug!("returning connection at gw"); Ok((remote_conn, inbound_conn, outbound_ack_packet)) } } @@ -560,6 +576,7 @@ impl UdpPacketsListener { let transport_secret_key = self.this_peer_keypair.secret.clone(); let (inbound_from_remote, mut next_inbound) = mpsc::channel::>(1); + let this_addr = self.this_addr; let f = async move { let mut state = ConnectionState::StartOutbound {}; // Initialize timeout and interval @@ -750,12 +767,12 @@ impl UdpPacketsListener { } } Ok(None) => { - tracing::debug!("debug: connection closed"); + tracing::debug!(%this_addr, "debug: connection closed"); return Err(TransportError::ConnectionClosed); } Err(_) => { failures += 1; - tracing::debug!("Failed to receive UDP response, time out"); + tracing::debug!(%this_addr, "Failed to receive UDP response, time out"); } } @@ -829,6 +846,7 @@ impl InboundRemoteConnection { mod test { use std::{ collections::HashMap, + net::Ipv4Addr, ops::Range, sync::{ atomic::{AtomicU16, AtomicU64, AtomicUsize, Ordering}, @@ -958,20 +976,38 @@ mod test { async fn set_peer_connection( packet_drop_policy: PacketDropPolicy, - ) -> Result<(TransportPublicKey, ConnectionHandler, SocketAddr), DynError> { - set_peer_connection_in(packet_drop_policy, false).await + ) -> Result<(TransportPublicKey, OutboundConnectionHandler, SocketAddr), DynError> { + set_peer_connection_in(packet_drop_policy, false) + .await + .map(|(pk, (o, _), s)| (pk, o, s)) } async fn set_gateway_connection( packet_drop_policy: PacketDropPolicy, - ) -> Result<(TransportPublicKey, ConnectionHandler, SocketAddr), DynError> { - set_peer_connection_in(packet_drop_policy, true).await + ) -> Result< + ( + TransportPublicKey, + mpsc::Receiver, + SocketAddr, + ), + DynError, + > { + set_peer_connection_in(packet_drop_policy, true) + .await + .map(|(pk, (_, i), s)| (pk, i, s)) } async fn set_peer_connection_in( packet_drop_policy: PacketDropPolicy, gateway: bool, - ) -> Result<(TransportPublicKey, ConnectionHandler, SocketAddr), DynError> { + ) -> Result< + ( + TransportPublicKey, + (OutboundConnectionHandler, mpsc::Receiver), + SocketAddr, + ), + DynError, + > { static PORT: AtomicU16 = AtomicU16::new(25000); let peer_keypair = TransportKeypair::new(); @@ -980,14 +1016,18 @@ mod test { let socket = Arc::new( MockSocket::test_config(packet_drop_policy, (Ipv4Addr::LOCALHOST, port).into()).await, ); - let peer_conn = ConnectionHandler::test_set_up( + let (peer_conn, inbound_conn) = OutboundConnectionHandler::test_set_up( (Ipv4Addr::LOCALHOST, port).into(), socket, peer_keypair, gateway, ) .expect("failed to create peer"); - Ok((peer_pub, peer_conn, (Ipv4Addr::LOCALHOST, port).into())) + Ok(( + peer_pub, + (peer_conn, inbound_conn), + (Ipv4Addr::LOCALHOST, port).into(), + )) } trait TestFixture: Clone + Send + Sync + 'static { @@ -1200,7 +1240,7 @@ mod test { let (gw_pub, mut gw_conn, gw_addr) = set_gateway_connection(Default::default()).await?; let gw = tokio::spawn(async move { - let gw_conn = gw_conn.next_connection(); + let gw_conn = gw_conn.recv(); let _ = tokio::time::timeout(Duration::from_secs(10), gw_conn) .await? .ok_or("no connection")?; @@ -1228,7 +1268,7 @@ mod test { set_gateway_connection(PacketDropPolicy::Range(0..1)).await?; let gw = tokio::spawn(async move { - let gw_conn = gw_conn.next_connection(); + let gw_conn = gw_conn.recv(); let _ = tokio::time::timeout(Duration::from_secs(10), gw_conn) .await? .ok_or("no connection")?; @@ -1256,7 +1296,7 @@ mod test { set_gateway_connection(PacketDropPolicy::Range(0..1)).await?; let gw = tokio::spawn(async move { - let gw_conn = gw_conn.next_connection(); + let gw_conn = gw_conn.recv(); let _ = tokio::time::timeout(Duration::from_secs(10), gw_conn) .await? .ok_or("no connection")?; @@ -1283,7 +1323,7 @@ mod test { let (gw_pub, mut gw_conn, gw_addr) = set_gateway_connection(Default::default()).await?; let gw = tokio::spawn(async move { - let gw_conn = gw_conn.next_connection(); + let gw_conn = gw_conn.recv(); let _ = tokio::time::timeout(Duration::from_secs(10), gw_conn) .await? .ok_or("no connection")?; diff --git a/crates/core/src/transport/crypto.rs b/crates/core/src/transport/crypto.rs index 0b5c73f61..7cbcaac00 100644 --- a/crates/core/src/transport/crypto.rs +++ b/crates/core/src/transport/crypto.rs @@ -2,9 +2,10 @@ use rand::rngs::OsRng; use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey}; use serde::{Deserialize, Serialize}; -pub(super) struct TransportKeypair { - pub public: TransportPublicKey, - pub secret: TransportSecretKey, +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TransportKeypair { + pub(crate) public: TransportPublicKey, + pub(crate) secret: TransportSecretKey, } impl TransportKeypair { @@ -22,8 +23,8 @@ impl TransportKeypair { } } -#[derive(Serialize, Deserialize, Clone)] -pub(super) struct TransportPublicKey(RsaPublicKey); +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Hash)] +pub struct TransportPublicKey(RsaPublicKey); impl TransportPublicKey { pub fn encrypt(&self, data: &[u8]) -> Vec { @@ -35,8 +36,8 @@ impl TransportPublicKey { } } -#[derive(Clone)] -pub(super) struct TransportSecretKey(RsaPrivateKey); +#[derive(Clone, Debug, Serialize, Deserialize)] +pub(crate) struct TransportSecretKey(RsaPrivateKey); impl TransportSecretKey { pub fn decrypt(&self, data: &[u8]) -> rsa::Result> { diff --git a/crates/core/src/transport/peer_connection.rs b/crates/core/src/transport/peer_connection.rs index 79aab3303..9f6f39a15 100644 --- a/crates/core/src/transport/peer_connection.rs +++ b/crates/core/src/transport/peer_connection.rs @@ -98,7 +98,7 @@ pub(crate) struct PeerConnection { } impl PeerConnection { - pub fn new(remote_conn: RemoteConnection) -> Self { + pub(super) fn new(remote_conn: RemoteConnection) -> Self { Self { remote_conn, received_tracker: ReceivedPacketTracker::new(), @@ -116,8 +116,10 @@ impl PeerConnection { .await .unwrap(); if data.len() + SymmetricMessage::short_message_overhead() > MAX_DATA_SIZE { + tracing::debug!("sending as stream"); self.outbound_stream(data).await; } else { + tracing::debug!("sending as short message"); self.outbound_short_message(data).await?; } Ok(()) @@ -127,7 +129,7 @@ impl PeerConnection { // listen for incoming messages or receipts or wait until is time to do anything else again let mut resend_check = Some(tokio::time::sleep(tokio::time::Duration::from_secs(1))); - const KEEP_ALIVE_INTERVAL: Duration = Duration::from_secs(30); + const KEEP_ALIVE_INTERVAL: Duration = Duration::from_secs(20); const KILL_CONNECTION_AFTER: Duration = Duration::from_secs(60); let mut keep_alive = tokio::time::interval(KEEP_ALIVE_INTERVAL); keep_alive.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); @@ -249,6 +251,10 @@ impl PeerConnection { self.remote_conn.my_address } + pub fn remote_addr(&self) -> SocketAddr { + self.remote_conn.remote_addr + } + async fn process_inbound( &mut self, payload: SymmetricMessagePayload, diff --git a/crates/core/src/util.rs b/crates/core/src/util.rs index 22354e53f..8fa8a260e 100644 --- a/crates/core/src/util.rs +++ b/crates/core/src/util.rs @@ -2,6 +2,7 @@ pub(crate) mod time_source; use std::{ collections::{BTreeMap, HashSet}, + net::{Ipv4Addr, SocketAddr, TcpListener}, time::Duration, }; @@ -37,6 +38,7 @@ pub fn set_cleanup_on_exit() -> Result<(), ctrlc::Error> { }) } +#[derive(Debug)] pub struct ExponentialBackoff { attempt: usize, max_attempts: usize, @@ -84,6 +86,25 @@ impl ExponentialBackoff { } } +pub fn get_free_port() -> Result { + let mut port; + for _ in 0..100 { + port = get_dynamic_port(); + let bind_addr = SocketAddr::from((Ipv4Addr::LOCALHOST, port)); + if let Ok(conn) = TcpListener::bind(bind_addr) { + std::mem::drop(conn); + return Ok(port); + } + } + Err(()) +} + +fn get_dynamic_port() -> u16 { + const FIRST_DYNAMIC_PORT: u16 = 49152; + const LAST_DYNAMIC_PORT: u16 = 65535; + rand::thread_rng().gen_range(FIRST_DYNAMIC_PORT..LAST_DYNAMIC_PORT) +} + // This is extremely inefficient for large sizes but is not what // we are really using this for so this ok for now. // TODO: if necessary implement in the future randomization via `modular multiplicative inverse` method diff --git a/crates/fdev/Cargo.toml b/crates/fdev/Cargo.toml index dcd594fe5..6fcd9067c 100644 --- a/crates/fdev/Cargo.toml +++ b/crates/fdev/Cargo.toml @@ -33,7 +33,6 @@ toml = { version = "0.8", features = ["default", "preserve_order"] } tracing = { workspace = true } tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] } xz2 = "0.1" -libp2p-identity = { features = ["ed25519", "rand"], version = "0.2.7" } reqwest = { version = "0.12", features = ["json"] } http = "1.1" diff --git a/crates/fdev/src/config.rs b/crates/fdev/src/config.rs index 488fc6936..d17588965 100644 --- a/crates/fdev/src/config.rs +++ b/crates/fdev/src/config.rs @@ -50,8 +50,14 @@ pub enum SubCommand { impl SubCommand { pub fn is_child(&self) -> bool { if let SubCommand::Test(config) = self { - if let crate::testing::TestMode::MultiProcess(config) = &config.command { - return matches!(config.mode, crate::testing::Process::Child); + match &config.command { + crate::testing::TestMode::MultiProcess(config) => { + return matches!(config.mode, crate::testing::Process::Child); + } + crate::testing::TestMode::Network(config) => { + return matches!(config.mode, crate::testing::network::Process::Peer); + } + _ => {} } } false diff --git a/crates/fdev/src/network_metrics_server.rs b/crates/fdev/src/network_metrics_server.rs index fc5d580f1..e001d504b 100644 --- a/crates/fdev/src/network_metrics_server.rs +++ b/crates/fdev/src/network_metrics_server.rs @@ -1,4 +1,4 @@ -use std::{net::Ipv4Addr, path::PathBuf, str::FromStr, sync::Arc, time::Duration}; +use std::{net::Ipv4Addr, path::PathBuf, sync::Arc, time::Duration}; use axum::{ body::Body, @@ -195,7 +195,7 @@ async fn pull_interface(ws: WebSocket, state: Arc) -> anyhow::Resul let (mut tx, _) = ws.split(); for peer in state.peer_data.iter() { let msg = PeerChange::current_state_msg( - *peer.key(), + peer.key().clone(), peer.value().location, peer.value().connections.iter(), ); @@ -276,65 +276,56 @@ pub(crate) enum Change { }, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub(crate) struct PeerIdHumanReadable(PeerId); -impl Serialize for PeerIdHumanReadable { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&self.0.to_string()) - } -} - -impl<'de> Deserialize<'de> for PeerIdHumanReadable { - fn deserialize>(deserializer: D) -> Result { - let s = String::deserialize(deserializer)?; - Ok(PeerIdHumanReadable( - PeerId::from_str(&s).map_err(serde::de::Error::custom)?, - )) - } -} - impl From for PeerIdHumanReadable { fn from(peer_id: PeerId) -> Self { Self(peer_id) } } +impl std::fmt::Display for PeerIdHumanReadable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.addr) + } +} + impl ServerState { fn save_record(&self, change: ChangesWrapper) -> Result<(), anyhow::Error> { match change { ChangesWrapper::PeerChange(PeerChange::AddedConnection(added)) => { - let from_peer_id = PeerId::from_str(added.from())?; + let from_peer_id: PeerId = bincode::deserialize(added.from().bytes())?; let from_loc = added.from_location(); - let to_peer_id = PeerId::from_str(added.to())?; + let to_peer_id: PeerId = bincode::deserialize(added.to().bytes())?; let to_loc = added.to_location(); - match self.peer_data.entry(from_peer_id) { + match self.peer_data.entry(from_peer_id.clone()) { dashmap::mapref::entry::Entry::Occupied(mut occ) => { let connections = &mut occ.get_mut().connections; - connections.push((to_peer_id, to_loc)); + connections.push((to_peer_id.clone(), to_loc)); connections.sort_unstable_by(|a, b| a.0.cmp(&b.0)); connections.dedup(); } dashmap::mapref::entry::Entry::Vacant(vac) => { vac.insert(PeerData { - connections: vec![(to_peer_id, to_loc)], + connections: vec![(to_peer_id.clone(), to_loc)], location: from_loc, }); } } - match self.peer_data.entry(to_peer_id) { + match self.peer_data.entry(to_peer_id.clone()) { dashmap::mapref::entry::Entry::Occupied(mut occ) => { let connections = &mut occ.get_mut().connections; - connections.push((from_peer_id, from_loc)); + connections.push((from_peer_id.clone(), from_loc)); connections.sort_unstable_by(|a, b| a.0.cmp(&b.0)); connections.dedup(); } dashmap::mapref::entry::Entry::Vacant(vac) => { vac.insert(PeerData { - connections: vec![(from_peer_id, from_loc)], + connections: vec![(from_peer_id.clone(), from_loc)], location: to_loc, }); } @@ -347,8 +338,8 @@ impl ServerState { }); } ChangesWrapper::PeerChange(PeerChange::RemovedConnection(removed)) => { - let from_peer_id = PeerId::from_str(removed.from())?; - let at_peer_id = PeerId::from_str(removed.at())?; + let from_peer_id = bincode::deserialize(removed.from().bytes())?; + let at_peer_id = bincode::deserialize(removed.at().bytes())?; if let Some(mut entry) = self.peer_data.get_mut(&from_peer_id) { entry diff --git a/crates/fdev/src/testing.rs b/crates/fdev/src/testing.rs index 83849a7d8..b1273dd85 100644 --- a/crates/fdev/src/testing.rs +++ b/crates/fdev/src/testing.rs @@ -4,7 +4,7 @@ use anyhow::Error; use freenet::dev_tool::SimNetwork; mod multiple_process; -mod network; +pub(crate) mod network; mod single_process; pub(crate) use multiple_process::Process; diff --git a/crates/fdev/src/testing/multiple_process.rs b/crates/fdev/src/testing/multiple_process.rs index f1f7cce87..c9317fd21 100644 --- a/crates/fdev/src/testing/multiple_process.rs +++ b/crates/fdev/src/testing/multiple_process.rs @@ -116,14 +116,15 @@ async fn supervisor(config: &super::TestConfig) -> anyhow::Result<(), Error> { }; let cmd_args = config.subprocess_command(seed); for (label, node) in &peers { - let mut subprocess = SubProcess::start(&cmd_args, label, node.peer_id)?; + let peer_id = node.get_peer_id().unwrap(); + let mut subprocess = SubProcess::start(&cmd_args, label, peer_id.clone())?; subprocess.config(node).await?; - supervisor.processes.insert(node.peer_id, subprocess); + supervisor.processes.insert(peer_id, subprocess); } let peers = peers .into_iter() - .map(|(label, config)| (label, config.peer_id)) + .map(|(label, config)| (label, config.get_peer_id().unwrap())) .collect(); let mut events = EventChain::new(peers, user_ev_controller, config.events, true); let next_event_wait_time = config @@ -247,7 +248,7 @@ impl Supervisor { continue; } }; - let peer_queue = &mut *self.queued.entry(subprocess.id).or_default(); + let peer_queue = &mut *self.queued.entry(subprocess.id.clone()).or_default(); if !peer_queue.is_empty() { let n = rand::thread_rng().gen_range(0..=peer_queue.len()); let messages = peer_queue.drain(..n).collect::>(); @@ -261,7 +262,7 @@ impl Supervisor { }.boxed(); self.sending.push(task); } else { - self.processes.insert(subprocess.id, subprocess); + self.processes.insert(subprocess.id.clone(), subprocess); } } event = event_rx.recv(), if !finished_events => { @@ -322,10 +323,26 @@ struct SubProcess { impl SubProcess { fn start(cmd_args: &[String], label: &NodeLabel, id: PeerId) -> anyhow::Result { + let mut command = if cfg!(debug_assertions) { + Command::new("cargo") + } else { + Command::new("fdev") + }; + #[cfg(debug_assertions)] + { + let args = ["run", "--"] + .into_iter() + .chain(cmd_args.iter().map(std::ops::Deref::deref)); + command.args(args); + } + #[cfg(not(debug_assertions))] + { + let args = cmd_args; + command.args(args); + } // the identifier used for multi-process tests is the peer id - let child = Command::new("fdev") + let child = command .kill_on_drop(true) - .args(cmd_args) .arg("--id") .arg(label.number().to_string()) .stdin(Stdio::piped()) @@ -397,16 +414,17 @@ async fn child( receiver_ch.borrow_and_update(); let mut input = BufReader::new(tokio::io::stdin()); let node_config = Child::get_config(&mut input).await?; + let peer_id = node_config.get_peer_id().unwrap(); let this_child = Child { input, user_ev_controller, - peer_id: node_config.peer_id, + peer_id: peer_id.clone(), }; - std::env::set_var("FREENET_PEER_ID", node_config.peer_id.to_string()); + std::env::set_var("FREENET_PEER_ID", peer_id.to_string()); freenet::config::set_logger(None); let mut event_generator: MemoryEventsGen = MemoryEventsGen::new_with_seed( receiver_ch.clone(), - node_config.peer_id, + peer_id, test_config .seed .expect("seed should be set for child process"), @@ -457,7 +475,7 @@ impl Child { break Err(err); } Ok(IPCMessage::FiredEvent(id)) => { - self.user_ev_controller.send((id, self.peer_id))?; + self.user_ev_controller.send((id, self.peer_id.clone()))?; } Ok(IPCMessage::Data(data)) => { InterProcessConnManager::push_msg(data); diff --git a/crates/fdev/src/testing/network.rs b/crates/fdev/src/testing/network.rs index deb88fc88..741d1c32d 100644 --- a/crates/fdev/src/testing/network.rs +++ b/crates/fdev/src/testing/network.rs @@ -1,4 +1,13 @@ -use super::{Error, TestConfig}; +use std::{ + collections::{HashMap, VecDeque}, + fmt::Display, + net::SocketAddr, + ops::Deref, + process::Stdio, + sync::Arc, + time::Duration, +}; + use anyhow::anyhow; use axum::{ body::Body, @@ -14,27 +23,20 @@ use freenet::dev_tool::{ EventChain, MemoryEventsGen, NetworkEventGenerator, NetworkPeer, NodeConfig, NodeLabel, PeerId, PeerMessage, PeerStatus, SimNetwork, }; -use futures::stream::{SplitSink, SplitStream}; -use futures::{SinkExt, StreamExt}; -use http::{Response, StatusCode}; -use libp2p_identity::Keypair; -use std::ops::Deref; -use std::{ - collections::{HashMap, VecDeque}, - fmt::Display, - net::SocketAddr, - process::Stdio, - sync::Arc, - time::Duration, +use futures::{ + stream::{SplitSink, SplitStream}, + SinkExt, StreamExt, }; - +use http::{Response, StatusCode}; use thiserror::Error; -use tokio::task::JoinHandle; use tokio::{ process::Command, sync::{oneshot, Mutex}, + task::JoinHandle, }; +use super::{Error, TestConfig}; + #[derive(Debug, Error)] pub enum NetworkSimulationError { #[error("Server start failed: {0}")] @@ -118,9 +120,25 @@ impl SubProcess { } async fn start(cmd_args: &[String], label: &NodeLabel) -> anyhow::Result { - let child = Command::new("fdev") + let mut command = if cfg!(debug_assertions) { + Command::new("cargo") + } else { + Command::new("fdev") + }; + #[cfg(debug_assertions)] + { + let args = ["run", "--"] + .into_iter() + .chain(cmd_args.iter().map(Deref::deref)); + command.args(args); + } + #[cfg(not(debug_assertions))] + { + let args = cmd_args; + command.args(args); + } + let child = command .kill_on_drop(true) - .args(cmd_args) .arg("--id") .arg(label.to_string()) .stdin(Stdio::inherit()) @@ -156,8 +174,11 @@ async fn start_supervisor(config: &TestConfig) -> anyhow::Result<(), Error> { Ok(()) } -async fn start_peer(config: &TestConfig, cmd_config: &NetworkProcessConfig) -> Result<(), Error> { - std::env::set_var("FREENET_PEER_ID", cmd_config.clone().id.unwrap()); +async fn start_child(config: &TestConfig, cmd_config: &NetworkProcessConfig) -> Result<(), Error> { + std::env::set_var( + "FREENET_PEER_ID", + cmd_config.clone().id.expect("id should be set"), + ); freenet::config::set_logger(None); if let Some(peer_id) = &cmd_config.id { let peer = NetworkPeer::new(peer_id.clone()).await?; @@ -172,7 +193,7 @@ pub(super) async fn run( ) -> Result<(), Error> { match &cmd_config.mode { Process::Supervisor => start_supervisor(config).await, - Process::Peer => start_peer(config, cmd_config).await, + Process::Peer => start_child(config, cmd_config).await, } } @@ -232,7 +253,7 @@ pub async fn run_network( .get_all_peers() .await .into_iter() - .map(|(label, config)| (label.clone(), config.peer_id)) + .map(|(label, config)| (label.clone(), config.get_peer_id().unwrap())) .collect(); let events_sender = supervisor.user_ev_controller.lock().await.clone(); @@ -251,6 +272,8 @@ pub async fn run_network( network_connection_percent * 100.0 ); network.check_partial_connectivity(connectivity_timeout, network_connection_percent)?; + // FIXME: we are getting connectivity check that is not real since peers are not reporting if they + // are connected or not to other peers tracing::info!("Network is sufficiently connected, start sending events"); while events.next().await.is_some() { tokio::time::sleep(next_event_wait_time).await; @@ -296,6 +319,7 @@ async fn config_handler( peers_config: Arc>>, Path(peer_id): Path, ) -> axum::response::Response { + tracing::debug!("Received config request for peer_id: {}", peer_id); let config = peers_config.lock().await; let id = NodeLabel::from(peer_id.as_str()); match config.get(&id) { @@ -378,11 +402,16 @@ async fn handle_outgoing_messages( let mut event_rx = supervisor.event_rx.lock().await; while let Some((event, peer_id)) = event_rx.recv().await { tracing::info!("Received event {} for peer {}", event, peer_id); - let serialized_msg: Vec = bincode::serialize(&(event, peer_id)) + let serialized_msg: Vec = bincode::serialize(&(event, peer_id.clone())) .map_err(|e| anyhow!("Failed to serialize message: {}", e))?; if let Err(e) = sender.send(Message::Binary(serialized_msg)).await { - tracing::error!("Failed to send event {} for peer {}: {}", event, peer_id, e); + tracing::error!( + "Failed to send event {} for peer {}: {}", + event, + peer_id.clone(), + e + ); } } Ok(()) @@ -491,7 +520,10 @@ impl Supervisor { config: &NodeConfig, ) -> Result<(), Error> { let process = SubProcess::start(cmd_args, label).await?; - self.processes.lock().await.insert(config.peer_id, process); + self.processes + .lock() + .await + .insert(config.get_peer_id().unwrap(), process); Ok(()) } @@ -508,7 +540,7 @@ impl Supervisor { .lock() .await .iter() - .filter(|(_, config)| !config.is_gateway()) + .filter(|(_, config)| !config.is_gateway) .map(|(label, config)| (label.clone(), config.clone())) .collect() } @@ -518,7 +550,7 @@ impl Supervisor { .lock() .await .iter() - .filter(|(_, config)| config.is_gateway()) + .filter(|(_, config)| config.is_gateway) .map(|(label, config)| (label.clone(), config.clone())) .collect() } @@ -552,6 +584,7 @@ impl Supervisor { pub async fn start_peer_gateways(&self, cmd_args: &[String]) -> Result<(), Error> { let nodes: Vec<(NodeLabel, NodeConfig)> = self.get_peer_gateways().await; + for (label, config) in nodes { self.enqueue_gateway(label.number()).await; self.start_process(cmd_args, &label, &config).await?; @@ -596,17 +629,18 @@ pub trait Runnable { impl Runnable for NetworkPeer { async fn run(&self, config: &TestConfig, peer_id: String) -> anyhow::Result<()> { - if self.config.is_gateway() { - tracing::info!("Starting gateway {}", peer_id); + let peer = self.config.get_peer_id().unwrap(); + if self.config.is_gateway { + tracing::info!(%peer, "Starting gateway {}", peer_id); } else { - tracing::info!("Starting node {}", peer_id); + tracing::info!(%peer, "Starting node {}", peer_id); } let mut receiver_ch = self.receiver_ch.deref().clone(); receiver_ch.borrow_and_update(); let mut memory_event_generator: MemoryEventsGen = MemoryEventsGen::new_with_seed( receiver_ch, - self.config.peer_id, + peer.clone(), config.seed.expect("seed should be set for child process"), ); let peer_id_num = NodeLabel::from(peer_id.as_str()).number(); @@ -626,23 +660,22 @@ impl Runnable for NetworkPeer { }; let event_generator = - NetworkEventGenerator::new(self.config.peer_id, memory_event_generator, ws_client); + NetworkEventGenerator::new(peer.clone(), memory_event_generator, ws_client); - // Obtain an identity::Keypair instance for the private_key - let private_key = Keypair::generate_ed25519(); + let peer_keypair = self.config.key_pair.clone().unwrap(); match self - .build(peer_id.clone(), [Box::new(event_generator)], private_key) + .build(peer_id.clone(), [Box::new(event_generator)], peer_keypair) .await { Ok(node) => match node.run().await { Ok(_) => { - if self.config.is_gateway() { + if self.config.is_gateway { tracing::info!("Gateway {} finished", peer_id); } else { tracing::info!("Node {} finished", peer_id); } - let msg = match self.config.is_gateway() { + let msg = match self.config.is_gateway { true => PeerMessage::Status(PeerStatus::GatewayStarted(peer_id_num)), false => PeerMessage::Status(PeerStatus::PeerStarted(peer_id_num)), }; diff --git a/schemas/flatbuffers/topology.fbs b/schemas/flatbuffers/topology.fbs index a0b5cd8e9..eecf8d52f 100644 --- a/schemas/flatbuffers/topology.fbs +++ b/schemas/flatbuffers/topology.fbs @@ -2,15 +2,15 @@ namespace topology; table AddedConnection { transaction: string; - from: string(required); // encoded PeerId + from: [ubyte](required); // encoded PeerId from_location: float64; - to: string(required); // encoded PeerId + to: [ubyte](required); // encoded PeerId to_location: float64; } table RemovedConnection { - at: string(required); - from: string(required); + at: [ubyte](required); + from: [ubyte](required); } table Error { diff --git a/stdlib b/stdlib index f5597dfd4..e1b54fe24 160000 --- a/stdlib +++ b/stdlib @@ -1 +1 @@ -Subproject commit f5597dfd440a0470bcd306ce9f50883b42060a6e +Subproject commit e1b54fe24b992ed9518212981a617b2ba1c15622