From f6438434785b41d630211f93b7d5b68a5fb49f83 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Sun, 3 Sep 2023 15:06:20 +0300 Subject: [PATCH 01/32] Rework the event system of `sc-network` This commit introduces a new concept called `NotificationService` which allows Polkadot protocols to communicate with the underlying notification protocol implementation directly, without routing events through `NetworkWorker`. This implies that each protocol has its own service which it uses to communicate with remote peers and that each `NotificationService` is unique with respect to the underlying notification protocol, meaning `NotificationService` for the transaction protocol can only be used to send and receive transaction-related notifications. The `NotificationService` concept introduces two additional benefits: * allow protocols to start using custom handshakes * allow protocols to accept/reject inbound peers Previously the validation of inbound connections was solely the responsibility of `ProtocolController`. This caused issues with light peers and `SyncingEngine` as `ProtocolController` would accept more peers than `SyncingEngine` could accept which caused peers to have differing views of their own states. `SyncingEngine` would reject excess peers but these rejections were not properly communicated to those peers causing them to assume that they were accepted. With `NotificationService`, the local handshake is not sent to remote peer if peer is rejected which allows it to detect that it was rejected. This commit also deprecates the use of `NetworkEventStream` for all notification-related events and going forward only DHT events are provided through `NetworkEventStream`. If protocols wish to follow each other's events, they must introduce additional abtractions, as is done for GRANDPA and transactions protocols by following the syncing protocol through `SyncEventStream`. Fixes https://github.com/paritytech/polkadot-sdk/issues/512 Fixes https://github.com/paritytech/polkadot-sdk/issues/514 Fixes https://github.com/paritytech/polkadot-sdk/issues/515 Fixes https://github.com/paritytech/polkadot-sdk/issues/554 Fixes https://github.com/paritytech/polkadot-sdk/issues/556 Co-authored-by: Dmitry Markin --- Cargo.lock | 220 ++-- .../relay-chain-minimal-node/Cargo.toml | 1 + .../src/collator_overseer.rs | 15 +- .../relay-chain-minimal-node/src/lib.rs | 14 +- .../relay-chain-minimal-node/src/network.rs | 25 +- polkadot/node/network/bridge/src/lib.rs | 1 + polkadot/node/network/bridge/src/network.rs | 60 +- polkadot/node/network/bridge/src/rx/mod.rs | 943 ++++++++++-------- polkadot/node/network/bridge/src/rx/tests.rs | 334 +++++-- polkadot/node/network/bridge/src/tx/mod.rs | 60 +- polkadot/node/network/bridge/src/tx/tests.rs | 142 ++- .../network/bridge/src/validator_discovery.rs | 13 +- .../node/network/protocol/src/peer_set.rs | 77 +- polkadot/node/service/Cargo.toml | 1 + polkadot/node/service/src/lib.rs | 54 +- polkadot/node/service/src/overseer.rs | 14 +- .../bin/node-template/node/src/service.rs | 7 +- substrate/bin/node/cli/src/service.rs | 28 +- .../consensus/beefy/src/communication/mod.rs | 12 +- substrate/client/consensus/beefy/src/lib.rs | 6 +- substrate/client/consensus/beefy/src/tests.rs | 41 +- .../client/consensus/beefy/src/worker.rs | 4 + .../grandpa/src/communication/mod.rs | 4 +- .../grandpa/src/communication/tests.rs | 227 +++-- substrate/client/consensus/grandpa/src/lib.rs | 22 +- .../client/consensus/grandpa/src/observer.rs | 23 +- .../client/consensus/grandpa/src/tests.rs | 82 +- substrate/client/network-gossip/Cargo.toml | 2 + substrate/client/network-gossip/src/bridge.rs | 236 +++-- .../network-gossip/src/state_machine.rs | 4 + substrate/client/network/Cargo.toml | 2 + substrate/client/network/common/src/role.rs | 14 +- substrate/client/network/src/config.rs | 90 +- substrate/client/network/src/error.rs | 9 + substrate/client/network/src/lib.rs | 17 +- substrate/client/network/src/mock.rs | 9 + substrate/client/network/src/peer_store.rs | 41 +- substrate/client/network/src/protocol.rs | 199 ++-- .../client/network/src/protocol/message.rs | 1 + .../network/src/protocol/notifications.rs | 2 + .../src/protocol/notifications/behaviour.rs | 586 ++++++++--- .../src/protocol/notifications/handler.rs | 102 +- .../protocol/notifications/service/metrics.rs | 124 +++ .../src/protocol/notifications/service/mod.rs | 576 +++++++++++ .../protocol/notifications/service/tests.rs | 770 ++++++++++++++ .../src/protocol/notifications/tests.rs | 29 +- .../client/network/src/protocol_controller.rs | 3 + substrate/client/network/src/service.rs | 67 +- .../client/network/src/service/signature.rs | 2 + .../client/network/src/service/traits.rs | 198 +++- substrate/client/network/statement/src/lib.rs | 118 +-- substrate/client/network/sync/src/engine.rs | 727 +++++++++++--- substrate/client/network/sync/src/lib.rs | 49 +- .../client/network/sync/src/service/mock.rs | 2 + substrate/client/network/test/src/lib.rs | 97 +- substrate/client/network/test/src/service.rs | 337 +++---- substrate/client/network/test/src/sync.rs | 86 +- .../client/network/transactions/src/lib.rs | 151 ++- substrate/client/offchain/src/api.rs | 6 +- substrate/client/offchain/src/lib.rs | 8 +- substrate/client/service/src/builder.rs | 26 +- 61 files changed, 5133 insertions(+), 1987 deletions(-) create mode 100644 substrate/client/network/src/protocol/notifications/service/metrics.rs create mode 100644 substrate/client/network/src/protocol/notifications/service/mod.rs create mode 100644 substrate/client/network/src/protocol/notifications/service/tests.rs diff --git a/Cargo.lock b/Cargo.lock index f3bbc2faf296..a1d226de0cfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -178,9 +178,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] @@ -617,7 +617,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.27", + "time 0.3.28", ] [[package]] @@ -633,7 +633,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.27", + "time 0.3.28", ] [[package]] @@ -1149,7 +1149,7 @@ checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", ] [[package]] @@ -1190,7 +1190,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", ] [[package]] @@ -1285,9 +1285,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" [[package]] name = "base64ct" @@ -2139,12 +2139,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "8042c26c77e5bd6897a7358e0abb3ec412ed126d826988135653fc669263899d" dependencies = [ "memchr", - "regex-automata 0.3.6", + "regex-automata 0.3.7", "serde", ] @@ -3795,6 +3795,7 @@ dependencies = [ "cumulus-relay-chain-interface", "cumulus-relay-chain-rpc-interface", "futures", + "parking_lot 0.12.1", "polkadot-availability-recovery", "polkadot-collator-protocol", "polkadot-core-primitives", @@ -4085,9 +4086,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28403c86fc49e3401fdf45499ba37fad6493d9329449d6449d7f0e10f4654d28" +checksum = "bbe98ba1789d56fb3db3bee5e032774d4f421b685de7ba703643584ba24effbe" dependencies = [ "cc", "cxxbridge-flags", @@ -4097,9 +4098,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78da94fef01786dc3e0c76eafcd187abcaa9972c78e05ff4041e24fdf059c285" +checksum = "c4ce20f6b8433da4841b1dadfb9468709868022d829d5ca1f2ffbda928455ea3" dependencies = [ "cc", "codespan-reporting", @@ -4112,15 +4113,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a6f5e1dfb4b34292ad4ea1facbfdaa1824705b231610087b00b17008641809" +checksum = "20888d9e1d2298e2ff473cee30efe7d5036e437857ab68bbfea84c74dba91da2" [[package]] name = "cxxbridge-macro" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" +checksum = "2fa16a70dd58129e4dfffdff535fb1bce66673f7bbeec4a5a1765a504e1ccd84" dependencies = [ "proc-macro2", "quote", @@ -4164,9 +4165,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.5.1" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd72493923899c6f10c641bdbdeddc7183d6396641d99c1a0d1597f37f92e28" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", "hashbrown 0.14.0", @@ -4782,9 +4783,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "erased-serde" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "837c0466252947ada828b975e12daf82e18bb5444e4df87be6038d4469e2a3d2" +checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" dependencies = [ "serde", ] @@ -4801,9 +4802,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", @@ -5565,7 +5566,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47" dependencies = [ - "rustix 0.38.8", + "rustix 0.38.10", "windows-sys 0.48.0", ] @@ -5641,7 +5642,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "waker-fn", ] @@ -5663,7 +5664,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls 0.20.8", + "rustls 0.20.9", "webpki 0.22.0", ] @@ -5698,7 +5699,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "pin-utils", "slab", ] @@ -6107,7 +6108,7 @@ checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", ] [[package]] @@ -6150,7 +6151,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "socket2 0.4.9", "tokio", "tower-service", @@ -6168,7 +6169,7 @@ dependencies = [ "http", "hyper", "log", - "rustls 0.21.6", + "rustls 0.21.7", "rustls-native-certs", "tokio", "tokio-rustls", @@ -6513,7 +6514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.2", - "rustix 0.38.8", + "rustix 0.38.10", "windows-sys 0.48.0", ] @@ -7261,7 +7262,7 @@ dependencies = [ "parking_lot 0.12.1", "quinn-proto", "rand 0.8.5", - "rustls 0.20.8", + "rustls 0.20.9", "thiserror", "tokio", ] @@ -7342,7 +7343,7 @@ dependencies = [ "libp2p-identity", "rcgen 0.10.0", "ring 0.16.20", - "rustls 0.20.8", + "rustls 0.20.9", "thiserror", "webpki 0.22.0", "x509-parser 0.14.0", @@ -7526,9 +7527,9 @@ dependencies = [ [[package]] name = "linregress" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de0b5f52a9f84544d268f5fabb71b38962d6aa3c6600b8bcd27d44ccf9c9c45" +checksum = "4de04dcecc58d366391f9920245b85ffa684558a5ef6e7736e754347c3aea9c2" dependencies = [ "nalgebra", ] @@ -7756,9 +7757,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f478948fd84d9f8e86967bf432640e46adfb5a4bd4f14ef7e864ab38220534ae" [[package]] name = "memfd" @@ -8169,16 +8170,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", "memoffset 0.7.1", "pin-utils", - "static_assertions", ] [[package]] @@ -8239,7 +8239,7 @@ dependencies = [ "jsonrpsee", "kitchensink-runtime", "log", - "nix 0.26.2", + "nix 0.26.4", "node-executor", "node-inspect", "node-primitives", @@ -11055,9 +11055,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" dependencies = [ "arrayvec 0.7.4", "bitvec", @@ -11070,9 +11070,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11385,9 +11385,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -11423,9 +11423,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" -version = "3.0.2" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" +checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" [[package]] name = "plotters" @@ -11461,7 +11461,7 @@ version = "1.0.0" dependencies = [ "assert_cmd", "color-eyre", - "nix 0.26.2", + "nix 0.26.4", "polkadot-cli", "polkadot-core-primitives", "polkadot-node-core-pvf", @@ -12429,7 +12429,7 @@ dependencies = [ "hex-literal 0.4.1", "jsonrpsee", "log", - "nix 0.26.2", + "nix 0.26.4", "pallet-transaction-payment-rpc", "parachains-common", "parity-scale-codec", @@ -12841,6 +12841,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parity-db", "parity-scale-codec", + "parking_lot 0.12.1", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", @@ -13187,7 +13188,7 @@ dependencies = [ "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "windows-sys 0.48.0", ] @@ -13239,9 +13240,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" +checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" [[package]] name = "portpicker" @@ -13263,7 +13264,7 @@ dependencies = [ "findshlibs", "libc", "log", - "nix 0.26.2", + "nix 0.26.4", "once_cell", "parking_lot 0.12.1", "smallvec", @@ -13423,9 +13424,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro-warning" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70550716265d1ec349c41f70dd4f964b4fd88394efe4405f0c1da679c4799a07" +checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", @@ -13641,7 +13642,7 @@ dependencies = [ "rand 0.8.5", "ring 0.16.20", "rustc-hash", - "rustls 0.20.8", + "rustls 0.20.9", "slab", "thiserror", "tinyvec", @@ -13790,7 +13791,7 @@ checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", "ring 0.16.20", - "time 0.3.27", + "time 0.3.28", "x509-parser 0.13.2", "yasna", ] @@ -13803,7 +13804,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring 0.16.20", - "time 0.3.27", + "time 0.3.28", "yasna", ] @@ -13883,14 +13884,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.3" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.6", - "regex-syntax 0.7.4", + "regex-automata 0.3.7", + "regex-syntax 0.7.5", ] [[package]] @@ -13904,13 +13905,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.7.5", ] [[package]] @@ -13921,9 +13922,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "remote-ext-tests-bags-list" @@ -13950,7 +13951,7 @@ version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "bytes", "encoding_rs", "futures-core", @@ -13966,8 +13967,8 @@ dependencies = [ "mime", "once_cell", "percent-encoding", - "pin-project-lite 0.2.12", - "rustls 0.21.6", + "pin-project-lite 0.2.13", + "rustls 0.21.7", "rustls-pemfile", "serde", "serde_json", @@ -14361,9 +14362,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.8" +version = "0.38.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +checksum = "ed6248e1caa625eb708e266e06159f135e8c26f2bb7ceb72dc4b2766d0340964" dependencies = [ "bitflags 2.4.0", "errno", @@ -14387,9 +14388,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" dependencies = [ "log", "ring 0.16.20", @@ -14399,9 +14400,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.6" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" dependencies = [ "log", "ring 0.16.20", @@ -14427,7 +14428,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", ] [[package]] @@ -15245,6 +15246,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tokio-stream", "tokio-test", "tokio-util", "unsigned-varint", @@ -15300,10 +15302,12 @@ name = "sc-network-gossip" version = "0.10.0-dev" dependencies = [ "ahash 0.8.3", + "async-trait", "futures", "futures-timer", "libp2p", "log", + "parity-scale-codec", "quickcheck", "sc-network", "sc-network-common", @@ -16528,7 +16532,7 @@ dependencies = [ "arrayvec 0.7.4", "async-lock", "atomic-take", - "base64 0.21.2", + "base64 0.21.3", "bip39", "blake2-rfc", "bs58 0.5.0", @@ -16581,7 +16585,7 @@ checksum = "256b5bad1d6b49045e95fe87492ce73d5af81545d8b4d8318a872d2007024c33" dependencies = [ "async-channel", "async-lock", - "base64 0.21.2", + "base64 0.21.3", "blake2-rfc", "derive_more", "either", @@ -18077,7 +18081,7 @@ version = "0.1.0" dependencies = [ "assert_cmd", "futures", - "nix 0.26.2", + "nix 0.26.4", "node-cli", "node-primitives", "regex", @@ -18515,7 +18519,7 @@ dependencies = [ "cfg-if", "fastrand 2.0.0", "redox_syscall 0.3.5", - "rustix 0.38.8", + "rustix 0.38.10", "windows-sys 0.48.0", ] @@ -18775,9 +18779,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb39ee79a6d8de55f48f2293a830e040392f1c5f16e336bdd1788cd0aadce07" +checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" dependencies = [ "deranged", "itoa", @@ -18794,9 +18798,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733d258752e9303d392b94b75230d07b0b9c489350c69b851fc6c065fde3e8f9" +checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" dependencies = [ "time-core", ] @@ -18866,7 +18870,7 @@ dependencies = [ "mio", "num_cpus", "parking_lot 0.12.1", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "signal-hook-registry", "socket2 0.5.3", "tokio-macros", @@ -18901,7 +18905,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.6", + "rustls 0.21.7", "tokio", ] @@ -18912,7 +18916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "tokio", "tokio-util", ] @@ -18952,7 +18956,7 @@ dependencies = [ "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "tokio", "tracing", ] @@ -19024,7 +19028,7 @@ dependencies = [ "http", "http-body", "http-range-header", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "tower-layer", "tower-service", ] @@ -19049,7 +19053,7 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "log", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.13", "tracing-attributes", "tracing-core", ] @@ -19480,9 +19484,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna 0.4.0", @@ -19725,9 +19729,9 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-encoder" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41763f20eafed1399fff1afb466496d3a959f58241436cfdc17e3f5ca954de16" +checksum = "1ba64e81215916eaeb48fee292f29401d69235d62d8b8fd92a7b2844ec5ae5f7" dependencies = [ "leb128", ] @@ -19899,7 +19903,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c86437fa68626fe896e5afc69234bb2b5894949083586535f200385adfd71213" dependencies = [ "anyhow", - "base64 0.21.2", + "base64 0.21.3", "bincode", "directories-next", "file-per-thread-logger", @@ -20052,9 +20056,9 @@ dependencies = [ [[package]] name = "wast" -version = "63.0.0" +version = "64.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2560471f60a48b77fccefaf40796fda61c97ce1e790b59dfcec9dc3995c9f63a" +checksum = "a259b226fd6910225aa7baeba82f9d9933b6d00f2ce1b49b80fa4214328237cc" dependencies = [ "leb128", "memchr", @@ -20064,9 +20068,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdc306c2c4c2f2bf2ba69e083731d0d2a77437fc6a350a19db139636e7e416c" +checksum = "53253d920ab413fca1c7dc2161d601c79b4fdf631d0ba51dd4343bf9b556c3f6" dependencies = [ "wast", ] @@ -20151,7 +20155,7 @@ dependencies = [ "sha2 0.10.7", "stun", "thiserror", - "time 0.3.27", + "time 0.3.28", "tokio", "turn", "url", @@ -20759,7 +20763,7 @@ dependencies = [ "ring 0.16.20", "rusticata-macros", "thiserror", - "time 0.3.27", + "time 0.3.28", ] [[package]] @@ -20777,7 +20781,7 @@ dependencies = [ "oid-registry 0.6.1", "rusticata-macros", "thiserror", - "time 0.3.27", + "time 0.3.28", ] [[package]] @@ -20947,7 +20951,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "time 0.3.27", + "time 0.3.28", ] [[package]] diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 39056d6b6511..7ecc7ef15537 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -40,6 +40,7 @@ schnellru = "0.2.1" tracing = "0.1.37" async-trait = "0.1.73" futures = "0.3.28" +parking_lot = "0.12.1" [features] network-protocol-staging = [ diff --git a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs index 491758c1329a..c7d536d116ca 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -15,8 +15,9 @@ // along with Polkadot. If not, see . use futures::{select, StreamExt}; +use parking_lot::Mutex; use schnellru::{ByLength, LruMap}; -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; use polkadot_availability_recovery::AvailabilityRecoverySubsystem; use polkadot_collator_protocol::{CollatorProtocolSubsystem, ProtocolSide}; @@ -27,7 +28,7 @@ use polkadot_network_bridge::{ use polkadot_node_collation_generation::CollationGenerationSubsystem; use polkadot_node_core_runtime_api::RuntimeApiSubsystem; use polkadot_node_network_protocol::{ - peer_set::PeerSetProtocolNames, + peer_set::{PeerSet, PeerSetProtocolNames}, request_response::{ v1::{self, AvailableDataFetchingRequest}, vstaging, IncomingRequestReceiver, ReqProtocolNames, @@ -41,7 +42,7 @@ use polkadot_overseer::{ use polkadot_primitives::CollatorPair; use sc_authority_discovery::Service as AuthorityDiscoveryService; -use sc_network::NetworkStateInfo; +use sc_network::{NetworkStateInfo, NotificationService}; use sc_service::TaskManager; use sp_runtime::traits::Block as BlockT; @@ -77,6 +78,8 @@ pub(crate) struct CollatorOverseerGenArgs<'a> { pub req_protocol_names: ReqProtocolNames, /// Peerset protocols name mapping pub peer_set_protocol_names: PeerSetProtocolNames, + /// Notification services for validation/collation protocols. + pub notification_services: HashMap>, } fn build_overseer( @@ -94,6 +97,7 @@ fn build_overseer( collator_pair, req_protocol_names, peer_set_protocol_names, + notification_services, }: CollatorOverseerGenArgs<'_>, ) -> Result< (Overseer, Arc>, OverseerHandle), @@ -101,6 +105,8 @@ fn build_overseer( > { let spawner = SpawnGlue(spawner); let network_bridge_metrics: NetworkBridgeMetrics = Metrics::register(registry)?; + let notification_sinks = Arc::new(Mutex::new(HashMap::new())); + let builder = Overseer::builder() .availability_distribution(DummySubsystem) .availability_recovery(AvailabilityRecoverySubsystem::with_availability_store_skip( @@ -131,6 +137,8 @@ fn build_overseer( sync_oracle, network_bridge_metrics.clone(), peer_set_protocol_names.clone(), + notification_services, + notification_sinks.clone(), )) .network_bridge_tx(NetworkBridgeTxSubsystem::new( network_service, @@ -138,6 +146,7 @@ fn build_overseer( network_bridge_metrics, req_protocol_names, peer_set_protocol_names, + notification_sinks, )) .provisioner(DummySubsystem) .runtime_api(RuntimeApiSubsystem::new( diff --git a/cumulus/client/relay-chain-minimal-node/src/lib.rs b/cumulus/client/relay-chain-minimal-node/src/lib.rs index 366d428eda70..cae093678ad6 100644 --- a/cumulus/client/relay-chain-minimal-node/src/lib.rs +++ b/cumulus/client/relay-chain-minimal-node/src/lib.rs @@ -21,7 +21,7 @@ use cumulus_relay_chain_rpc_interface::{RelayChainRpcClient, RelayChainRpcInterf use network::build_collator_network; use polkadot_network_bridge::{peer_sets_info, IsAuthority}; use polkadot_node_network_protocol::{ - peer_set::PeerSetProtocolNames, + peer_set::{PeerSet, PeerSetProtocolNames}, request_response::{ v1, vstaging, IncomingRequest, IncomingRequestReceiver, Protocol, ReqProtocolNames, }, @@ -176,10 +176,13 @@ async fn new_minimal_relay_chain( let peer_set_protocol_names = PeerSetProtocolNames::new(genesis_hash, config.chain_spec.fork_id()); let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No }; - - for config in peer_sets_info(is_authority, &peer_set_protocol_names) { - net_config.add_notification_protocol(config); - } + let notification_services = peer_sets_info(is_authority, &peer_set_protocol_names) + .into_iter() + .map(|(config, (peerset, service))| { + net_config.add_notification_protocol(config); + (peerset, service) + }) + .collect::>>(); let request_protocol_names = ReqProtocolNames::new(genesis_hash, config.chain_spec.fork_id()); let (collation_req_receiver_v1, collation_req_receiver_vstaging, available_data_req_receiver) = @@ -219,6 +222,7 @@ async fn new_minimal_relay_chain( collator_pair, req_protocol_names: request_protocol_names, peer_set_protocol_names, + notification_services, }; let overseer_handle = diff --git a/cumulus/client/relay-chain-minimal-node/src/network.rs b/cumulus/client/relay-chain-minimal-node/src/network.rs index f39d7a26dd88..0258cf9ddd58 100644 --- a/cumulus/client/relay-chain-minimal-node/src/network.rs +++ b/cumulus/client/relay-chain-minimal-node/src/network.rs @@ -25,10 +25,9 @@ use sc_network::{ NetworkService, }; -use sc_network::config::FullNetworkConfiguration; +use sc_network::{config::FullNetworkConfiguration, NotificationService}; use sc_network_common::{role::Roles, sync::message::BlockAnnouncesHandshake}; use sc_service::{error::Error, Configuration, NetworkStarter, SpawnTaskHandle}; -use sc_utils::mpsc::tracing_unbounded; use std::{iter, sync::Arc}; @@ -44,7 +43,7 @@ pub(crate) fn build_collator_network( Error, > { let protocol_id = config.protocol_id(); - let block_announce_config = get_block_announce_proto_config::( + let (block_announce_config, _notification_service) = get_block_announce_proto_config::( protocol_id.clone(), &None, Roles::from(&config.role), @@ -64,8 +63,6 @@ pub(crate) fn build_collator_network( let peer_store_handle = peer_store.handle(); spawn_handle.spawn("peer-store", Some("networking"), peer_store.run()); - // RX is not used for anything because syncing is not started for the minimal node - let (tx, _rx) = tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let network_params = sc_network::config::Params:: { role: config.role.clone(), executor: { @@ -81,7 +78,6 @@ pub(crate) fn build_collator_network( protocol_id, metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_announce_config, - tx, }; let network_worker = sc_network::NetworkWorker::new(network_params)?; @@ -133,7 +129,7 @@ fn get_block_announce_proto_config( best_number: NumberFor, best_hash: B::Hash, genesis_hash: B::Hash, -) -> NonDefaultSetConfig { +) -> (NonDefaultSetConfig, Box) { let block_announces_protocol = { let genesis_hash = genesis_hash.as_ref(); if let Some(ref fork_id) = fork_id { @@ -143,12 +139,11 @@ fn get_block_announce_proto_config( } }; - NonDefaultSetConfig { - notifications_protocol: block_announces_protocol.into(), - fallback_names: iter::once(format!("/{}/block-announces/1", protocol_id.as_ref()).into()) - .collect(), - max_notification_size: 1024 * 1024, - handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( + NonDefaultSetConfig::new( + block_announces_protocol.into(), + iter::once(format!("/{}/block-announces/1", protocol_id.as_ref()).into()).collect(), + 1024 * 1024, + Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( roles, best_number, best_hash, @@ -156,11 +151,11 @@ fn get_block_announce_proto_config( ))), // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement // protocol is still hardcoded into the peerset. - set_config: SetConfig { + SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), non_reserved_mode: NonReservedPeerMode::Deny, }, - } + ) } diff --git a/polkadot/node/network/bridge/src/lib.rs b/polkadot/node/network/bridge/src/lib.rs index 46d4a00faace..ddce99d5c2a8 100644 --- a/polkadot/node/network/bridge/src/lib.rs +++ b/polkadot/node/network/bridge/src/lib.rs @@ -83,6 +83,7 @@ pub(crate) enum WireMessage { ViewUpdate(View), } +#[derive(Debug)] pub(crate) struct PeerData { /// The Latest view sent by the peer. view: View, diff --git a/polkadot/node/network/bridge/src/network.rs b/polkadot/node/network/bridge/src/network.rs index 4f21212dcb64..1bdc602dfe04 100644 --- a/polkadot/node/network/bridge/src/network.rs +++ b/polkadot/node/network/bridge/src/network.rs @@ -14,21 +14,24 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::{collections::HashSet, sync::Arc}; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; use async_trait::async_trait; -use futures::{prelude::*, stream::BoxStream}; +use parking_lot::Mutex; use parity_scale_codec::Encode; use sc_network::{ - config::parse_addr, multiaddr::Multiaddr, types::ProtocolName, Event as NetworkEvent, - IfDisconnected, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkRequest, - NetworkService, OutboundFailure, ReputationChange, RequestFailure, + config::parse_addr, multiaddr::Multiaddr, types::ProtocolName, IfDisconnected, MessageSink, + NetworkPeers, NetworkRequest, NetworkService, OutboundFailure, ReputationChange, + RequestFailure, }; use polkadot_node_network_protocol::{ - peer_set::{PeerSet, PeerSetProtocolNames, ProtocolVersion}, + peer_set::{PeerSet, ProtocolVersion}, request_response::{OutgoingRequest, Recipient, ReqProtocolNames, Requests}, PeerId, }; @@ -45,51 +48,50 @@ const LOG_TARGET: &'static str = "parachain::network-bridge-net"; /// messages that are compatible with the passed peer set, as that is currently not enforced by /// this function. These are messages of type `WireMessage` parameterized on the matching type. pub(crate) fn send_message( - net: &mut impl Network, mut peers: Vec, peer_set: PeerSet, version: ProtocolVersion, - protocol_names: &PeerSetProtocolNames, message: M, metrics: &super::Metrics, + network_notification_sinks: &Arc>>>, ) where M: Encode + Clone, { if peers.is_empty() { return } + let message = { let encoded = message.encode(); metrics.on_notification_sent(peer_set, version, encoded.len(), peers.len()); encoded }; + let notification_sinks = network_notification_sinks.lock(); + // optimization: avoid cloning the message for the last peer in the // list. The message payload can be quite large. If the underlying // network used `Bytes` this would not be necessary. + // + // peer may have gotten disconnect by the time `send_message()` is called + // at which point the the sink is not available. let last_peer = peers.pop(); - - // We always send messages on the "main" name even when a negotiated - // fallback is used. The libp2p implementation handles the fallback - // under the hood. - let protocol_name = protocol_names.get_main_name(peer_set); peers.into_iter().for_each(|peer| { - net.write_notification(peer, protocol_name.clone(), message.clone()); + if let Some(sink) = notification_sinks.get(&(peer_set, peer)) { + sink.send_sync_notification(message.clone()); + } }); + if let Some(peer) = last_peer { - net.write_notification(peer, protocol_name, message); + if let Some(sink) = notification_sinks.get(&(peer_set, peer)) { + sink.send_sync_notification(message.clone()); + } } } /// An abstraction over networking for the purposes of this subsystem. #[async_trait] pub trait Network: Clone + Send + 'static { - /// Get a stream of all events occurring on the network. This may include events unrelated - /// to the Polkadot protocol - the user of this function should filter only for events related - /// to the [`VALIDATION_PROTOCOL_NAME`](VALIDATION_PROTOCOL_NAME) - /// or [`COLLATION_PROTOCOL_NAME`](COLLATION_PROTOCOL_NAME) - fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent>; - /// Ask the network to keep a substream open with these nodes and not disconnect from them /// until removed from the protocol's peer set. /// Note that `out_peers` setting has no effect on this. @@ -121,16 +123,12 @@ pub trait Network: Clone + Send + 'static { /// Disconnect a given peer from the protocol specified without harming reputation. fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName); - /// Write a notification to a peer on the given protocol. - fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec); + /// Get peer role. + fn peer_role(&self, who: PeerId, handshake: Vec) -> Option; } #[async_trait] impl Network for Arc> { - fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent> { - NetworkService::event_stream(self, "polkadot-network-bridge").boxed() - } - async fn set_reserved_peers( &mut self, protocol: ProtocolName, @@ -155,10 +153,6 @@ impl Network for Arc> { NetworkService::disconnect_peer(&**self, who, protocol); } - fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec) { - NetworkService::write_notification(&**self, who, protocol, message); - } - async fn start_request( &self, authority_discovery: &mut AD, @@ -230,6 +224,10 @@ impl Network for Arc> { if_disconnected, ); } + + fn peer_role(&self, who: PeerId, handshake: Vec) -> Option { + NetworkService::peer_role(self, who, handshake) + } } /// We assume one `peer_id` per `authority_id`. diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 51d248ca2d49..378fbd3a1a2b 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -20,10 +20,13 @@ use super::*; use always_assert::never; use bytes::Bytes; -use futures::stream::BoxStream; use parity_scale_codec::{Decode, DecodeAll}; +use parking_lot::Mutex; -use sc_network::Event as NetworkEvent; +use sc_network::{ + service::traits::{NotificationEvent, ValidationResult}, + MessageSink, NotificationService, +}; use sp_consensus::SyncOracle; use polkadot_node_network_protocol::{ @@ -85,6 +88,9 @@ pub struct NetworkBridgeRx { shared: Shared, metrics: Metrics, peerset_protocol_names: PeerSetProtocolNames, + validation_service: Box, + collation_service: Box, + notification_sinks: Arc>>>, } impl NetworkBridgeRx { @@ -99,8 +105,18 @@ impl NetworkBridgeRx { sync_oracle: Box, metrics: Metrics, peerset_protocol_names: PeerSetProtocolNames, + mut notification_services: HashMap>, + notification_sinks: Arc>>>, ) -> Self { let shared = Shared::default(); + + let validation_service = notification_services + .remove(&PeerSet::Validation) + .expect("validation protocol was enabled so `NotificationService` must exist; qed"); + let collation_service = notification_services + .remove(&PeerSet::Collation) + .expect("collation protocol was enabled so `NotificationService` must exist; qed"); + Self { network_service, authority_discovery_service, @@ -108,6 +124,9 @@ impl NetworkBridgeRx { shared, metrics, peerset_protocol_names, + validation_service, + collation_service, + notification_sinks, } } } @@ -118,423 +137,542 @@ where Net: Network + Sync, AD: validator_discovery::AuthorityDiscovery + Clone + Sync, { - fn start(mut self, ctx: Context) -> SpawnedSubsystem { - // The stream of networking events has to be created at initialization, otherwise the - // networking might open connections before the stream of events has been grabbed. - let network_stream = self.network_service.event_stream(); - + fn start(self, ctx: Context) -> SpawnedSubsystem { // Swallow error because failure is fatal to the node and we log with more precision // within `run_network`. - let future = run_network_in(self, ctx, network_stream) + let future = run_network_in(self, ctx) .map_err(|e| SubsystemError::with_origin("network-bridge", e)) .boxed(); SpawnedSubsystem { name: "network-bridge-rx-subsystem", future } } } -async fn handle_network_messages( - mut sender: impl overseer::NetworkBridgeRxSenderTrait, - mut network_service: impl Network, - network_stream: BoxStream<'static, NetworkEvent>, - mut authority_discovery_service: AD, - metrics: Metrics, - shared: Shared, - peerset_protocol_names: PeerSetProtocolNames, -) -> Result<(), Error> -where +/// Handle notification event received over the validation protocol. +async fn handle_validation_message( + event: NotificationEvent, + network_service: &mut impl Network, + sender: &mut impl overseer::NetworkBridgeRxSenderTrait, + authority_discovery_service: &mut AD, + metrics: &Metrics, + shared: &Shared, + peerset_protocol_names: &PeerSetProtocolNames, + notification_service: &mut Box, + notification_sinks: &mut Arc>>>, +) where AD: validator_discovery::AuthorityDiscovery + Send, { - let mut network_stream = network_stream.fuse(); - loop { - match network_stream.next().await { - None => return Err(Error::EventStreamConcluded), - Some(NetworkEvent::Dht(_)) => {}, - Some(NetworkEvent::NotificationStreamOpened { - remote: peer, - protocol, - role, - negotiated_fallback, - received_handshake: _, - }) => { - let role = ObservedRole::from(role); - let (peer_set, version) = { - let (peer_set, version) = - match peerset_protocol_names.try_get_protocol(&protocol) { - None => continue, - Some(p) => p, - }; - - if let Some(fallback) = negotiated_fallback { - match peerset_protocol_names.try_get_protocol(&fallback) { - None => { + match event { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + let _ = result_tx.send(ValidationResult::Accept); + }, + NotificationEvent::NotificationStreamOpened { + peer, + handshake, + negotiated_fallback, + .. + } => { + let role = match network_service.peer_role(peer, handshake) { + Some(role) => ObservedRole::from(role), + None => { + gum::debug!( + target: LOG_TARGET, + ?peer, + "Failed to determine peer role for validation protocol", + ); + return + }, + }; + + let (peer_set, version) = { + let (peer_set, version) = + (PeerSet::Validation, PeerSet::Validation.get_main_version()); + + if let Some(fallback) = negotiated_fallback { + match peerset_protocol_names.try_get_protocol(&fallback) { + None => { + gum::debug!( + target: LOG_TARGET, + fallback = &*fallback, + ?peer, + ?peer_set, + "Unknown fallback", + ); + + return + }, + Some((p2, v2)) => { + if p2 != peer_set { gum::debug!( target: LOG_TARGET, fallback = &*fallback, - ?peer, - ?peer_set, - "Unknown fallback", + fallback_peerset = ?p2, + peerset = ?peer_set, + "Fallback mismatched peer-set", ); - continue - }, - Some((p2, v2)) => { - if p2 != peer_set { - gum::debug!( - target: LOG_TARGET, - fallback = &*fallback, - fallback_peerset = ?p2, - protocol = &*protocol, - peerset = ?peer_set, - "Fallback mismatched peer-set", - ); - - continue - } - - (p2, v2) - }, - } - } else { - (peer_set, version) - } - }; - - gum::debug!( - target: LOG_TARGET, - action = "PeerConnected", - peer_set = ?peer_set, - version = %version, - peer = ?peer, - role = ?role - ); - - let local_view = { - let mut shared = shared.0.lock(); - let peer_map = match peer_set { - PeerSet::Validation => &mut shared.validation_peers, - PeerSet::Collation => &mut shared.collation_peers, - }; + return + } - match peer_map.entry(peer) { - hash_map::Entry::Occupied(_) => continue, - hash_map::Entry::Vacant(vacant) => { - vacant.insert(PeerData { view: View::default(), version }); + (p2, v2) }, } - - metrics.on_peer_connected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); - - shared.local_view.clone().unwrap_or(View::default()) - }; - - let maybe_authority = - authority_discovery_service.get_authority_ids_by_peer_id(peer).await; - - match peer_set { - PeerSet::Validation => { - dispatch_validation_events_to_all( - vec![ - NetworkBridgeEvent::PeerConnected( - peer, - role, - version, - maybe_authority, - ), - NetworkBridgeEvent::PeerViewChange(peer, View::default()), - ], - &mut sender, - ) - .await; - - match ValidationVersion::try_from(version) - .expect("try_get_protocol has already checked version is known; qed") - { - ValidationVersion::V1 => send_message( - &mut network_service, - vec![peer], - PeerSet::Validation, - version, - &peerset_protocol_names, - WireMessage::::ViewUpdate( - local_view, - ), - &metrics, - ), - ValidationVersion::VStaging => send_message( - &mut network_service, - vec![peer], - PeerSet::Validation, - version, - &peerset_protocol_names, - WireMessage::::ViewUpdate( - local_view, - ), - &metrics, - ), - } - }, - PeerSet::Collation => { - dispatch_collation_events_to_all( - vec![ - NetworkBridgeEvent::PeerConnected( - peer, - role, - version, - maybe_authority, - ), - NetworkBridgeEvent::PeerViewChange(peer, View::default()), - ], - &mut sender, - ) - .await; - - match CollationVersion::try_from(version) - .expect("try_get_protocol has already checked version is known; qed") - { - CollationVersion::V1 => send_message( - &mut network_service, - vec![peer], - PeerSet::Collation, - version, - &peerset_protocol_names, - WireMessage::::ViewUpdate( - local_view, - ), - &metrics, - ), - CollationVersion::VStaging => send_message( - &mut network_service, - vec![peer], - PeerSet::Collation, - version, - &peerset_protocol_names, - WireMessage::::ViewUpdate( - local_view, - ), - &metrics, - ), - } + } else { + (peer_set, version) + } + }; + // store the notification sink to `notification_sinks` so both `NetworkBridgeRx` + // and `NetworkBridgeTx` can send messages to the peer. + match notification_service.message_sink(&peer) { + Some(sink) => { + notification_sinks.lock().insert((peer_set, peer), sink); + }, + None => { + gum::warn!( + target: LOG_TARGET, + peer_set = ?peer_set, + version = %version, + peer = ?peer, + role = ?role, + "Message sink not available for peer", + ); + return + }, + } + + gum::debug!( + target: LOG_TARGET, + action = "PeerConnected", + peer_set = ?peer_set, + version = %version, + peer = ?peer, + role = ?role + ); + + let local_view = { + let mut shared = shared.0.lock(); + let peer_map = &mut shared.validation_peers; + + match peer_map.entry(peer) { + hash_map::Entry::Occupied(_) => return, + hash_map::Entry::Vacant(vacant) => { + vacant.insert(PeerData { view: View::default(), version }); }, } - }, - Some(NetworkEvent::NotificationStreamClosed { remote: peer, protocol }) => { - let (peer_set, version) = match peerset_protocol_names.try_get_protocol(&protocol) { - None => continue, - Some(peer_set) => peer_set, - }; - gum::debug!( - target: LOG_TARGET, - action = "PeerDisconnected", - peer_set = ?peer_set, - peer = ?peer - ); - - let was_connected = { - let mut shared = shared.0.lock(); - let peer_map = match peer_set { - PeerSet::Validation => &mut shared.validation_peers, - PeerSet::Collation => &mut shared.collation_peers, - }; + metrics.on_peer_connected(peer_set, version); + metrics.note_peer_count(peer_set, version, peer_map.len()); - let w = peer_map.remove(&peer).is_some(); + shared.local_view.clone().unwrap_or(View::default()) + }; - metrics.on_peer_disconnected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); + let maybe_authority = + authority_discovery_service.get_authority_ids_by_peer_id(peer).await; - w - }; + dispatch_validation_events_to_all( + vec![ + NetworkBridgeEvent::PeerConnected(peer, role, version, maybe_authority), + NetworkBridgeEvent::PeerViewChange(peer, View::default()), + ], + sender, + ) + .await; - if was_connected && version == peer_set.get_main_version() { - match peer_set { - PeerSet::Validation => - dispatch_validation_event_to_all( - NetworkBridgeEvent::PeerDisconnected(peer), - &mut sender, - ) - .await, - PeerSet::Collation => - dispatch_collation_event_to_all( - NetworkBridgeEvent::PeerDisconnected(peer), - &mut sender, - ) - .await, - } + match ValidationVersion::try_from(version) + .expect("try_get_protocol has already checked version is known; qed") + { + ValidationVersion::V1 => send_message( + vec![peer], + PeerSet::Validation, + version, + WireMessage::::ViewUpdate(local_view), + metrics, + notification_sinks, + ), + ValidationVersion::VStaging => send_message( + vec![peer], + PeerSet::Validation, + version, + WireMessage::::ViewUpdate(local_view), + metrics, + notification_sinks, + ), + } + }, + NotificationEvent::NotificationStreamClosed { peer } => { + let (peer_set, version) = (PeerSet::Validation, PeerSet::Validation.get_main_version()); + + gum::debug!( + target: LOG_TARGET, + action = "PeerDisconnected", + ?peer_set, + ?peer + ); + + let was_connected = { + let mut shared = shared.0.lock(); + let peer_map = &mut shared.validation_peers; + + let w = peer_map.remove(&peer).is_some(); + + metrics.on_peer_disconnected(peer_set, version); + metrics.note_peer_count(peer_set, version, peer_map.len()); + + w + }; + + if was_connected && version == peer_set.get_main_version() { + dispatch_validation_event_to_all( + NetworkBridgeEvent::PeerDisconnected(peer), + sender, + ) + .await; + } + }, + NotificationEvent::NotificationReceived { peer, notification } => { + let expected_versions = { + let mut versions = PerPeerSet::>::default(); + let shared = shared.0.lock(); + + if let Some(peer_data) = shared.validation_peers.get(&peer) { + versions[PeerSet::Validation] = Some(peer_data.version); } - }, - Some(NetworkEvent::NotificationsReceived { remote, messages }) => { - let expected_versions = { - let mut versions = PerPeerSet::>::default(); - let shared = shared.0.lock(); - if let Some(peer_data) = shared.validation_peers.get(&remote) { - versions[PeerSet::Validation] = Some(peer_data.version); - } - if let Some(peer_data) = shared.collation_peers.get(&remote) { - versions[PeerSet::Collation] = Some(peer_data.version); - } + versions + }; + + gum::trace!( + target: LOG_TARGET, + action = "PeerMessage", + peerset = ?PeerSet::Validation, + ?peer, + ); + + let (events, reports) = + if expected_versions[PeerSet::Validation] == Some(ValidationVersion::V1.into()) { + handle_peer_messages::( + peer, + PeerSet::Validation, + &mut shared.0.lock().validation_peers, + vec![notification.into()], + metrics, + ) + } else if expected_versions[PeerSet::Validation] == + Some(ValidationVersion::VStaging.into()) + { + handle_peer_messages::( + peer, + PeerSet::Validation, + &mut shared.0.lock().validation_peers, + vec![notification.into()], + metrics, + ) + } else { + gum::warn!( + target: LOG_TARGET, + version = ?expected_versions[PeerSet::Validation], + "Major logic bug. Peer somehow has unsupported validation protocol version." + ); - versions - }; + never!("Only versions 1 and 2 are supported; peer set connection checked above; qed"); - // non-decoded, but version-checked validation messages. - let v_messages: Result, _> = messages - .iter() - .filter_map(|(protocol, msg_bytes)| { - // version doesn't matter because we always receive on the 'correct' - // protocol name, not the negotiated fallback. - let (peer_set, _version) = - peerset_protocol_names.try_get_protocol(protocol)?; - if peer_set == PeerSet::Validation { - if expected_versions[PeerSet::Validation].is_none() { - return Some(Err(UNCONNECTED_PEERSET_COST)) - } + // If a peer somehow triggers this, we'll disconnect them + // eventually. + (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) + }; - Some(Ok(msg_bytes.clone())) - } else { - None - } - }) - .collect(); + for report in reports { + network_service.report_peer(peer, report.into()); + } - let v_messages = match v_messages { - Err(rep) => { - gum::debug!(target: LOG_TARGET, action = "ReportPeer"); - network_service.report_peer(remote, rep.into()); + dispatch_validation_events_to_all(events, sender).await; + }, + } +} - continue - }, - Ok(v) => v, - }; +/// Handle notification event received over the collation protocol. +async fn handle_collation_message( + event: NotificationEvent, + network_service: &mut impl Network, + sender: &mut impl overseer::NetworkBridgeRxSenderTrait, + authority_discovery_service: &mut AD, + metrics: &Metrics, + shared: &Shared, + peerset_protocol_names: &PeerSetProtocolNames, + notification_service: &mut Box, + notification_sinks: &mut Arc>>>, +) where + AD: validator_discovery::AuthorityDiscovery + Send, +{ + match event { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + let _ = result_tx.send(ValidationResult::Accept); + }, + NotificationEvent::NotificationStreamOpened { + peer, + handshake, + negotiated_fallback, + .. + } => { + let role = match network_service.peer_role(peer, handshake) { + Some(role) => ObservedRole::from(role), + None => { + gum::debug!( + target: LOG_TARGET, + ?peer, + "Failed to determine peer role for validation protocol", + ); + return + }, + }; + + let (peer_set, version) = { + let (peer_set, version) = + (PeerSet::Collation, PeerSet::Collation.get_main_version()); + + if let Some(fallback) = negotiated_fallback { + match peerset_protocol_names.try_get_protocol(&fallback) { + None => { + gum::debug!( + target: LOG_TARGET, + fallback = &*fallback, + ?peer, + ?peer_set, + "Unknown fallback", + ); + + return + }, + Some((p2, v2)) => { + if p2 != peer_set { + gum::debug!( + target: LOG_TARGET, + fallback = &*fallback, + fallback_peerset = ?p2, + peerset = ?peer_set, + "Fallback mismatched peer-set", + ); - // non-decoded, but version-checked collation messages. - let c_messages: Result, _> = messages - .iter() - .filter_map(|(protocol, msg_bytes)| { - // version doesn't matter because we always receive on the 'correct' - // protocol name, not the negotiated fallback. - let (peer_set, _version) = - peerset_protocol_names.try_get_protocol(protocol)?; - - if peer_set == PeerSet::Collation { - if expected_versions[PeerSet::Collation].is_none() { - return Some(Err(UNCONNECTED_PEERSET_COST)) + return } - Some(Ok(msg_bytes.clone())) - } else { - None - } - }) - .collect(); - - let c_messages = match c_messages { - Err(rep) => { - gum::debug!(target: LOG_TARGET, action = "ReportPeer"); - network_service.report_peer(remote, rep.into()); - - continue + (p2, v2) + }, + } + } else { + (peer_set, version) + } + }; + + // store the notification sink to `notification_sinks` so both `NetworkBridgeRx` + // and `NetworkBridgeTx` can send messages to the peer. + match notification_service.message_sink(&peer) { + Some(sink) => { + notification_sinks.lock().insert((peer_set, peer), sink); + }, + None => { + gum::warn!( + target: LOG_TARGET, + peer_set = ?peer_set, + version = %version, + peer = ?peer, + role = ?role, + "Message sink not available for peer", + ); + return + }, + } + + gum::debug!( + target: LOG_TARGET, + action = "PeerConnected", + peer_set = ?peer_set, + version = %version, + peer = ?peer, + role = ?role + ); + + let local_view = { + let mut shared = shared.0.lock(); + let peer_map = &mut shared.collation_peers; + + match peer_map.entry(peer) { + hash_map::Entry::Occupied(_) => return, + hash_map::Entry::Vacant(vacant) => { + vacant.insert(PeerData { view: View::default(), version }); }, - Ok(v) => v, - }; - - if v_messages.is_empty() && c_messages.is_empty() { - continue } - gum::trace!( - target: LOG_TARGET, - action = "PeerMessages", - peer = ?remote, - num_validation_messages = %v_messages.len(), - num_collation_messages = %c_messages.len() - ); - - if !v_messages.is_empty() { - let (events, reports) = if expected_versions[PeerSet::Validation] == - Some(ValidationVersion::V1.into()) - { - handle_peer_messages::( - remote, - PeerSet::Validation, - &mut shared.0.lock().validation_peers, - v_messages, - &metrics, - ) - } else if expected_versions[PeerSet::Validation] == - Some(ValidationVersion::VStaging.into()) - { - handle_peer_messages::( - remote, - PeerSet::Validation, - &mut shared.0.lock().validation_peers, - v_messages, - &metrics, - ) - } else { - gum::warn!( - target: LOG_TARGET, - version = ?expected_versions[PeerSet::Validation], - "Major logic bug. Peer somehow has unsupported validation protocol version." - ); + metrics.on_peer_connected(peer_set, version); + metrics.note_peer_count(peer_set, version, peer_map.len()); - never!("Only versions 1 and 2 are supported; peer set connection checked above; qed"); + shared.local_view.clone().unwrap_or(View::default()) + }; - // If a peer somehow triggers this, we'll disconnect them - // eventually. - (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) - }; + let maybe_authority = + authority_discovery_service.get_authority_ids_by_peer_id(peer).await; - for report in reports { - network_service.report_peer(remote, report.into()); - } + dispatch_collation_events_to_all( + vec![ + NetworkBridgeEvent::PeerConnected(peer, role, version, maybe_authority), + NetworkBridgeEvent::PeerViewChange(peer, View::default()), + ], + sender, + ) + .await; - dispatch_validation_events_to_all(events, &mut sender).await; + match CollationVersion::try_from(version) + .expect("try_get_protocol has already checked version is known; qed") + { + CollationVersion::V1 => send_message( + vec![peer], + PeerSet::Collation, + version, + WireMessage::::ViewUpdate(local_view), + metrics, + notification_sinks, + ), + CollationVersion::VStaging => send_message( + vec![peer], + PeerSet::Collation, + version, + WireMessage::::ViewUpdate(local_view), + metrics, + notification_sinks, + ), + } + }, + NotificationEvent::NotificationStreamClosed { peer } => { + let (peer_set, version) = (PeerSet::Collation, PeerSet::Collation.get_main_version()); + + gum::debug!( + target: LOG_TARGET, + action = "PeerDisconnected", + ?peer_set, + ?peer + ); + + let was_connected = { + let mut shared = shared.0.lock(); + let peer_map = &mut shared.collation_peers; + + let w = peer_map.remove(&peer).is_some(); + + metrics.on_peer_disconnected(peer_set, version); + metrics.note_peer_count(peer_set, version, peer_map.len()); + + w + }; + + if was_connected && version == peer_set.get_main_version() { + dispatch_collation_event_to_all(NetworkBridgeEvent::PeerDisconnected(peer), sender) + .await; + } + }, + NotificationEvent::NotificationReceived { peer, notification } => { + let expected_versions = { + let mut versions = PerPeerSet::>::default(); + let shared = shared.0.lock(); + + if let Some(peer_data) = shared.collation_peers.get(&peer) { + versions[PeerSet::Collation] = Some(peer_data.version); } - if !c_messages.is_empty() { - let (events, reports) = if expected_versions[PeerSet::Collation] == - Some(CollationVersion::V1.into()) - { - handle_peer_messages::( - remote, - PeerSet::Collation, - &mut shared.0.lock().collation_peers, - c_messages, - &metrics, - ) - } else if expected_versions[PeerSet::Collation] == - Some(CollationVersion::VStaging.into()) - { - handle_peer_messages::( - remote, - PeerSet::Collation, - &mut shared.0.lock().collation_peers, - c_messages, - &metrics, - ) - } else { - gum::warn!( - target: LOG_TARGET, - version = ?expected_versions[PeerSet::Collation], - "Major logic bug. Peer somehow has unsupported collation protocol version." - ); + versions + }; + + gum::trace!( + target: LOG_TARGET, + action = "PeerMessage", + peerset = ?PeerSet::Collation, + ?peer, + ); + + let (events, reports) = + if expected_versions[PeerSet::Collation] == Some(CollationVersion::V1.into()) { + handle_peer_messages::( + peer, + PeerSet::Collation, + &mut shared.0.lock().collation_peers, + vec![notification.into()], + metrics, + ) + } else if expected_versions[PeerSet::Collation] == + Some(CollationVersion::VStaging.into()) + { + handle_peer_messages::( + peer, + PeerSet::Collation, + &mut shared.0.lock().collation_peers, + vec![notification.into()], + metrics, + ) + } else { + gum::warn!( + target: LOG_TARGET, + version = ?expected_versions[PeerSet::Collation], + "Major logic bug. Peer somehow has unsupported collation protocol version." + ); - never!("Only versions 1 and 2 are supported; peer set connection checked above; qed"); + never!("Only versions 1 and 2 are supported; peer set connection checked above; qed"); - // If a peer somehow triggers this, we'll disconnect them - // eventually. - (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) - }; + // If a peer somehow triggers this, we'll disconnect them + // eventually. + (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) + }; - for report in reports { - network_service.report_peer(remote, report.into()); - } + for report in reports { + network_service.report_peer(peer, report.into()); + } - dispatch_collation_events_to_all(events, &mut sender).await; - } + dispatch_collation_events_to_all(events, sender).await; + }, + } +} + +async fn handle_network_messages( + mut sender: impl overseer::NetworkBridgeRxSenderTrait, + mut network_service: impl Network, + mut authority_discovery_service: AD, + metrics: Metrics, + shared: Shared, + peerset_protocol_names: PeerSetProtocolNames, + mut validation_service: Box, + mut collation_service: Box, + mut notification_sinks: Arc>>>, +) -> Result<(), Error> +where + AD: validator_discovery::AuthorityDiscovery + Send, +{ + loop { + futures::select! { + event = validation_service.next_event().fuse() => match event { + Some(event) => handle_validation_message( + event, + &mut network_service, + &mut sender, + &mut authority_discovery_service, + &metrics, + &shared, + &peerset_protocol_names, + &mut validation_service, + &mut notification_sinks, + ).await, + None => return Err(Error::EventStreamConcluded), }, + event = collation_service.next_event().fuse() => match event { + Some(event) => handle_collation_message( + event, + &mut network_service, + &mut sender, + &mut authority_discovery_service, + &metrics, + &shared, + &peerset_protocol_names, + &mut collation_service, + &mut notification_sinks, + ).await, + None => return Err(Error::EventStreamConcluded), + } } } } @@ -560,17 +698,15 @@ where } #[overseer::contextbounds(NetworkBridgeRx, prefix = self::overseer)] -async fn run_incoming_orchestra_signals( +async fn run_incoming_orchestra_signals( mut ctx: Context, - mut network_service: N, mut authority_discovery_service: AD, shared: Shared, sync_oracle: Box, metrics: Metrics, - peerset_protocol_names: PeerSetProtocolNames, + notification_sinks: Arc>>>, ) -> Result<(), Error> where - N: Network, AD: validator_discovery::AuthorityDiscovery + Clone, { // This is kept sorted, descending, by block number. @@ -662,13 +798,12 @@ where mode = Mode::Active; update_our_view( - &mut network_service, &mut ctx, &live_heads, &shared, finalized_number, &metrics, - &peerset_protocol_names, + ¬ification_sinks, ); } } @@ -702,7 +837,6 @@ where async fn run_network_in( bridge: NetworkBridgeRx, mut ctx: Context, - network_stream: BoxStream<'static, NetworkEvent>, ) -> Result<(), Error> where N: Network, @@ -715,16 +849,21 @@ where sync_oracle, shared, peerset_protocol_names, + validation_service, + collation_service, + notification_sinks, } = bridge; let (task, network_event_handler) = handle_network_messages( ctx.sender().clone(), network_service.clone(), - network_stream, authority_discovery_service.clone(), metrics.clone(), shared.clone(), peerset_protocol_names.clone(), + validation_service, + collation_service, + notification_sinks.clone(), ) .remote_handle(); @@ -733,12 +872,11 @@ where let orchestra_signal_handler = run_incoming_orchestra_signals( ctx, - network_service, authority_discovery_service, shared, sync_oracle, metrics, - peerset_protocol_names, + notification_sinks, ); futures::pin_mut!(orchestra_signal_handler); @@ -758,17 +896,14 @@ fn construct_view( } #[overseer::contextbounds(NetworkBridgeRx, prefix = self::overseer)] -fn update_our_view( - net: &mut Net, +fn update_our_view( ctx: &mut Context, live_heads: &[ActivatedLeaf], shared: &Shared, finalized_number: BlockNumber, metrics: &Metrics, - peerset_protocol_names: &PeerSetProtocolNames, -) where - Net: Network, -{ + notification_sinks: &Arc>>>, +) { let new_view = construct_view(live_heads.iter().map(|v| v.hash), finalized_number); let (validation_peers, collation_peers) = { @@ -817,35 +952,31 @@ fn update_our_view( filter_by_version(&collation_peers, ValidationVersion::VStaging.into()); send_validation_message_v1( - net, v1_validation_peers, - peerset_protocol_names, WireMessage::ViewUpdate(new_view.clone()), metrics, + notification_sinks, ); send_collation_message_v1( - net, v1_collation_peers, - peerset_protocol_names, WireMessage::ViewUpdate(new_view.clone()), metrics, + notification_sinks, ); send_validation_message_vstaging( - net, vstaging_validation_peers, - peerset_protocol_names, WireMessage::ViewUpdate(new_view.clone()), metrics, + notification_sinks, ); send_collation_message_vstaging( - net, vstaging_collation_peers, - peerset_protocol_names, WireMessage::ViewUpdate(new_view), metrics, + notification_sinks, ); let our_view = OurView::new( @@ -918,74 +1049,66 @@ fn handle_peer_messages>( } fn send_validation_message_v1( - net: &mut impl Network, peers: Vec, - peerset_protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Validation, ValidationVersion::V1.into(), - peerset_protocol_names, message, metrics, + notification_sinks, ); } fn send_collation_message_v1( - net: &mut impl Network, peers: Vec, - peerset_protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Collation, CollationVersion::V1.into(), - peerset_protocol_names, message, metrics, + notification_sinks, ); } fn send_validation_message_vstaging( - net: &mut impl Network, peers: Vec, - protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Validation, ValidationVersion::VStaging.into(), - protocol_names, message, metrics, + notification_sinks, ); } fn send_collation_message_vstaging( - net: &mut impl Network, peers: Vec, - protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Collation, CollationVersion::VStaging.into(), - protocol_names, message, metrics, + notification_sinks, ); } diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 88a4b247fdc6..3161801aa2c2 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use super::*; -use futures::{channel::oneshot, executor, stream::BoxStream}; +use futures::{channel::oneshot, executor}; use polkadot_node_network_protocol::{self as net_protocol, OurView}; use polkadot_node_subsystem::{messages::NetworkBridgeEvent, ActivatedLeaf}; @@ -28,7 +28,11 @@ use std::{ task::Poll, }; -use sc_network::{Event as NetworkEvent, IfDisconnected, ProtocolName, ReputationChange}; +use sc_network::{ + service::traits::{Direction, MessageSink, NotificationService}, + IfDisconnected, Multiaddr, ObservedRole as SubstrateObservedRole, ProtocolName, + ReputationChange, Roles, +}; use polkadot_node_network_protocol::{ peer_set::PeerSetProtocolNames, @@ -49,7 +53,6 @@ use polkadot_node_subsystem_test_helpers::{ use polkadot_node_subsystem_util::metered; use polkadot_primitives::{AuthorityDiscoveryId, CandidateHash, Hash}; -use sc_network::Multiaddr; use sp_keyring::Sr25519Keyring; use crate::{network::Network, validator_discovery::AuthorityDiscovery}; @@ -64,10 +67,9 @@ pub enum NetworkAction { WriteNotification(PeerId, PeerSet, Vec), } -// The subsystem's view of the network - only supports a single call to `event_stream`. +// The subsystem's view of the network. #[derive(Clone)] struct TestNetwork { - net_events: Arc>>>, action_tx: Arc>>, protocol_names: Arc, } @@ -79,37 +81,42 @@ struct TestAuthorityDiscovery; // of `NetworkAction`s. struct TestNetworkHandle { action_rx: metered::UnboundedMeteredReceiver, - net_tx: SingleItemSink, - protocol_names: PeerSetProtocolNames, + validation_tx: SingleItemSink, + collation_tx: SingleItemSink, } fn new_test_network( protocol_names: PeerSetProtocolNames, -) -> (TestNetwork, TestNetworkHandle, TestAuthorityDiscovery) { - let (net_tx, net_rx) = polkadot_node_subsystem_test_helpers::single_item_sink(); +) -> ( + TestNetwork, + TestNetworkHandle, + TestAuthorityDiscovery, + Box, + Box, +) { let (action_tx, action_rx) = metered::unbounded(); + let (validation_tx, validation_rx) = polkadot_node_subsystem_test_helpers::single_item_sink(); + let (collation_tx, collation_rx) = polkadot_node_subsystem_test_helpers::single_item_sink(); + let action_tx = Arc::new(Mutex::new(action_tx)); ( TestNetwork { - net_events: Arc::new(Mutex::new(Some(net_rx))), - action_tx: Arc::new(Mutex::new(action_tx)), + action_tx: action_tx.clone(), protocol_names: Arc::new(protocol_names.clone()), }, - TestNetworkHandle { action_rx, net_tx, protocol_names }, + TestNetworkHandle { action_rx, validation_tx, collation_tx }, TestAuthorityDiscovery, + Box::new(TestNotificationService::new( + PeerSet::Validation, + action_tx.clone(), + validation_rx, + )), + Box::new(TestNotificationService::new(PeerSet::Collation, action_tx, collation_rx)), ) } #[async_trait] impl Network for TestNetwork { - fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent> { - self.net_events - .lock() - .take() - .expect("Subsystem made more than one call to `event_stream`") - .boxed() - } - async fn set_reserved_peers( &mut self, _protocol: ProtocolName, @@ -143,7 +150,8 @@ impl Network for TestNetwork { } fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { - let (peer_set, _) = self.protocol_names.try_get_protocol(&protocol).unwrap(); + let (peer_set, version) = self.protocol_names.try_get_protocol(&protocol).unwrap(); + assert_eq!(version, peer_set.get_main_version()); self.action_tx .lock() @@ -151,13 +159,10 @@ impl Network for TestNetwork { .unwrap(); } - fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec) { - let (peer_set, _) = self.protocol_names.try_get_protocol(&protocol).unwrap(); - - self.action_tx - .lock() - .unbounded_send(NetworkAction::WriteNotification(who, peer_set, message)) - .unwrap(); + fn peer_role(&self, _peer_id: PeerId, handshake: Vec) -> Option { + Roles::decode_all(&mut &handshake[..]) + .ok() + .and_then(|role| Some(SubstrateObservedRole::from(role))) } } @@ -194,42 +199,93 @@ impl TestNetworkHandle { v } + // async fn connect_peer( + // &mut self, + // peer: PeerId, + // protocol_version: ValidationVersion, + // peer_set: PeerSet, + // role: ObservedRole, + // ) { + // // let protocol_version = ProtocolVersion::from(protocol_version); + // // self.send_network_event(NetworkEvent::NotificationStreamOpened { + // // remote: peer, + // // protocol: self.protocol_names.get_name(peer_set, protocol_version), + // // negotiated_fallback: None, + // // role: role.into(), + // // received_handshake: vec![], + // // }) + // // .await; + // } + async fn connect_peer( &mut self, peer: PeerId, - protocol_version: ValidationVersion, + _protocol_version: ValidationVersion, peer_set: PeerSet, role: ObservedRole, ) { - let protocol_version = ProtocolVersion::from(protocol_version); - self.send_network_event(NetworkEvent::NotificationStreamOpened { - remote: peer, - protocol: self.protocol_names.get_name(peer_set, protocol_version), - negotiated_fallback: None, - role: role.into(), - received_handshake: vec![], - }) - .await; + fn observed_role_to_handshake(role: &ObservedRole) -> Vec { + match role { + &ObservedRole::Light => Roles::LIGHT.encode(), + &ObservedRole::Authority => Roles::AUTHORITY.encode(), + &ObservedRole::Full => Roles::FULL.encode(), + } + } + + match peer_set { + PeerSet::Validation => { + self.validation_tx + .send(NotificationEvent::NotificationStreamOpened { + peer, + direction: Direction::Inbound, + handshake: observed_role_to_handshake(&role), + negotiated_fallback: None, + }) + .await + .expect("subsystem concluded early"); + }, + PeerSet::Collation => { + self.collation_tx + .send(NotificationEvent::NotificationStreamOpened { + peer, + direction: Direction::Inbound, + handshake: observed_role_to_handshake(&role), + negotiated_fallback: None, + }) + .await + .expect("subsystem concluded early"); + }, + } } async fn disconnect_peer(&mut self, peer: PeerId, peer_set: PeerSet) { - self.send_network_event(NetworkEvent::NotificationStreamClosed { - remote: peer, - protocol: self.protocol_names.get_main_name(peer_set), - }) - .await; + match peer_set { + PeerSet::Validation => self + .validation_tx + .send(NotificationEvent::NotificationStreamClosed { peer }) + .await + .expect("subsystem concluded early"), + PeerSet::Collation => self + .collation_tx + .send(NotificationEvent::NotificationStreamClosed { peer }) + .await + .expect("subsystem concluded early"), + } } async fn peer_message(&mut self, peer: PeerId, peer_set: PeerSet, message: Vec) { - self.send_network_event(NetworkEvent::NotificationsReceived { - remote: peer, - messages: vec![(self.protocol_names.get_main_name(peer_set), message.into())], - }) - .await; - } - - async fn send_network_event(&mut self, event: NetworkEvent) { - self.net_tx.send(event).await.expect("subsystem concluded early"); + match peer_set { + PeerSet::Validation => self + .validation_tx + .send(NotificationEvent::NotificationReceived { peer, notification: message }) + .await + .expect("subsystem concluded early"), + PeerSet::Collation => self + .collation_tx + .send(NotificationEvent::NotificationReceived { peer, notification: message }) + .await + .expect("subsystem concluded early"), + } } } @@ -240,6 +296,119 @@ fn assert_network_actions_contains(actions: &[NetworkAction], action: &NetworkAc } } +struct TestNotificationService { + peer_set: PeerSet, + action_tx: Arc>>, + rx: SingleItemStream, +} + +impl std::fmt::Debug for TestNotificationService { + fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Ok(()) + } +} + +impl TestNotificationService { + pub fn new( + peer_set: PeerSet, + action_tx: Arc>>, + rx: SingleItemStream, + ) -> Self { + Self { peer_set, action_tx, rx } + } +} + +struct TestMessageSink { + peer: PeerId, + peer_set: PeerSet, + action_tx: Arc>>, +} + +impl TestMessageSink { + fn new( + peer: PeerId, + peer_set: PeerSet, + action_tx: Arc>>, + ) -> TestMessageSink { + Self { peer, peer_set, action_tx } + } +} + +#[async_trait::async_trait] +impl MessageSink for TestMessageSink { + fn send_sync_notification(&self, notification: Vec) { + self.action_tx + .lock() + .unbounded_send(NetworkAction::WriteNotification( + self.peer, + self.peer_set, + notification, + )) + .unwrap(); + } + + async fn send_async_notification( + &self, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } +} + +// TODO: how to implement this? +#[async_trait::async_trait] +impl NotificationService for TestNotificationService { + /// Instruct `Notifications` to open a new substream for `peer`. + async fn open_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Instruct `Notifications` to close substream for `peer`. + async fn close_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Send synchronous `notification` to `peer`. + fn send_sync_notification(&self, _peer: &PeerId, _notification: Vec) { + unimplemented!(); + } + + /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure. + async fn send_async_notification( + &self, + _peer: &PeerId, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } + + /// Set handshake for the notification protocol replacing the old handshake. + async fn set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + /// Get next event from the `Notifications` event stream. + async fn next_event(&mut self) -> Option { + self.rx.next().await + } + + // Clone [`NotificationService`] + fn clone(&mut self) -> Result, ()> { + unimplemented!(); + } + + /// Get protocol name. + fn protocol(&self) -> &ProtocolName { + unimplemented!(); + } + + /// Get notification sink of the peer. + fn message_sink(&self, peer: &PeerId) -> Option> { + // TODO: verify that peer exists? + Some(Box::new(TestMessageSink::new(*peer, self.peer_set, self.action_tx.clone()))) + } +} + #[derive(Clone)] struct TestSyncOracle { is_major_syncing: Arc, @@ -334,11 +503,14 @@ fn test_harness>( let fork_id = None; let peerset_protocol_names = PeerSetProtocolNames::new(genesis_hash, fork_id); + println!("protocol names: {peerset_protocol_names:#?}"); + let pool = sp_core::testing::TaskExecutor::new(); - let (mut network, network_handle, discovery) = new_test_network(peerset_protocol_names.clone()); + let (network, network_handle, discovery, validation_service, collation_service) = + new_test_network(peerset_protocol_names.clone()); let (context, virtual_overseer) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool); - let network_stream = network.event_stream(); + let notification_sinks = Arc::new(Mutex::new(HashMap::new())); let shared = Shared::default(); let bridge = NetworkBridgeRx { @@ -348,9 +520,12 @@ fn test_harness>( sync_oracle, shared: shared.clone(), peerset_protocol_names, + validation_service, + collation_service, + notification_sinks, }; - let network_bridge = run_network_in(bridge, context, network_stream) + let network_bridge = run_network_in(bridge, context) .map_err(|_| panic!("subsystem execution failed")) .map(|_| ()); @@ -972,8 +1147,6 @@ fn relays_collation_protocol_messages() { .await; } - // peer A gets reported for sending a collation message. - let collator_protocol_message = protocol_v1::CollatorProtocolMessage::Declare( Sr25519Keyring::Alice.public().into(), Default::default(), @@ -983,19 +1156,23 @@ fn relays_collation_protocol_messages() { let message_v1 = protocol_v1::CollationProtocol::CollatorProtocol(collator_protocol_message.clone()); - network_handle - .peer_message( - peer_a, - PeerSet::Collation, - WireMessage::ProtocolMessage(message_v1.clone()).encode(), - ) - .await; - - let actions = network_handle.next_network_actions(3).await; - assert_network_actions_contains( - &actions, - &NetworkAction::ReputationChange(peer_a, UNCONNECTED_PEERSET_COST.into()), - ); + // peer A gets reported for sending a collation message. + // NOTE: this is not possible since peer A cannot send + // a collation message if it has not opened a collation protocol + + // network_handle + // .peer_message( + // peer_a, + // PeerSet::Collation, + // WireMessage::ProtocolMessage(message_v1.clone()).encode(), + // ) + // .await; + + // let actions = network_handle.next_network_actions(3).await; + // assert_network_actions_contains( + // &actions, + // &NetworkAction::ReputationChange(peer_a, UNCONNECTED_PEERSET_COST.into()), + // ); // peer B has the message relayed. @@ -1252,7 +1429,7 @@ fn our_view_updates_decreasing_order_and_limited_to_max() { fn network_protocol_versioning_view_update() { let (oracle, handle) = make_sync_oracle(false); test_harness(Box::new(oracle), |test_harness| async move { - let TestHarness { mut network_handle, mut virtual_overseer, .. } = test_harness; + let TestHarness { mut network_handle, mut virtual_overseer, shared } = test_harness; let peer_ids: Vec<_> = (0..4).map(|_| PeerId::random()).collect(); let peers = [ @@ -1276,12 +1453,22 @@ fn network_protocol_versioning_view_update() { handle.await_mode_switch().await; + let mut total_validation_peers = 0; + let mut total_collation_peers = 0; + for &(peer_id, peer_set, version) in &peers { network_handle .connect_peer(peer_id, version, peer_set, ObservedRole::Full) .await; + + match peer_set { + PeerSet::Validation => total_validation_peers += 1, + PeerSet::Collation => total_collation_peers += 1, + } } + await_peer_connections(&shared, total_validation_peers, total_collation_peers).await; + let view = view![head]; let actions = network_handle.next_network_actions(4).await; @@ -1304,11 +1491,13 @@ fn network_protocol_versioning_view_update() { }); } +// TODO: discuss with parachains engineering #[test] +#[cfg(feature = "network-protocol-staging")] fn network_protocol_versioning_subsystem_msg() { let (oracle, _handle) = make_sync_oracle(false); test_harness(Box::new(oracle), |test_harness| async move { - let TestHarness { mut network_handle, mut virtual_overseer, .. } = test_harness; + let TestHarness { mut network_handle, mut virtual_overseer, shared } = test_harness; let peer = PeerId::random(); @@ -1320,6 +1509,7 @@ fn network_protocol_versioning_subsystem_msg() { ObservedRole::Full, ) .await; + await_peer_connections(&shared, 1, 0).await; // bridge will inform about all connected peers. { diff --git a/polkadot/node/network/bridge/src/tx/mod.rs b/polkadot/node/network/bridge/src/tx/mod.rs index 1b386ce1239b..2cbe7883d38a 100644 --- a/polkadot/node/network/bridge/src/tx/mod.rs +++ b/polkadot/node/network/bridge/src/tx/mod.rs @@ -33,7 +33,7 @@ use polkadot_node_subsystem::{ /// /// To be passed to [`FullNetworkConfiguration::add_notification_protocol`](). pub use polkadot_node_network_protocol::peer_set::{peer_sets_info, IsAuthority}; -use sc_network::ReputationChange; +use sc_network::{MessageSink, ReputationChange}; use crate::validator_discovery; @@ -58,6 +58,7 @@ pub struct NetworkBridgeTx { metrics: Metrics, req_protocol_names: ReqProtocolNames, peerset_protocol_names: PeerSetProtocolNames, + notification_sinks: Arc>>>, } impl NetworkBridgeTx { @@ -72,6 +73,7 @@ impl NetworkBridgeTx { metrics: Metrics, req_protocol_names: ReqProtocolNames, peerset_protocol_names: PeerSetProtocolNames, + notification_sinks: Arc>>>, ) -> Self { Self { network_service, @@ -79,6 +81,7 @@ impl NetworkBridgeTx { metrics, req_protocol_names, peerset_protocol_names, + notification_sinks, } } } @@ -105,6 +108,7 @@ async fn handle_subsystem_messages( metrics: Metrics, req_protocol_names: ReqProtocolNames, peerset_protocol_names: PeerSetProtocolNames, + notification_sinks: Arc>>>, ) -> Result<(), Error> where N: Network, @@ -128,6 +132,7 @@ where &metrics, &req_protocol_names, &peerset_protocol_names, + ¬ification_sinks, ) .await; }, @@ -138,13 +143,14 @@ where #[overseer::contextbounds(NetworkBridgeTx, prefix = self::overseer)] async fn handle_incoming_subsystem_communication( _ctx: &mut Context, - mut network_service: N, + network_service: N, validator_discovery: &mut validator_discovery::Service, mut authority_discovery_service: AD, msg: NetworkBridgeTxMessage, metrics: &Metrics, req_protocol_names: &ReqProtocolNames, peerset_protocol_names: &PeerSetProtocolNames, + notification_sinks: &Arc>>>, ) -> (N, AD) where N: Network, @@ -191,18 +197,16 @@ where match msg { Versioned::V1(msg) => send_validation_message_v1( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::VStaging(msg) => send_validation_message_vstaging( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), } }, @@ -216,18 +220,16 @@ where for (peers, msg) in msgs { match msg { Versioned::V1(msg) => send_validation_message_v1( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::VStaging(msg) => send_validation_message_vstaging( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), } } @@ -241,18 +243,16 @@ where match msg { Versioned::V1(msg) => send_collation_message_v1( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::VStaging(msg) => send_collation_message_vstaging( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), } }, @@ -266,18 +266,16 @@ where for (peers, msg) in msgs { match msg { Versioned::V1(msg) => send_collation_message_v1( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::VStaging(msg) => send_collation_message_vstaging( - &mut network_service, peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), } } @@ -359,6 +357,7 @@ where metrics, req_protocol_names, peerset_protocol_names, + notification_sinks, } = bridge; handle_subsystem_messages( @@ -368,6 +367,7 @@ where metrics, req_protocol_names, peerset_protocol_names, + notification_sinks, ) .await?; @@ -375,73 +375,65 @@ where } fn send_validation_message_v1( - net: &mut impl Network, peers: Vec, - protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Validation, ValidationVersion::V1.into(), - protocol_names, message, metrics, + notification_sinks, ); } fn send_collation_message_v1( - net: &mut impl Network, peers: Vec, - protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Collation, CollationVersion::V1.into(), - protocol_names, message, metrics, + notification_sinks, ); } fn send_validation_message_vstaging( - net: &mut impl Network, peers: Vec, - protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Validation, ValidationVersion::VStaging.into(), - protocol_names, message, metrics, + notification_sinks, ); } fn send_collation_message_vstaging( - net: &mut impl Network, peers: Vec, - protocol_names: &PeerSetProtocolNames, message: WireMessage, metrics: &Metrics, + notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Collation, CollationVersion::VStaging.into(), - protocol_names, message, metrics, + notification_sinks, ); } diff --git a/polkadot/node/network/bridge/src/tx/tests.rs b/polkadot/node/network/bridge/src/tx/tests.rs index 21cd134c54f2..a19df51dc575 100644 --- a/polkadot/node/network/bridge/src/tx/tests.rs +++ b/polkadot/node/network/bridge/src/tx/tests.rs @@ -15,15 +15,18 @@ // along with Polkadot. If not, see . use super::*; -use futures::{executor, stream::BoxStream}; +use futures::executor; use polkadot_node_subsystem_util::TimeoutExt; use async_trait::async_trait; use parking_lot::Mutex; use std::collections::HashSet; -use sc_network::{Event as NetworkEvent, IfDisconnected, ProtocolName, ReputationChange}; +use sc_network::{ + IfDisconnected, ObservedRole as SubstrateObservedRole, ProtocolName, ReputationChange, Roles, +}; +use parity_scale_codec::DecodeAll; use polkadot_node_network_protocol::{ peer_set::PeerSetProtocolNames, request_response::{outgoing::Requests, ReqProtocolNames}, @@ -51,10 +54,9 @@ pub enum NetworkAction { WriteNotification(PeerId, PeerSet, Vec), } -// The subsystem's view of the network - only supports a single call to `event_stream`. +// The subsystem's view of the network. #[derive(Clone)] struct TestNetwork { - net_events: Arc>>>, action_tx: Arc>>, peerset_protocol_names: Arc, } @@ -66,37 +68,98 @@ struct TestAuthorityDiscovery; // of `NetworkAction`s. struct TestNetworkHandle { action_rx: metered::UnboundedMeteredReceiver, - net_tx: metered::MeteredSender, - peerset_protocol_names: PeerSetProtocolNames, + _peerset_protocol_names: PeerSetProtocolNames, + notification_sinks: Arc>>>, + action_tx: Arc>>, +} + +struct TestMessageSink { + peer: PeerId, + peer_set: PeerSet, + action_tx: Arc>>, +} + +impl TestMessageSink { + fn new( + peer: PeerId, + peer_set: PeerSet, + action_tx: Arc>>, + ) -> TestMessageSink { + Self { peer, peer_set, action_tx } + } +} + +#[async_trait::async_trait] +impl MessageSink for TestMessageSink { + fn send_sync_notification(&self, notification: Vec) { + self.action_tx + .lock() + .unbounded_send(NetworkAction::WriteNotification( + self.peer, + self.peer_set, + notification, + )) + .unwrap(); + } + + async fn send_async_notification( + &self, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } } fn new_test_network( peerset_protocol_names: PeerSetProtocolNames, -) -> (TestNetwork, TestNetworkHandle, TestAuthorityDiscovery) { - let (net_tx, net_rx) = metered::channel(10); +) -> ( + TestNetwork, + TestNetworkHandle, + TestAuthorityDiscovery, + Arc>>>, +) { let (action_tx, action_rx) = metered::unbounded(); + let notification_sinks = Arc::new(Mutex::new(HashMap::new())); + let action_tx = Arc::new(Mutex::new(action_tx)); ( TestNetwork { - net_events: Arc::new(Mutex::new(Some(net_rx))), - action_tx: Arc::new(Mutex::new(action_tx)), + action_tx: action_tx.clone(), peerset_protocol_names: Arc::new(peerset_protocol_names.clone()), }, - TestNetworkHandle { action_rx, net_tx, peerset_protocol_names }, + TestNetworkHandle { + action_rx, + _peerset_protocol_names: peerset_protocol_names, + action_tx, + notification_sinks: notification_sinks.clone(), + }, TestAuthorityDiscovery, + notification_sinks, ) } -#[async_trait] -impl Network for TestNetwork { - fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent> { - self.net_events - .lock() - .take() - .expect("Subsystem made more than one call to `event_stream`") - .boxed() +// wait until all needed validation and collation peers have connected. +async fn await_peer_connections( + shared: &Shared, + num_validation_peers: usize, + num_collation_peers: usize, +) { + loop { + { + let shared = shared.0.lock(); + if shared.validation_peers.len() == num_validation_peers && + shared.collation_peers.len() == num_collation_peers + { + break + } + } + + futures_timer::Delay::new(std::time::Duration::from_millis(100)).await; } +} +#[async_trait] +impl Network for TestNetwork { async fn set_reserved_peers( &mut self, _protocol: ProtocolName, @@ -130,7 +193,8 @@ impl Network for TestNetwork { } fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { - let (peer_set, _) = self.peerset_protocol_names.try_get_protocol(&protocol).unwrap(); + let (peer_set, version) = self.peerset_protocol_names.try_get_protocol(&protocol).unwrap(); + assert_eq!(version, peer_set.get_main_version()); self.action_tx .lock() @@ -138,13 +202,10 @@ impl Network for TestNetwork { .unwrap(); } - fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec) { - let (peer_set, _) = self.peerset_protocol_names.try_get_protocol(&protocol).unwrap(); - - self.action_tx - .lock() - .unbounded_send(NetworkAction::WriteNotification(who, peer_set, message)) - .unwrap(); + fn peer_role(&self, _peer_id: PeerId, handshake: Vec) -> Option { + Roles::decode_all(&mut &handshake[..]) + .ok() + .and_then(|role| Some(SubstrateObservedRole::from(role))) } } @@ -174,23 +235,14 @@ impl TestNetworkHandle { async fn connect_peer( &mut self, peer: PeerId, - protocol_version: ValidationVersion, + _protocol_version: ValidationVersion, peer_set: PeerSet, - role: ObservedRole, + _role: ObservedRole, ) { - let protocol_version = ProtocolVersion::from(protocol_version); - self.send_network_event(NetworkEvent::NotificationStreamOpened { - remote: peer, - protocol: self.peerset_protocol_names.get_name(peer_set, protocol_version), - negotiated_fallback: None, - role: role.into(), - received_handshake: vec![], - }) - .await; - } - - async fn send_network_event(&mut self, event: NetworkEvent) { - self.net_tx.send(event).await.expect("subsystem concluded early"); + self.notification_sinks.lock().insert( + (peer_set, peer), + Box::new(TestMessageSink::new(peer, peer_set, self.action_tx.clone())), + ); } } @@ -208,7 +260,8 @@ fn test_harness>(test: impl FnOnce(TestHarne let peerset_protocol_names = PeerSetProtocolNames::new(genesis_hash, fork_id); let pool = sp_core::testing::TaskExecutor::new(); - let (network, network_handle, discovery) = new_test_network(peerset_protocol_names.clone()); + let (network, network_handle, discovery, network_notification_sinks) = + new_test_network(peerset_protocol_names.clone()); let (context, virtual_overseer) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool); @@ -219,6 +272,7 @@ fn test_harness>(test: impl FnOnce(TestHarne Metrics(None), req_protocol_names, peerset_protocol_names, + network_notification_sinks, ); let network_bridge_out_fut = run_network_out(bridge_out, context) @@ -334,7 +388,9 @@ fn send_messages_to_peers() { }); } +// TODO: discuss with parachains engineering #[test] +#[cfg(feature = "network-protocol-staging")] fn network_protocol_versioning_send() { test_harness(|test_harness| async move { let TestHarness { mut network_handle, mut virtual_overseer } = test_harness; diff --git a/polkadot/node/network/bridge/src/validator_discovery.rs b/polkadot/node/network/bridge/src/validator_discovery.rs index 86e861fbc5b5..b11af8a8a089 100644 --- a/polkadot/node/network/bridge/src/validator_discovery.rs +++ b/polkadot/node/network/bridge/src/validator_discovery.rs @@ -169,13 +169,12 @@ mod tests { use crate::network::Network; use async_trait::async_trait; - use futures::stream::BoxStream; use polkadot_node_network_protocol::{ request_response::{outgoing::Requests, ReqProtocolNames}, PeerId, }; use polkadot_primitives::Hash; - use sc_network::{Event as NetworkEvent, IfDisconnected, ProtocolName, ReputationChange}; + use sc_network::{IfDisconnected, ProtocolName, ReputationChange}; use sp_keyring::Sr25519Keyring; use std::collections::{HashMap, HashSet}; @@ -224,10 +223,6 @@ mod tests { #[async_trait] impl Network for TestNetwork { - fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent> { - panic!() - } - async fn set_reserved_peers( &mut self, _protocol: ProtocolName, @@ -263,7 +258,11 @@ mod tests { panic!() } - fn write_notification(&self, _: PeerId, _: ProtocolName, _: Vec) { + fn peer_role( + &self, + _peer_id: PeerId, + _handshake: Vec, + ) -> Option { panic!() } } diff --git a/polkadot/node/network/protocol/src/peer_set.rs b/polkadot/node/network/protocol/src/peer_set.rs index c2163783c2ce..9db5d4771d4b 100644 --- a/polkadot/node/network/protocol/src/peer_set.rs +++ b/polkadot/node/network/protocol/src/peer_set.rs @@ -21,6 +21,7 @@ use polkadot_primitives::Hash; use sc_network::{ config::{NonDefaultSetConfig, SetConfig}, types::ProtocolName, + NotificationService, }; use std::{ collections::{hash_map::Entry, HashMap}, @@ -68,7 +69,7 @@ impl PeerSet { self, is_authority: IsAuthority, peerset_protocol_names: &PeerSetProtocolNames, - ) -> NonDefaultSetConfig { + ) -> (NonDefaultSetConfig, (PeerSet, Box)) { // Networking layer relies on `get_main_name()` being the main name of the protocol // for peersets and connection management. let protocol = peerset_protocol_names.get_main_name(self); @@ -76,39 +77,47 @@ impl PeerSet { let max_notification_size = self.get_max_notification_size(is_authority); match self { - PeerSet::Validation => NonDefaultSetConfig { - notifications_protocol: protocol, - fallback_names, - max_notification_size, - handshake: None, - set_config: SetConfig { - // we allow full nodes to connect to validators for gossip - // to ensure any `MIN_GOSSIP_PEERS` always include reserved peers - // we limit the amount of non-reserved slots to be less - // than `MIN_GOSSIP_PEERS` in total - in_peers: super::MIN_GOSSIP_PEERS as u32 / 2 - 1, - out_peers: super::MIN_GOSSIP_PEERS as u32 / 2 - 1, - reserved_nodes: Vec::new(), - non_reserved_mode: sc_network::config::NonReservedPeerMode::Accept, - }, + PeerSet::Validation => { + let (config, notification_service) = NonDefaultSetConfig::new( + protocol, + fallback_names, + max_notification_size, + None, + SetConfig { + // we allow full nodes to connect to validators for gossip + // to ensure any `MIN_GOSSIP_PEERS` always include reserved peers + // we limit the amount of non-reserved slots to be less + // than `MIN_GOSSIP_PEERS` in total + in_peers: super::MIN_GOSSIP_PEERS as u32 / 2 - 1, + out_peers: super::MIN_GOSSIP_PEERS as u32 / 2 - 1, + reserved_nodes: Vec::new(), + non_reserved_mode: sc_network::config::NonReservedPeerMode::Accept, + }, + ); + + (config, (PeerSet::Validation, notification_service)) }, - PeerSet::Collation => NonDefaultSetConfig { - notifications_protocol: protocol, - fallback_names, - max_notification_size, - handshake: None, - set_config: SetConfig { - // Non-authority nodes don't need to accept incoming connections on this peer - // set: - in_peers: if is_authority == IsAuthority::Yes { 100 } else { 0 }, - out_peers: 0, - reserved_nodes: Vec::new(), - non_reserved_mode: if is_authority == IsAuthority::Yes { - sc_network::config::NonReservedPeerMode::Accept - } else { - sc_network::config::NonReservedPeerMode::Deny + PeerSet::Collation => { + let (config, notification_service) = NonDefaultSetConfig::new( + protocol, + fallback_names, + max_notification_size, + None, + SetConfig { + // Non-authority nodes don't need to accept incoming connections on this + // peer set: + in_peers: if is_authority == IsAuthority::Yes { 100 } else { 0 }, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: if is_authority == IsAuthority::Yes { + sc_network::config::NonReservedPeerMode::Accept + } else { + sc_network::config::NonReservedPeerMode::Deny + }, }, - }, + ); + + (config, (PeerSet::Collation, notification_service)) }, } } @@ -202,7 +211,7 @@ impl IndexMut for PerPeerSet { pub fn peer_sets_info( is_authority: IsAuthority, peerset_protocol_names: &PeerSetProtocolNames, -) -> Vec { +) -> Vec<(NonDefaultSetConfig, (PeerSet, Box))> { PeerSet::iter() .map(|s| s.get_info(is_authority, &peerset_protocol_names)) .collect() @@ -281,7 +290,7 @@ impl From for ProtocolVersion { } /// On the wire protocol name to [`PeerSet`] mapping. -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct PeerSetProtocolNames { protocols: HashMap, names: HashMap<(PeerSet, ProtocolVersion), ProtocolName>, diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 90881aa051a0..f9ebb03d497b 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -84,6 +84,7 @@ kvdb = "0.13.0" kvdb-rocksdb = { version = "0.19.0", optional = true } parity-db = { version = "0.4.8", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } +parking_lot = "0.12.1" async-trait = "0.1.57" schnellru = "0.2.1" diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 95c887947c98..7d10a212ae30 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -51,7 +51,8 @@ use { }, polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig, polkadot_node_network_protocol::{ - peer_set::PeerSetProtocolNames, request_response::ReqProtocolNames, + peer_set::{PeerSet, PeerSetProtocolNames}, + request_response::ReqProtocolNames, }, sc_client_api::BlockBackend, sc_transaction_pool_api::OffchainTransactionPoolFactory, @@ -74,7 +75,7 @@ pub use { #[cfg(feature = "full-node")] use polkadot_node_subsystem::jaeger; -use std::{path::PathBuf, sync::Arc, time::Duration}; +use std::{collections::HashMap, path::PathBuf, sync::Arc, time::Duration}; use prometheus_endpoint::Registry; #[cfg(feature = "full-node")] @@ -810,9 +811,9 @@ pub fn new_full( // anything in terms of behaviour, but makes the logs more consistent with the other // Substrate nodes. let grandpa_protocol_name = grandpa::protocol_standard_name(&genesis_hash, &config.chain_spec); - net_config.add_notification_protocol(grandpa::grandpa_peers_set_config( - grandpa_protocol_name.clone(), - )); + let (grandpa_protocol_config, grandpa_notification_service) = + grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone()); + net_config.add_notification_protocol(grandpa_protocol_config); let beefy_gossip_proto_name = beefy::gossip_protocol_name(&genesis_hash, config.chain_spec.fork_id()); @@ -825,12 +826,17 @@ pub fn new_full( client.clone(), prometheus_registry.clone(), ); - if enable_beefy { - net_config.add_notification_protocol(beefy::communication::beefy_peers_set_config( - beefy_gossip_proto_name.clone(), - )); - net_config.add_request_response_protocol(beefy_req_resp_cfg); - } + let beefy_notification_service = match enable_beefy { + false => None, + true => { + let (beefy_notification_config, beefy_notification_service) = + beefy::communication::beefy_peers_set_config(beefy_gossip_proto_name.clone()); + + net_config.add_notification_protocol(beefy_notification_config); + net_config.add_request_response_protocol(beefy_req_resp_cfg); + Some(beefy_notification_service) + }, + }; // validation/collation protocols are enabled only if `Overseer` is enabled let peerset_protocol_names = @@ -841,13 +847,21 @@ pub fn new_full( // // Collators and parachain full nodes require the collator and validator networking to send // collations and to be able to recover PoVs. - if role.is_authority() || is_parachain_node.is_running_alongside_parachain_node() { - use polkadot_network_bridge::{peer_sets_info, IsAuthority}; - let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No }; - for config in peer_sets_info(is_authority, &peerset_protocol_names) { - net_config.add_notification_protocol(config); - } - } + let notification_services = + if role.is_authority() || is_parachain_node.is_running_alongside_parachain_node() { + use polkadot_network_bridge::{peer_sets_info, IsAuthority}; + let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No }; + + peer_sets_info(is_authority, &peerset_protocol_names) + .into_iter() + .map(|(config, (peerset, service))| { + net_config.add_notification_protocol(config); + (peerset, service) + }) + .collect::>>() + } else { + std::collections::HashMap::new() + }; let req_protocol_names = ReqProtocolNames::new(&genesis_hash, config.chain_spec.fork_id()); @@ -1074,6 +1088,7 @@ pub fn new_full( offchain_transaction_pool_factory: OffchainTransactionPoolFactory::new( transaction_pool.clone(), ), + notification_services, }, ) .map_err(|e| { @@ -1182,6 +1197,8 @@ pub fn new_full( sync: sync_service.clone(), gossip_protocol_name: beefy_gossip_proto_name, justifications_protocol_name, + notification_service: beefy_notification_service + .expect("BEEFY was enabled so `NotificationService` exists; qed"), _phantom: core::marker::PhantomData::, }; let payload_provider = beefy_primitives::mmr::MmrRootProvider::new(client.clone()); @@ -1279,6 +1296,7 @@ pub fn new_full( prometheus_registry: prometheus_registry.clone(), shared_voter_state, telemetry: telemetry.as_ref().map(|x| x.handle()), + notification_service: grandpa_notification_service, offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool.clone()), }; diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index 33127b638e5a..99265541c0bb 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -26,7 +26,7 @@ use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig use polkadot_node_core_chain_selection::Config as ChainSelectionConfig; use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig; use polkadot_node_network_protocol::{ - peer_set::PeerSetProtocolNames, + peer_set::{PeerSet, PeerSetProtocolNames}, request_response::{ v1 as request_v1, vstaging as request_vstaging, IncomingRequestReceiver, ReqProtocolNames, }, @@ -42,15 +42,16 @@ use polkadot_overseer::{ }; use schnellru::{ByLength, LruMap}; +use parking_lot::Mutex; use polkadot_primitives::runtime_api::ParachainHost; use sc_authority_discovery::Service as AuthorityDiscoveryService; use sc_client_api::AuxStore; use sc_keystore::LocalKeystore; -use sc_network::NetworkStateInfo; +use sc_network::{NetworkStateInfo, NotificationService}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_consensus_babe::BabeApi; -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; pub use polkadot_approval_distribution::ApprovalDistribution as ApprovalDistributionSubsystem; pub use polkadot_availability_bitfield_distribution::BitfieldDistribution as BitfieldDistributionSubsystem; @@ -143,6 +144,8 @@ where pub peerset_protocol_names: PeerSetProtocolNames, /// The offchain transaction pool factory. pub offchain_transaction_pool_factory: OffchainTransactionPoolFactory, + /// Notification services for validation/collation protocols. + pub notification_services: HashMap>, } /// Obtain a prepared `OverseerBuilder`, that is initialized @@ -176,6 +179,7 @@ pub fn prepared_overseer_builder( req_protocol_names, peerset_protocol_names, offchain_transaction_pool_factory, + notification_services, }: OverseerGenArgs, ) -> Result< InitializedOverseerBuilder< @@ -221,6 +225,7 @@ where use polkadot_node_subsystem_util::metrics::Metrics; let metrics = ::register(registry)?; + let notification_sinks = Arc::new(Mutex::new(HashMap::new())); let spawner = SpawnGlue(spawner); @@ -238,6 +243,7 @@ where network_bridge_metrics.clone(), req_protocol_names, peerset_protocol_names.clone(), + notification_sinks.clone(), )) .network_bridge_rx(NetworkBridgeRxSubsystem::new( network_service.clone(), @@ -245,6 +251,8 @@ where Box::new(sync_service.clone()), network_bridge_metrics, peerset_protocol_names, + notification_services, + notification_sinks, )) .availability_distribution(AvailabilityDistributionSubsystem::new( keystore.clone(), diff --git a/substrate/bin/node-template/node/src/service.rs b/substrate/bin/node-template/node/src/service.rs index 7303f5cd6dd6..f80dd1bb73a6 100644 --- a/substrate/bin/node-template/node/src/service.rs +++ b/substrate/bin/node-template/node/src/service.rs @@ -163,9 +163,9 @@ pub fn new_full(config: Configuration) -> Result { &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), &config.chain_spec, ); - net_config.add_notification_protocol(sc_consensus_grandpa::grandpa_peers_set_config( - grandpa_protocol_name.clone(), - )); + let (grandpa_protocol_config, grandpa_notification_service) = + sc_consensus_grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone()); + net_config.add_notification_protocol(grandpa_protocol_config); let warp_sync = Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new( backend.clone(), @@ -315,6 +315,7 @@ pub fn new_full(config: Configuration) -> Result { link: grandpa_link, network, sync: Arc::new(sync_service), + notification_service: grandpa_notification_service, voting_rule: sc_consensus_grandpa::VotingRulesBuilder::default().build(), prometheus_registry, shared_voter_state: SharedVoterState::empty(), diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index ecca5c60db51..6ed890c8a7b3 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -359,19 +359,20 @@ pub fn new_full_base( &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), &config.chain_spec, ); - net_config.add_notification_protocol(grandpa::grandpa_peers_set_config( - grandpa_protocol_name.clone(), - )); - - let statement_handler_proto = sc_network_statement::StatementHandlerPrototype::new( - client - .block_hash(0u32.into()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), - config.chain_spec.fork_id(), - ); - net_config.add_notification_protocol(statement_handler_proto.set_config()); + let (grandpa_protocol_config, grandpa_notification_service) = + grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone()); + net_config.add_notification_protocol(grandpa_protocol_config); + + let (statement_handler_proto, statement_config) = + sc_network_statement::StatementHandlerPrototype::new( + client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + config.chain_spec.fork_id(), + ); + net_config.add_notification_protocol(statement_config); let warp_sync = Arc::new(grandpa::warp_proof::NetworkProvider::new( backend.clone(), @@ -551,6 +552,7 @@ pub fn new_full_base( link: grandpa_link, network: network.clone(), sync: Arc::new(sync_service.clone()), + notification_service: grandpa_notification_service, telemetry: telemetry.as_ref().map(|x| x.handle()), voting_rule: grandpa::VotingRulesBuilder::default().build(), prometheus_registry: prometheus_registry.clone(), diff --git a/substrate/client/consensus/beefy/src/communication/mod.rs b/substrate/client/consensus/beefy/src/communication/mod.rs index 7f9535bfc23f..d92d3be7d687 100644 --- a/substrate/client/consensus/beefy/src/communication/mod.rs +++ b/substrate/client/consensus/beefy/src/communication/mod.rs @@ -67,10 +67,16 @@ pub(crate) mod beefy_protocol_name { /// For standard protocol name see [`beefy_protocol_name::gossip_protocol_name`]. pub fn beefy_peers_set_config( gossip_protocol_name: sc_network::ProtocolName, -) -> sc_network::config::NonDefaultSetConfig { - let mut cfg = sc_network::config::NonDefaultSetConfig::new(gossip_protocol_name, 1024 * 1024); +) -> (sc_network::config::NonDefaultSetConfig, Box) { + let (mut cfg, notification_service) = sc_network::config::NonDefaultSetConfig::new( + gossip_protocol_name, + Vec::new(), + 1024 * 1024, + None, + Default::default(), + ); cfg.allow_non_reserved(25, 25); - cfg + (cfg, notification_service) } // cost scalars for reporting peers. diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 72df3cab8550..2b62dec4a626 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -38,7 +38,7 @@ use parking_lot::Mutex; use prometheus::Registry; use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotifications, Finalizer}; use sc_consensus::BlockImport; -use sc_network::{NetworkRequest, ProtocolName}; +use sc_network::{NetworkRequest, NotificationService, ProtocolName}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing}; use sp_api::{HeaderT, NumberFor, ProvideRuntimeApi}; use sp_blockchain::{ @@ -178,6 +178,8 @@ pub struct BeefyNetworkParams { pub network: Arc, /// Syncing service implementing a sync oracle and an event stream for peers. pub sync: Arc, + /// Handle for receiving notification events. + pub notification_service: Box, /// Chain specific BEEFY gossip protocol name. See /// [`communication::beefy_protocol_name::gossip_protocol_name`]. pub gossip_protocol_name: ProtocolName, @@ -243,6 +245,7 @@ pub async fn start_beefy_gadget( let BeefyNetworkParams { network, sync, + notification_service, gossip_protocol_name, justifications_protocol_name, .. @@ -264,6 +267,7 @@ pub async fn start_beefy_gadget( let gossip_engine = GossipEngine::new( network.clone(), sync.clone(), + notification_service, gossip_protocol_name.clone(), gossip_validator.clone(), None, diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 3bb65e9d57f4..5bc183387599 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -71,7 +71,7 @@ use substrate_test_runtime_client::{BlockBuilderExt, ClientExt}; use tokio::time::Duration; const GENESIS_HASH: H256 = H256::zero(); -fn beefy_gossip_proto_name() -> ProtocolName { +pub(crate) fn beefy_gossip_proto_name() -> ProtocolName { gossip_protocol_name(GENESIS_HASH, None) } @@ -370,6 +370,7 @@ async fn voter_init_setup( let mut gossip_engine = sc_network_gossip::GossipEngine::new( net.peer(0).network_service().clone(), net.peer(0).sync_service().clone(), + net.peer(0).take_notification_service(&beefy_gossip_proto_name()).unwrap(), "/beefy/whatever", gossip_validator, None, @@ -391,6 +392,14 @@ where { let tasks = FuturesUnordered::new(); + let mut notification_services = peers + .iter() + .map(|(peer_id, _, _)| { + let peer = &mut net.peers[*peer_id]; + (*peer_id, peer.take_notification_service(&beefy_gossip_proto_name()).unwrap()) + }) + .collect::>(); + for (peer_id, key, api) in peers.into_iter() { let peer = &net.peers[peer_id]; @@ -408,6 +417,7 @@ where let network_params = crate::BeefyNetworkParams { network: peer.network_service().clone(), sync: peer.sync_service().clone(), + notification_service: notification_services.remove(&peer_id).unwrap(), gossip_protocol_name: beefy_gossip_proto_name(), justifications_protocol_name: on_demand_justif_handler.protocol_name(), _phantom: PhantomData, @@ -1031,7 +1041,25 @@ async fn should_initialize_voter_at_custom_genesis() { net.peer(0).client().as_client().finalize_block(hashes[8], None).unwrap(); // load persistent state - nothing in DB, should init at genesis - let persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + // + // NOTE: code from `voter_init_setup()` is moved here because the new network event system + // doesn't allow creating a new `GossipEngine` as the notification handle is consumed by the + // first `GossipEngine` + let known_peers = Arc::new(Mutex::new(KnownPeers::new())); + let (gossip_validator, _) = GossipValidator::new(known_peers); + let gossip_validator = Arc::new(gossip_validator); + let mut gossip_engine = sc_network_gossip::GossipEngine::new( + net.peer(0).network_service().clone(), + net.peer(0).sync_service().clone(), + net.peer(0).take_notification_service(&beefy_gossip_proto_name()).unwrap(), + "/beefy/whatever", + gossip_validator, + None, + ); + let (beefy_genesis, best_grandpa) = + wait_for_runtime_pallet(&api, &mut gossip_engine, &mut finality).await.unwrap(); + let persisted_state = + load_or_init_voter_state(&*backend, &api, beefy_genesis, best_grandpa, 1).unwrap(); // Test initialization at session boundary. // verify voter initialized with single session starting at block `custom_pallet_genesis` (7) @@ -1061,7 +1089,11 @@ async fn should_initialize_voter_at_custom_genesis() { net.peer(0).client().as_client().finalize_block(hashes[10], None).unwrap(); // load persistent state - state preset in DB, but with different pallet genesis - let new_persisted_state = voter_init_setup(&mut net, &mut finality, &api).await.unwrap(); + // the network state persists and uses the old `GossipEngine` initialized for `peer(0)` + let (beefy_genesis, best_grandpa) = + wait_for_runtime_pallet(&api, &mut gossip_engine, &mut finality).await.unwrap(); + let new_persisted_state = + load_or_init_voter_state(&*backend, &api, beefy_genesis, best_grandpa, 1).unwrap(); // verify voter initialized with single session starting at block `new_pallet_genesis` (10) let sessions = new_persisted_state.voting_oracle().sessions(); @@ -1309,7 +1341,7 @@ async fn gossipped_finality_proofs() { let api = Arc::new(TestApi::with_validator_set(&validator_set)); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); - let charlie = &net.peers[2]; + let charlie = &mut net.peers[2]; let known_peers = Arc::new(Mutex::new(KnownPeers::::new())); // Charlie will run just the gossip engine and not the full voter. let (gossip_validator, _) = GossipValidator::new(known_peers); @@ -1322,6 +1354,7 @@ async fn gossipped_finality_proofs() { let mut charlie_gossip_engine = sc_network_gossip::GossipEngine::new( charlie.network_service().clone(), charlie.sync_service().clone(), + charlie.take_notification_service(&beefy_gossip_proto_name()).unwrap(), beefy_gossip_proto_name(), charlie_gossip_validator.clone(), None, diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index a239e34030c2..a50fdab28ec4 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -1131,12 +1131,16 @@ pub(crate) mod tests { let api = Arc::new(TestApi::with_validator_set(&genesis_validator_set)); let network = peer.network_service().clone(); let sync = peer.sync_service().clone(); + let notification_service = peer + .take_notification_service(&crate::tests::beefy_gossip_proto_name()) + .unwrap(); let known_peers = Arc::new(Mutex::new(KnownPeers::new())); let (gossip_validator, gossip_report_stream) = GossipValidator::new(known_peers.clone()); let gossip_validator = Arc::new(gossip_validator); let gossip_engine = GossipEngine::new( network.clone(), sync.clone(), + notification_service, "/beefy/1", gossip_validator.clone(), None, diff --git a/substrate/client/consensus/grandpa/src/communication/mod.rs b/substrate/client/consensus/grandpa/src/communication/mod.rs index c0749858568f..22785639e1f6 100644 --- a/substrate/client/consensus/grandpa/src/communication/mod.rs +++ b/substrate/client/consensus/grandpa/src/communication/mod.rs @@ -46,7 +46,7 @@ use finality_grandpa::{ Message::{Precommit, Prevote, PrimaryPropose}, }; use parity_scale_codec::{Decode, DecodeAll, Encode}; -use sc_network::{NetworkBlock, NetworkSyncForkRequest, ReputationChange}; +use sc_network::{NetworkBlock, NetworkSyncForkRequest, NotificationService, ReputationChange}; use sc_network_gossip::{GossipEngine, Network as GossipNetwork}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; use sp_keystore::KeystorePtr; @@ -247,6 +247,7 @@ impl, S: Syncing> NetworkBridge { pub(crate) fn new( service: N, sync: S, + notification_service: Box, config: crate::Config, set_state: crate::environment::SharedVoterSetState, prometheus_registry: Option<&Registry>, @@ -260,6 +261,7 @@ impl, S: Syncing> NetworkBridge { let gossip_engine = Arc::new(Mutex::new(GossipEngine::new( service.clone(), sync.clone(), + notification_service, protocol, validator.clone(), prometheus_registry, diff --git a/substrate/client/consensus/grandpa/src/communication/tests.rs b/substrate/client/consensus/grandpa/src/communication/tests.rs index 10c4772fc76d..3fbc954d89cf 100644 --- a/substrate/client/consensus/grandpa/src/communication/tests.rs +++ b/substrate/client/consensus/grandpa/src/communication/tests.rs @@ -24,17 +24,18 @@ use super::{ }; use crate::{communication::grandpa_protocol_name, environment::SharedVoterSetState}; use futures::prelude::*; -use parity_scale_codec::Encode; +use parity_scale_codec::{DecodeAll, Encode}; use sc_network::{ config::{MultiaddrWithPeerId, Role}, event::Event as NetworkEvent, + service::traits::{Direction, MessageSink, NotificationEvent, NotificationService}, types::ProtocolName, Multiaddr, NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkSyncForkRequest, NotificationSenderError, NotificationSenderT as NotificationSender, PeerId, ReputationChange, }; use sc_network_common::{ - role::ObservedRole, + role::{ObservedRole, Roles}, sync::{SyncEvent as SyncStreamEvent, SyncEventStream}, }; use sc_network_gossip::Validator; @@ -125,6 +126,12 @@ impl NetworkPeers for TestNetwork { fn sync_num_connected(&self) -> usize { unimplemented!(); } + + fn peer_role(&self, _peer_id: PeerId, handshake: Vec) -> Option { + Roles::decode_all(&mut &handshake[..]) + .ok() + .and_then(|role| Some(ObservedRole::from(role))) + } } impl NetworkEventStream for TestNetwork { @@ -213,10 +220,65 @@ impl NetworkSyncForkRequest> for TestSync { fn set_sync_fork_request(&self, _peers: Vec, _hash: Hash, _number: NumberFor) {} } +#[derive(Debug)] +pub(crate) struct TestNotificationService { + rx: TracingUnboundedReceiver, +} + +#[async_trait::async_trait] +impl NotificationService for TestNotificationService { + /// Instruct `Notifications` to open a new substream for `peer`. + async fn open_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Instruct `Notifications` to close substream for `peer`. + async fn close_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Send synchronous `notification` to `peer`. + fn send_sync_notification(&self, _peer: &PeerId, _notification: Vec) { + unimplemented!(); + } + + /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure. + async fn send_async_notification( + &self, + _peer: &PeerId, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } + + /// Set handshake for the notification protocol replacing the old handshake. + async fn set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + /// Get next event from the `Notifications` event stream. + async fn next_event(&mut self) -> Option { + self.rx.next().await + } + + fn clone(&mut self) -> Result, ()> { + unimplemented!(); + } + + fn protocol(&self) -> &ProtocolName { + unimplemented!(); + } + + fn message_sink(&self, _peer: &PeerId) -> Option> { + unimplemented!(); + } +} + pub(crate) struct Tester { pub(crate) net_handle: super::NetworkBridge, gossip_validator: Arc>, pub(crate) events: TracingUnboundedReceiver, + pub(crate) notification_tx: TracingUnboundedSender, } impl Tester { @@ -281,6 +343,9 @@ fn voter_set_state() -> SharedVoterSetState { // needs to run in a tokio runtime. pub(crate) fn make_test_network() -> (impl Future, TestNetwork) { let (tx, rx) = tracing_unbounded("test", 100_000); + let (notification_tx, notification_rx) = tracing_unbounded("test-notification", 100_000); + + let notification_service = TestNotificationService { rx: notification_rx }; let net = TestNetwork { sender: tx }; let sync = TestSync {}; @@ -295,14 +360,22 @@ pub(crate) fn make_test_network() -> (impl Future, TestNetwork) } } - let bridge = - super::NetworkBridge::new(net.clone(), sync, config(), voter_set_state(), None, None); + let bridge = super::NetworkBridge::new( + net.clone(), + sync, + Box::new(notification_service), + config(), + voter_set_state(), + None, + None, + ); ( futures::future::ready(Tester { gossip_validator: bridge.validator.clone(), net_handle: bridge, events: rx, + notification_tx, }), net, ) @@ -387,63 +460,62 @@ fn good_commit_leads_to_relay() { let commit_to_send = encoded_commit.clone(); let network_bridge = tester.net_handle.clone(); - // asking for global communication will cause the test network - // to send us an event asking us for a stream. use it to - // send a message. + // `NetworkBridge` will be operational as soon as it's created and it's + // waiting for events from the network. Send it events that inform that + // a notification stream was opened and that a notification was received. + // + // Since each protocol has its own notification stream, events need not be filtered. let sender_id = id; - let send_message = tester.filter_network_events(move |event| match event { - Event::EventStream(sender) => { - // Add the sending peer and send the commit - let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { - remote: sender_id, - protocol: grandpa_protocol_name::NAME.into(), + + let send_message = async move { + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationStreamOpened { + peer: sender_id, + direction: Direction::Inbound, + negotiated_fallback: None, + handshake: Roles::FULL.encode(), + }, + ); + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationReceived { + peer: sender_id, + notification: commit_to_send.clone(), + }, + ); + + // Add a random peer which will be the recipient of this message + let receiver_id = PeerId::random(); + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationStreamOpened { + peer: receiver_id, + direction: Direction::Inbound, negotiated_fallback: None, - role: ObservedRole::Full, - received_handshake: vec![], + handshake: Roles::FULL.encode(), + }, + ); + + // Announce its local set being on the current set id through a neighbor + // packet, otherwise it won't be eligible to receive the commit + let _ = { + let update = gossip::VersionedNeighborPacket::V1(gossip::NeighborPacket { + round: Round(round), + set_id: SetId(set_id), + commit_finalized_height: 1, }); - let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { - remote: sender_id, - messages: vec![( - grandpa_protocol_name::NAME.into(), - commit_to_send.clone().into(), - )], - }); + let msg = gossip::GossipMessage::::Neighbor(update); - // Add a random peer which will be the recipient of this message - let receiver_id = PeerId::random(); - let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { - remote: receiver_id, - protocol: grandpa_protocol_name::NAME.into(), - negotiated_fallback: None, - role: ObservedRole::Full, - received_handshake: vec![], - }); + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationReceived { + peer: receiver_id, + notification: msg.encode(), + }, + ); + }; - // Announce its local set has being on the current set id through a neighbor - // packet, otherwise it won't be eligible to receive the commit - let _ = { - let update = gossip::VersionedNeighborPacket::V1(gossip::NeighborPacket { - round: Round(round), - set_id: SetId(set_id), - commit_finalized_height: 1, - }); - - let msg = gossip::GossipMessage::::Neighbor(update); - - sender.unbounded_send(NetworkEvent::NotificationsReceived { - remote: receiver_id, - messages: vec![( - grandpa_protocol_name::NAME.into(), - msg.encode().into(), - )], - }) - }; - - true - }, - _ => false, - }); + tester + } + .boxed(); // when the commit comes in, we'll tell the callback it was good. let handle_commit = commits_in.into_future().map(|(item, _)| match item.unwrap() { @@ -539,31 +611,32 @@ fn bad_commit_leads_to_report() { let commit_to_send = encoded_commit.clone(); let network_bridge = tester.net_handle.clone(); - // asking for global communication will cause the test network - // to send us an event asking us for a stream. use it to - // send a message. + // `NetworkBridge` will be operational as soon as it's created and it's + // waiting for events from the network. Send it events that inform that + // a notification stream was opened and that a notification was received. + // + // Since each protocol has its own notification stream, events need not be filtered. let sender_id = id; - let send_message = tester.filter_network_events(move |event| match event { - Event::EventStream(sender) => { - let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { - remote: sender_id, - protocol: grandpa_protocol_name::NAME.into(), + + let send_message = async move { + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationStreamOpened { + peer: sender_id, + direction: Direction::Inbound, negotiated_fallback: None, - role: ObservedRole::Full, - received_handshake: vec![], - }); - let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { - remote: sender_id, - messages: vec![( - grandpa_protocol_name::NAME.into(), - commit_to_send.clone().into(), - )], - }); + handshake: Roles::FULL.encode(), + }, + ); + let _ = tester.notification_tx.unbounded_send( + NotificationEvent::NotificationReceived { + peer: sender_id, + notification: commit_to_send.clone(), + }, + ); - true - }, - _ => false, - }); + tester + } + .boxed(); // when the commit comes in, we'll tell the callback it was bad. let handle_commit = commits_in.into_future().map(|(item, _)| match item.unwrap() { diff --git a/substrate/client/consensus/grandpa/src/lib.rs b/substrate/client/consensus/grandpa/src/lib.rs index da621abd254c..34e5b375de8e 100644 --- a/substrate/client/consensus/grandpa/src/lib.rs +++ b/substrate/client/consensus/grandpa/src/lib.rs @@ -67,7 +67,7 @@ use sc_client_api::{ BlockchainEvents, CallExecutor, ExecutorProvider, Finalizer, LockImportRun, StorageProvider, }; use sc_consensus::BlockImport; -use sc_network::types::ProtocolName; +use sc_network::{types::ProtocolName, NotificationService}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; @@ -690,6 +690,8 @@ pub struct GrandpaParams { pub network: N, /// Event stream for syncing-related events. pub sync: S, + /// Handle for interacting with `Notifications`. + pub notification_service: Box, /// A voting rule used to potentially restrict target votes. pub voting_rule: VR, /// The prometheus metrics registry. @@ -710,21 +712,21 @@ pub struct GrandpaParams { /// For standard protocol name see [`crate::protocol_standard_name`]. pub fn grandpa_peers_set_config( protocol_name: ProtocolName, -) -> sc_network::config::NonDefaultSetConfig { +) -> (sc_network::config::NonDefaultSetConfig, Box) { use communication::grandpa_protocol_name; - sc_network::config::NonDefaultSetConfig { - notifications_protocol: protocol_name, - fallback_names: grandpa_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect(), + sc_network::config::NonDefaultSetConfig::new( + protocol_name, + grandpa_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect(), // Notifications reach ~256kiB in size at the time of writing on Kusama and Polkadot. - max_notification_size: 1024 * 1024, - handshake: None, - set_config: sc_network::config::SetConfig { + 1024 * 1024, + None, + sc_network::config::SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), non_reserved_mode: sc_network::config::NonReservedPeerMode::Deny, }, - } + ) } /// Run a GRANDPA voter as a task. Provide configuration and a link to a @@ -747,6 +749,7 @@ where link, network, sync, + notification_service, voting_rule, prometheus_registry, shared_voter_state, @@ -773,6 +776,7 @@ where let network = NetworkBridge::new( network, sync, + notification_service, config.clone(), persistent_data.set_state.clone(), prometheus_registry.as_ref(), diff --git a/substrate/client/consensus/grandpa/src/observer.rs b/substrate/client/consensus/grandpa/src/observer.rs index 8541baa822bb..608ff5e46a0e 100644 --- a/substrate/client/consensus/grandpa/src/observer.rs +++ b/substrate/client/consensus/grandpa/src/observer.rs @@ -28,6 +28,7 @@ use futures::prelude::*; use log::{debug, info, warn}; use sc_client_api::backend::Backend; +use sc_network::NotificationService; use sc_telemetry::TelemetryHandle; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_blockchain::HeaderMetadata; @@ -168,6 +169,7 @@ pub fn run_grandpa_observer( link: LinkHalf, network: N, sync: S, + notification_service: Box, ) -> sp_blockchain::Result + Send> where BE: Backend + Unpin + 'static, @@ -189,6 +191,7 @@ where let network = NetworkBridge::new( network, sync, + notification_service, config.clone(), persistent_data.set_state.clone(), None, @@ -414,14 +417,14 @@ mod tests { use futures::executor; - /// Ensure `Future` implementation of `ObserverWork` is polling its `NetworkBridge`. Regression - /// test for bug introduced in d4fbb897c and fixed in b7af8b339. + /// Ensure `Future` implementation of `ObserverWork` is polling its `NetworkBridge`. + /// Regression test for bug introduced in d4fbb897c and fixed in b7af8b339. /// - /// When polled, `NetworkBridge` forwards reputation change requests from the `GossipValidator` - /// to the underlying `dyn Network`. This test triggers a reputation change by calling - /// `GossipValidator::validate` with an invalid gossip message. After polling the `ObserverWork` - /// which should poll the `NetworkBridge`, the reputation change should be forwarded to the test - /// network. + /// When polled, `NetworkBridge` forwards reputation change requests from the + /// `GossipValidator` to the underlying `dyn Network`. This test triggers a reputation change + /// by calling `GossipValidator::validate` with an invalid gossip message. After polling the + /// `ObserverWork` which should poll the `NetworkBridge`, the reputation change should be + /// forwarded to the test network. #[test] fn observer_work_polls_underlying_network_bridge() { // Create a test network. @@ -463,12 +466,6 @@ mod tests { // validator to the test network. assert!(observer.now_or_never().is_none()); - // Ignore initial event stream request by gossip engine. - match tester.events.next().now_or_never() { - Some(Some(Event::EventStream(_))) => {}, - _ => panic!("expected event stream request"), - }; - assert_matches!(tester.events.next().now_or_never(), Some(Some(Event::Report(_, _)))); }); } diff --git a/substrate/client/consensus/grandpa/src/tests.rs b/substrate/client/consensus/grandpa/src/tests.rs index 0175f7d1b473..6fa3f3637671 100644 --- a/substrate/client/consensus/grandpa/src/tests.rs +++ b/substrate/client/consensus/grandpa/src/tests.rs @@ -317,6 +317,9 @@ fn initialize_grandpa( (net.peers[peer_id].network_service().clone(), link) }; let sync = net.peers[peer_id].sync_service().clone(); + let notification_service = net.peers[peer_id] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(); let grandpa_params = GrandpaParams { config: Config { @@ -332,6 +335,7 @@ fn initialize_grandpa( link, network: net_service, sync, + notification_service, voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -472,6 +476,9 @@ async fn finalize_3_voters_1_full_observer() { let net_service = net.peers[peer_id].network_service().clone(); let sync = net.peers[peer_id].sync_service().clone(); let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); + let notification_service = net.peers[peer_id] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(); let grandpa_params = GrandpaParams { config: Config { @@ -487,6 +494,7 @@ async fn finalize_3_voters_1_full_observer() { link, network: net_service, sync, + notification_service, voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -557,14 +565,17 @@ async fn transition_3_voters_twice_1_full_observer() { for (peer_id, local_key) in all_peers.clone().into_iter().enumerate() { let keystore = create_keystore(local_key); - let (net_service, link, sync) = { - let net = net.lock(); + let (net_service, link, sync, notification_service) = { + let mut net = net.lock(); let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed"); ( net.peers[peer_id].network_service().clone(), link, net.peers[peer_id].sync_service().clone(), + net.peers[peer_id] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(), ) }; @@ -582,6 +593,7 @@ async fn transition_3_voters_twice_1_full_observer() { link, network: net_service, sync, + notification_service, voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -1019,6 +1031,9 @@ async fn voter_persists_its_votes() { communication::NetworkBridge::new( net.peers[1].network_service().clone(), net.peers[1].sync_service().clone(), + net.peers[1] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(), config.clone(), set_state, None, @@ -1037,6 +1052,9 @@ async fn voter_persists_its_votes() { (net.peers[0].network_service().clone(), link) }; let sync = net.peers[0].sync_service().clone(); + let notification_service = net.peers[0] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(); let grandpa_params = GrandpaParams { config: Config { @@ -1052,6 +1070,7 @@ async fn voter_persists_its_votes() { link, network: net_service, sync, + notification_service, voting_rule: VotingRulesBuilder::default().build(), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -1076,6 +1095,9 @@ async fn voter_persists_its_votes() { net.add_authority_peer(); let net_service = net.peers[2].network_service().clone(); let sync = net.peers[2].sync_service().clone(); + let notification_service = net.peers[2] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(); // but we'll reuse the client from the first peer (alice_voter1) // since we want to share the same database, so that we can // read the persisted state after aborting alice_voter1. @@ -1098,6 +1120,7 @@ async fn voter_persists_its_votes() { link, network: net_service, sync, + notification_service, voting_rule: VotingRulesBuilder::default().build(), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -1249,6 +1272,9 @@ async fn finalize_3_voters_1_light_observer() { let mut net = GrandpaTestNet::new(TestApi::new(voters), 3, 1); let voters = initialize_grandpa(&mut net, authorities); + let notification_service = net.peers[3] + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(); let observer = observer::run_grandpa_observer( Config { gossip_duration: TEST_GOSSIP_DURATION, @@ -1263,6 +1289,7 @@ async fn finalize_3_voters_1_light_observer() { net.peers[3].data.lock().take().expect("link initialized at startup; qed"), net.peers[3].network_service().clone(), net.peers[3].sync_service().clone(), + notification_service, ) .unwrap(); net.peer(0).push_blocks(20, false); @@ -1311,6 +1338,10 @@ async fn voter_catches_up_to_latest_round_when_behind() { link, network: net.peer(peer_id).network_service().clone(), sync: net.peer(peer_id).sync_service().clone(), + notification_service: net + .peer(peer_id) + .take_notification_service(&grandpa_protocol_name::NAME.into()) + .unwrap(), voting_rule: (), prometheus_registry: None, shared_voter_state: SharedVoterState::empty(), @@ -1403,6 +1434,7 @@ fn test_environment_with_select_chain( keystore: Option, network_service: N, sync_service: S, + notification_service: Box, select_chain: SC, voting_rule: VR, ) -> TestEnvironment @@ -1427,6 +1459,7 @@ where let network = NetworkBridge::new( network_service.clone(), sync_service, + notification_service, config.clone(), set_state.clone(), None, @@ -1456,6 +1489,7 @@ fn test_environment( keystore: Option, network_service: N, sync_service: S, + notification_service: Box, voting_rule: VR, ) -> TestEnvironment, VR> where @@ -1468,6 +1502,7 @@ where keystore, network_service, sync_service, + notification_service, link.select_chain.clone(), voting_rule, ) @@ -1484,14 +1519,22 @@ async fn grandpa_environment_respects_voting_rules() { let peer = net.peer(0); let network_service = peer.network_service().clone(); let sync_service = peer.sync_service().clone(); + let mut notification_service = + peer.take_notification_service(&grandpa_protocol_name::NAME.into()).unwrap(); let link = peer.data.lock().take().unwrap(); // add 21 blocks let hashes = peer.push_blocks(21, false); // create an environment with no voting rule restrictions - let unrestricted_env = - test_environment(&link, None, network_service.clone(), sync_service.clone(), ()); + let unrestricted_env = test_environment( + &link, + None, + network_service.clone(), + sync_service.clone(), + notification_service.clone().unwrap(), + (), + ); // another with 3/4 unfinalized chain voting rule restriction let three_quarters_env = test_environment( @@ -1499,6 +1542,7 @@ async fn grandpa_environment_respects_voting_rules() { None, network_service.clone(), sync_service.clone(), + notification_service.clone().unwrap(), voting_rule::ThreeQuartersOfTheUnfinalizedChain, ); @@ -1509,6 +1553,7 @@ async fn grandpa_environment_respects_voting_rules() { None, network_service.clone(), sync_service, + notification_service, VotingRulesBuilder::default().build(), ); @@ -1602,6 +1647,8 @@ async fn grandpa_environment_passes_actual_best_block_to_voting_rules() { let peer = net.peer(0); let network_service = peer.network_service().clone(); let sync_service = peer.sync_service().clone(); + let notification_service = + peer.take_notification_service(&grandpa_protocol_name::NAME.into()).unwrap(); let link = peer.data.lock().take().unwrap(); let client = peer.client().as_client().clone(); let select_chain = MockSelectChain::default(); @@ -1616,6 +1663,7 @@ async fn grandpa_environment_passes_actual_best_block_to_voting_rules() { None, network_service.clone(), sync_service, + notification_service, select_chain.clone(), voting_rule::BeforeBestBlockBy(5), ); @@ -1663,6 +1711,8 @@ async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_targ let peer = net.peer(0); let network_service = peer.network_service().clone(); let sync_service = peer.sync_service().clone(); + let notification_service = + peer.take_notification_service(&grandpa_protocol_name::NAME.into()).unwrap(); let link = peer.data.lock().take().unwrap(); let client = peer.client().as_client().clone(); let select_chain = MockSelectChain::default(); @@ -1672,6 +1722,7 @@ async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_targ None, network_service.clone(), sync_service.clone(), + notification_service, select_chain.clone(), voting_rule.clone(), ); @@ -1774,11 +1825,19 @@ async fn grandpa_environment_never_overwrites_round_voter_state() { let peer = net.peer(0); let network_service = peer.network_service().clone(); let sync_service = peer.sync_service().clone(); + let notification_service = + peer.take_notification_service(&grandpa_protocol_name::NAME.into()).unwrap(); let link = peer.data.lock().take().unwrap(); let keystore = create_keystore(peers[0]); - let environment = - test_environment(&link, Some(keystore), network_service.clone(), sync_service, ()); + let environment = test_environment( + &link, + Some(keystore), + network_service.clone(), + sync_service, + notification_service, + (), + ); let round_state = || finality_grandpa::round::State::genesis(Default::default()); let base = || Default::default(); @@ -2001,9 +2060,18 @@ async fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() { let peer = net.peer(0); let network_service = peer.network_service().clone(); let sync_service = peer.sync_service().clone(); + let notification_service = + peer.take_notification_service(&grandpa_protocol_name::NAME.into()).unwrap(); let link = peer.data.lock().take().unwrap(); let keystore = create_keystore(alice); - test_environment(&link, Some(keystore), network_service.clone(), sync_service, ()) + test_environment( + &link, + Some(keystore), + network_service.clone(), + sync_service, + notification_service, + (), + ) }; let signed_prevote = { diff --git a/substrate/client/network-gossip/Cargo.toml b/substrate/client/network-gossip/Cargo.toml index 73d2d3fa051e..98c75fc2159d 100644 --- a/substrate/client/network-gossip/Cargo.toml +++ b/substrate/client/network-gossip/Cargo.toml @@ -28,5 +28,7 @@ sp-runtime = { path = "../../primitives/runtime" } [dev-dependencies] tokio = "1.22.0" +async-trait = "0.1.73" +codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } quickcheck = { version = "1.0.3", default-features = false } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/substrate/client/network-gossip/src/bridge.rs b/substrate/client/network-gossip/src/bridge.rs index 6a3790ee2b2b..595cca9b773b 100644 --- a/substrate/client/network-gossip/src/bridge.rs +++ b/substrate/client/network-gossip/src/bridge.rs @@ -21,7 +21,11 @@ use crate::{ Network, Syncing, Validator, }; -use sc_network::{event::Event, types::ProtocolName, ReputationChange}; +use sc_network::{ + service::traits::{NotificationEvent, ValidationResult}, + types::ProtocolName, + NotificationService, ReputationChange, +}; use sc_network_common::sync::SyncEvent; use futures::{ @@ -48,10 +52,10 @@ pub struct GossipEngine { periodic_maintenance_interval: futures_timer::Delay, protocol: ProtocolName, - /// Incoming events from the network. - network_event_stream: Pin + Send>>, /// Incoming events from the syncing service. sync_event_stream: Pin + Send>>, + /// Handle for polling notification-related events. + notification_service: Box, /// Outgoing events to the consumer. message_sinks: HashMap>>, /// Buffered messages (see [`ForwardingState`]). @@ -81,6 +85,7 @@ impl GossipEngine { pub fn new( network: N, sync: S, + notification_service: Box, protocol: impl Into, validator: Arc>, metrics_registry: Option<&Registry>, @@ -91,17 +96,16 @@ impl GossipEngine { S: Syncing + Send + Clone + 'static, { let protocol = protocol.into(); - let network_event_stream = network.event_stream("network-gossip"); let sync_event_stream = sync.event_stream("network-gossip"); GossipEngine { state_machine: ConsensusGossip::new(validator, protocol.clone(), metrics_registry), network: Box::new(network), sync: Box::new(sync), + notification_service, periodic_maintenance_interval: futures_timer::Delay::new(PERIODIC_MAINTENANCE_INTERVAL), protocol, - network_event_stream, sync_event_stream, message_sinks: HashMap::new(), forwarding_state: ForwardingState::Idle, @@ -173,6 +177,11 @@ impl GossipEngine { pub fn announce(&self, block: B::Hash, associated_data: Option>) { self.sync.announce_block(block, associated_data); } + + /// Consume [`GossipEngine`] and return the notification service. + pub fn take_notification_service(self) -> Box { + self.notification_service + } } impl Future for GossipEngine { @@ -184,46 +193,40 @@ impl Future for GossipEngine { 'outer: loop { match &mut this.forwarding_state { ForwardingState::Idle => { - let net_event_stream = this.network_event_stream.poll_next_unpin(cx); + let next_notification_event = + this.notification_service.next_event().poll_unpin(cx); let sync_event_stream = this.sync_event_stream.poll_next_unpin(cx); - if net_event_stream.is_pending() && sync_event_stream.is_pending() { + if next_notification_event.is_pending() && sync_event_stream.is_pending() { break } - match net_event_stream { + match next_notification_event { Poll::Ready(Some(event)) => match event { - Event::NotificationStreamOpened { remote, protocol, role, .. } => - if protocol == this.protocol { - this.state_machine.new_peer(&mut *this.network, remote, role); - }, - Event::NotificationStreamClosed { remote, protocol } => { - if protocol == this.protocol { - this.state_machine - .peer_disconnected(&mut *this.network, remote); - } + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + let _ = result_tx.send(ValidationResult::Accept); }, - Event::NotificationsReceived { remote, messages } => { - let messages = messages - .into_iter() - .filter_map(|(engine, data)| { - if engine == this.protocol { - Some(data.to_vec()) - } else { - None - } - }) - .collect(); - + NotificationEvent::NotificationStreamOpened { + peer, handshake, .. + } => { + let Some(role) = this.network.peer_role(peer, handshake) else { + log::debug!(target: "gossip", "role for {peer} couldn't be determined"); + continue + }; + + this.state_machine.new_peer(&mut *this.network, peer, role); + }, + NotificationEvent::NotificationStreamClosed { peer } => { + this.state_machine.peer_disconnected(&mut *this.network, peer); + }, + NotificationEvent::NotificationReceived { peer, notification } => { let to_forward = this.state_machine.on_incoming( &mut *this.network, - remote, - messages, + peer, + vec![notification], ); - this.forwarding_state = ForwardingState::Busy(to_forward.into()); }, - Event::Dht(_) => {}, }, // The network event stream closed. Do the same for [`GossipValidator`]. Poll::Ready(None) => { @@ -328,15 +331,19 @@ impl futures::future::FusedFuture for GossipEngine { mod tests { use super::*; use crate::{multiaddr::Multiaddr, ValidationResult, ValidatorContext}; + use codec::{DecodeAll, Encode}; use futures::{ - channel::mpsc::{unbounded, UnboundedSender}, + channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, executor::{block_on, block_on_stream}, future::poll_fn, }; use quickcheck::{Arbitrary, Gen, QuickCheck}; use sc_network::{ - config::MultiaddrWithPeerId, NetworkBlock, NetworkEventStream, NetworkNotification, - NetworkPeers, NotificationSenderError, NotificationSenderT as NotificationSender, + config::MultiaddrWithPeerId, + service::traits::{Direction, MessageSink, NotificationEvent}, + Event, NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, + NotificationSenderError, NotificationSenderT as NotificationSender, NotificationService, + Roles, }; use sc_network_common::{role::ObservedRole, sync::SyncEventStream}; use sp_runtime::{ @@ -350,14 +357,10 @@ mod tests { use substrate_test_runtime_client::runtime::Block; #[derive(Clone, Default)] - struct TestNetwork { - inner: Arc>, - } + struct TestNetwork {} #[derive(Clone, Default)] - struct TestNetworkInner { - event_senders: Vec>, - } + struct TestNetworkInner {} impl NetworkPeers for TestNetwork { fn set_authorized_peers(&self, _peers: HashSet) { @@ -421,14 +424,17 @@ mod tests { fn sync_num_connected(&self) -> usize { unimplemented!(); } + + fn peer_role(&self, _peer_id: PeerId, handshake: Vec) -> Option { + Roles::decode_all(&mut &handshake[..]) + .ok() + .and_then(|role| Some(ObservedRole::from(role))) + } } impl NetworkEventStream for TestNetwork { fn event_stream(&self, _name: &'static str) -> Pin + Send>> { - let (tx, rx) = unbounded(); - self.inner.lock().unwrap().event_senders.push(tx); - - Box::pin(rx) + unimplemented!(); } } @@ -500,6 +506,54 @@ mod tests { } } + #[derive(Debug)] + pub(crate) struct TestNotificationService { + rx: UnboundedReceiver, + } + + #[async_trait::async_trait] + impl sc_network::service::traits::NotificationService for TestNotificationService { + async fn open_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + async fn close_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + fn send_sync_notification(&self, _peer: &PeerId, _notification: Vec) { + unimplemented!(); + } + + async fn send_async_notification( + &self, + _peer: &PeerId, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } + + async fn set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + async fn next_event(&mut self) -> Option { + self.rx.next().await + } + + fn clone(&mut self) -> Result, ()> { + unimplemented!(); + } + + fn protocol(&self) -> &ProtocolName { + unimplemented!(); + } + + fn message_sink(&self, _peer: &PeerId) -> Option> { + unimplemented!(); + } + } + struct AllowAll; impl Validator for AllowAll { fn validate( @@ -520,16 +574,19 @@ mod tests { fn returns_when_network_event_stream_closes() { let network = TestNetwork::default(); let sync = Arc::new(TestSync::default()); + let (tx, rx) = unbounded(); + let notification_service = Box::new(TestNotificationService { rx }); let mut gossip_engine = GossipEngine::::new( network.clone(), sync, + notification_service, "/my_protocol", Arc::new(AllowAll {}), None, ); - // Drop network event stream sender side. - drop(network.inner.lock().unwrap().event_senders.pop()); + // drop notification service sender side. + drop(tx); block_on(poll_fn(move |ctx| { if let Poll::Pending = gossip_engine.poll_unpin(ctx) { @@ -549,42 +606,37 @@ mod tests { let remote_peer = PeerId::random(); let network = TestNetwork::default(); let sync = Arc::new(TestSync::default()); + let (mut tx, rx) = unbounded(); + let notification_service = Box::new(TestNotificationService { rx }); let mut gossip_engine = GossipEngine::::new( network.clone(), sync.clone(), + notification_service, protocol.clone(), Arc::new(AllowAll {}), None, ); - let mut event_sender = network.inner.lock().unwrap().event_senders.pop().unwrap(); - // Register the remote peer. - event_sender - .start_send(Event::NotificationStreamOpened { - remote: remote_peer, - protocol: protocol.clone(), - negotiated_fallback: None, - role: ObservedRole::Authority, - received_handshake: vec![], - }) - .expect("Event stream is unbounded; qed."); + tx.send(NotificationEvent::NotificationStreamOpened { + peer: remote_peer, + direction: Direction::Inbound, + negotiated_fallback: None, + handshake: Roles::FULL.encode(), + }) + .await + .unwrap(); let messages = vec![vec![1], vec![2]]; - let events = messages - .iter() - .cloned() - .map(|m| Event::NotificationsReceived { - remote: remote_peer, - messages: vec![(protocol.clone(), m.into())], - }) - .collect::>(); // Send first event before subscribing. - event_sender - .start_send(events[0].clone()) - .expect("Event stream is unbounded; qed."); + tx.send(NotificationEvent::NotificationReceived { + peer: remote_peer, + notification: messages[0].clone().into(), + }) + .await + .unwrap(); let mut subscribers = vec![]; for _ in 0..2 { @@ -592,9 +644,12 @@ mod tests { } // Send second event after subscribing. - event_sender - .start_send(events[1].clone()) - .expect("Event stream is unbounded; qed."); + tx.send(NotificationEvent::NotificationReceived { + peer: remote_peer, + notification: messages[1].clone().into(), + }) + .await + .unwrap(); tokio::spawn(gossip_engine); @@ -671,6 +726,8 @@ mod tests { let remote_peer = PeerId::random(); let network = TestNetwork::default(); let sync = Arc::new(TestSync::default()); + let (mut tx, rx) = unbounded(); + let notification_service = Box::new(TestNotificationService { rx }); let num_channels_per_topic = channels.iter().fold( HashMap::new(), @@ -698,6 +755,7 @@ mod tests { let mut gossip_engine = GossipEngine::::new( network.clone(), sync.clone(), + notification_service, protocol.clone(), Arc::new(TestValidator {}), None, @@ -723,22 +781,18 @@ mod tests { } } - let mut event_sender = network.inner.lock().unwrap().event_senders.pop().unwrap(); - // Register the remote peer. - event_sender - .start_send(Event::NotificationStreamOpened { - remote: remote_peer, - protocol: protocol.clone(), - negotiated_fallback: None, - role: ObservedRole::Authority, - received_handshake: vec![], - }) - .expect("Event stream is unbounded; qed."); + tx.start_send(NotificationEvent::NotificationStreamOpened { + peer: remote_peer, + direction: Direction::Inbound, + negotiated_fallback: None, + handshake: Roles::FULL.encode(), + }) + .unwrap(); // Send messages into the network event stream. for (i_notification, messages) in notifications.iter().enumerate() { - let messages = messages + let messages: Vec> = messages .into_iter() .enumerate() .map(|(i_message, Message { topic })| { @@ -751,13 +805,17 @@ mod tests { message.push(i_notification.try_into().unwrap()); message.push(i_message.try_into().unwrap()); - (protocol.clone(), message.into()) + message.into() }) .collect(); - event_sender - .start_send(Event::NotificationsReceived { remote: remote_peer, messages }) - .expect("Event stream is unbounded; qed."); + for message in messages { + tx.start_send(NotificationEvent::NotificationReceived { + peer: remote_peer, + notification: message, + }) + .unwrap(); + } } let mut received_msgs_per_topic_all_chan = HashMap::::new(); diff --git a/substrate/client/network-gossip/src/state_machine.rs b/substrate/client/network-gossip/src/state_machine.rs index 4bfb5a7d37f4..724a4e3e07b8 100644 --- a/substrate/client/network-gossip/src/state_machine.rs +++ b/substrate/client/network-gossip/src/state_machine.rs @@ -651,6 +651,10 @@ mod tests { fn sync_num_connected(&self) -> usize { unimplemented!(); } + + fn peer_role(&self, _peer_id: PeerId, _handshake: Vec) -> Option { + None + } } impl NetworkEventStream for NoOpNetwork { diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index 72e38ce498d3..2ed366037a51 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -37,6 +37,8 @@ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.85" smallvec = "1.11.0" thiserror = "1.0" +tokio = { version = "1.22.0", features = ["macros", "sync"] } +tokio-stream = "0.1.7" unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } zeroize = "1.4.3" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } diff --git a/substrate/client/network/common/src/role.rs b/substrate/client/network/common/src/role.rs index cd43f6655b72..487ad7a5107f 100644 --- a/substrate/client/network/common/src/role.rs +++ b/substrate/client/network/common/src/role.rs @@ -24,7 +24,7 @@ use codec::{self, Encode, EncodeLike, Input, Output}; /// > **Note**: This enum is different from the `Role` enum. The `Role` enum indicates what a /// > node says about itself, while `ObservedRole` is a `Role` merged with the /// > information known locally about that node. -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ObservedRole { /// Full node. Full, @@ -41,6 +41,18 @@ impl ObservedRole { } } +impl From for ObservedRole { + fn from(roles: Roles) -> Self { + if roles.is_authority() { + ObservedRole::Authority + } else if roles.is_full() { + ObservedRole::Full + } else { + ObservedRole::Light + } + } +} + /// Role of the local node. #[derive(Debug, Clone)] pub enum Role { diff --git a/substrate/client/network/src/config.rs b/substrate/client/network/src/config.rs index d069c3f458ff..57250b1abd92 100644 --- a/substrate/client/network/src/config.rs +++ b/substrate/client/network/src/config.rs @@ -23,10 +23,11 @@ pub use crate::{ discovery::DEFAULT_KADEMLIA_REPLICATION_FACTOR, - protocol::NotificationsSink, + protocol::{notification_service, NotificationsSink, ProtocolHandlePair}, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, + service::traits::NotificationService, types::ProtocolName, }; @@ -42,7 +43,6 @@ pub use sc_network_common::{ sync::{warp::WarpSyncProvider, SyncMode}, ExHashT, }; -use sc_utils::mpsc::TracingUnboundedSender; use sp_runtime::traits::Block as BlockT; use std::{ @@ -454,14 +454,14 @@ impl Default for SetConfig { /// /// > **Note**: As new fields might be added in the future, please consider using the `new` method /// > and modifiers instead of creating this struct manually. -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct NonDefaultSetConfig { /// Name of the notifications protocols of this set. A substream on this set will be /// considered established once this protocol is open. /// /// > **Note**: This field isn't present for the default set, as this is handled internally /// > by the networking code. - pub notifications_protocol: ProtocolName, + protocol_name: ProtocolName, /// If the remote reports that it doesn't support the protocol indicated in the /// `notifications_protocol` field, then each of these fallback names will be tried one by @@ -469,37 +469,84 @@ pub struct NonDefaultSetConfig { /// /// If a fallback is used, it will be reported in /// `sc_network::protocol::event::Event::NotificationStreamOpened::negotiated_fallback` - pub fallback_names: Vec, + fallback_names: Vec, /// Handshake of the protocol /// /// NOTE: Currently custom handshakes are not fully supported. See issue #5685 for more /// details. This field is temporarily used to allow moving the hardcoded block announcement /// protocol out of `protocol.rs`. - pub handshake: Option, + handshake: Option, /// Maximum allowed size of single notifications. - pub max_notification_size: u64, + max_notification_size: u64, /// Base configuration. - pub set_config: SetConfig, + set_config: SetConfig, + + /// Notification handle. + /// + /// Notification handle is created during `NonDefaultSetConfig` creation and its other half, + /// `Box` is given to the protocol created the config and + /// `ProtocolHandle` is given to `Notifications` when it initializes itself. This handle allows + /// `Notifications ` to communicate with the protocol directly without relaying events through + /// `sc-network.` + protocol_handle_pair: ProtocolHandlePair, } impl NonDefaultSetConfig { /// Creates a new [`NonDefaultSetConfig`]. Zero slots and accepts only reserved nodes. - pub fn new(notifications_protocol: ProtocolName, max_notification_size: u64) -> Self { - Self { - notifications_protocol, - max_notification_size, - fallback_names: Vec::new(), - handshake: None, - set_config: SetConfig { - in_peers: 0, - out_peers: 0, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Deny, + /// Also returns an object which allows the protocol to communicate with `Notifications`. + pub fn new( + protocol_name: ProtocolName, + fallback_names: Vec, + max_notification_size: u64, + handshake: Option, + set_config: SetConfig, + ) -> (Self, Box) { + let (protocol_handle_pair, notification_service) = + notification_service(protocol_name.clone()); + ( + Self { + protocol_name, + max_notification_size, + fallback_names, + handshake, + set_config, + protocol_handle_pair, }, - } + notification_service, + ) + } + + /// Get reference to protocol name. + pub fn protocol_name(&self) -> &ProtocolName { + &self.protocol_name + } + + /// Get reference to fallback protocol names. + pub fn fallback_names(&self) -> impl Iterator { + self.fallback_names.iter() + } + + /// Get reference to handshake. + pub fn handshake(&self) -> &Option { + &self.handshake + } + + /// Get maximum notification size. + pub fn max_notification_size(&self) -> u64 { + self.max_notification_size + } + + /// Get reference to `SetConfig`. + pub fn set_config(&self) -> &SetConfig { + &self.set_config + } + + /// Take `ProtocolHandlePair` from `NonDefaultSetConfig` + pub fn take_protocol_handle(self) -> ProtocolHandlePair { + self.protocol_handle_pair } /// Modifies the configuration to allow non-reserved nodes. @@ -703,9 +750,6 @@ pub struct Params { /// Block announce protocol configuration pub block_announce_config: NonDefaultSetConfig, - - /// TX channel for direct communication with `SyncingEngine` and `Protocol`. - pub tx: TracingUnboundedSender>, } /// Full network configuration. diff --git a/substrate/client/network/src/error.rs b/substrate/client/network/src/error.rs index f0828fb821f3..01e8356fb553 100644 --- a/substrate/client/network/src/error.rs +++ b/substrate/client/network/src/error.rs @@ -68,6 +68,15 @@ pub enum Error { /// Name of the protocol registered multiple times. protocol: ProtocolName, }, + /// Peer does not exist. + #[error("Peer `{0}` does not exist.")] + PeerDoesntExist(PeerId), + /// Channel closed. + #[error("Channel closed")] + ChannelClosed, + /// Connection closed. + #[error("Connection closed")] + ConnectionClosed, } // Make `Debug` use the `Display` implementation. diff --git a/substrate/client/network/src/lib.rs b/substrate/client/network/src/lib.rs index ee3075968784..2f297f45ccc6 100644 --- a/substrate/client/network/src/lib.rs +++ b/substrate/client/network/src/lib.rs @@ -244,7 +244,6 @@ mod behaviour; mod protocol; -mod service; #[cfg(test)] mod mock; @@ -258,6 +257,7 @@ pub mod peer_info; pub mod peer_store; pub mod protocol_controller; pub mod request_responses; +pub mod service; pub mod transport; pub mod types; pub mod utils; @@ -267,7 +267,7 @@ pub use event::{DhtEvent, Event, SyncEvent}; pub use libp2p::{multiaddr, Multiaddr, PeerId}; pub use request_responses::{Config, IfDisconnected, RequestFailure}; pub use sc_network_common::{ - role::ObservedRole, + role::{ObservedRole, Roles}, sync::{ warp::{WarpSyncPhase, WarpSyncProgress}, ExtendedPeerInfo, StateDownloadProgress, SyncEventStream, SyncState, SyncStatusProvider, @@ -277,13 +277,14 @@ pub use sc_network_common::{ pub use service::{ signature::Signature, traits::{ - KademliaKey, NetworkBlock, NetworkDHTProvider, NetworkEventStream, NetworkNotification, - NetworkPeers, NetworkRequest, NetworkSigner, NetworkStateInfo, NetworkStatus, - NetworkStatusProvider, NetworkSyncForkRequest, NotificationSender as NotificationSenderT, - NotificationSenderError, NotificationSenderReady, + KademliaKey, MessageSink, NetworkBlock, NetworkDHTProvider, NetworkEventStream, + NetworkNotification, NetworkPeers, NetworkRequest, NetworkSigner, NetworkStateInfo, + NetworkStatus, NetworkStatusProvider, NetworkSyncForkRequest, + NotificationSender as NotificationSenderT, NotificationSenderError, + NotificationSenderReady, NotificationService, }, - DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, NotificationsSink, - OutboundFailure, PublicKey, + DecodingError, Keypair, NetworkService, NetworkWorker, NotificationCommand, NotificationSender, + NotificationsSink, OutboundFailure, ProtocolHandle, PublicKey, }; pub use types::ProtocolName; diff --git a/substrate/client/network/src/mock.rs b/substrate/client/network/src/mock.rs index bc596b0fa579..534b81189707 100644 --- a/substrate/client/network/src/mock.rs +++ b/substrate/client/network/src/mock.rs @@ -20,6 +20,7 @@ use crate::{peer_store::PeerStoreProvider, protocol_controller::ProtocolHandle, ReputationChange}; use libp2p::PeerId; +use sc_network_common::role::ObservedRole; use std::collections::HashSet; /// No-op `PeerStore`. @@ -49,6 +50,14 @@ impl PeerStoreProvider for MockPeerStore { 0 } + fn peer_role(&self, _peer_id: &PeerId) -> Option { + None + } + + fn set_peer_role(&mut self, _peer_id: &PeerId, _role: ObservedRole) { + unimplemented!(); + } + fn outgoing_candidates(&self, _count: usize, _ignored: HashSet<&PeerId>) -> Vec { unimplemented!() } diff --git a/substrate/client/network/src/peer_store.rs b/substrate/client/network/src/peer_store.rs index 35d17e588cb9..4b28b8e75440 100644 --- a/substrate/client/network/src/peer_store.rs +++ b/substrate/client/network/src/peer_store.rs @@ -23,7 +23,7 @@ use libp2p::PeerId; use log::trace; use parking_lot::Mutex; use partial_sort::PartialSort; -use sc_network_common::types::ReputationChange; +use sc_network_common::{role::ObservedRole, types::ReputationChange}; use std::{ cmp::{Ord, Ordering, PartialOrd}, collections::{hash_map::Entry, HashMap, HashSet}, @@ -66,9 +66,15 @@ pub trait PeerStoreProvider: Debug + Send { /// Adjust peer reputation. fn report_peer(&mut self, peer_id: PeerId, change: ReputationChange); + /// Set peer role. + fn set_peer_role(&mut self, peer_id: &PeerId, role: ObservedRole); + /// Get peer reputation. fn peer_reputation(&self, peer_id: &PeerId) -> i32; + /// Get peer role, if available. + fn peer_role(&self, peer_id: &PeerId) -> Option; + /// Get candidates with highest reputations for initiating outgoing connections. fn outgoing_candidates(&self, count: usize, ignored: HashSet<&PeerId>) -> Vec; } @@ -96,10 +102,18 @@ impl PeerStoreProvider for PeerStoreHandle { self.inner.lock().report_peer(peer_id, change) } + fn set_peer_role(&mut self, peer_id: &PeerId, role: ObservedRole) { + self.inner.lock().set_peer_role(peer_id, role) + } + fn peer_reputation(&self, peer_id: &PeerId) -> i32 { self.inner.lock().peer_reputation(peer_id) } + fn peer_role(&self, peer_id: &PeerId) -> Option { + self.inner.lock().peer_role(peer_id) + } + fn outgoing_candidates(&self, count: usize, ignored: HashSet<&PeerId>) -> Vec { self.inner.lock().outgoing_candidates(count, ignored) } @@ -122,13 +136,19 @@ impl PeerStoreHandle { #[derive(Debug, Clone, Copy)] struct PeerInfo { + /// Reputation of the peer. reputation: i32, + + /// Instant when the peer was last updated. last_updated: Instant, + + /// Role of the peer, if known. + role: Option, } impl Default for PeerInfo { fn default() -> Self { - Self { reputation: 0, last_updated: Instant::now() } + Self { reputation: 0, last_updated: Instant::now(), role: None } } } @@ -242,10 +262,27 @@ impl PeerStoreInner { } } + fn set_peer_role(&mut self, peer_id: &PeerId, role: ObservedRole) { + log::trace!(target: LOG_TARGET, "Set {peer_id} role to {role:?}"); + + match self.peers.entry(*peer_id) { + Entry::Occupied(mut entry) => { + entry.get_mut().role = Some(role); + }, + Entry::Vacant(entry) => { + entry.insert(PeerInfo { role: Some(role), ..Default::default() }); + }, + } + } + fn peer_reputation(&self, peer_id: &PeerId) -> i32 { self.peers.get(peer_id).map_or(0, |info| info.reputation) } + fn peer_role(&self, peer_id: &PeerId) -> Option { + self.peers.get(peer_id).map_or(None, |info| info.role) + } + fn outgoing_candidates(&self, count: usize, ignored: HashSet<&PeerId>) -> Vec { let mut candidates = self .peers diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index 9b94f2883528..c78dfebdcb52 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -25,7 +25,7 @@ use crate::{ use bytes::Bytes; use codec::{DecodeAll, Encode}; -use futures::{channel::oneshot, stream::FuturesUnordered, StreamExt}; +use futures::{stream::FuturesUnordered, StreamExt}; use libp2p::{ core::Endpoint, swarm::{ @@ -36,8 +36,9 @@ use libp2p::{ }; use log::{debug, error, warn}; -use sc_network_common::{role::Roles, sync::message::BlockAnnouncesHandshake}; -use sc_utils::mpsc::{TracingUnboundedReceiver, TracingUnboundedSender}; +use prometheus_endpoint::Registry; +use sc_network_common::role::Roles; +use sc_utils::mpsc::TracingUnboundedReceiver; use sp_runtime::traits::Block as BlockT; use std::{ @@ -48,10 +49,12 @@ use std::{ task::Poll, }; -use message::{generic::Message as GenericMessage, Message}; use notifications::{Notifications, NotificationsOut}; -pub use notifications::{NotificationsSink, NotifsHandlerError, Ready}; +pub use notifications::{ + notification_service, NotificationCommand, NotificationsSink, NotifsHandlerError, + ProtocolHandle, ProtocolHandlePair, Ready, +}; mod notifications; @@ -91,7 +94,6 @@ pub struct Protocol { /// Connected peers on sync protocol. peers: HashMap, sync_substream_validations: FuturesUnordered, - tx: TracingUnboundedSender>, _marker: std::marker::PhantomData, } @@ -99,45 +101,68 @@ impl Protocol { /// Create a new instance. pub fn new( roles: Roles, + registry: &Option, notification_protocols: Vec, block_announces_protocol: config::NonDefaultSetConfig, peer_store_handle: PeerStoreHandle, protocol_controller_handles: Vec, from_protocol_controllers: TracingUnboundedReceiver, - tx: TracingUnboundedSender>, ) -> error::Result { - let behaviour = { - Notifications::new( - protocol_controller_handles, - from_protocol_controllers, - // NOTE: Block announcement protocol is still very much hardcoded into `Protocol`. - // This protocol must be the first notification protocol given to - // `Notifications` - iter::once(notifications::ProtocolConfig { - name: block_announces_protocol.notifications_protocol.clone(), - fallback_names: block_announces_protocol.fallback_names.clone(), - handshake: block_announces_protocol.handshake.as_ref().unwrap().to_vec(), - max_notification_size: block_announces_protocol.max_notification_size, - }) - .chain(notification_protocols.iter().map(|s| notifications::ProtocolConfig { - name: s.notifications_protocol.clone(), - fallback_names: s.fallback_names.clone(), - handshake: s.handshake.as_ref().map_or(roles.encode(), |h| (*h).to_vec()), - max_notification_size: s.max_notification_size, - })), + let (behaviour, notification_protocols) = { + let installed_protocols = iter::once(block_announces_protocol.protocol_name().clone()) + .chain(notification_protocols.iter().map(|p| p.protocol_name().clone())) + .collect::>(); + + ( + Notifications::new( + protocol_controller_handles, + from_protocol_controllers, + registry, + // NOTE: Block announcement protocol is still very much hardcoded into + // `Protocol`. This protocol must be the first notification protocol given to + // `Notifications` + iter::once(( + notifications::ProtocolConfig { + name: block_announces_protocol.protocol_name().clone(), + fallback_names: block_announces_protocol + .fallback_names() + .cloned() + .collect(), + handshake: block_announces_protocol + .handshake() + .as_ref() + .unwrap() + .to_vec(), + max_notification_size: block_announces_protocol.max_notification_size(), + }, + block_announces_protocol.take_protocol_handle(), + )) + .chain(notification_protocols.into_iter().map(|s| { + ( + notifications::ProtocolConfig { + name: s.protocol_name().clone(), + fallback_names: s.fallback_names().cloned().collect(), + handshake: s + .handshake() + .as_ref() + .map_or(roles.encode(), |h| (*h).to_vec()), + max_notification_size: s.max_notification_size(), + }, + s.take_protocol_handle(), + ) + })), + ), + installed_protocols, ) }; let protocol = Self { peer_store_handle, behaviour, - notification_protocols: iter::once(block_announces_protocol.notifications_protocol) - .chain(notification_protocols.iter().map(|s| s.notifications_protocol.clone())) - .collect(), + notification_protocols, bad_handshake_substreams: Default::default(), peers: HashMap::new(), sync_substream_validations: FuturesUnordered::new(), - tx, // TODO: remove when `BlockAnnouncesHandshake` is moved away from `Protocol` _marker: Default::default(), }; @@ -165,7 +190,7 @@ impl Protocol { /// Returns the number of peers we're connected to on sync protocol. pub fn num_connected_peers(&self) -> usize { - self.peers.len() + self.behaviour.num_connected_peers(HARDCODED_PEERSETS_SYNC) } /// Set handshake for the notification protocol. @@ -310,103 +335,9 @@ impl NetworkBehaviour for Protocol { received_handshake, notifications_sink, negotiated_fallback, - inbound, + .. } => { - // Set number 0 is hardcoded the default set of peers we sync from. - if set_id == HARDCODED_PEERSETS_SYNC { - // `received_handshake` can be either a `Status` message if received from the - // legacy substream ,or a `BlockAnnouncesHandshake` if received from the block - // announces substream. - match as DecodeAll>::decode_all(&mut &received_handshake[..]) { - Ok(GenericMessage::Status(handshake)) => { - let roles = handshake.roles; - let handshake = BlockAnnouncesHandshake:: { - roles: handshake.roles, - best_number: handshake.best_number, - best_hash: handshake.best_hash, - genesis_hash: handshake.genesis_hash, - }; - - let (tx, rx) = oneshot::channel(); - let _ = self.tx.unbounded_send( - crate::SyncEvent::NotificationStreamOpened { - inbound, - remote: peer_id, - received_handshake: handshake, - sink: notifications_sink, - tx, - }, - ); - self.sync_substream_validations.push(Box::pin(async move { - match rx.await { - Ok(accepted) => - if accepted { - Ok((peer_id, roles)) - } else { - Err(peer_id) - }, - Err(_) => Err(peer_id), - } - })); - - CustomMessageOutcome::None - }, - Ok(msg) => { - debug!( - target: "sync", - "Expected Status message from {}, but got {:?}", - peer_id, - msg, - ); - self.peer_store_handle.report_peer(peer_id, rep::BAD_MESSAGE); - CustomMessageOutcome::None - }, - Err(err) => { - match as DecodeAll>::decode_all( - &mut &received_handshake[..], - ) { - Ok(handshake) => { - let roles = handshake.roles; - - let (tx, rx) = oneshot::channel(); - let _ = self.tx.unbounded_send( - crate::SyncEvent::NotificationStreamOpened { - inbound, - remote: peer_id, - received_handshake: handshake, - sink: notifications_sink, - tx, - }, - ); - self.sync_substream_validations.push(Box::pin(async move { - match rx.await { - Ok(accepted) => - if accepted { - Ok((peer_id, roles)) - } else { - Err(peer_id) - }, - Err(_) => Err(peer_id), - } - })); - CustomMessageOutcome::None - }, - Err(err2) => { - log::debug!( - target: "sync", - "Couldn't decode handshake sent by {}: {:?}: {} & {}", - peer_id, - received_handshake, - err, - err2, - ); - self.peer_store_handle.report_peer(peer_id, rep::BAD_MESSAGE); - CustomMessageOutcome::None - }, - } - }, - } - } else { + if set_id != HARDCODED_PEERSETS_SYNC { match ( Roles::decode_all(&mut &received_handshake[..]), self.peers.get(&peer_id), @@ -441,16 +372,14 @@ impl NetworkBehaviour for Protocol { CustomMessageOutcome::None }, } + } else { + CustomMessageOutcome::None } }, NotificationsOut::CustomProtocolReplaced { peer_id, notifications_sink, set_id } => if self.bad_handshake_substreams.contains(&(peer_id, set_id)) { CustomMessageOutcome::None } else if set_id == HARDCODED_PEERSETS_SYNC { - let _ = self.tx.unbounded_send(crate::SyncEvent::NotificationSinkReplaced { - remote: peer_id, - sink: notifications_sink, - }); CustomMessageOutcome::None } else { CustomMessageOutcome::NotificationStreamReplaced { @@ -466,10 +395,6 @@ impl NetworkBehaviour for Protocol { // substream, and consequently shouldn't receive a closing event either. CustomMessageOutcome::None } else if set_id == HARDCODED_PEERSETS_SYNC { - let _ = self.tx.unbounded_send(crate::SyncEvent::NotificationStreamClosed { - remote: peer_id, - }); - self.peers.remove(&peer_id); CustomMessageOutcome::None } else { CustomMessageOutcome::NotificationStreamClosed { @@ -482,10 +407,6 @@ impl NetworkBehaviour for Protocol { if self.bad_handshake_substreams.contains(&(peer_id, set_id)) { CustomMessageOutcome::None } else if set_id == HARDCODED_PEERSETS_SYNC { - let _ = self.tx.unbounded_send(crate::SyncEvent::NotificationsReceived { - remote: peer_id, - messages: vec![message.freeze()], - }); CustomMessageOutcome::None } else { let protocol_name = self.notification_protocols[usize::from(set_id)].clone(); diff --git a/substrate/client/network/src/protocol/message.rs b/substrate/client/network/src/protocol/message.rs index 66dca2975375..247580083f99 100644 --- a/substrate/client/network/src/protocol/message.rs +++ b/substrate/client/network/src/protocol/message.rs @@ -29,6 +29,7 @@ use sc_network_common::message::RequestId; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; /// Type alias for using the message type using block type parameters. +#[allow(unused)] pub type Message = generic::Message< ::Header, ::Hash, diff --git a/substrate/client/network/src/protocol/notifications.rs b/substrate/client/network/src/protocol/notifications.rs index aa49cfcf9d44..b5b8b697456e 100644 --- a/substrate/client/network/src/protocol/notifications.rs +++ b/substrate/client/network/src/protocol/notifications.rs @@ -22,9 +22,11 @@ pub use self::{ behaviour::{Notifications, NotificationsOut, ProtocolConfig}, handler::{NotificationsSink, NotifsHandlerError, Ready}, + service::{notification_service, NotificationCommand, ProtocolHandle, ProtocolHandlePair}, }; mod behaviour; mod handler; +mod service; mod tests; mod upgrade; diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index 89513e004c6d..1ae8c35b4921 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -17,16 +17,19 @@ // along with this program. If not, see . use crate::{ - protocol::notifications::handler::{ - self, NotificationsSink, NotifsHandler, NotifsHandlerIn, NotifsHandlerOut, + config::ProtocolHandlePair, + protocol::notifications::{ + handler::{self, NotificationsSink, NotifsHandler, NotifsHandlerIn, NotifsHandlerOut}, + service::{metrics, NotificationCommand, ProtocolHandle}, }, protocol_controller::{self, IncomingIndex, Message, SetId}, + service::traits::{Direction, ValidationResult}, types::ProtocolName, }; use bytes::BytesMut; use fnv::FnvHashMap; -use futures::prelude::*; +use futures::{future::BoxFuture, prelude::*, stream::FuturesUnordered}; use libp2p::{ core::{ConnectedPoint, Endpoint, Multiaddr}, swarm::{ @@ -38,9 +41,13 @@ use libp2p::{ }; use log::{debug, error, info, trace, warn}; use parking_lot::RwLock; +use prometheus_endpoint::Registry; use rand::distributions::{Distribution as _, Uniform}; use sc_utils::mpsc::TracingUnboundedReceiver; use smallvec::SmallVec; +use tokio::sync::oneshot::error::RecvError; +use tokio_stream::StreamMap; + use std::{ cmp, collections::{hash_map::Entry, VecDeque}, @@ -51,6 +58,13 @@ use std::{ time::{Duration, Instant}, }; +/// Type representing a pending substream validation. +type PendingInboundValidation = + BoxFuture<'static, (Result, IncomingIndex)>; + +/// Logging target for the file. +const LOG_TARGET: &str = "sub-libp2p"; + /// Network behaviour that handles opening substreams for custom protocols with other peers. /// /// # How it works @@ -106,6 +120,12 @@ pub struct Notifications { /// Notification protocols. Entries never change after initialization. notif_protocols: Vec, + /// Protocol handles. + protocol_handles: Vec, + + // Command streams. + command_streams: StreamMap + Send + Unpin>>, + /// Protocol controllers are responsible for peer connections management. protocol_controller_handles: Vec, @@ -138,6 +158,18 @@ pub struct Notifications { /// Events to produce from `poll()`. events: VecDeque>, + + /// Pending inbound substream validations. + // + // NOTE: it's possible to read a stale response from `pending_inbound_validations` + // as the substream may get closed by the remote peer before the protocol has had + // a chance to validate it. [`Notifications`] must compare the `crate::peerset::IncomingIndex` + // returned by the completed future against the `crate::peerset::IncomingIndex` stored in + // `PeerState::Incoming` to check whether the completed future is stale or not. + pending_inbound_validations: FuturesUnordered, + + /// Metrics for notifications. + metrics: Option, } /// Configuration for a notifications protocol. @@ -303,6 +335,8 @@ struct IncomingPeer { alive: bool, /// Id that the we sent to the peerset. incoming_id: IncomingIndex, + /// Received handshake. + handshake: Vec, } /// Event that can be emitted by the `Notifications`. @@ -367,21 +401,40 @@ impl Notifications { pub fn new( protocol_controller_handles: Vec, from_protocol_controllers: TracingUnboundedReceiver, - notif_protocols: impl Iterator, + registry: &Option, + notif_protocols: impl Iterator, ) -> Self { - let notif_protocols = notif_protocols - .map(|cfg| handler::ProtocolConfig { - name: cfg.name, - fallback_names: cfg.fallback_names, - handshake: Arc::new(RwLock::new(cfg.handshake)), - max_notification_size: cfg.max_notification_size, + let (notif_protocols, protocol_handle_pairs): (Vec<_>, Vec<_>) = notif_protocols + .map(|(cfg, protocol_handle_pair)| { + ( + handler::ProtocolConfig { + name: cfg.name, + fallback_names: cfg.fallback_names, + handshake: Arc::new(RwLock::new(cfg.handshake)), + max_notification_size: cfg.max_notification_size, + }, + protocol_handle_pair, + ) }) - .collect::>(); - + .unzip(); assert!(!notif_protocols.is_empty()); + let metrics = registry.as_ref().and_then(|registry| metrics::register(®istry).ok()); + let (protocol_handles, command_streams): (Vec<_>, Vec<_>) = protocol_handle_pairs + .into_iter() + .enumerate() + .map(|(set_id, protocol_handle_pair)| { + let (mut protocol_handle, command_stream) = protocol_handle_pair.split(); + protocol_handle.set_metrics(metrics.clone()); + + (protocol_handle, (set_id, command_stream)) + }) + .unzip(); + Self { notif_protocols, + protocol_handles, + command_streams: StreamMap::from_iter(command_streams.into_iter()), protocol_controller_handles, from_protocol_controllers, peers: FnvHashMap::default(), @@ -390,6 +443,8 @@ impl Notifications { incoming: SmallVec::new(), next_incoming_index: IncomingIndex(0), events: VecDeque::new(), + pending_inbound_validations: FuturesUnordered::new(), + metrics, } } @@ -407,6 +462,11 @@ impl Notifications { } } + /// Get the number of connected peers for a given set. + pub fn num_connected_peers(&self, set_id: SetId) -> usize { + self.protocol_handles[usize::from(set_id)].num_peers() + } + /// Returns the list of all the peers we have an open channel to. pub fn open_peers(&self) -> impl Iterator { self.peers.iter().filter(|(_, state)| state.is_open()).map(|((id, _), _)| id) @@ -458,6 +518,8 @@ impl Notifications { let event = NotificationsOut::CustomProtocolClosed { peer_id: *peer_id, set_id }; self.events.push_back(ToSwarm::GenerateEvent(event)); + let _ = self.protocol_handles[usize::from(set_id)] + .report_substream_closed(*peer_id); } for (connec_id, connec_state) in @@ -759,6 +821,8 @@ impl Notifications { let event = NotificationsOut::CustomProtocolClosed { peer_id: entry.key().0, set_id }; self.events.push_back(ToSwarm::GenerateEvent(event)); + let _ = self.protocol_handles[usize::from(set_id)] + .report_substream_closed(entry.key().0); } for (connec_id, connec_state) in @@ -823,9 +887,37 @@ impl Notifications { } } + /// Substream has been accepted by the `ProtocolController` and must now be sent + /// to the protocol for validation. + fn peerset_report_preaccept(&mut self, index: IncomingIndex) { + let Some(pos) = self.incoming.iter().position(|i| i.incoming_id == index) else { + error!(target: LOG_TARGET, "PSM => Preaccept({:?}): Invalid index", index); + return + }; + + trace!( + target: LOG_TARGET, + "PSM => Preaccept({:?}): Sent to protocol for validation", + index + ); + let incoming = &self.incoming[pos]; + + match self.protocol_handles[usize::from(incoming.set_id)] + .report_incoming_substream(incoming.peer_id, incoming.handshake.clone()) + { + Ok(rx) => self + .pending_inbound_validations + .push(Box::pin(async move { (rx.await, index) })), + Err(err) => { + error!(target: LOG_TARGET, "protocol has exited: {err:?}"); + debug_assert!(false); + }, + } + } + /// Function that is called when the peerset wants us to accept a connection /// request from a peer. - fn peerset_report_accept(&mut self, index: IncomingIndex) { + fn protocol_report_accept(&mut self, index: IncomingIndex) { let incoming = if let Some(pos) = self.incoming.iter().position(|i| i.incoming_id == index) { self.incoming.remove(pos) @@ -911,40 +1003,52 @@ impl Notifications { } } - /// Function that is called when the peerset wants us to reject an incoming peer. + /// Function that is called when `ProtocolController` wants us to reject an incoming peer. fn peerset_report_reject(&mut self, index: IncomingIndex) { + let _ = self.report_reject(index); + } + + /// Function that is called when the protocol wants us to reject an incoming peer. + fn protocol_report_reject(&mut self, index: IncomingIndex) { + if let Some((set_id, peer_id)) = self.report_reject(index) { + self.protocol_controller_handles[usize::from(set_id)].dropped(peer_id) + } + } + + /// Function that is called when the peerset wants us to reject an incoming peer. + fn report_reject(&mut self, index: IncomingIndex) -> Option<(SetId, PeerId)> { let incoming = if let Some(pos) = self.incoming.iter().position(|i| i.incoming_id == index) { self.incoming.remove(pos) } else { error!(target: "sub-libp2p", "PSM => Reject({:?}): Invalid index", index); - return + return None }; if !incoming.alive { trace!(target: "sub-libp2p", "PSM => Reject({:?}, {}, {:?}): Obsolete incoming, \ ignoring", index, incoming.peer_id, incoming.set_id); - return + return None } let state = match self.peers.get_mut(&(incoming.peer_id, incoming.set_id)) { Some(s) => s, None => { debug_assert!(false); - return + return None }, }; match mem::replace(state, PeerState::Poisoned) { // Incoming => Disabled - PeerState::Incoming { mut connections, backoff_until, incoming_index } => { + PeerState::Incoming { mut connections, backoff_until, incoming_index, .. } => { if index < incoming_index { warn!( target: "sub-libp2p", "PSM => Reject({:?}, {}, {:?}): Ignoring obsolete incoming index, we are already awaiting {:?}.", index, incoming.peer_id, incoming.set_id, incoming_index ); - return + return None } else if index > incoming_index { error!( target: "sub-libp2p", @@ -952,7 +1056,7 @@ impl Notifications { index, incoming.peer_id, incoming.set_id, incoming_index ); debug_assert!(false); - return + return None } trace!(target: "sub-libp2p", "PSM => Reject({:?}, {}, {:?}): Rejecting connections.", @@ -976,10 +1080,15 @@ impl Notifications { } *state = PeerState::Disabled { connections, backoff_until }; + Some((incoming.set_id, incoming.peer_id)) + }, + peer => { + error!( + target: LOG_TARGET, + "State mismatch in libp2p: Expected alive incoming. Got {peer:?}.", + ); + None }, - peer => error!(target: "sub-libp2p", - "State mismatch in libp2p: Expected alive incoming. Got {:?}.", - peer), } } } @@ -1021,6 +1130,7 @@ impl NetworkBehaviour for Notifications { send_back_addr: remote_addr.clone(), }, self.notif_protocols.clone(), + self.metrics.clone(), )) } @@ -1035,6 +1145,7 @@ impl NetworkBehaviour for Notifications { peer, ConnectedPoint::Dialer { address: addr.clone(), role_override }, self.notif_protocols.clone(), + self.metrics.clone(), )) } @@ -1195,7 +1306,12 @@ impl NetworkBehaviour for Notifications { }, // Incoming => Incoming | Disabled | Backoff | Ø - PeerState::Incoming { mut connections, backoff_until, incoming_index } => { + PeerState::Incoming { + mut connections, + backoff_until, + incoming_index, + .. + } => { trace!( target: "sub-libp2p", "Libp2p => Disconnected({}, {:?}, {:?}): OpenDesiredByRemote.", @@ -1313,9 +1429,14 @@ impl NetworkBehaviour for Notifications { let event = NotificationsOut::CustomProtocolReplaced { peer_id, set_id, - notifications_sink: replacement_sink, + notifications_sink: replacement_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); + let _ = self.protocol_handles[usize::from(set_id)] + .report_notification_sink_replaced( + peer_id, + replacement_sink, + ); } } else { trace!( @@ -1327,6 +1448,8 @@ impl NetworkBehaviour for Notifications { set_id, }; self.events.push_back(ToSwarm::GenerateEvent(event)); + let _ = self.protocol_handles[usize::from(set_id)] + .report_substream_closed(peer_id); } } } else { @@ -1475,7 +1598,7 @@ impl NetworkBehaviour for Notifications { event: THandlerOutEvent, ) { match event { - NotifsHandlerOut::OpenDesiredByRemote { protocol_index } => { + NotifsHandlerOut::OpenDesiredByRemote { protocol_index, handshake } => { let set_id = SetId::from(protocol_index); trace!(target: "sub-libp2p", @@ -1589,6 +1712,7 @@ impl NetworkBehaviour for Notifications { set_id, alive: true, incoming_id, + handshake, }); *entry.into_mut() = PeerState::Incoming { @@ -1726,9 +1850,11 @@ impl NetworkBehaviour for Notifications { let event = NotificationsOut::CustomProtocolReplaced { peer_id, set_id, - notifications_sink: replacement_sink, + notifications_sink: replacement_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); + let _ = self.protocol_handles[usize::from(set_id)] + .report_notification_sink_replaced(peer_id, replacement_sink); } *entry.into_mut() = PeerState::Enabled { connections }; @@ -1750,6 +1876,8 @@ impl NetworkBehaviour for Notifications { trace!(target: "sub-libp2p", "External API <= Closed({}, {:?})", peer_id, set_id); let event = NotificationsOut::CustomProtocolClosed { peer_id, set_id }; self.events.push_back(ToSwarm::GenerateEvent(event)); + let _ = self.protocol_handles[usize::from(set_id)] + .report_substream_closed(peer_id); } }, @@ -1831,11 +1959,21 @@ impl NetworkBehaviour for Notifications { peer_id, set_id, inbound, - negotiated_fallback, - received_handshake, + received_handshake: received_handshake.clone(), + negotiated_fallback: negotiated_fallback.clone(), notifications_sink: notifications_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); + let direction = + if inbound { Direction::Inbound } else { Direction::Outbound }; + let _ = self.protocol_handles[protocol_index] + .report_substream_opened( + peer_id, + direction, + received_handshake, + negotiated_fallback, + notifications_sink.clone(), + ); } *connec_state = ConnectionState::Open(notifications_sink); } else if let Some((_, connec_state)) = @@ -1980,9 +2118,14 @@ impl NetworkBehaviour for Notifications { peer_id, set_id, ); - let event = NotificationsOut::Notification { peer_id, set_id, message }; - + let event = NotificationsOut::Notification { + peer_id, + set_id, + message: message.clone(), + }; self.events.push_back(ToSwarm::GenerateEvent(event)); + let _ = self.protocol_handles[protocol_index] + .report_notification_received(peer_id, message.to_vec()); } else { trace!( target: "sub-libp2p", @@ -2010,10 +2153,10 @@ impl NetworkBehaviour for Notifications { loop { match futures::Stream::poll_next(Pin::new(&mut self.from_protocol_controllers), cx) { Poll::Ready(Some(Message::Accept(index))) => { - self.peerset_report_accept(index); + self.peerset_report_preaccept(index); }, Poll::Ready(Some(Message::Reject(index))) => { - self.peerset_report_reject(index); + let _ = self.peerset_report_reject(index); }, Poll::Ready(Some(Message::Connect { peer_id, set_id, .. })) => { self.peerset_report_connect(peer_id, set_id); @@ -2032,6 +2175,43 @@ impl NetworkBehaviour for Notifications { } } + // poll commands from protocols + loop { + match futures::Stream::poll_next(Pin::new(&mut self.command_streams), cx) { + Poll::Ready(Some((set_id, command))) => match command { + NotificationCommand::SetHandshake(handshake) => { + self.set_notif_protocol_handshake(set_id.into(), handshake); + }, + NotificationCommand::OpenSubstream(_peer) | + NotificationCommand::CloseSubstream(_peer) => { + todo!("substream control not implemented"); + }, + }, + Poll::Ready(None) => { + error!(target: LOG_TARGET, "Protocol command streams have been shut down"); + break + }, + Poll::Pending => break, + } + } + + while let Poll::Ready(Some((result, index))) = + self.pending_inbound_validations.poll_next_unpin(cx) + { + match result { + Ok(ValidationResult::Accept) => { + self.protocol_report_accept(index); + }, + Ok(ValidationResult::Reject) => { + self.protocol_report_reject(index); + }, + Err(_) => { + error!(target: LOG_TARGET, "Protocol has shut down"); + break + }, + } + } + while let Poll::Ready(Some((delay_id, peer_id, set_id))) = Pin::new(&mut self.delays).poll_next(cx) { @@ -2154,7 +2334,10 @@ mod tests { } } - fn development_notifs() -> (Notifications, ProtocolController) { + fn development_notifs( + ) -> (Notifications, ProtocolController, Box) { + let (protocol_handle_pair, notif_service) = + crate::protocol::notifications::service::notification_service("/proto/1".into()); let (to_notifications, from_controller) = tracing_unbounded("test_controller_to_notifications", 10_000); @@ -2174,20 +2357,25 @@ mod tests { Notifications::new( vec![handle], from_controller, - iter::once(ProtocolConfig { - name: "/foo".into(), - fallback_names: Vec::new(), - handshake: vec![1, 2, 3, 4], - max_notification_size: u64::MAX, - }), + &None, + iter::once(( + ProtocolConfig { + name: "/foo".into(), + fallback_names: Vec::new(), + handshake: vec![1, 2, 3, 4], + max_notification_size: u64::MAX, + }, + protocol_handle_pair, + )), ), controller, + notif_service, ) } #[test] fn update_handshake() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let inner = notif.notif_protocols.get_mut(0).unwrap().handshake.read().clone(); assert_eq!(inner, vec![1, 2, 3, 4]); @@ -2202,14 +2390,14 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn update_unknown_handshake() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); notif.set_notif_protocol_handshake(1337.into(), vec![5, 6, 7, 8]); } #[test] fn disconnect_backoff_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); notif.peers.insert( @@ -2226,7 +2414,7 @@ mod tests { #[test] fn disconnect_pending_request() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); notif.peers.insert( @@ -2243,7 +2431,7 @@ mod tests { #[test] fn disconnect_requested_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); notif.peers.insert((peer, 0.into()), PeerState::Requested); @@ -2254,7 +2442,7 @@ mod tests { #[test] fn disconnect_disabled_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); notif.peers.insert( (peer, 0.into()), @@ -2270,7 +2458,7 @@ mod tests { #[test] fn remote_opens_connection_and_substream() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let connected = ConnectedPoint::Listener { @@ -2300,7 +2488,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); if let Some(&PeerState::Incoming { ref connections, backoff_until: None, .. }) = @@ -2320,7 +2511,7 @@ mod tests { #[tokio::test] async fn disconnect_remote_substream_before_handled_by_controller() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let connected = ConnectedPoint::Listener { @@ -2340,7 +2531,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); notif.disconnect_peer(&peer, 0.into()); @@ -2356,7 +2550,7 @@ mod tests { #[test] fn peerset_report_connect_backoff() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -2394,7 +2588,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -2421,7 +2615,7 @@ mod tests { #[test] fn peerset_connect_incoming() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2445,19 +2639,22 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); // attempt to connect to the peer and verify that the peer state is `Enabled`; // we rely on implementation detail that incoming indices are counted from 0 // to not mock the `Peerset` - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); } #[test] fn peerset_disconnect_disable_pending_enable() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -2504,7 +2701,7 @@ mod tests { #[test] fn peerset_disconnect_enabled() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2526,11 +2723,14 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); // we rely on the implementation detail that incoming indices are counted from 0 // to not mock the `Peerset` - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); // disconnect peer and verify that the state is `Disabled` @@ -2540,7 +2740,7 @@ mod tests { #[test] fn peerset_disconnect_requested() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); @@ -2555,7 +2755,7 @@ mod tests { #[test] fn peerset_disconnect_pending_request() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -2588,7 +2788,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -2608,7 +2808,7 @@ mod tests { #[test] fn peerset_accept_peer_not_alive() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2632,7 +2832,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -2648,14 +2851,14 @@ mod tests { IncomingPeer { alive: false, incoming_id: IncomingIndex(0), .. }, )); - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); assert_eq!(notif.incoming.len(), 0); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(PeerState::Disabled { .. }))); } #[test] fn secondary_connection_peer_state_incoming() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let conn2 = ConnectionId::new_unchecked(1); @@ -2679,7 +2882,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); if let Some(PeerState::Incoming { connections, .. }) = notif.peers.get(&(peer, set_id)) { assert_eq!(connections.len(), 1); @@ -2710,7 +2916,7 @@ mod tests { #[test] fn close_connection_for_disabled_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2735,7 +2941,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -2744,7 +2950,7 @@ mod tests { #[test] fn close_connection_for_incoming_peer_one_connection() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2767,7 +2973,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -2776,7 +2985,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -2789,7 +2998,7 @@ mod tests { #[test] fn close_connection_for_incoming_peer_two_connections() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let conn1 = ConnectionId::new_unchecked(1); @@ -2816,7 +3025,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -2843,7 +3055,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -2858,7 +3070,7 @@ mod tests { #[test] fn connection_and_substream_open() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -2883,13 +3095,16 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); // We rely on the implementation detail that incoming indices are counted // from 0 to not mock the `Peerset`. - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); // open new substream @@ -2912,7 +3127,7 @@ mod tests { #[test] fn connection_closed_sink_replaced() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn1 = ConnectionId::new_unchecked(0); let conn2 = ConnectionId::new_unchecked(1); @@ -2948,7 +3163,10 @@ mod tests { notif.on_connection_handler_event( peer, conn2, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); if let Some(PeerState::Enabled { connections, .. }) = notif.peers.get(&(peer, set_id)) { @@ -2985,7 +3203,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3006,7 +3224,7 @@ mod tests { #[test] fn dial_failure_for_requested_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); @@ -3029,7 +3247,7 @@ mod tests { #[tokio::test] async fn write_notification() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -3078,7 +3296,7 @@ mod tests { #[test] fn peerset_report_connect_backoff_expired() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -3111,7 +3329,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3126,7 +3344,7 @@ mod tests { #[test] fn peerset_report_disconnect_disabled() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); @@ -3152,7 +3370,7 @@ mod tests { #[test] fn peerset_report_disconnect_backoff() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -3185,7 +3403,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3198,7 +3416,7 @@ mod tests { #[test] fn peer_is_backed_off_if_both_connections_get_closed_while_peer_is_disabled_with_back_off() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn1 = ConnectionId::new_unchecked(0); @@ -3248,7 +3466,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected.clone(), vec![]), + handler: NotifsHandler::new(peer, connected.clone(), vec![], None), remaining_established: 0usize, }, )); @@ -3262,7 +3480,7 @@ mod tests { peer_id: peer, connection_id: conn2, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3271,7 +3489,7 @@ mod tests { #[test] fn inject_connection_closed_incoming_with_backoff() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); @@ -3295,7 +3513,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); // manually add backoff for the entry @@ -3313,7 +3534,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3322,7 +3543,7 @@ mod tests { #[test] fn two_connections_inactive_connection_gets_closed_peer_state_is_still_incoming() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn1 = ConnectionId::new_unchecked(0); let conn2 = ConnectionId::new_unchecked(1); @@ -3356,7 +3577,10 @@ mod tests { notif.on_connection_handler_event( peer, conn1, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!( notif.peers.get_mut(&(peer, 0.into())), @@ -3368,7 +3592,7 @@ mod tests { peer_id: peer, connection_id: conn2, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3377,7 +3601,7 @@ mod tests { #[test] fn two_connections_active_connection_gets_closed_peer_state_is_disabled() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn1 = ConnectionId::new_unchecked(0); let conn2 = ConnectionId::new_unchecked(1); @@ -3414,7 +3638,10 @@ mod tests { notif.on_connection_handler_event( peer, conn1, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!( notif.peers.get_mut(&(peer, 0.into())), @@ -3426,7 +3653,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3435,7 +3662,7 @@ mod tests { #[test] fn inject_connection_closed_for_active_connection() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn1 = ConnectionId::new_unchecked(0); let conn2 = ConnectionId::new_unchecked(1); @@ -3495,7 +3722,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3503,7 +3730,7 @@ mod tests { #[test] fn inject_dial_failure_for_pending_request() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -3536,7 +3763,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3566,7 +3793,7 @@ mod tests { #[test] fn peerstate_incoming_open_desired_by_remote() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn1 = ConnectionId::new_unchecked(0); @@ -3600,7 +3827,10 @@ mod tests { notif.on_connection_handler_event( peer, conn1, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -3608,7 +3838,10 @@ mod tests { notif.on_connection_handler_event( peer, conn2, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); if let Some(PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) @@ -3620,7 +3853,7 @@ mod tests { #[tokio::test] async fn remove_backoff_peer_after_timeout() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); @@ -3653,7 +3886,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3698,7 +3931,7 @@ mod tests { #[tokio::test] async fn reschedule_disabled_pending_enable_when_connection_not_closed() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -3727,13 +3960,16 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); // we rely on the implementation detail that incoming indices are counted from 0 // to not mock the `Peerset` - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); @@ -3816,7 +4052,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn peerset_report_connect_with_enabled_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -3841,7 +4077,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -3866,7 +4105,7 @@ mod tests { #[test] #[cfg(debug_assertions)] fn peerset_report_connect_with_disabled_pending_enable_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -3912,7 +4151,7 @@ mod tests { #[test] #[cfg(debug_assertions)] fn peerset_report_connect_with_requested_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); @@ -3928,7 +4167,7 @@ mod tests { #[test] #[cfg(debug_assertions)] fn peerset_report_connect_with_pending_requested() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -3961,7 +4200,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -3985,7 +4224,7 @@ mod tests { #[test] #[cfg(debug_assertions)] fn peerset_report_connect_with_incoming_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); @@ -4009,7 +4248,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -4020,7 +4262,7 @@ mod tests { #[test] #[cfg(debug_assertions)] fn peerset_report_disconnect_with_incoming_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); @@ -4044,7 +4286,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -4055,8 +4300,8 @@ mod tests { #[test] #[should_panic] #[cfg(debug_assertions)] - fn peerset_report_accept_incoming_peer() { - let (mut notif, _controller) = development_notifs(); + fn protocol_report_accept_incoming_peer() { + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4080,7 +4325,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -4090,14 +4338,14 @@ mod tests { )); notif.peers.remove(&(peer, set_id)); - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); } #[test] #[should_panic] #[cfg(debug_assertions)] - fn peerset_report_accept_not_incoming_peer() { - let (mut notif, _controller) = development_notifs(); + fn protocol_report_accept_not_incoming_peer() { + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4122,7 +4370,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -4139,14 +4390,14 @@ mod tests { assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); notif.incoming[0].alive = true; - notif.peerset_report_accept(IncomingIndex(0)); + notif.protocol_report_accept(IncomingIndex(0)); } #[test] #[should_panic] #[cfg(debug_assertions)] fn inject_connection_closed_non_existent_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let endpoint = ConnectedPoint::Listener { local_addr: Multiaddr::empty(), @@ -4158,7 +4409,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(0), endpoint: &endpoint.clone(), - handler: NotifsHandler::new(peer, endpoint, vec![]), + handler: NotifsHandler::new(peer, endpoint, vec![], None), remaining_established: 0usize, }, )); @@ -4166,7 +4417,7 @@ mod tests { #[test] fn disconnect_non_existent_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let set_id = SetId::from(0); @@ -4178,9 +4429,9 @@ mod tests { #[test] fn accept_non_existent_connection() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); - notif.peerset_report_accept(0.into()); + notif.protocol_report_accept(0.into()); assert!(notif.peers.is_empty()); assert!(notif.incoming.is_empty()); @@ -4188,9 +4439,9 @@ mod tests { #[test] fn reject_non_existent_connection() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); - notif.peerset_report_reject(0.into()); + notif.protocol_report_reject(0.into()); assert!(notif.peers.is_empty()); assert!(notif.incoming.is_empty()); @@ -4198,7 +4449,7 @@ mod tests { #[test] fn reject_non_active_connection() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4222,12 +4473,15 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); notif.incoming[0].alive = false; - notif.peerset_report_reject(0.into()); + notif.protocol_report_reject(0.into()); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); } @@ -4236,7 +4490,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn reject_non_existent_peer_but_alive_connection() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4260,7 +4514,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); assert!(std::matches!( @@ -4269,14 +4526,14 @@ mod tests { )); notif.peers.remove(&(peer, set_id)); - notif.peerset_report_reject(0.into()); + notif.protocol_report_reject(0.into()); } #[test] #[should_panic] #[cfg(debug_assertions)] fn inject_non_existent_connection_closed_for_incoming_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4300,7 +4557,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -4309,7 +4569,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4319,7 +4579,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn inject_non_existent_connection_closed_for_disabled_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -4344,7 +4604,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4354,7 +4614,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn inject_non_existent_connection_closed_for_disabled_pending_enable() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -4395,7 +4655,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4405,7 +4665,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn inject_connection_closed_for_incoming_peer_state_mismatch() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4429,7 +4689,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); notif.incoming[0].alive = false; @@ -4439,7 +4702,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4449,7 +4712,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn inject_connection_closed_for_enabled_state_mismatch() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); @@ -4473,7 +4736,10 @@ mod tests { notif.on_connection_handler_event( peer, conn, - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); @@ -4486,7 +4752,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4496,7 +4762,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn inject_connection_closed_for_backoff_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let set_id = SetId::from(0); let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); @@ -4529,7 +4795,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected.clone(), vec![]), + handler: NotifsHandler::new(peer, connected.clone(), vec![], None), remaining_established: 0usize, }, )); @@ -4540,7 +4806,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![]), + handler: NotifsHandler::new(peer, connected, vec![], None), remaining_established: 0usize, }, )); @@ -4550,7 +4816,7 @@ mod tests { #[should_panic] #[cfg(debug_assertions)] fn open_result_ok_non_existent_peer() { - let (mut notif, _controller) = development_notifs(); + let (mut notif, _controller, _notif_service) = development_notifs(); let conn = ConnectionId::new_unchecked(0); let connected = ConnectedPoint::Listener { local_addr: Multiaddr::empty(), diff --git a/substrate/client/network/src/protocol/notifications/handler.rs b/substrate/client/network/src/protocol/notifications/handler.rs index cffdec7d71ee..c2adcbc96f14 100644 --- a/substrate/client/network/src/protocol/notifications/handler.rs +++ b/substrate/client/network/src/protocol/notifications/handler.rs @@ -58,9 +58,12 @@ //! [`NotifsHandlerIn::Open`] has gotten an answer. use crate::{ - protocol::notifications::upgrade::{ - NotificationsIn, NotificationsInSubstream, NotificationsOut, NotificationsOutSubstream, - UpgradeCollec, + protocol::notifications::{ + service::metrics, + upgrade::{ + NotificationsIn, NotificationsInSubstream, NotificationsOut, NotificationsOutSubstream, + UpgradeCollec, + }, }, types::ProtocolName, }; @@ -92,7 +95,7 @@ use std::{ /// Number of pending notifications in asynchronous contexts. /// See [`NotificationsSink::reserve_notification`] for context. -const ASYNC_NOTIFICATIONS_BUFFER_SIZE: usize = 8; +pub(crate) const ASYNC_NOTIFICATIONS_BUFFER_SIZE: usize = 8; /// Number of pending notifications in synchronous contexts. const SYNC_NOTIFICATIONS_BUFFER_SIZE: usize = 2048; @@ -106,6 +109,28 @@ const OPEN_TIMEOUT: Duration = Duration::from_secs(10); /// open substreams. const INITIAL_KEEPALIVE_TIME: Duration = Duration::from_secs(5); +/// Metrics-related information. +#[derive(Debug)] +pub struct MetricsInfo { + /// Protocol name. + protocol: ProtocolName, + + /// Metrics. + metrics: Option, +} + +impl MetricsInfo { + /// Create new [`MetricsInfo`]. + pub fn new(protocol: ProtocolName, metrics: Option) -> Self { + Self { protocol, metrics } + } + + /// Create new empty [`MetricsInfo`]. + pub fn new_empty() -> Self { + Self { protocol: ProtocolName::from(""), metrics: None } + } +} + /// The actual handler once the connection has been established. /// /// See the documentation at the module level for more information. @@ -126,11 +151,24 @@ pub struct NotifsHandler { events_queue: VecDeque< ConnectionHandlerEvent, >, + + /// Metrics-related information. + metrics_info: Vec>, } impl NotifsHandler { /// Creates new [`NotifsHandler`]. - pub fn new(peer_id: PeerId, endpoint: ConnectedPoint, protocols: Vec) -> Self { + pub fn new( + peer_id: PeerId, + endpoint: ConnectedPoint, + protocols: Vec, + metrics: Option, + ) -> Self { + let metrics_info = protocols + .iter() + .map(|config| Arc::new(MetricsInfo::new(config.name.clone(), metrics.clone()))) + .collect(); + Self { protocols: protocols .into_iter() @@ -148,6 +186,7 @@ impl NotifsHandler { endpoint, when_connection_open: Instant::now(), events_queue: VecDeque::with_capacity(16), + metrics_info, } } } @@ -303,6 +342,8 @@ pub enum NotifsHandlerOut { OpenDesiredByRemote { /// Index of the protocol in the list of protocols passed at initialization. protocol_index: usize, + /// Received handshake. + handshake: Vec, }, /// The remote would like the substreams to be closed. Send a [`NotifsHandlerIn::Close`] in @@ -333,6 +374,30 @@ pub struct NotificationsSink { inner: Arc, } +// NOTE: only used for testing but must be `pub` as other crates in `client/network` use this. +impl NotificationsSink { + /// Create new + pub fn new( + peer_id: PeerId, + ) -> (Self, mpsc::Receiver, mpsc::Receiver) + { + let (async_tx, async_rx) = mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); + let (sync_tx, sync_rx) = mpsc::channel(SYNC_NOTIFICATIONS_BUFFER_SIZE); + ( + NotificationsSink { + inner: Arc::new(NotificationsSinkInner { + peer_id, + async_channel: FuturesMutex::new(async_tx), + sync_channel: Mutex::new(Some(sync_tx)), + metrics_info: Arc::new(MetricsInfo::new_empty()), + }), + }, + async_rx, + sync_rx, + ) + } +} + #[derive(Debug)] struct NotificationsSinkInner { /// Target of the sink. @@ -346,12 +411,14 @@ struct NotificationsSinkInner { /// back-pressure cannot be properly exerted. /// It will be removed in a future version. sync_channel: Mutex>>, + /// Metrics-related information. + metrics_info: Arc, } /// Message emitted through the [`NotificationsSink`] and processed by the background task /// dedicated to the peer. -#[derive(Debug)] -enum NotificationsSinkMessage { +#[derive(Debug, PartialEq, Eq)] +pub enum NotificationsSinkMessage { /// Message emitted by [`NotificationsSink::reserve_notification`] and /// [`NotificationsSink::write_notification_now`]. Notification { message: Vec }, @@ -379,8 +446,14 @@ impl NotificationsSink { let mut lock = self.inner.sync_channel.lock(); if let Some(tx) = lock.as_mut() { - let result = - tx.try_send(NotificationsSinkMessage::Notification { message: message.into() }); + let message = message.into(); + metrics::register_notification_sent( + &self.inner.metrics_info.metrics, + &self.inner.metrics_info.protocol, + message.len(), + ); + + let result = tx.try_send(NotificationsSinkMessage::Notification { message }); if result.is_err() { // Cloning the `mpsc::Sender` guarantees the allocation of an extra spot in the @@ -476,7 +549,10 @@ impl ConnectionHandler for NotifsHandler { match protocol_info.state { State::Closed { pending_opening } => { self.events_queue.push_back(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenDesiredByRemote { protocol_index }, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index, + handshake: in_substream_open.handshake, + }, )); protocol_info.state = State::OpenDesiredByRemote { @@ -530,6 +606,7 @@ impl ConnectionHandler for NotifsHandler { peer_id: self.peer_id, async_channel: FuturesMutex::new(async_tx), sync_channel: Mutex::new(Some(sync_tx)), + metrics_info: self.metrics_info[protocol_index].clone(), }), }; @@ -880,6 +957,7 @@ pub mod tests { peer_id: peer, async_channel: FuturesMutex::new(async_tx), sync_channel: Mutex::new(Some(sync_tx)), + metrics_info: Arc::new(MetricsInfo::new_empty()), }), }; let (in_substream, out_substream) = MockSubstream::new(); @@ -1040,6 +1118,7 @@ pub mod tests { }, peer_id: PeerId::random(), events_queue: VecDeque::new(), + metrics_info: vec![Arc::new(MetricsInfo::new_empty())], } } @@ -1544,6 +1623,7 @@ pub mod tests { peer_id: PeerId::random(), async_channel: FuturesMutex::new(async_tx), sync_channel: Mutex::new(Some(sync_tx)), + metrics_info: Arc::new(MetricsInfo::new_empty()), }), }; @@ -1597,7 +1677,7 @@ pub mod tests { assert!(std::matches!( handler.poll(cx), Poll::Ready(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0, .. }, )) )); assert!(std::matches!( diff --git a/substrate/client/network/src/protocol/notifications/service/metrics.rs b/substrate/client/network/src/protocol/notifications/service/metrics.rs new file mode 100644 index 000000000000..65ccedac0762 --- /dev/null +++ b/substrate/client/network/src/protocol/notifications/service/metrics.rs @@ -0,0 +1,124 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::types::ProtocolName; + +use prometheus_endpoint::{ + self as prometheus, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError, Registry, + U64, +}; + +/// Notification metrics. +#[derive(Debug, Clone)] +pub struct Metrics { + // Total number of opened substreams. + pub notifications_streams_opened_total: CounterVec, + + /// Total number of closed substreams. + pub notifications_streams_closed_total: CounterVec, + + /// In/outbound notification sizes. + pub notifications_sizes: HistogramVec, +} + +impl Metrics { + fn register(registry: &Registry) -> Result { + Ok(Self { + notifications_sizes: prometheus::register( + HistogramVec::new( + HistogramOpts { + common_opts: Opts::new( + "substrate_sub_libp2p_notification_service_total_sizes", + "Sizes of the notifications send to and received from all nodes", + ), + buckets: prometheus::exponential_buckets(64.0, 4.0, 8) + .expect("parameters are always valid values; qed"), + }, + &["direction", "protocol"], + )?, + registry, + )?, + notifications_streams_closed_total: prometheus::register( + CounterVec::new( + Opts::new( + "substrate_sub_libp2p_notification_service_streams_closed_total", + "Total number of notification substreams that have been closed", + ), + &["protocol"], + )?, + registry, + )?, + notifications_streams_opened_total: prometheus::register( + CounterVec::new( + Opts::new( + "substrate_sub_libp2p_notification_service_streams_opened_total", + "Total number of notification substreams that have been opened", + ), + &["protocol"], + )?, + registry, + )?, + }) + } +} + +/// Register metrics. +pub fn register(registry: &Registry) -> Result { + Metrics::register(registry) +} + +/// Register opened substream to Prometheus. +pub fn register_substream_opened(metrics: &Option, protocol: &ProtocolName) { + if let Some(metrics) = metrics { + metrics.notifications_streams_opened_total.with_label_values(&[&protocol]).inc(); + } +} + +/// Register closed substream to Prometheus. +pub fn register_substream_closed(metrics: &Option, protocol: &ProtocolName) { + if let Some(metrics) = metrics { + metrics + .notifications_streams_closed_total + .with_label_values(&[&protocol[..]]) + .inc(); + } +} + +/// Register sent notification to Prometheus. +pub fn register_notification_sent(metrics: &Option, protocol: &ProtocolName, size: usize) { + if let Some(metrics) = metrics { + metrics + .notifications_sizes + .with_label_values(&["out", protocol]) + .observe(size as f64); + } +} + +/// Register received notification to Prometheus. +pub fn register_notification_received( + metrics: &Option, + protocol: &ProtocolName, + size: usize, +) { + if let Some(metrics) = metrics { + metrics + .notifications_sizes + .with_label_values(&["in", protocol]) + .observe(size as f64); + } +} diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs new file mode 100644 index 000000000000..05aa8fc41615 --- /dev/null +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -0,0 +1,576 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Notification service implementation. + +use crate::{ + error, + protocol::notifications::handler::NotificationsSink, + service::traits::{ + Direction, MessageSink, NotificationEvent, NotificationService, ValidationResult, + }, + types::ProtocolName, +}; + +use futures::{ + stream::{FuturesUnordered, Stream}, + StreamExt, +}; +use libp2p::PeerId; +use parking_lot::Mutex; +use tokio::sync::{mpsc, oneshot}; +use tokio_stream::wrappers::ReceiverStream; + +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; + +use std::{collections::HashMap, fmt::Debug, sync::Arc}; + +pub(crate) mod metrics; +#[cfg(test)] +mod tests; + +/// Logging target for the file. +const LOG_TARGET: &str = "notification-service"; + +/// Default command queue size. +const COMMAND_QUEUE_SIZE: usize = 64; + +/// Type representing subscribers of a notification protocol. +type Subscribers = Arc>>>; + +/// Type represending a distributable message sink. +/// +/// See documentation for [`PeerContext`] for more details. +type NotificationSink = Arc>; + +#[async_trait::async_trait] +impl MessageSink for NotificationSink { + /// Send synchronous `notification` to the peer associated with this [`MessageSink`]. + fn send_sync_notification(&self, notification: Vec) { + self.lock().send_sync_notification(notification); + } + + /// Send an asynchronous `notification` to to the peer associated with this [`MessageSink`], + /// allowing sender to exercise backpressure. + /// + /// Returns an error if the peer does not exist. + async fn send_async_notification(&self, notification: Vec) -> Result<(), error::Error> { + // notification sink must be cloned because the lock cannot be held across `.await` + // this makes the implementation less efficient but not prohibitively so as the same + // method is also used by `NetworkService` when sending notifications. + let sink = self.lock().clone(); + let sink = sink.reserve_notification().await.map_err(|_| error::Error::ConnectionClosed)?; + sink.send(notification).map_err(|_| error::Error::ChannelClosed) + } +} + +/// Inner notification event to deal with `NotificationsSinks` without exposing that +/// implementation detail to [`NotificationService`] consumers. +#[derive(Debug)] +enum InnerNotificationEvent { + /// Validate inbound substream. + ValidateInboundSubstream { + /// Peer ID. + peer: PeerId, + + /// Received handshake. + handshake: Vec, + + /// `oneshot::Sender` for sending validation result back to `Notifications` + result_tx: oneshot::Sender, + }, + + /// Notification substream open to `peer`. + NotificationStreamOpened { + /// Peer ID. + peer: PeerId, + + /// Direction of the substream. + direction: Direction, + + /// Received handshake. + handshake: Vec, + + /// Negotiated fallback. + negotiated_fallback: Option, + + /// Notification sink. + sink: NotificationsSink, + }, + + /// Substream was closed. + NotificationStreamClosed { + /// Peer ID. + peer: PeerId, + }, + + /// Notification was received from the substream. + NotificationReceived { + /// Peer ID. + peer: PeerId, + + /// Received notification. + notification: Vec, + }, + + /// Notification sink has been replaced. + NotificationSinkReplaced { + /// Peer ID. + peer: PeerId, + + /// Notification sink. + sink: NotificationsSink, + }, +} + +/// Notification commands. +/// +/// Sent by the installed protocols to `Notifications` to open/close/modify substreams. +#[derive(Debug)] +pub enum NotificationCommand { + /// Instruct `Notifications` to open a substream to peer. + OpenSubstream(PeerId), + + /// Instruct `Notifications` to close the substream to peer. + CloseSubstream(PeerId), + + /// Set handshake for the notifications protocol. + SetHandshake(Vec), +} + +/// Context assigned to each peer. +/// +/// Contains `NotificationsSink` used by [`NotificationService`] to send notifications +/// and an additional, distributable `NotificationsSink` which the protocol may acquire +/// if it wishes to send notifications through `NotificationsSink` directly. +/// +/// The distributable `NoticationsSink` is wrapped in an `Arc>` to allow +/// `NotificationsService` to swap the underlying sink in case it's replaced. +#[derive(Debug, Clone)] +struct PeerContext { + /// Sink for sending notificaitons. + sink: NotificationsSink, + + /// Distributable notification sink. + shared_sink: NotificationSink, +} + +/// Handle that is passed on to the notifications protocol. +#[derive(Debug)] +pub struct NotificationHandle { + /// Protocol name. + protocol: ProtocolName, + + /// TX channel for sending commands to `Notifications`. + tx: mpsc::Sender, + + /// RX channel for receiving events from `Notifications`. + rx: TracingUnboundedReceiver, + + /// All subscribers of `NotificationEvent`s. + subscribers: Subscribers, + + /// Connected peers. + peers: HashMap, +} + +impl NotificationHandle { + /// Create new [`NotificationHandle`]. + fn new( + protocol: ProtocolName, + tx: mpsc::Sender, + rx: TracingUnboundedReceiver, + subscribers: Arc>>>, + ) -> Self { + Self { protocol, tx, rx, subscribers, peers: HashMap::new() } + } +} + +#[async_trait::async_trait] +impl NotificationService for NotificationHandle { + /// Instruct `Notifications` to open a new substream for `peer`. + async fn open_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + todo!("support for opening substreams not implemented yet"); + } + + /// Instruct `Notifications` to close substream for `peer`. + async fn close_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + todo!("support for closing substreams not implemented yet, call `NetworkService::disconnect_peer()` instead"); + } + + /// Send synchronous `notification` to `peer`. + fn send_sync_notification(&self, peer: &PeerId, notification: Vec) { + log::trace!(target: LOG_TARGET, "{}: send sync notification to {peer:?}", self.protocol); + + if let Some(info) = self.peers.get(&peer) { + let _ = info.sink.send_sync_notification(notification); + } + } + + /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure. + async fn send_async_notification( + &self, + peer: &PeerId, + notification: Vec, + ) -> Result<(), error::Error> { + log::trace!(target: LOG_TARGET, "{}: send async notification to {peer:?}", self.protocol); + + self.peers + .get(&peer) + .ok_or_else(|| error::Error::PeerDoesntExist(*peer))? + .sink + .reserve_notification() + .await + .map_err(|_| error::Error::ConnectionClosed)? + .send(notification) + .map_err(|_| error::Error::ChannelClosed) + } + + /// Set handshake for the notification protocol replacing the old handshake. + async fn set_handshake(&mut self, handshake: Vec) -> Result<(), ()> { + log::trace!(target: LOG_TARGET, "{}: set handshake to {handshake:?}", self.protocol); + + self.tx.send(NotificationCommand::SetHandshake(handshake)).await.map_err(|_| ()) + } + + /// Get next event from the `Notifications` event stream. + async fn next_event(&mut self) -> Option { + loop { + match self.rx.next().await? { + InnerNotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx } => + return Some(NotificationEvent::ValidateInboundSubstream { + peer, + handshake, + result_tx, + }), + InnerNotificationEvent::NotificationStreamOpened { + peer, + handshake, + negotiated_fallback, + direction, + sink, + } => { + self.peers.insert( + peer, + PeerContext { sink: sink.clone(), shared_sink: Arc::new(Mutex::new(sink)) }, + ); + return Some(NotificationEvent::NotificationStreamOpened { + peer, + handshake, + direction, + negotiated_fallback, + }) + }, + InnerNotificationEvent::NotificationStreamClosed { peer } => { + self.peers.remove(&peer); + return Some(NotificationEvent::NotificationStreamClosed { peer }) + }, + InnerNotificationEvent::NotificationReceived { peer, notification } => + return Some(NotificationEvent::NotificationReceived { peer, notification }), + InnerNotificationEvent::NotificationSinkReplaced { peer, sink } => { + match self.peers.get_mut(&peer) { + None => log::error!( + "{}: notification sink replaced for {peer} but peer does not exist", + self.protocol + ), + Some(context) => { + context.sink = sink.clone(); + *context.shared_sink.lock() = sink.clone(); + }, + } + }, + } + } + } + + // Clone [`NotificationService`] + fn clone(&mut self) -> Result, ()> { + let mut subscribers = self.subscribers.lock(); + let (event_tx, event_rx) = tracing_unbounded("mpsc-notification-to-protocol", 100_000); + subscribers.push(event_tx); + + Ok(Box::new(NotificationHandle { + protocol: self.protocol.clone(), + tx: self.tx.clone(), + rx: event_rx, + peers: self.peers.clone(), + subscribers: self.subscribers.clone(), + })) + } + + /// Get protocol name. + fn protocol(&self) -> &ProtocolName { + &self.protocol + } + + /// Get message sink of the peer. + fn message_sink(&self, peer: &PeerId) -> Option> { + match self.peers.get(peer) { + Some(context) => Some(Box::new(context.shared_sink.clone())), + None => None, + } + } +} + +/// Channel pair which allows `Notifications` to interact with a protocol. +#[derive(Debug)] +pub struct ProtocolHandlePair { + /// Protocol name. + protocol: ProtocolName, + + /// Subscribers of the notification protocol events. + subscribers: Subscribers, + + // Receiver for notification commands received from the protocol implementation. + rx: mpsc::Receiver, +} + +impl ProtocolHandlePair { + /// Create new [`ProtocolHandlePair`]. + fn new( + protocol: ProtocolName, + subscribers: Subscribers, + rx: mpsc::Receiver, + ) -> Self { + Self { protocol, subscribers, rx } + } + + /// Consume `self` and split [`ProtocolHandlePair`] into a handle which allows it to send events + /// to the protocol and a stream of commands received from the protocol. + pub fn split( + self, + ) -> (ProtocolHandle, Box + Send + Unpin>) { + ( + ProtocolHandle::new(self.protocol, self.subscribers), + Box::new(ReceiverStream::new(self.rx)), + ) + } +} + +/// Handle that is passed on to `Notifications` and allows it to directly communicate +/// with the protocol. +#[derive(Debug)] +pub struct ProtocolHandle { + /// Protocol name. + protocol: ProtocolName, + + /// Subscribers of the notification protocol. + subscribers: Subscribers, + + /// Number of connected peers. + num_peers: usize, + + /// Prometheus metrics. + metrics: Option, +} + +impl ProtocolHandle { + /// Create new [`ProtocolHandle`]. + fn new(protocol: ProtocolName, subscribers: Subscribers) -> Self { + Self { protocol, subscribers, num_peers: 0usize, metrics: None } + } + + /// Set metrics. + pub fn set_metrics(&mut self, metrics: Option) { + self.metrics = metrics; + } + + /// Report to the protocol that a substream has been opened and it must be validated by the + /// protocol. + /// + /// Return `oneshot::Receiver` which allows `Notifications` to poll for the validation result + /// from protocol. + pub fn report_incoming_substream( + &self, + peer: PeerId, + handshake: Vec, + ) -> Result, ()> { + let subscribers = self.subscribers.lock(); + + log::trace!( + target: LOG_TARGET, + "{}: report incoming substream for {peer}, handshake {handshake:?}", + self.protocol + ); + + // if there is only one subscriber, `Notifications` can wait directly on the + // `oneshot::channel()`'s RX half without indirection + if subscribers.len() == 1 { + let (result_tx, rx) = oneshot::channel(); + return subscribers[0] + .unbounded_send(InnerNotificationEvent::ValidateInboundSubstream { + peer, + handshake, + result_tx, + }) + .map(|_| rx) + .map_err(|_| ()) + } + + // if there are multiple subscribers, create a task which waits for all of the + // validations to finish and returns the combined result to `Notifications` + let mut results: FuturesUnordered<_> = subscribers + .iter() + .filter_map(|subscriber| { + let (result_tx, rx) = oneshot::channel(); + + subscriber + .unbounded_send(InnerNotificationEvent::ValidateInboundSubstream { + peer, + handshake: handshake.clone(), + result_tx, + }) + .is_ok() + .then_some(rx) + }) + .collect(); + + let (tx, rx) = oneshot::channel(); + tokio::spawn(async move { + while let Some(event) = results.next().await { + match event { + Err(_) | Ok(ValidationResult::Reject) => + return tx.send(ValidationResult::Reject), + Ok(ValidationResult::Accept) => {}, + } + } + + return tx.send(ValidationResult::Accept) + }); + + Ok(rx) + } + + /// Report to the protocol that a substream has been opened and that it can now use the handle + /// to send notifications to the remote peer. + pub fn report_substream_opened( + &mut self, + peer: PeerId, + direction: Direction, + handshake: Vec, + negotiated_fallback: Option, + sink: NotificationsSink, + ) -> Result<(), ()> { + metrics::register_substream_opened(&self.metrics, &self.protocol); + + let mut subscribers = self.subscribers.lock(); + log::trace!(target: LOG_TARGET, "{}: substream opened for {peer:?}", self.protocol); + + subscribers.retain(|subscriber| { + subscriber + .unbounded_send(InnerNotificationEvent::NotificationStreamOpened { + peer, + direction, + handshake: handshake.clone(), + negotiated_fallback: negotiated_fallback.clone(), + sink: sink.clone(), + }) + .is_ok() + }); + self.num_peers += 1; + + Ok(()) + } + + /// Substream was closed. + pub fn report_substream_closed(&mut self, peer: PeerId) -> Result<(), ()> { + metrics::register_substream_closed(&self.metrics, &self.protocol); + + let mut subscribers = self.subscribers.lock(); + log::trace!(target: LOG_TARGET, "{}: substream closed for {peer:?}", self.protocol); + + subscribers.retain(|subscriber| { + subscriber + .unbounded_send(InnerNotificationEvent::NotificationStreamClosed { peer }) + .is_ok() + }); + self.num_peers -= 1; + + Ok(()) + } + + /// Notification was received from the substream. + pub fn report_notification_received( + &mut self, + peer: PeerId, + notification: Vec, + ) -> Result<(), ()> { + metrics::register_notification_received(&self.metrics, &self.protocol, notification.len()); + + let mut subscribers = self.subscribers.lock(); + log::trace!(target: LOG_TARGET, "{}: notification received from {peer:?}", self.protocol); + + subscribers.retain(|subscriber| { + subscriber + .unbounded_send(InnerNotificationEvent::NotificationReceived { + peer, + notification: notification.clone(), + }) + .is_ok() + }); + + Ok(()) + } + + /// Notification sink was replaced. + pub fn report_notification_sink_replaced( + &mut self, + peer: PeerId, + sink: NotificationsSink, + ) -> Result<(), ()> { + let mut subscribers = self.subscribers.lock(); + + log::trace!( + target: LOG_TARGET, + "{}: notification sink replaced for {peer:?}", + self.protocol + ); + + subscribers.retain(|subscriber| { + subscriber + .unbounded_send(InnerNotificationEvent::NotificationSinkReplaced { + peer, + sink: sink.clone(), + }) + .is_ok() + }); + + Ok(()) + } + + /// Get the number of connected peers. + pub fn num_peers(&self) -> usize { + self.num_peers + } +} + +/// Create new (protocol, notification) handle pair. +/// +/// Handle pair allows `Notifications` and the protocol to communicate with each other directly. +pub fn notification_service( + protocol: ProtocolName, +) -> (ProtocolHandlePair, Box) { + let (cmd_tx, cmd_rx) = mpsc::channel(COMMAND_QUEUE_SIZE); + let (event_tx, event_rx) = tracing_unbounded("mpsc-notification-to-protocol", 100_000); + let subscribers = Arc::new(Mutex::new(vec![event_tx])); + + ( + ProtocolHandlePair::new(protocol.clone(), subscribers.clone(), cmd_rx), + Box::new(NotificationHandle::new(protocol.clone(), cmd_tx, event_rx, subscribers)), + ) +} diff --git a/substrate/client/network/src/protocol/notifications/service/tests.rs b/substrate/client/network/src/protocol/notifications/service/tests.rs new file mode 100644 index 000000000000..72e97b79b50f --- /dev/null +++ b/substrate/client/network/src/protocol/notifications/service/tests.rs @@ -0,0 +1,770 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; +use crate::protocol::notifications::handler::{ + NotificationsSinkMessage, ASYNC_NOTIFICATIONS_BUFFER_SIZE, +}; + +use std::future::Future; + +#[tokio::test] +async fn validate_and_accept_substream() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (handle, _stream) = proto.split(); + + let peer_id = PeerId::random(); + let rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + + assert_eq!(rx.await.unwrap(), ValidationResult::Accept); +} + +#[tokio::test] +async fn substream_opened() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, _, _) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + + let peer_id = PeerId::random(); + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } +} + +#[tokio::test] +async fn send_sync_notification() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, _, mut sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + notif.send_sync_notification(&peer_id, vec![1, 3, 3, 8]); + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 8] }) + ); +} + +#[tokio::test] +async fn send_async_notification() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, mut async_rx, _) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + notif.send_async_notification(&peer_id, vec![1, 3, 3, 9]).await.unwrap(); + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 9] }) + ); +} + +#[tokio::test] +async fn send_sync_notification_to_non_existent_peer() { + let (proto, notif) = notification_service("/proto/1".into()); + let (_sink, _, _sync_rx) = NotificationsSink::new(PeerId::random()); + let (_handle, _stream) = proto.split(); + let peer = PeerId::random(); + + // as per the original implementation, the call doesn't fail + notif.send_sync_notification(&peer, vec![1, 3, 3, 7]) +} + +#[tokio::test] +async fn send_async_notification_to_non_existent_peer() { + let (proto, notif) = notification_service("/proto/1".into()); + let (_sink, _, _sync_rx) = NotificationsSink::new(PeerId::random()); + let (_handle, _stream) = proto.split(); + let peer = PeerId::random(); + + if let Err(error::Error::PeerDoesntExist(peer_id)) = + notif.send_async_notification(&peer, vec![1, 3, 3, 7]).await + { + assert_eq!(peer, peer_id); + } else { + panic!("invalid error received from `send_async_notification()`"); + } +} + +#[tokio::test] +async fn receive_notification() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, _, _sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // notification is received + handle.report_notification_received(peer_id, vec![1, 3, 3, 8]).unwrap(); + + if let Some(NotificationEvent::NotificationReceived { peer, notification }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(notification, vec![1, 3, 3, 8]); + } else { + panic!("invalid event received"); + } +} + +#[tokio::test] +async fn backpressure_works() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, mut async_rx, _) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // fill the message buffer with messages + for i in 0..=ASYNC_NOTIFICATIONS_BUFFER_SIZE { + assert!(futures::poll!(notif.send_async_notification(&peer_id, vec![1, 3, 3, i as u8])) + .is_ready()); + } + + // try to send one more message and verify that the call blocks + assert!(futures::poll!(notif.send_async_notification(&peer_id, vec![1, 3, 3, 9])).is_pending()); + + // release one slot from the buffer for new message + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 0] }) + ); + + // verify that a message can be sent + assert!(futures::poll!(notif.send_async_notification(&peer_id, vec![1, 3, 3, 9])).is_ready()); +} + +#[tokio::test] +async fn peer_disconnects_then_sync_notification_is_sent() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, _, sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // report that a substream has been closed but don't poll `notif` to receive this + // information + handle.report_substream_closed(peer_id).unwrap(); + drop(sync_rx); + + // as per documentation, error is not reported but the notification is silently dropped + notif.send_sync_notification(&peer_id, vec![1, 3, 3, 7]); +} + +#[tokio::test] +async fn peer_disconnects_then_async_notification_is_sent() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, async_rx, _) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // report that a substream has been closed but don't poll `notif` to receive this + // information + handle.report_substream_closed(peer_id).unwrap(); + drop(async_rx); + + // as per documentation, error is not reported but the notification is silently dropped + if let Err(error::Error::ConnectionClosed) = + notif.send_async_notification(&peer_id, vec![1, 3, 3, 7]).await + { + } else { + panic!("invalid state after calling `send_async_notificatio()` on closed connection") + } +} + +#[tokio::test] +async fn cloned_service_opening_substream_works() { + let (proto, mut notif1) = notification_service("/proto/1".into()); + let (_sink, _async_rx, _) = NotificationsSink::new(PeerId::random()); + let (handle, _stream) = proto.split(); + let mut notif2 = notif1.clone().unwrap(); + let peer_id = PeerId::random(); + + // validate inbound substream + let mut result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + // verify that `notif1` gets the event + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif1.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + + // verify that because only one listener has thus far send their result, the result is + // pending + assert!(result_rx.try_recv().is_err()); + + // verify that `notif2` also gets the event + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif2.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); +} + +#[tokio::test] +async fn cloned_service_one_service_rejects_substream() { + let (proto, mut notif1) = notification_service("/proto/1".into()); + let (_sink, _async_rx, _) = NotificationsSink::new(PeerId::random()); + let (handle, _stream) = proto.split(); + let mut notif2 = notif1.clone().unwrap(); + let mut notif3 = notif2.clone().unwrap(); + let peer_id = PeerId::random(); + + // validate inbound substream + let mut result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + for notif in vec![&mut notif1, &mut notif2] { + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + } + + // `notif3` has not yet sent their validation result + assert!(result_rx.try_recv().is_err()); + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif3.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Reject).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Reject); +} + +#[tokio::test] +async fn cloned_service_opening_substream_sending_and_receiving_notifications_work() { + let (proto, mut notif1) = notification_service("/proto/1".into()); + let (sink, _, mut sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let mut notif2 = notif1.clone().unwrap(); + let mut notif3 = notif1.clone().unwrap(); + let peer_id = PeerId::random(); + + // validate inbound substream + let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + for notif in vec![&mut notif1, &mut notif2, &mut notif3] { + // accept the inbound substream for all services + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that then notification stream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + for notif in vec![&mut notif1, &mut notif2, &mut notif3] { + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + } + // receive a notification from peer and verify all services receive it + handle.report_notification_received(peer_id, vec![1, 3, 3, 8]).unwrap(); + + for notif in vec![&mut notif1, &mut notif2, &mut notif3] { + if let Some(NotificationEvent::NotificationReceived { peer, notification }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(notification, vec![1, 3, 3, 8]); + } else { + panic!("invalid event received"); + } + } + + for (i, notif) in vec![&mut notif1, &mut notif2, &mut notif3].iter().enumerate() { + // send notification from each service and verify peer receives it + notif.send_sync_notification(&peer_id, vec![1, 3, 3, i as u8]); + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, i as u8] }) + ); + } + + // close the substream for peer and verify all services receive the event + handle.report_substream_closed(peer_id).unwrap(); + + for notif in vec![&mut notif1, &mut notif2, &mut notif3] { + if let Some(NotificationEvent::NotificationStreamClosed { peer }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + } else { + panic!("invalid event received"); + } + } +} + +#[tokio::test] +async fn sending_notifications_using_notifications_sink_works() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, mut async_rx, mut sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // get a copy of the notification sink and send a synchronous notification using. + let sink = notif.message_sink(&peer_id).unwrap(); + sink.send_sync_notification(vec![1, 3, 3, 6]); + + // send an asynchronous notification using the acquired notifications sink. + let _ = sink.send_async_notification(vec![1, 3, 3, 7]).await.unwrap(); + + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 6] }), + ); + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 7] }), + ); + + // send notifications using the stored notification sink as well. + notif.send_sync_notification(&peer_id, vec![1, 3, 3, 8]); + notif.send_async_notification(&peer_id, vec![1, 3, 3, 9]).await.unwrap(); + + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 8] }), + ); + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 9] }), + ); +} + +#[test] +fn try_to_get_notifications_sink_for_non_existent_peer() { + let (_proto, notif) = notification_service("/proto/1".into()); + assert!(notif.message_sink(&PeerId::random()).is_none()); +} + +#[tokio::test] +async fn notification_sink_replaced() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (sink, mut async_rx, mut sync_rx) = NotificationsSink::new(PeerId::random()); + let (mut handle, _stream) = proto.split(); + let peer_id = PeerId::random(); + + // validate inbound substream + let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + + if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = + notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(handshake, vec![1, 3, 3, 7]); + let _ = result_tx.send(ValidationResult::Accept).unwrap(); + } else { + panic!("invalid event received"); + } + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); + + // report that a substream has been opened + handle + .report_substream_opened(peer_id, Direction::Inbound, vec![1, 3, 3, 7], None, sink) + .unwrap(); + + if let Some(NotificationEvent::NotificationStreamOpened { + peer, + negotiated_fallback, + handshake, + direction, + }) = notif.next_event().await + { + assert_eq!(peer_id, peer); + assert_eq!(negotiated_fallback, None); + assert_eq!(handshake, vec![1, 3, 3, 7]); + assert_eq!(direction, Direction::Inbound); + } else { + panic!("invalid event received"); + } + + // get a copy of the notification sink and send a synchronous notification using. + let sink = notif.message_sink(&peer_id).unwrap(); + sink.send_sync_notification(vec![1, 3, 3, 6]); + + // send an asynchronous notification using the acquired notifications sink. + let _ = sink.send_async_notification(vec![1, 3, 3, 7]).await.unwrap(); + + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 6] }), + ); + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 7] }), + ); + + // send notifications using the stored notification sink as well. + notif.send_sync_notification(&peer_id, vec![1, 3, 3, 8]); + notif.send_async_notification(&peer_id, vec![1, 3, 3, 9]).await.unwrap(); + + assert_eq!( + sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 8] }), + ); + assert_eq!( + async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 9] }), + ); + + // the initial connection was closed and `Notifications` switched to secondary connection + // and emitted `CustomProtocolReplaced` which informs the local `NotificationService` that + // the notification sink was replaced. + let (new_sink, mut new_async_rx, mut new_sync_rx) = NotificationsSink::new(PeerId::random()); + handle.report_notification_sink_replaced(peer_id, new_sink).unwrap(); + + // drop the old sinks and poll `notif` once to register the sink replacement + drop(sync_rx); + drop(async_rx); + + futures::future::poll_fn(|cx| { + let _ = std::pin::Pin::new(&mut notif.next_event()).poll(cx); + std::task::Poll::Ready(()) + }) + .await; + + // verify that using the `NotificationService` API automatically results in using the correct + // sink + notif.send_sync_notification(&peer_id, vec![1, 3, 3, 8]); + notif.send_async_notification(&peer_id, vec![1, 3, 3, 9]).await.unwrap(); + + assert_eq!( + new_sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 8] }), + ); + assert_eq!( + new_async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 9] }), + ); + + // now send two notifications using the acquired message sink and verify that + // it's also updated + sink.send_sync_notification(vec![1, 3, 3, 6]); + + // send an asynchronous notification using the acquired notifications sink. + let _ = sink.send_async_notification(vec![1, 3, 3, 7]).await.unwrap(); + + assert_eq!( + new_sync_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 6] }), + ); + assert_eq!( + new_async_rx.next().await, + Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 7] }), + ); +} diff --git a/substrate/client/network/src/protocol/notifications/tests.rs b/substrate/client/network/src/protocol/notifications/tests.rs index d57c24144f57..30bbe0275054 100644 --- a/substrate/client/network/src/protocol/notifications/tests.rs +++ b/substrate/client/network/src/protocol/notifications/tests.rs @@ -22,6 +22,7 @@ use crate::{ peer_store::PeerStore, protocol::notifications::{Notifications, NotificationsOut, ProtocolConfig}, protocol_controller::{ProtoSetConfig, ProtocolController, SetId}, + service::traits::{NotificationEvent, ValidationResult}, }; use futures::{future::BoxFuture, prelude::*}; @@ -70,6 +71,8 @@ fn build_nodes() -> (Swarm, Swarm) { .timeout(Duration::from_secs(20)) .boxed(); + let (protocol_handle_pair, mut notif_service) = + crate::protocol::notifications::service::notification_service("/foo".into()); let peer_store = PeerStore::new(if index == 0 { keypairs.iter().skip(1).map(|keypair| keypair.public().to_peer_id()).collect() } else { @@ -95,12 +98,16 @@ fn build_nodes() -> (Swarm, Swarm) { inner: Notifications::new( vec![controller_handle], from_controller, - iter::once(ProtocolConfig { - name: "/foo".into(), - fallback_names: Vec::new(), - handshake: Vec::new(), - max_notification_size: 1024 * 1024, - }), + &None, + iter::once(( + ProtocolConfig { + name: "/foo".into(), + fallback_names: Vec::new(), + handshake: Vec::new(), + max_notification_size: 1024 * 1024, + }, + protocol_handle_pair, + )), ), peer_store_future: peer_store.run().boxed(), protocol_controller_future: controller.run().boxed(), @@ -118,6 +125,16 @@ fn build_nodes() -> (Swarm, Swarm) { }; let runtime = tokio::runtime::Runtime::new().unwrap(); + runtime.spawn(async move { + loop { + if let NotificationEvent::ValidateInboundSubstream { result_tx, .. } = + notif_service.next_event().await.unwrap() + { + result_tx.send(ValidationResult::Accept).unwrap(); + } + } + }); + let mut swarm = SwarmBuilder::with_executor( transport, behaviour, diff --git a/substrate/client/network/src/protocol_controller.rs b/substrate/client/network/src/protocol_controller.rs index c9baa0a77d4b..1c26d8ce1d89 100644 --- a/substrate/client/network/src/protocol_controller.rs +++ b/substrate/client/network/src/protocol_controller.rs @@ -840,6 +840,7 @@ mod tests { use super::*; use crate::{peer_store::PeerStoreProvider, ReputationChange}; use libp2p::PeerId; + use sc_network_common::role::ObservedRole; use sc_utils::mpsc::{tracing_unbounded, TryRecvError}; use std::collections::HashSet; @@ -851,8 +852,10 @@ mod tests { fn is_banned(&self, peer_id: &PeerId) -> bool; fn register_protocol(&self, protocol_handle: ProtocolHandle); fn report_disconnect(&mut self, peer_id: PeerId); + fn set_peer_role(&mut self, peer_id: &PeerId, role: ObservedRole); fn report_peer(&mut self, peer_id: PeerId, change: ReputationChange); fn peer_reputation(&self, peer_id: &PeerId) -> i32; + fn peer_role(&self, peer_id: &PeerId) -> Option; fn outgoing_candidates<'a>(&self, count: usize, ignored: HashSet<&'a PeerId>) -> Vec; } } diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index aca0072a31de..16ef1d1cd7df 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -54,6 +54,7 @@ use crate::{ ReputationChange, }; +use codec::DecodeAll; use either::Either; use futures::{channel::oneshot, prelude::*}; #[allow(deprecated)] @@ -74,7 +75,10 @@ use log::{debug, error, info, trace, warn}; use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; use parking_lot::Mutex; -use sc_network_common::ExHashT; +use sc_network_common::{ + role::{ObservedRole, Roles}, + ExHashT, +}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_runtime::traits::Block as BlockT; @@ -94,7 +98,7 @@ use std::{ pub use behaviour::{InboundFailure, OutboundFailure, ResponseFailure}; pub use libp2p::identity::{DecodingError, Keypair, PublicKey}; -pub use protocol::NotificationsSink; +pub use protocol::{NotificationCommand, NotificationsSink, ProtocolHandle}; mod metrics; mod out_events; @@ -132,6 +136,8 @@ pub struct NetworkService { protocol_handles: Vec, /// Shortcut to sync protocol handle (`protocol_handles[0]`). sync_protocol_handle: protocol_controller::ProtocolHandle, + /// Handle to `PeerStore`. + peer_store_handle: PeerStoreHandle, /// Marker to pin the `H` generic. Serves no purpose except to not break backwards /// compatibility. _marker: PhantomData, @@ -199,7 +205,7 @@ where )?; for notification_protocol in ¬ification_protocols { ensure_addresses_consistent_with_transport( - notification_protocol.set_config.reserved_nodes.iter().map(|x| &x.multiaddr), + notification_protocol.set_config().reserved_nodes.iter().map(|x| &x.multiaddr), &network_config.transport, )?; } @@ -241,7 +247,7 @@ where .map(|cfg| usize::try_from(cfg.max_response_size).unwrap_or(usize::MAX)); let notifs_max = notification_protocols .iter() - .map(|cfg| usize::try_from(cfg.max_notification_size).unwrap_or(usize::MAX)); + .map(|cfg| usize::try_from(cfg.max_notification_size()).unwrap_or(usize::MAX)); // A "default" max is added to cover all the other protocols: ping, identify, // kademlia, block announces, and transactions. @@ -273,7 +279,7 @@ where // We must prepend a hardcoded default peer set to notification protocols. let all_peer_sets_iter = iter::once(&network_config.default_peers_set) - .chain(notification_protocols.iter().map(|protocol| &protocol.set_config)); + .chain(notification_protocols.iter().map(|protocol| protocol.set_config())); let (protocol_handles, protocol_controllers): (Vec<_>, Vec<_>) = all_peer_sets_iter .enumerate() @@ -312,21 +318,9 @@ where iter::once(¶ms.block_announce_config) .chain(notification_protocols.iter()) .enumerate() - .map(|(index, protocol)| { - (protocol.notifications_protocol.clone(), SetId::from(index)) - }) + .map(|(index, protocol)| (protocol.protocol_name().clone(), SetId::from(index))) .collect(); - let protocol = Protocol::new( - From::from(¶ms.role), - notification_protocols.clone(), - params.block_announce_config, - params.peer_store.clone(), - protocol_handles.clone(), - from_protocol_controllers, - params.tx, - )?; - let known_addresses = { // Collect all reserved nodes and bootnodes addresses. let mut addresses: Vec<_> = network_config @@ -336,7 +330,7 @@ where .map(|reserved| (reserved.peer_id, reserved.multiaddr.clone())) .chain(notification_protocols.iter().flat_map(|protocol| { protocol - .set_config + .set_config() .reserved_nodes .iter() .map(|reserved| (reserved.peer_id, reserved.multiaddr.clone())) @@ -389,6 +383,16 @@ where let num_connected = Arc::new(AtomicUsize::new(0)); let external_addresses = Arc::new(Mutex::new(HashSet::new())); + let protocol = Protocol::new( + From::from(¶ms.role), + ¶ms.metrics_registry, + notification_protocols, + params.block_announce_config, + params.peer_store.clone(), + protocol_handles.clone(), + from_protocol_controllers, + )?; + // Build the swarm. let (mut swarm, bandwidth): (Swarm>, _) = { let user_agent = @@ -525,6 +529,7 @@ where notification_protocol_ids, protocol_handles, sync_protocol_handle, + peer_store_handle: params.peer_store.clone(), _marker: PhantomData, _block: Default::default(), }); @@ -943,9 +948,10 @@ where peers: HashSet, ) -> Result<(), String> { let Some(set_id) = self.notification_protocol_ids.get(&protocol) else { - return Err( - format!("Cannot add peers to reserved set of unknown protocol: {}", protocol) - ) + return Err(format!( + "Cannot add peers to reserved set of unknown protocol: {}", + protocol + )) }; let peers = self.split_multiaddr_and_peer_id(peers)?; @@ -974,9 +980,10 @@ where peers: Vec, ) -> Result<(), String> { let Some(set_id) = self.notification_protocol_ids.get(&protocol) else { - return Err( - format!("Cannot remove peers from reserved set of unknown protocol: {}", protocol) - ) + return Err(format!( + "Cannot remove peers from reserved set of unknown protocol: {}", + protocol + )) }; for peer_id in peers.into_iter() { @@ -989,6 +996,16 @@ where fn sync_num_connected(&self) -> usize { self.num_connected.load(Ordering::Relaxed) } + + fn peer_role(&self, peer_id: PeerId, handshake: Vec) -> Option { + match Roles::decode_all(&mut &handshake[..]) { + Ok(role) => Some(role.into()), + Err(_) => { + log::debug!(target: "sub-libp2p", "handshake doesn't contain peer role: {handshake:?}"); + self.peer_store_handle.peer_role(&peer_id) + }, + } + } } impl NetworkEventStream for NetworkService diff --git a/substrate/client/network/src/service/signature.rs b/substrate/client/network/src/service/signature.rs index 024f60e4c466..5b2ba6be8cf8 100644 --- a/substrate/client/network/src/service/signature.rs +++ b/substrate/client/network/src/service/signature.rs @@ -18,6 +18,8 @@ // // If you read this, you are very thorough, congratulations. +//! Signature-related code + use libp2p::{ identity::{Keypair, PublicKey}, PeerId, diff --git a/substrate/client/network/src/service/traits.rs b/substrate/client/network/src/service/traits.rs index bed325ede4a8..a62283155166 100644 --- a/substrate/client/network/src/service/traits.rs +++ b/substrate/client/network/src/service/traits.rs @@ -18,8 +18,11 @@ // // If you read this, you are very thorough, congratulations. +//! Traits defined by `sc-network`. + use crate::{ config::MultiaddrWithPeerId, + error, event::Event, request_responses::{IfDisconnected, RequestFailure}, service::signature::Signature, @@ -30,7 +33,9 @@ use crate::{ use futures::{channel::oneshot, Stream}; use libp2p::{Multiaddr, PeerId}; -use std::{collections::HashSet, future::Future, pin::Pin, sync::Arc}; +use sc_network_common::role::ObservedRole; + +use std::{collections::HashSet, fmt::Debug, future::Future, pin::Pin, sync::Arc}; pub use libp2p::{identity::SigningError, kad::record::Key as KademliaKey}; @@ -221,6 +226,14 @@ pub trait NetworkPeers { /// Returns the number of peers in the sync peer set we're connected to. fn sync_num_connected(&self) -> usize; + + /// Attempt to get peer role. + /// + /// Right now the peer role is decoded from the received handshake for all protocols + /// (`/block-announces/1` has other information as well). If the handshake cannot be + /// decoded into a role, the role queried from `PeerStore` and if the role is not stored + /// there either, `None` is returned and the peer should be discarded. + fn peer_role(&self, peer_id: PeerId, handshake: Vec) -> Option; } // Manual implementation to avoid extra boxing here @@ -296,6 +309,10 @@ where fn sync_num_connected(&self) -> usize { T::sync_num_connected(self) } + + fn peer_role(&self, peer_id: PeerId, handshake: Vec) -> Option { + T::peer_role(self, peer_id, handshake) + } } /// Provides access to network-level event stream. @@ -611,3 +628,182 @@ where T::new_best_block_imported(self, hash, number) } } + +/// Substream acceptance result. +#[derive(Debug, PartialEq, Eq)] +pub enum ValidationResult { + /// Accept inbound substream. + Accept, + + /// Reject inbound substream. + Reject, +} + +/// Substream direction. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Direction { + /// Substream opened by the remote node. + Inbound, + + /// Substream opened by the local node. + Outbound, +} + +impl Direction { + /// Is the direction inbound. + pub fn is_inbound(&self) -> bool { + std::matches!(self, Direction::Inbound) + } +} + +/// Events received by the protocol from `Notifications`. +#[derive(Debug)] +pub enum NotificationEvent { + /// Validate inbound substream. + ValidateInboundSubstream { + /// Peer ID. + peer: PeerId, + + /// Received handshake. + handshake: Vec, + + /// `oneshot::Sender` for sending validation result back to `Notifications` + result_tx: tokio::sync::oneshot::Sender, + }, + + /// Remote identified by `PeerId` opened a substream and sent `Handshake`. + /// Validate `Handshake` and report status (accept/reject) to `Notifications`. + NotificationStreamOpened { + /// Peer ID. + peer: PeerId, + + /// Is the substream inbound or outbound. + direction: Direction, + + /// Received handshake. + handshake: Vec, + + /// Negotiated fallback. + negotiated_fallback: Option, + }, + + /// Substream was closed. + NotificationStreamClosed { + /// Peer Id. + peer: PeerId, + }, + + /// Notification was received from the substream. + NotificationReceived { + /// Peer ID. + peer: PeerId, + + /// Received notification. + notification: Vec, + }, +} + +/// Notification service +/// +/// Defines behaviors that both the protocol implementations and `Notifications` can expect from +/// each other. +/// +/// `Notifications` can send two different kinds of information to protocol: +/// * substream-related information +/// * notification-related information +/// +/// When an unvalidated, inbound substream is received by `Notifications`, it sends the inbound +/// stream information (peer ID, handshake) to protocol for validation. Protocol must then verify +/// that the handshake is valid (and in the future that it has a slot it can allocate for the peer) +/// and then report back the `ValidationResult` which is either `Accept` or `Reject`. +/// +/// After the validation result has been received by `Notifications`, it prepares the +/// substream for communication by initializing the necessary sinks and emits +/// `NotificationStreamOpened` which informs the protocol that the remote peer is ready to receive +/// notifications. +/// +/// Two different flavors of sending options are provided: +/// * synchronous sending ([`NotificationService::send_sync_notification()`]) +/// * asynchronous sending ([`NotificationService::send_async_notification()`]) +/// +/// The former is used by the protocols not ready to exercise backpressure and the latter by the +/// protocols that can do it. +/// +/// Both local and remote peer can close the substream at any time. Local peer can do so by calling +/// [`NotificationService::close_substream()`] which instrucs `Notifications` to close the +/// substream. Remote closing the substream is indicated to the local peer by receiving +/// [`NotificationEvent::NotificationStreamClosed`] event. +/// +/// In case the protocol must update its handshake while it's operating (such as updating the best +/// block information), it can do so by calling [`NotificationService::set_handshake()`] +/// which instructs `Notifications` to update the handshake it stored during protocol +/// initialization. +/// +/// All peer events are multiplexed on the same incoming event stream from `Notifications` and thus +/// each event carries a `PeerId` so the protocol knows whose information to update when receiving +/// an event. +#[async_trait::async_trait] +pub trait NotificationService: Debug + Send { + /// Instruct `Notifications` to open a new substream for `peer`. + /// + /// `dial_if_disconnected` informs `Notifications` whether to dial + // the peer if there is currently no active connection to it. + // + // NOTE: not offered by the current implementation + async fn open_substream(&mut self, peer: PeerId) -> Result<(), ()>; + + /// Instruct `Notifications` to close substream for `peer`. + // + // NOTE: not offered by the current implementation + async fn close_substream(&mut self, peer: PeerId) -> Result<(), ()>; + + /// Send synchronous `notification` to `peer`. + fn send_sync_notification(&self, peer: &PeerId, notification: Vec); + + /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure. + /// + /// Returns an error if the peer doesn't exist. + async fn send_async_notification( + &self, + peer: &PeerId, + notification: Vec, + ) -> Result<(), error::Error>; + + /// Set handshake for the notification protocol replacing the old handshake. + async fn set_handshake(&mut self, handshake: Vec) -> Result<(), ()>; + + /// Get next event from the `Notifications` event stream. + async fn next_event(&mut self) -> Option; + + /// Make a copy of the object so it can be shared between protocol components + /// who wish to have access to the same underlying notification protocol. + fn clone(&mut self) -> Result, ()>; + + /// Get protocol name of the `NotificationService`. + fn protocol(&self) -> &ProtocolName; + + /// Get message sink of the peer. + fn message_sink(&self, peer: &PeerId) -> Option>; +} + +/// Message sink for peers. +/// +/// If protocol cannot use [`NotificationService`] to send notifications to peers and requires, +/// e.g., notifications to be sent in another task, the protocol may acquire a [`MessageSink`] +/// object for each peer by calling [`NotificationService::message_sink()`]. Calling this +/// function returns an object which allows the protocol to send notifications to the remote peer. +/// +/// Use of this API is discouraged as it's not as performant as sending notifications through +/// [`NotificationService`] due to synchronization required to keep the underlying notification +/// sink up to date with possible sink replacement events. +#[async_trait::async_trait] +pub trait MessageSink: Send { + /// Send synchronous `notification` to the peer associated with this [`MessageSink`]. + fn send_sync_notification(&self, notification: Vec); + + /// Send an asynchronous `notification` to to the peer associated with this [`MessageSink`], + /// allowing sender to exercise backpressure. + /// + /// Returns an error if the peer does not exist. + async fn send_async_notification(&self, notification: Vec) -> Result<(), error::Error>; +} diff --git a/substrate/client/network/statement/src/lib.rs b/substrate/client/network/statement/src/lib.rs index c5d83b59b260..ae73034a975f 100644 --- a/substrate/client/network/statement/src/lib.rs +++ b/substrate/client/network/statement/src/lib.rs @@ -21,12 +21,13 @@ //! Usage: //! //! - Use [`StatementHandlerPrototype::new`] to create a prototype. -//! - Pass the return value of [`StatementHandlerPrototype::set_config`] to the network -//! configuration as an extra peers set. +//! - Pass the `NonDefaultSetConfig` returned from [`StatementHandlerPrototype::new`] to the network +//! configuration as an extra peers set. //! - Use [`StatementHandlerPrototype::build`] then [`StatementHandler::run`] to obtain a //! `Future` that processes statements. use crate::config::*; + use codec::{Decode, Encode}; use futures::{channel::oneshot, prelude::*, stream::FuturesUnordered, FutureExt}; use libp2p::{multiaddr, PeerId}; @@ -34,7 +35,7 @@ use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network::{ config::{NonDefaultSetConfig, NonReservedPeerMode, SetConfig}, error, - event::Event, + service::traits::{NotificationEvent, NotificationService, ValidationResult}, types::ProtocolName, utils::{interval, LruHashSet}, NetworkEventStream, NetworkNotification, NetworkPeers, @@ -103,35 +104,35 @@ impl Metrics { /// Prototype for a [`StatementHandler`]. pub struct StatementHandlerPrototype { protocol_name: ProtocolName, + notification_service: Box, } impl StatementHandlerPrototype { /// Create a new instance. - pub fn new>(genesis_hash: Hash, fork_id: Option<&str>) -> Self { + pub fn new>( + genesis_hash: Hash, + fork_id: Option<&str>, + ) -> (Self, NonDefaultSetConfig) { let genesis_hash = genesis_hash.as_ref(); let protocol_name = if let Some(fork_id) = fork_id { format!("/{}/{}/statement/1", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { format!("/{}/statement/1", array_bytes::bytes2hex("", genesis_hash)) }; - - Self { protocol_name: protocol_name.into() } - } - - /// Returns the configuration of the set to put in the network configuration. - pub fn set_config(&self) -> NonDefaultSetConfig { - NonDefaultSetConfig { - notifications_protocol: self.protocol_name.clone(), - fallback_names: Vec::new(), - max_notification_size: MAX_STATEMENT_SIZE, - handshake: None, - set_config: SetConfig { + let (config, notification_service) = NonDefaultSetConfig::new( + protocol_name.clone().into(), + Vec::new(), + MAX_STATEMENT_SIZE, + None, + SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), non_reserved_mode: NonReservedPeerMode::Deny, }, - } + ); + + (Self { protocol_name: protocol_name.into(), notification_service }, config) } /// Turns the prototype into the actual handler. @@ -149,7 +150,6 @@ impl StatementHandlerPrototype { metrics_registry: Option<&Registry>, executor: impl Fn(Pin + Send>>) + Send, ) -> error::Result> { - let net_event_stream = network.event_stream("statement-handler-net"); let sync_event_stream = sync.event_stream("statement-handler-sync"); let (queue_sender, mut queue_receiver) = async_channel::bounded(100_000); @@ -178,6 +178,7 @@ impl StatementHandlerPrototype { let handler = StatementHandler { protocol_name: self.protocol_name, + notification_service: self.notification_service, propagate_timeout: (Box::pin(interval(PROPAGATE_TIMEOUT)) as Pin + Send>>) .fuse(), @@ -185,7 +186,6 @@ impl StatementHandlerPrototype { pending_statements_peers: HashMap::new(), network, sync, - net_event_stream: net_event_stream.fuse(), sync_event_stream: sync_event_stream.fuse(), peers: HashMap::new(), statement_store, @@ -221,10 +221,10 @@ pub struct StatementHandler< network: N, /// Syncing service. sync: S, - /// Stream of networking events. - net_event_stream: stream::Fuse + Send>>>, /// Receiver for syncing-related events. sync_event_stream: stream::Fuse + Send>>>, + /// Notification service. + notification_service: Box, // All connected peers peers: HashMap, statement_store: Arc, @@ -263,14 +263,6 @@ where log::warn!(target: LOG_TARGET, "Inconsistent state, no peers for pending statement!"); } }, - network_event = self.net_event_stream.next() => { - if let Some(network_event) = network_event { - self.handle_network_event(network_event).await; - } else { - // Networking has seemingly closed. Closing as well. - return; - } - }, sync_event = self.sync_event_stream.next() => { if let Some(sync_event) = sync_event { self.handle_sync_event(sync_event); @@ -279,6 +271,14 @@ where return; } } + event = self.notification_service.next_event().fuse() => { + if let Some(event) = event { + self.handle_notification_event(event) + } else { + // `Notifications` has seemingly closed. Closing as well. + return + } + } } } } @@ -308,14 +308,19 @@ where } } - async fn handle_network_event(&mut self, event: Event) { + fn handle_notification_event(&mut self, event: NotificationEvent) { match event { - Event::Dht(_) => {}, - Event::NotificationStreamOpened { remote, protocol, role, .. } - if protocol == self.protocol_name => - { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + let _ = result_tx.send(ValidationResult::Accept); + }, + NotificationEvent::NotificationStreamOpened { peer, handshake, .. } => { + let Some(role) = self.network.peer_role(peer, handshake) else { + log::debug!(target: LOG_TARGET, "role for {peer} couldn't be determined"); + return + }; + let _was_in = self.peers.insert( - remote, + peer, Peer { known_statements: LruHashSet::new( NonZeroUsize::new(MAX_KNOWN_STATEMENTS).expect("Constant is nonzero"), @@ -325,39 +330,26 @@ where ); debug_assert!(_was_in.is_none()); }, - Event::NotificationStreamClosed { remote, protocol } - if protocol == self.protocol_name => - { - let _peer = self.peers.remove(&remote); + NotificationEvent::NotificationStreamClosed { peer } => { + let _peer = self.peers.remove(&peer); debug_assert!(_peer.is_some()); }, + NotificationEvent::NotificationReceived { peer, notification } => { + // Accept statements only when node is not major syncing + if self.sync.is_major_syncing() { + log::trace!( + target: LOG_TARGET, + "{peer}: Ignoring statements while major syncing or offline" + ); + return + } - Event::NotificationsReceived { remote, messages } => { - for (protocol, message) in messages { - if protocol != self.protocol_name { - continue - } - // Accept statements only when node is not major syncing - if self.sync.is_major_syncing() { - log::trace!( - target: LOG_TARGET, - "{remote}: Ignoring statements while major syncing or offline" - ); - continue - } - if let Ok(statements) = ::decode(&mut message.as_ref()) { - self.on_statements(remote, statements); - } else { - log::debug!( - target: LOG_TARGET, - "Failed to decode statement list from {remote}" - ); - } + if let Ok(statements) = ::decode(&mut notification.as_ref()) { + self.on_statements(peer, statements); + } else { + log::debug!(target: LOG_TARGET, "Failed to decode statement list from {peer}"); } }, - - // Not our concern. - Event::NotificationStreamOpened { .. } | Event::NotificationStreamClosed { .. } => {}, } } diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 65bd56a28958..71abbcdd7f21 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -24,7 +24,7 @@ use crate::{ ChainSync, ClientError, SyncingService, }; -use codec::{Decode, Encode}; +use codec::{Decode, DecodeAll, Encode}; use futures::{FutureExt, StreamExt}; use futures_timer::Delay; use libp2p::PeerId; @@ -37,8 +37,11 @@ use sc_client_api::{BlockBackend, HeaderBackend, ProofProvider}; use sc_consensus::import_queue::ImportQueueService; use sc_network::{ config::{FullNetworkConfiguration, NonDefaultSetConfig, ProtocolId}, + peer_store::{PeerStoreHandle, PeerStoreProvider}, + service::traits::{Direction, NotificationEvent, ValidationResult}, + types::ProtocolName, utils::LruHashSet, - NotificationsSink, ProtocolName, ReputationChange, + NotificationService, ReputationChange, }; use sc_network_common::{ role::Roles, @@ -51,7 +54,7 @@ use sc_network_common::{ use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_blockchain::HeaderMetadata; use sp_consensus::block_validation::BlockAnnounceValidator; -use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; +use sp_runtime::traits::{Block as BlockT, Header, Zero}; use std::{ collections::{HashMap, HashSet}, @@ -70,6 +73,9 @@ const TICK_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(1100) /// Maximum number of known block hashes to keep for a peer. const MAX_KNOWN_BLOCKS: usize = 1024; // ~32kb per peer + LruHashSet overhead +/// Logging target for the file. +const LOG_TARGET: &str = "sync"; + /// If the block announces stream to peer has been inactive for 30 seconds meaning local node /// has not sent or received block announcements to/from the peer, report the node for inactivity, /// disconnect it and attempt to establish connection to some other peer. @@ -172,8 +178,6 @@ pub struct Peer { pub info: ExtendedPeerInfo, /// Holds a set of blocks known to this peer. pub known_blocks: LruHashSet, - /// Notification sink. - sink: NotificationsSink, /// Is the peer inbound. inbound: bool, } @@ -198,9 +202,6 @@ pub struct SyncingEngine { /// Channel for receiving service commands service_rx: TracingUnboundedReceiver>, - /// Channel for receiving inbound connections from `Protocol`. - rx: sc_utils::mpsc::TracingUnboundedReceiver>, - /// Assigned roles. roles: Roles, @@ -251,12 +252,18 @@ pub struct SyncingEngine { /// Prometheus metrics. metrics: Option, + /// Handle that is used to communicate with `sc_network::Notifications`. + notification_service: Box, + /// When the syncing was started. /// /// Stored as an `Option` so once the initial wait has passed, `SyncingEngine` /// can reset the peer timers and continue with the normal eviction process. syncing_started: Option, + /// Handle to `PeerStore`. + peer_store_handle: PeerStoreHandle, + /// Instant when the last notification was sent or received. last_notification_io: Instant, } @@ -286,7 +293,7 @@ where block_request_protocol_name: ProtocolName, state_request_protocol_name: ProtocolName, warp_sync_protocol_name: Option, - rx: sc_utils::mpsc::TracingUnboundedReceiver>, + peer_store_handle: PeerStoreHandle, ) -> Result<(Self, SyncingService, NonDefaultSetConfig), ClientError> { let mode = net_config.network_config.sync_mode; let max_parallel_downloads = net_config.network_config.max_parallel_downloads; @@ -308,7 +315,7 @@ where } for config in net_config.notification_protocols() { let peer_ids = config - .set_config + .set_config() .reserved_nodes .iter() .map(|info| info.peer_id) @@ -346,7 +353,7 @@ where total.saturating_sub(net_config.network_config.default_peers_set_num_full) as usize }; - let (chain_sync, block_announce_config) = ChainSync::new( + let (chain_sync, block_announce_config, notification_service) = ChainSync::new( mode, client.clone(), protocol_id, @@ -364,7 +371,7 @@ where warp_sync_protocol_name, )?; - let block_announce_protocol_name = block_announce_config.notifications_protocol.clone(); + let block_announce_protocol_name = block_announce_config.protocol_name().clone(); let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync", 100_000); let num_connected = Arc::new(AtomicUsize::new(0)); let is_major_syncing = Arc::new(AtomicBool::new(false)); @@ -392,7 +399,6 @@ where num_connected: num_connected.clone(), is_major_syncing: is_major_syncing.clone(), service_rx, - rx, genesis_hash, important_peers, default_peers_set_no_slot_connected_peers: HashSet::new(), @@ -403,8 +409,10 @@ where num_in_peers: 0usize, max_in_peers, event_streams: Vec::new(), + notification_service, tick_timeout: Delay::new(TICK_TIMEOUT), syncing_started: None, + peer_store_handle, last_notification_io: Instant::now(), metrics: if let Some(r) = metrics_registry { match Metrics::register(r, is_major_syncing.clone()) { @@ -569,23 +577,11 @@ where }; self.last_notification_io = Instant::now(); - peer.sink.send_sync_notification(message.encode()); + let _ = self.notification_service.send_sync_notification(who, message.encode()); } } } - /// Inform sync about new best imported block. - pub fn new_best_block_imported(&mut self, hash: B::Hash, number: NumberFor) { - log::debug!(target: "sync", "New best block imported {:?}/#{}", hash, number); - - self.chain_sync.update_chain_info(&hash, number); - self.network_service.set_notification_handshake( - self.block_announce_protocol_name.clone(), - BlockAnnouncesHandshake::::build(self.roles, number, hash, self.genesis_hash) - .encode(), - ) - } - pub async fn run(mut self) { self.syncing_started = Some(Instant::now()); @@ -669,8 +665,25 @@ where } }, ToServiceCommand::AnnounceBlock(hash, data) => self.announce_block(hash, data), - ToServiceCommand::NewBestBlockImported(hash, number) => - self.new_best_block_imported(hash, number), + ToServiceCommand::NewBestBlockImported(hash, number) => { + log::debug!(target: "sync", "New best block imported {:?}/#{}", hash, number); + + self.chain_sync.update_chain_info(&hash, number); + // TODO: remove once `SyncingEngine` is refactored + while let Poll::Pending = self + .notification_service + .set_handshake( + BlockAnnouncesHandshake::::build( + self.roles, + number, + hash, + self.genesis_hash, + ) + .encode(), + ) + .poll_unpin(cx) + {} + }, ToServiceCommand::Status(tx) => { let mut status = self.chain_sync.status(); status.num_connected_peers = self.peers.len() as u32; @@ -707,64 +720,74 @@ where } } - while let Poll::Ready(Some(event)) = self.rx.poll_next_unpin(cx) { + loop { + let Poll::Ready(Some(event)) = self.notification_service.next_event().poll_unpin(cx) + else { + break + }; + match event { - sc_network::SyncEvent::NotificationStreamOpened { - remote, - received_handshake, - sink, - inbound, - tx, - } => match self.on_sync_peer_connected(remote, &received_handshake, sink, inbound) { - Ok(()) => { - let _ = tx.send(true); - }, - Err(()) => { - log::debug!( - target: "sync", - "Failed to register peer {remote:?}: {received_handshake:?}", - ); - let _ = tx.send(false); - }, - }, - sc_network::SyncEvent::NotificationStreamClosed { remote } => { - if self.on_sync_peer_disconnected(remote).is_err() { - log::trace!( - target: "sync", - "Disconnected peer which had earlier been refused by on_sync_peer_connected {}", - remote - ); - } + NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx } => { + let validation_result = self + .validate_connection(&peer, handshake, Direction::Inbound) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + + let _ = result_tx.send(validation_result); }, - sc_network::SyncEvent::NotificationsReceived { remote, messages } => { - for message in messages { - if self.peers.contains_key(&remote) { - if let Ok(announce) = BlockAnnounce::decode(&mut message.as_ref()) { - self.last_notification_io = Instant::now(); - self.push_block_announce_validation(remote, announce); - - // Make sure that the newly added block announce validation future - // was polled once to be registered in the task. - if let Poll::Ready(res) = - self.chain_sync.poll_block_announce_validation(cx) - { - self.process_block_announce_validation_result(res) - } - } else { - log::warn!(target: "sub-libp2p", "Failed to decode block announce"); + NotificationEvent::NotificationStreamOpened { + peer, handshake, direction, .. + } => { + log::debug!( + target: LOG_TARGET, + "Substream opened for {peer}, handshake {handshake:?}" + ); + + match self.validate_connection(&peer, handshake, direction) { + Ok(handshake) => { + if self.on_sync_peer_connected(peer, &handshake, direction).is_err() { + log::debug!(target: LOG_TARGET, "Failed to register peer {peer}"); + self.network_service.disconnect_peer( + peer, + self.block_announce_protocol_name.clone(), + ); } - } else { - log::trace!( - target: "sync", - "Received sync for peer earlier refused by sync layer: {}", - remote - ); - } + }, + Err(wrong_genesis) => { + log::debug!(target: LOG_TARGET, "`SyncingEngine` rejected {peer}"); + + if wrong_genesis { + self.peer_store_handle.report_peer(peer, rep::GENESIS_MISMATCH); + } + + self.network_service + .disconnect_peer(peer, self.block_announce_protocol_name.clone()); + }, } }, - sc_network::SyncEvent::NotificationSinkReplaced { remote, sink } => { - if let Some(peer) = self.peers.get_mut(&remote) { - peer.sink = sink; + NotificationEvent::NotificationStreamClosed { peer } => { + self.on_sync_peer_disconnected(peer); + }, + NotificationEvent::NotificationReceived { peer, notification } => { + if !self.peers.contains_key(&peer) { + log::error!( + target: LOG_TARGET, + "received notification from {peer} who had been earlier refused by `SyncingEngine`", + ); + continue + } + + let Ok(announce) = BlockAnnounce::decode(&mut notification.as_ref()) else { + log::warn!(target: LOG_TARGET, "failed to decode block announce"); + continue + }; + + // push the block announcement for validation and make sure it's polled + // once to register it in the task. + self.last_notification_io = Instant::now(); + self.push_block_announce_validation(peer, announce); + + if let Poll::Ready(res) = self.chain_sync.poll_block_announce_validation(cx) { + self.process_block_announce_validation_result(res) } }, } @@ -783,120 +806,166 @@ where /// Called by peer when it is disconnecting. /// /// Returns a result if the handshake of this peer was indeed accepted. - pub fn on_sync_peer_disconnected(&mut self, peer: PeerId) -> Result<(), ()> { - if let Some(info) = self.peers.remove(&peer) { - if self.important_peers.contains(&peer) { - log::warn!(target: "sync", "Reserved peer {} disconnected", peer); - } else { - log::debug!(target: "sync", "{} disconnected", peer); - } - - if !self.default_peers_set_no_slot_connected_peers.remove(&peer) && - info.inbound && info.info.roles.is_full() - { - match self.num_in_peers.checked_sub(1) { - Some(value) => { - self.num_in_peers = value; - }, - None => { - log::error!( - target: "sync", - "trying to disconnect an inbound node which is not counted as inbound" - ); - debug_assert!(false); - }, - } - } + pub fn on_sync_peer_disconnected(&mut self, peer: PeerId) { + let Some(info) = self.peers.remove(&peer) else { + log::debug!(target: LOG_TARGET, "{peer} does not exist in `SyncingEngine`"); + return + }; - self.chain_sync.peer_disconnected(&peer); - self.event_streams - .retain(|stream| stream.unbounded_send(SyncEvent::PeerDisconnected(peer)).is_ok()); - Ok(()) + if self.important_peers.contains(&peer) { + log::warn!(target: "sync", "Reserved peer {} disconnected", peer); } else { - Err(()) + log::debug!(target: "sync", "{} disconnected", peer); } - } - /// Called on the first connection between two peers on the default set, after their exchange - /// of handshake. - /// - /// Returns `Ok` if the handshake is accepted and the peer added to the list of peers we sync - /// from. - pub fn on_sync_peer_connected( - &mut self, - who: PeerId, - status: &BlockAnnouncesHandshake, - sink: NotificationsSink, - inbound: bool, - ) -> Result<(), ()> { - log::trace!(target: "sync", "New peer {} {:?}", who, status); - - if self.peers.contains_key(&who) { - log::error!(target: "sync", "Called on_sync_peer_connected with already connected peer {}", who); - debug_assert!(false); - return Err(()) + if !self.default_peers_set_no_slot_connected_peers.remove(&peer) && + info.inbound && info.info.roles.is_full() + { + match self.num_in_peers.checked_sub(1) { + Some(value) => { + self.num_in_peers = value; + }, + None => { + log::error!( + target: "sync", + "trying to disconnect an inbound node which is not counted as inbound" + ); + debug_assert!(false); + }, + } } - if status.genesis_hash != self.genesis_hash { - self.network_service.report_peer(who, rep::GENESIS_MISMATCH); + self.chain_sync.peer_disconnected(&peer); + self.event_streams + .retain(|stream| stream.unbounded_send(SyncEvent::PeerDisconnected(peer)).is_ok()); + } - if self.important_peers.contains(&who) { + /// Validate received handshake. + fn validate_handshake( + &mut self, + peer_id: &PeerId, + handshake: Vec, + ) -> Result, bool> { + log::trace!(target: LOG_TARGET, "Validate handshake for {peer_id}"); + + let handshake = as DecodeAll>::decode_all(&mut &handshake[..]) + .map_err(|error| { + log::debug!(target: LOG_TARGET, "Failed to decode handshake for {peer_id}: {error:?}"); + false + })?; + + if handshake.genesis_hash != self.genesis_hash { + if self.important_peers.contains(&peer_id) { log::error!( - target: "sync", - "Reserved peer id `{}` is on a different chain (our genesis: {} theirs: {})", - who, + target: LOG_TARGET, + "Reserved peer id `{peer_id}` is on a different chain (our genesis: {} theirs: {})", self.genesis_hash, - status.genesis_hash, + handshake.genesis_hash, ); - } else if self.boot_node_ids.contains(&who) { + } else if self.boot_node_ids.contains(&peer_id) { log::error!( - target: "sync", - "Bootnode with peer id `{}` is on a different chain (our genesis: {} theirs: {})", - who, + target: LOG_TARGET, + "Bootnode with peer id `{peer_id}` is on a different chain (our genesis: {} theirs: {})", self.genesis_hash, - status.genesis_hash, + handshake.genesis_hash, ); } else { log::debug!( - target: "sync", + target: LOG_TARGET, "Peer is on different chain (our genesis: {} theirs: {})", - self.genesis_hash, status.genesis_hash + self.genesis_hash, + handshake.genesis_hash ); } - return Err(()) + return Err(true) } - let no_slot_peer = self.default_peers_set_no_slot_peers.contains(&who); - let this_peer_reserved_slot: usize = if no_slot_peer { 1 } else { 0 }; + Ok(handshake) + } - // make sure to accept no more than `--in-peers` many full nodes - if !no_slot_peer && - status.roles.is_full() && - inbound && self.num_in_peers == self.max_in_peers - { - log::debug!(target: "sync", "All inbound slots have been consumed, rejecting {who}"); - return Err(()) + /// Validate connection. + // NOTE Returning `Err(bool)` is a really ugly hack to work around the issue + // that `ProtocolController` thinks the peer is connected when in fact it can + // still be under validation. If the peer has different genesis than the + // local node the validation fails but the peer cannot be reported in + // `validate_connection()` as that is also called by + // `ValiateInboundSubstream` which means that the peer is still being + // validated and banning the peer when handling that event would + // result in peer getting dropped twice. + // + // The proper way to fix this is to integrate `ProtocolController` more + // tightly with `NotificationService` or add an additional API call for + // banning pre-accepted peers (which is not desirable) + fn validate_connection( + &mut self, + peer_id: &PeerId, + handshake: Vec, + direction: Direction, + ) -> Result, bool> { + log::trace!(target: LOG_TARGET, "New peer {peer_id} {handshake:?}"); + + let handshake = self.validate_handshake(peer_id, handshake)?; + + if self.peers.contains_key(&peer_id) { + log::error!( + target: LOG_TARGET, + "Called `validate_connection()` with already connected peer {peer_id}", + ); + debug_assert!(false); + return Err(false) } - if status.roles.is_full() && + let no_slot_peer = self.default_peers_set_no_slot_peers.contains(&peer_id); + let this_peer_reserved_slot: usize = if no_slot_peer { 1 } else { 0 }; + + if handshake.roles.is_full() && self.chain_sync.num_peers() >= self.default_peers_set_num_full + self.default_peers_set_no_slot_connected_peers.len() + this_peer_reserved_slot { - log::debug!(target: "sync", "Too many full nodes, rejecting {}", who); - return Err(()) + log::debug!(target: LOG_TARGET, "Too many full nodes, rejecting {peer_id}"); + return Err(false) + } + + // make sure to accept no more than `--in-peers` many full nodes + if !no_slot_peer && + handshake.roles.is_full() && + direction.is_inbound() && + self.num_in_peers == self.max_in_peers + { + log::debug!(target: LOG_TARGET, "All inbound slots have been consumed, rejecting {peer_id}"); + return Err(false) } - if status.roles.is_light() && + // make sure that all slots are not occupied by light peers + // + // `ChainSync` only accepts full peers whereas `SyncingEngine` accepts both full and light + // peers. Verify that there is a slot in `SyncingEngine` for the inbound light peer + if handshake.roles.is_light() && (self.peers.len() - self.chain_sync.num_peers()) >= self.default_peers_set_num_light { - // Make sure that not all slots are occupied by light clients. - log::debug!(target: "sync", "Too many light nodes, rejecting {}", who); - return Err(()) + log::debug!(target: LOG_TARGET, "Too many light nodes, rejecting {peer_id}"); + return Err(false) } + Ok(handshake) + } + + /// Called on the first connection between two peers on the default set, after their exchange + /// of handshake. + /// + /// Returns `Ok` if the handshake is accepted and the peer added to the list of peers we sync + /// from. + pub fn on_sync_peer_connected( + &mut self, + who: PeerId, + status: &BlockAnnouncesHandshake, + direction: Direction, + ) -> Result<(), ()> { + log::trace!(target: "sync", "New peer {} {:?}", who, status); + let peer = Peer { info: ExtendedPeerInfo { roles: status.roles, @@ -906,8 +975,7 @@ where known_blocks: LruHashSet::new( NonZeroUsize::new(MAX_KNOWN_BLOCKS).expect("Constant is nonzero"), ), - sink, - inbound, + inbound: direction.is_inbound(), }; let req = if peer.info.roles.is_full() { @@ -922,13 +990,14 @@ where None }; - log::debug!(target: "sync", "Connected {}", who); + log::debug!(target: LOG_TARGET, "Peer connected {who}"); self.peers.insert(who, peer); + self.peer_store_handle.set_peer_role(&who, status.roles.into()); - if no_slot_peer { + if self.default_peers_set_no_slot_peers.contains(&who) { self.default_peers_set_no_slot_connected_peers.insert(who); - } else if inbound && status.roles.is_full() { + } else if direction.is_inbound() && status.roles.is_full() { self.num_in_peers += 1; } @@ -942,3 +1011,331 @@ where Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::service::network::NetworkServiceProvider; + use sc_block_builder::BlockBuilderProvider; + use sc_network::{ + config::NetworkConfiguration, peer_store::PeerStore, service::traits::Direction, + NetworkBlock, NotificationCommand, NotificationsSink, + }; + use sp_consensus::block_validation::DefaultBlockAnnounceValidator; + use substrate_test_runtime_client::{ + runtime::Block, DefaultTestClientBuilderExt, TestClient, TestClientBuilder, + TestClientBuilderExt, + }; + + fn make_syncing_engine() -> ( + Arc, + SyncingEngine, + SyncingService, + NonDefaultSetConfig, + ) { + let mut net_config = NetworkConfiguration::new_local(); + + // 8 outbound full nodes, 32 inbound full nodes and 100 inbound light nodes + net_config.default_peers_set_num_full = 40; + net_config.default_peers_set.in_peers = 132; + net_config.default_peers_set.out_peers = 8; + + let full_config = FullNetworkConfiguration::new(&net_config); + let client = Arc::new(TestClientBuilder::new().build()); + let block_announce_validator = Box::new(DefaultBlockAnnounceValidator); + let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); + let (_chain_sync_network_provider, chain_sync_network_handle) = + NetworkServiceProvider::new(); + let peer_store = PeerStore::new(vec![]); + let handle = peer_store.handle(); + + let (engine, service, config) = SyncingEngine::new( + Roles::FULL, + client.clone(), + None, + &full_config, + ProtocolId::from("test-protocol-name"), + &None, + block_announce_validator, + None, + chain_sync_network_handle, + import_queue, + ProtocolName::from("/block-request/1"), + ProtocolName::from("/state-request/1"), + None, + handle, + ) + .unwrap(); + + (client, engine, service, config) + } + + #[tokio::test] + async fn reject_invalid_handshake() { + let (_client, engine, _service, config) = make_syncing_engine(); + let (handle, _) = config.take_protocol_handle().split(); + + tokio::spawn(engine.run()); + + let rx = handle.report_incoming_substream(PeerId::random(), vec![1, 2, 3, 4]).unwrap(); + + assert_eq!(rx.await, Ok(ValidationResult::Reject)); + } + + #[tokio::test] + async fn accept_valid_peer() { + let (client, engine, _service, config) = make_syncing_engine(); + let (handle, _) = config.take_protocol_handle().split(); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let handshake = BlockAnnouncesHandshake::::build( + engine.roles, + *block.header().number(), + block.hash(), + engine.genesis_hash, + ) + .encode(); + + tokio::spawn(engine.run()); + + let rx = handle.report_incoming_substream(PeerId::random(), handshake).unwrap(); + + assert_eq!(rx.await, Ok(ValidationResult::Accept)); + } + + #[tokio::test] + async fn valid_peer_included_into_peers() { + let (client, engine, service, config) = make_syncing_engine(); + let (mut handle, _) = config.take_protocol_handle().split(); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let handshake = BlockAnnouncesHandshake::::build( + engine.roles, + *block.header().number(), + block.hash(), + engine.genesis_hash, + ) + .encode(); + + tokio::spawn(engine.run()); + + let peer_id = PeerId::random(); + let rx = handle.report_incoming_substream(peer_id, handshake.clone()).unwrap(); + assert_eq!(rx.await, Ok(ValidationResult::Accept)); + let (sink, _, _) = NotificationsSink::new(peer_id); + + handle + .report_substream_opened(peer_id, Direction::Inbound, handshake, None, sink) + .unwrap(); + + if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { + loop { + if service.num_sync_peers().await.unwrap() == 1 { + break + } + } + }) + .await + { + panic!("failed to add sync peer"); + } + } + + #[tokio::test] + async fn syncing_engine_full_of_inbound_peers() { + let (client, engine, service, config) = make_syncing_engine(); + let (mut handle, _) = config.take_protocol_handle().split(); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let handshake = BlockAnnouncesHandshake::::build( + engine.roles, + *block.header().number(), + block.hash(), + engine.genesis_hash, + ) + .encode(); + + tokio::spawn(engine.run()); + + // add maximum number of allowed full inbound peers to `SyncingEngine` + let num_in_peers = 32; + for i in 0..num_in_peers { + let peer_id = PeerId::random(); + let rx = handle.report_incoming_substream(peer_id, handshake.clone()).unwrap(); + assert_eq!(rx.await, Ok(ValidationResult::Accept)); + let (sink, _, _) = NotificationsSink::new(peer_id); + + handle + .report_substream_opened(peer_id, Direction::Inbound, handshake.clone(), None, sink) + .unwrap(); + let sync_service = service.clone(); + + if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { + loop { + if sync_service.num_sync_peers().await.unwrap() == i + 1 { + break + } + } + }) + .await + { + panic!("failed to add sync peer"); + } + } + + // try to add one more peer and verify the peer is rejected during handshake validation + let peer_id = PeerId::random(); + let rx = handle.report_incoming_substream(peer_id, handshake.clone()).unwrap(); + assert_eq!(rx.await, Ok(ValidationResult::Reject)); + } + + #[tokio::test] + async fn syncing_engine_full_of_inbound_peers_outbound_accepted() { + let (client, engine, service, config) = make_syncing_engine(); + let (mut handle, _) = config.take_protocol_handle().split(); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let handshake = BlockAnnouncesHandshake::::build( + engine.roles, + *block.header().number(), + block.hash(), + engine.genesis_hash, + ) + .encode(); + + tokio::spawn(engine.run()); + + // add maximum number of allowed inbound peers to `SyncingEngine` + let num_in_peers = 32; + for i in 0..num_in_peers { + let peer_id = PeerId::random(); + let rx = handle.report_incoming_substream(peer_id, handshake.clone()).unwrap(); + assert_eq!(rx.await, Ok(ValidationResult::Accept)); + let (sink, _, _) = NotificationsSink::new(peer_id); + + handle + .report_substream_opened(peer_id, Direction::Inbound, handshake.clone(), None, sink) + .unwrap(); + let sync_service = service.clone(); + + if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { + loop { + if sync_service.num_sync_peers().await.unwrap() == i + 1 { + break + } + } + }) + .await + { + panic!("failed to add sync peer"); + } + } + + // try to add one more peer, this time outbound and verify it's accepted + let peer_id = PeerId::random(); + let (sink, _, _) = NotificationsSink::new(peer_id); + handle + .report_substream_opened(peer_id, Direction::Outbound, handshake.clone(), None, sink) + .unwrap(); + let sync_service = service.clone(); + + if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { + loop { + if sync_service.num_sync_peers().await.unwrap() == num_in_peers + 1 { + break + } + } + }) + .await + { + panic!("failed to add sync peer"); + } + } + + #[tokio::test] + async fn syncing_engine_full_of_inbound_full_peers_but_not_light_peers() { + let (client, engine, service, config) = make_syncing_engine(); + let (mut handle, _) = config.take_protocol_handle().split(); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let genesis = engine.genesis_hash.clone(); + let handshake = BlockAnnouncesHandshake::::build( + engine.roles, + *block.header().number(), + block.hash(), + engine.genesis_hash, + ) + .encode(); + + tokio::spawn(engine.run()); + + // add maximum number of allowed inbound peers to `SyncingEngine` + let num_in_peers = 32; + for i in 0..num_in_peers { + let peer_id = PeerId::random(); + let rx = handle.report_incoming_substream(peer_id, handshake.clone()).unwrap(); + assert_eq!(rx.await, Ok(ValidationResult::Accept)); + let (sink, _, _) = NotificationsSink::new(peer_id); + + handle + .report_substream_opened(peer_id, Direction::Inbound, handshake.clone(), None, sink) + .unwrap(); + let sync_service = service.clone(); + + if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { + loop { + if sync_service.num_sync_peers().await.unwrap() == i + 1 { + break + } + } + }) + .await + { + panic!("failed to add sync peer"); + } + } + + // try to add one more peer, this time outbound and verify it's accepted + let handshake = BlockAnnouncesHandshake::::build( + Roles::LIGHT, + *block.header().number(), + block.hash(), + genesis, + ) + .encode(); + let peer_id = PeerId::random(); + let (sink, _, _) = NotificationsSink::new(peer_id); + handle + .report_substream_opened(peer_id, Direction::Inbound, handshake.clone(), None, sink) + .unwrap(); + let sync_service = service.clone(); + + if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { + loop { + if sync_service.status().await.unwrap().num_connected_peers == num_in_peers + 1 { + break + } + } + }) + .await + { + panic!("failed to add sync peer"); + } + } + + #[tokio::test] + async fn best_block_import_updates_handshake() { + let (client, engine, service, config) = make_syncing_engine(); + let (_handle, mut commands) = config.take_protocol_handle().split(); + + tokio::spawn(engine.run()); + + let block = client.new_block(Default::default()).unwrap().build().unwrap().block; + service.new_best_block_imported(block.hash(), *block.header().number()); + + assert!(std::matches!( + commands.next().await.unwrap(), + NotificationCommand::SetHandshake(_) + )); + } +} diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index 175c1c43f46f..bb7fea9b0ae1 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -55,6 +55,7 @@ use sc_network::{ }, request_responses::{IfDisconnected, RequestFailure}, types::ProtocolName, + NotificationService, }; use sc_network_common::{ role::Roles, @@ -1405,8 +1406,8 @@ where block_request_protocol_name: ProtocolName, state_request_protocol_name: ProtocolName, warp_sync_protocol_name: Option, - ) -> Result<(Self, NonDefaultSetConfig), ClientError> { - let block_announce_config = Self::get_block_announce_proto_config( + ) -> Result<(Self, NonDefaultSetConfig, Box), ClientError> { + let (block_announce_config, notification_service) = Self::get_block_announce_proto_config( protocol_id, fork_id, roles, @@ -1445,10 +1446,7 @@ where state_request_protocol_name, warp_sync_params, warp_sync_protocol_name, - block_announce_protocol_name: block_announce_config - .notifications_protocol - .clone() - .into(), + block_announce_protocol_name: block_announce_config.protocol_name().clone().into(), pending_responses: HashMap::new(), import_queue, metrics: if let Some(r) = &metrics_registry { @@ -1465,7 +1463,7 @@ where }; sync.reset_sync_start_point()?; - Ok((sync, block_announce_config)) + Ok((sync, block_announce_config, notification_service)) } /// Returns the median seen block number. @@ -1933,7 +1931,7 @@ where best_number: NumberFor, best_hash: B::Hash, genesis_hash: B::Hash, - ) -> NonDefaultSetConfig { + ) -> (NonDefaultSetConfig, Box) { let block_announces_protocol = { let genesis_hash = genesis_hash.as_ref(); if let Some(ref fork_id) = fork_id { @@ -1947,14 +1945,11 @@ where } }; - NonDefaultSetConfig { - notifications_protocol: block_announces_protocol.into(), - fallback_names: iter::once( - format!("/{}/block-announces/1", protocol_id.as_ref()).into(), - ) - .collect(), - max_notification_size: MAX_BLOCK_ANNOUNCE_SIZE, - handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( + NonDefaultSetConfig::new( + block_announces_protocol.into(), + iter::once(format!("/{}/block-announces/1", protocol_id.as_ref()).into()).collect(), + MAX_BLOCK_ANNOUNCE_SIZE, + Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( roles, best_number, best_hash, @@ -1962,13 +1957,13 @@ where ))), // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement // protocol is still hardcoded into the peerset. - set_config: SetConfig { + SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), non_reserved_mode: NonReservedPeerMode::Deny, }, - } + ) } fn decode_block_response(response: &[u8]) -> Result { @@ -3189,7 +3184,7 @@ mod test { let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), ProtocolId::from("test-protocol-name"), @@ -3256,7 +3251,7 @@ mod test { let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), ProtocolId::from("test-protocol-name"), @@ -3438,7 +3433,7 @@ mod test { let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), ProtocolId::from("test-protocol-name"), @@ -3565,7 +3560,7 @@ mod test { NetworkServiceProvider::new(); let info = client.info(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), ProtocolId::from("test-protocol-name"), @@ -3723,7 +3718,7 @@ mod test { let info = client.info(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), ProtocolId::from("test-protocol-name"), @@ -3866,7 +3861,7 @@ mod test { let info = client.info(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), ProtocolId::from("test-protocol-name"), @@ -4011,7 +4006,7 @@ mod test { let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..3).map(|_| build_block(&mut client, None, false)).collect::>(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), ProtocolId::from("test-protocol-name"), @@ -4057,7 +4052,7 @@ mod test { let empty_client = Arc::new(TestClientBuilder::new().build()); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, empty_client.clone(), ProtocolId::from("test-protocol-name"), @@ -4111,7 +4106,7 @@ mod test { let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (mut sync, _) = ChainSync::new( + let (mut sync, _, _) = ChainSync::new( SyncMode::Full, client.clone(), ProtocolId::from("test-protocol-name"), diff --git a/substrate/client/network/sync/src/service/mock.rs b/substrate/client/network/sync/src/service/mock.rs index 885eb1f8da59..47986a71d012 100644 --- a/substrate/client/network/sync/src/service/mock.rs +++ b/substrate/client/network/sync/src/service/mock.rs @@ -27,6 +27,7 @@ use sc_network::{ NetworkNotification, NetworkPeers, NetworkRequest, NetworkSyncForkRequest, NotificationSenderError, NotificationSenderT, ReputationChange, }; +use sc_network_common::role::ObservedRole; use sp_runtime::traits::{Block as BlockT, NumberFor}; use std::collections::HashSet; @@ -105,6 +106,7 @@ mockall::mock! { peers: Vec ) -> Result<(), String>; fn sync_num_connected(&self) -> usize; + fn peer_role(&self, peer_id: PeerId, handshake: Vec) -> Option; } #[async_trait::async_trait] diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index 2a20da5a556b..7aaac5d78c3a 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -58,7 +58,7 @@ use sc_network::{ request_responses::ProtocolConfig as RequestResponseConfig, types::ProtocolName, Multiaddr, NetworkBlock, NetworkService, NetworkStateInfo, NetworkSyncForkRequest, - NetworkWorker, + NetworkWorker, NotificationService, }; use sc_network_common::{ role::Roles, @@ -241,6 +241,7 @@ pub struct Peer { imported_blocks_stream: Pin> + Send>>, finality_notification_stream: Pin> + Send>>, listen_addr: Multiaddr, + notification_services: HashMap>, } impl Peer @@ -265,8 +266,8 @@ where } /// Returns the number of peers we're connected to. - pub fn num_peers(&self) -> usize { - self.network.num_connected_peers() + pub async fn num_peers(&self) -> usize { + self.sync_service.status().await.unwrap().num_connected_peers as usize } /// Returns the number of downloaded blocks. @@ -505,10 +506,19 @@ where self.network.service() } + /// Get `SyncingService`. pub fn sync_service(&self) -> &Arc> { &self.sync_service } + /// Take notification handle for enabled protocol. + pub fn take_notification_service( + &mut self, + protocol: &ProtocolName, + ) -> Option> { + self.notification_services.remove(protocol) + } + /// Get a reference to the network worker. pub fn network(&self) -> &NetworkWorker::Hash> { &self.network @@ -781,6 +791,23 @@ pub trait TestNetFactory: Default + Sized + Send { network_config.transport = TransportConfig::MemoryOnly; network_config.listen_addresses = vec![listen_addr.clone()]; network_config.allow_non_globals_in_dht = true; + + let (notif_configs, notif_handles): (Vec<_>, Vec<_>) = config + .notifications_protocols + .into_iter() + .map(|p| { + let (config, handle) = NonDefaultSetConfig::new( + p.clone(), + Vec::new(), + 1024 * 1024, + None, + Default::default(), + ); + + (config, (p, handle)) + }) + .unzip(); + if let Some(connect_to) = config.connect_to_peers { let addrs = connect_to .iter() @@ -846,13 +873,18 @@ pub trait TestNetFactory: Default + Sized + Send { protocol_config }; + let peer_store = PeerStore::new( + network_config.boot_nodes.iter().map(|bootnode| bootnode.peer_id).collect(), + ); + let peer_store_handle = peer_store.handle(); + self.spawn_task(peer_store.run().boxed()); + let block_announce_validator = config .block_announce_validator .unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator)); let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); - let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let (engine, sync_service, block_announce_config) = sc_network_sync::engine::SyncingEngine::new( Roles::from(if config.is_authority { &Role::Authority } else { &Role::Full }), @@ -868,7 +900,7 @@ pub trait TestNetFactory: Default + Sized + Send { block_request_protocol_config.name.clone(), state_request_protocol_config.name.clone(), Some(warp_protocol_config.name.clone()), - rx, + peer_store_handle.clone(), ) .unwrap(); let sync_service_import_queue = Box::new(sync_service.clone()); @@ -886,22 +918,10 @@ pub trait TestNetFactory: Default + Sized + Send { full_net_config.add_request_response_protocol(config); } - for protocol in config.notifications_protocols { - full_net_config.add_notification_protocol(NonDefaultSetConfig { - notifications_protocol: protocol, - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - handshake: None, - set_config: Default::default(), - }); + for config in notif_configs { + full_net_config.add_notification_protocol(config); } - let peer_store = PeerStore::new( - network_config.boot_nodes.iter().map(|bootnode| bootnode.peer_id).collect(), - ); - let peer_store_handle = peer_store.handle(); - self.spawn_task(peer_store.run().boxed()); - let genesis_hash = client.hash(Zero::zero()).ok().flatten().expect("Genesis block exists; qed"); let network = NetworkWorker::new(sc_network::config::Params { @@ -916,7 +936,6 @@ pub trait TestNetFactory: Default + Sized + Send { fork_id, metrics_registry: None, block_announce_config, - tx, }) .unwrap(); @@ -952,6 +971,7 @@ pub trait TestNetFactory: Default + Sized + Send { backend: Some(backend), imported_blocks_stream, finality_notification_stream, + notification_services: HashMap::from_iter(notif_handles.into_iter()), block_import, verifier, network, @@ -966,20 +986,6 @@ pub trait TestNetFactory: Default + Sized + Send { tokio::spawn(f); } - /// Polls the testnet until all peers are connected to each other. - /// - /// Must be executed in a task context. - fn poll_until_connected(&mut self, cx: &mut FutureContext) -> Poll<()> { - self.poll(cx); - - let num_peers = self.peers().len(); - if self.peers().iter().all(|p| p.num_peers() == num_peers - 1) { - return Poll::Ready(()) - } - - Poll::Pending - } - async fn is_in_sync(&mut self) -> bool { let mut highest = None; let peers = self.peers_mut(); @@ -1057,10 +1063,27 @@ pub trait TestNetFactory: Default + Sized + Send { } /// Run the network until all peers are connected to each other. - /// - /// Calls `poll_until_connected` repeatedly with the runtime passed as parameter. async fn run_until_connected(&mut self) { - futures::future::poll_fn::<(), _>(|cx| self.poll_until_connected(cx)).await; + let num_peers = self.peers().len(); + let sync_services = + self.peers().iter().map(|info| info.sync_service.clone()).collect::>(); + + 'outer: loop { + for sync_service in &sync_services { + if sync_service.status().await.unwrap().num_connected_peers as usize != + num_peers - 1 + { + futures::future::poll_fn::<(), _>(|cx| { + self.poll(cx); + Poll::Ready(()) + }) + .await; + continue 'outer + } + } + + break + } } /// Polls the testnet. Processes all the pending actions. diff --git a/substrate/client/network/test/src/service.rs b/substrate/client/network/test/src/service.rs index 68e780545bb1..6fda1b86a51c 100644 --- a/substrate/client/network/test/src/service.rs +++ b/substrate/client/network/test/src/service.rs @@ -24,8 +24,9 @@ use sc_network::{ config::{self, FullNetworkConfiguration, MultiaddrWithPeerId, ProtocolId, TransportConfig}, event::Event, peer_store::PeerStore, - NetworkEventStream, NetworkNotification, NetworkPeers, NetworkService, NetworkStateInfo, - NetworkWorker, + service::traits::{NotificationEvent, ValidationResult}, + NetworkEventStream, NetworkPeers, NetworkService, NetworkStateInfo, NetworkWorker, + NotificationService, }; use sc_network_common::role::Roles; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; @@ -116,7 +117,7 @@ impl TestNetworkBuilder { self } - pub fn build(mut self) -> TestNetwork { + pub fn build(mut self) -> (TestNetwork, Option>) { let client = self.client.as_mut().map_or( Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0), |v| v.clone(), @@ -177,9 +178,14 @@ impl TestNetworkBuilder { protocol_config }; + let peer_store = PeerStore::new( + network_config.boot_nodes.iter().map(|bootnode| bootnode.peer_id).collect(), + ); + let peer_store_handle = peer_store.handle(); + tokio::spawn(peer_store.run().boxed()); + let (chain_sync_network_provider, chain_sync_network_handle) = self.chain_sync_network.unwrap_or(NetworkServiceProvider::new()); - let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let (engine, chain_sync_service, block_announce_config) = SyncingEngine::new( Roles::from(&config::Role::Full), client.clone(), @@ -194,24 +200,27 @@ impl TestNetworkBuilder { block_request_protocol_config.name.clone(), state_request_protocol_config.name.clone(), None, - rx, + peer_store_handle.clone(), ) .unwrap(); let mut link = self.link.unwrap_or(Box::new(chain_sync_service.clone())); - if !self.notification_protocols.is_empty() { + let handle = if !self.notification_protocols.is_empty() { for config in self.notification_protocols { full_net_config.add_notification_protocol(config); } + None } else { - full_net_config.add_notification_protocol(config::NonDefaultSetConfig { - notifications_protocol: PROTOCOL_NAME.into(), - fallback_names: Vec::new(), - max_notification_size: 1024 * 1024, - handshake: None, - set_config: self.set_config.unwrap_or_default(), - }); - } + let (config, handle) = config::NonDefaultSetConfig::new( + PROTOCOL_NAME.into(), + Vec::new(), + 1024 * 1024, + None, + self.set_config.unwrap_or_default(), + ); + full_net_config.add_notification_protocol(config); + Some(handle) + }; for config in [ block_request_protocol_config, @@ -221,12 +230,6 @@ impl TestNetworkBuilder { full_net_config.add_request_response_protocol(config); } - let peer_store = PeerStore::new( - network_config.boot_nodes.iter().map(|bootnode| bootnode.peer_id).collect(), - ); - let peer_store_handle = peer_store.handle(); - tokio::spawn(peer_store.run().boxed()); - let genesis_hash = client.hash(Zero::zero()).ok().flatten().expect("Genesis block exists; qed"); let worker = NetworkWorker::< @@ -244,7 +247,6 @@ impl TestNetworkBuilder { protocol_id, fork_id, metrics_registry: None, - tx, }) .unwrap(); @@ -264,7 +266,7 @@ impl TestNetworkBuilder { }); tokio::spawn(engine.run()); - TestNetwork::new(worker) + (TestNetwork::new(worker), handle) } } @@ -272,18 +274,18 @@ impl TestNetworkBuilder { /// The nodes are connected together and have the `PROTOCOL_NAME` protocol registered. fn build_nodes_one_proto() -> ( Arc, - impl Stream, + Option>, Arc, - impl Stream, + Option>, ) { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (node1, events_stream1) = TestNetworkBuilder::new() + let (network1, handle1) = TestNetworkBuilder::new() .with_listen_addresses(vec![listen_addr.clone()]) - .build() - .start_network(); + .build(); + let (node1, _) = network1.start_network(); - let (node2, events_stream2) = TestNetworkBuilder::new() + let (network2, handle2) = TestNetworkBuilder::new() .with_set_config(config::SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -291,10 +293,11 @@ fn build_nodes_one_proto() -> ( }], ..Default::default() }) - .build() - .start_network(); + .build(); + + let (node2, _) = network2.start_network(); - (node1, events_stream1, node2, events_stream2) + (node1, handle1, node2, handle2) } #[tokio::test] @@ -302,22 +305,15 @@ async fn notifications_state_consistent() { // Runs two nodes and ensures that events are propagated out of the API in a consistent // correct order, which means no notification received on a closed substream. - let (node1, mut events_stream1, node2, mut events_stream2) = build_nodes_one_proto(); + let (node1, handle1, node2, handle2) = build_nodes_one_proto(); + let (mut handle1, mut handle2) = (handle1.unwrap(), handle2.unwrap()); // Write some initial notifications that shouldn't get through. for _ in 0..(rand::random::() % 5) { - node1.write_notification( - node2.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle1.send_sync_notification(&node2.local_peer_id(), b"hello world".to_vec()); } for _ in 0..(rand::random::() % 5) { - node2.write_notification( - node1.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle2.send_sync_notification(&node1.local_peer_id(), b"hello world".to_vec()); } // True if we have an active substream from node1 to node2. @@ -339,18 +335,10 @@ async fn notifications_state_consistent() { // Start by sending a notification from node1 to node2 and vice-versa. Part of the // test consists in ensuring that notifications get ignored if the stream isn't open. if rand::random::() % 5 >= 3 { - node1.write_notification( - node2.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle1.send_sync_notification(&node2.local_peer_id(), b"hello world".to_vec()); } if rand::random::() % 5 >= 3 { - node2.write_notification( - node1.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle2.send_sync_notification(&node1.local_peer_id(), b"hello world".to_vec()); } // Also randomly disconnect the two nodes from time to time. @@ -363,8 +351,8 @@ async fn notifications_state_consistent() { // Grab next event from either `events_stream1` or `events_stream2`. let next_event = { - let next1 = events_stream1.next(); - let next2 = events_stream2.next(); + let next1 = handle1.next_event(); + let next2 = handle2.next_event(); // We also await on a small timer, otherwise it is possible for the test to wait // forever while nothing at all happens on the network. let continue_test = futures_timer::Delay::new(Duration::from_millis(20)); @@ -379,58 +367,55 @@ async fn notifications_state_consistent() { }; match next_event { - future::Either::Left(Event::NotificationStreamOpened { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME.into() { - something_happened = true; - assert!(!node1_to_node2_open); - node1_to_node2_open = true; - assert_eq!(remote, node2.local_peer_id()); - }, - future::Either::Right(Event::NotificationStreamOpened { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME.into() { - something_happened = true; - assert!(!node2_to_node1_open); - node2_to_node1_open = true; - assert_eq!(remote, node1.local_peer_id()); - }, - future::Either::Left(Event::NotificationStreamClosed { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME.into() { - assert!(node1_to_node2_open); - node1_to_node2_open = false; - assert_eq!(remote, node2.local_peer_id()); - }, - future::Either::Right(Event::NotificationStreamClosed { remote, protocol, .. }) => - if protocol == PROTOCOL_NAME.into() { - assert!(node2_to_node1_open); - node2_to_node1_open = false; - assert_eq!(remote, node1.local_peer_id()); - }, - future::Either::Left(Event::NotificationsReceived { remote, .. }) => { + future::Either::Left(NotificationEvent::ValidateInboundSubstream { + result_tx, .. + }) => { + result_tx.send(ValidationResult::Accept).unwrap(); + }, + future::Either::Right(NotificationEvent::ValidateInboundSubstream { + result_tx, + .. + }) => { + result_tx.send(ValidationResult::Accept).unwrap(); + }, + future::Either::Left(NotificationEvent::NotificationStreamOpened { peer, .. }) => { + something_happened = true; + assert!(!node1_to_node2_open); + node1_to_node2_open = true; + assert_eq!(peer, node2.local_peer_id()); + }, + future::Either::Right(NotificationEvent::NotificationStreamOpened { peer, .. }) => { + something_happened = true; + assert!(!node2_to_node1_open); + node2_to_node1_open = true; + assert_eq!(peer, node1.local_peer_id()); + }, + future::Either::Left(NotificationEvent::NotificationStreamClosed { peer, .. }) => { assert!(node1_to_node2_open); - assert_eq!(remote, node2.local_peer_id()); + node1_to_node2_open = false; + assert_eq!(peer, node2.local_peer_id()); + }, + future::Either::Right(NotificationEvent::NotificationStreamClosed { peer, .. }) => { + assert!(node2_to_node1_open); + node2_to_node1_open = false; + assert_eq!(peer, node1.local_peer_id()); + }, + future::Either::Left(NotificationEvent::NotificationReceived { peer, .. }) => { + assert!(node1_to_node2_open); + assert_eq!(peer, node2.local_peer_id()); if rand::random::() % 5 >= 4 { - node1.write_notification( - node2.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle1 + .send_sync_notification(&node2.local_peer_id(), b"hello world".to_vec()); } }, - future::Either::Right(Event::NotificationsReceived { remote, .. }) => { + future::Either::Right(NotificationEvent::NotificationReceived { peer, .. }) => { assert!(node2_to_node1_open); - assert_eq!(remote, node1.local_peer_id()); + assert_eq!(peer, node1.local_peer_id()); if rand::random::() % 5 >= 4 { - node2.write_notification( - node1.local_peer_id(), - PROTOCOL_NAME.into(), - b"hello world".to_vec(), - ); + let _ = handle2 + .send_sync_notification(&node1.local_peer_id(), b"hello world".to_vec()); } }, - - // Add new events here. - future::Either::Left(Event::Dht(_)) => {}, - future::Either::Right(Event::Dht(_)) => {}, }; } } @@ -440,20 +425,29 @@ async fn lots_of_incoming_peers_works() { sp_tracing::try_init_simple(); let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (main_node, _) = TestNetworkBuilder::new() + let (main_node, handle1) = TestNetworkBuilder::new() .with_listen_addresses(vec![listen_addr.clone()]) .with_set_config(config::SetConfig { in_peers: u32::MAX, ..Default::default() }) - .build() - .start_network(); + .build(); + let mut handle1 = handle1.unwrap(); + let (main_node, _) = main_node.start_network(); let main_node_peer_id = main_node.local_peer_id(); + tokio::spawn(async move { + while let Some(event) = handle1.next_event().await { + if let NotificationEvent::ValidateInboundSubstream { result_tx, .. } = event { + result_tx.send(ValidationResult::Accept).unwrap(); + } + } + }); + // We spawn background tasks and push them in this `Vec`. They will all be waited upon before // this test ends. let mut background_tasks_to_wait = Vec::new(); for _ in 0..32 { - let (_dialing_node, event_stream) = TestNetworkBuilder::new() + let (dialing_node, handle) = TestNetworkBuilder::new() .with_set_config(config::SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr.clone(), @@ -461,8 +455,9 @@ async fn lots_of_incoming_peers_works() { }], ..Default::default() }) - .build() - .start_network(); + .build(); + let mut handle = handle.unwrap(); + let (_, _) = dialing_node.start_network(); background_tasks_to_wait.push(tokio::spawn(async move { // Create a dummy timer that will "never" fire, and that will be overwritten when we @@ -470,34 +465,23 @@ async fn lots_of_incoming_peers_works() { // make the code below way more complicated. let mut timer = futures_timer::Delay::new(Duration::from_secs(3600 * 24 * 7)).fuse(); - let mut event_stream = event_stream.fuse(); - let mut sync_protocol_name = None; loop { futures::select! { _ = timer => { // Test succeeds when timer fires. return; } - ev = event_stream.next() => { - match ev.unwrap() { - Event::NotificationStreamOpened { protocol, remote, .. } => { - if let None = sync_protocol_name { - sync_protocol_name = Some(protocol.clone()); - } - - assert_eq!(remote, main_node_peer_id); - // Test succeeds after 5 seconds. This timer is here in order to - // detect a potential problem after opening. - timer = futures_timer::Delay::new(Duration::from_secs(5)).fuse(); - } - Event::NotificationStreamClosed { protocol, .. } => { - if Some(protocol) != sync_protocol_name { - // Test failed. - panic!(); - } - } - _ => {} + ev = handle.next_event().fuse() => match ev.unwrap() { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + result_tx.send(ValidationResult::Accept).unwrap(); } + NotificationEvent::NotificationStreamOpened { peer, .. } => { + assert_eq!(peer, main_node_peer_id); + // Test succeeds after 5 seconds. This timer is here in order to + // detect a potential problem after opening. + timer = futures_timer::Delay::new(Duration::from_secs(5)).fuse(); + } + _ => {} } } } @@ -514,33 +498,27 @@ async fn notifications_back_pressure() { const TOTAL_NOTIFS: usize = 10_000; - let (node1, mut events_stream1, node2, mut events_stream2) = build_nodes_one_proto(); + let (_node1, handle1, node2, handle2) = build_nodes_one_proto(); + let (mut handle1, mut handle2) = (handle1.unwrap(), handle2.unwrap()); let node2_id = node2.local_peer_id(); let receiver = tokio::spawn(async move { let mut received_notifications = 0; - let mut sync_protocol_name = None; while received_notifications < TOTAL_NOTIFS { - match events_stream2.next().await.unwrap() { - Event::NotificationStreamOpened { protocol, .. } => { - if let None = sync_protocol_name { - sync_protocol_name = Some(protocol); - } + match handle2.next_event().await.unwrap() { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + result_tx.send(ValidationResult::Accept).unwrap(); }, - Event::NotificationStreamClosed { protocol, .. } => { - if Some(&protocol) != sync_protocol_name.as_ref() { - panic!() - } + NotificationEvent::NotificationReceived { notification, .. } => { + assert_eq!( + notification, + format!("hello #{}", received_notifications).into_bytes() + ); + received_notifications += 1; }, - Event::NotificationsReceived { messages, .. } => - for message in messages { - assert_eq!(message.0, PROTOCOL_NAME.into()); - assert_eq!(message.1, format!("hello #{}", received_notifications)); - received_notifications += 1; - }, _ => {}, - }; + } if rand::random::() < 2 { tokio::time::sleep(Duration::from_millis(rand::random::() % 750)).await; @@ -550,20 +528,20 @@ async fn notifications_back_pressure() { // Wait for the `NotificationStreamOpened`. loop { - match events_stream1.next().await.unwrap() { - Event::NotificationStreamOpened { .. } => break, + match handle1.next_event().await.unwrap() { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + result_tx.send(ValidationResult::Accept).unwrap(); + }, + NotificationEvent::NotificationStreamOpened { .. } => break, _ => {}, }; } // Sending! for num in 0..TOTAL_NOTIFS { - let notif = node1.notification_sender(node2_id, PROTOCOL_NAME.into()).unwrap(); - notif - .ready() + handle1 + .send_async_notification(&node2_id, format!("hello #{}", num).into_bytes()) .await - .unwrap() - .send(format!("hello #{}", num).into_bytes()) .unwrap(); } @@ -572,28 +550,31 @@ async fn notifications_back_pressure() { #[tokio::test] async fn fallback_name_working() { + sp_tracing::try_init_simple(); // Node 1 supports the protocols "new" and "old". Node 2 only supports "old". Checks whether // they can connect. const NEW_PROTOCOL_NAME: &str = "/new-shiny-protocol-that-isnt-PROTOCOL_NAME"; let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - let (node1, mut events_stream1) = TestNetworkBuilder::new() - .with_notification_protocol(config::NonDefaultSetConfig { - notifications_protocol: NEW_PROTOCOL_NAME.into(), - fallback_names: vec![PROTOCOL_NAME.into()], - max_notification_size: 1024 * 1024, - handshake: None, - set_config: Default::default(), - }) + let (config, mut handle1) = config::NonDefaultSetConfig::new( + NEW_PROTOCOL_NAME.into(), + vec![PROTOCOL_NAME.into()], + 1024 * 1024, + None, + Default::default(), + ); + let (network1, _) = TestNetworkBuilder::new() + .with_notification_protocol(config) .with_config(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }) - .build() - .start_network(); + .build(); - let (_, mut events_stream2) = TestNetworkBuilder::new() + let (node1, _) = network1.start_network(); + + let (network2, handle2) = TestNetworkBuilder::new() .with_set_config(config::SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, @@ -601,34 +582,38 @@ async fn fallback_name_working() { }], ..Default::default() }) - .build() - .start_network(); + .build(); + let mut handle2 = handle2.unwrap(); + let _ = network2.start_network(); let receiver = tokio::spawn(async move { // Wait for the `NotificationStreamOpened`. loop { - match events_stream2.next().await.unwrap() { - Event::NotificationStreamOpened { protocol, negotiated_fallback, .. } => { - assert_eq!(protocol, PROTOCOL_NAME.into()); + match handle2.next_event().await.unwrap() { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + result_tx.send(ValidationResult::Accept).unwrap(); + }, + NotificationEvent::NotificationStreamOpened { negotiated_fallback, .. } => { assert_eq!(negotiated_fallback, None); break }, _ => {}, - }; + } } }); // Wait for the `NotificationStreamOpened`. loop { - match events_stream1.next().await.unwrap() { - Event::NotificationStreamOpened { protocol, negotiated_fallback, .. } - if protocol == NEW_PROTOCOL_NAME.into() => - { + match handle1.next_event().await.unwrap() { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + result_tx.send(ValidationResult::Accept).unwrap(); + }, + NotificationEvent::NotificationStreamOpened { negotiated_fallback, .. } => { assert_eq!(negotiated_fallback, Some(PROTOCOL_NAME.into())); break }, _ => {}, - }; + } } receiver.await.unwrap(); @@ -651,6 +636,7 @@ async fn ensure_listen_addresses_consistent_with_transport_memory() { ) }) .build() + .0 .start_network(); } @@ -670,6 +656,7 @@ async fn ensure_listen_addresses_consistent_with_transport_not_memory() { ) }) .build() + .0 .start_network(); } @@ -695,6 +682,7 @@ async fn ensure_boot_node_addresses_consistent_with_transport_memory() { ) }) .build() + .0 .start_network(); } @@ -719,6 +707,7 @@ async fn ensure_boot_node_addresses_consistent_with_transport_not_memory() { ) }) .build() + .0 .start_network(); } @@ -747,6 +736,7 @@ async fn ensure_reserved_node_addresses_consistent_with_transport_memory() { ) }) .build() + .0 .start_network(); } @@ -774,6 +764,7 @@ async fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() { ) }) .build() + .0 .start_network(); } @@ -796,6 +787,7 @@ async fn ensure_public_addresses_consistent_with_transport_memory() { ) }) .build() + .0 .start_network(); } @@ -817,5 +809,6 @@ async fn ensure_public_addresses_consistent_with_transport_not_memory() { ) }) .build() + .0 .start_network(); } diff --git a/substrate/client/network/test/src/sync.rs b/substrate/client/network/test/src/sync.rs index 389177b4aaf1..f2be662ada16 100644 --- a/substrate/client/network/test/src/sync.rs +++ b/substrate/client/network/test/src/sync.rs @@ -44,16 +44,16 @@ async fn sync_peers_works() { sp_tracing::try_init_simple(); let mut net = TestNet::new(3); - futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - for peer in 0..3 { - if net.peer(peer).num_peers() != 2 { - return Poll::Pending - } - } - Poll::Ready(()) - }) - .await; + while net.peer(0).num_peers().await != 2 && + net.peer(1).num_peers().await != 2 && + net.peer(2).num_peers().await != 2 + { + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); + Poll::Ready(()) + }) + .await; + } } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] @@ -412,15 +412,13 @@ async fn can_sync_small_non_best_forks() { assert!(net.peer(1).client().header(small_hash).unwrap().is_none()); // poll until the two nodes connect, otherwise announcing the block will not work - futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 { - Poll::Pending - } else { + while net.peer(0).num_peers().await == 0 || net.peer(1).num_peers().await == 0 { + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); Poll::Ready(()) - } - }) - .await; + }) + .await; + } // synchronization: 0 synced to longer chain and 1 didn't sync to small chain. @@ -465,6 +463,7 @@ async fn can_sync_forks_ahead_of_the_best_chain() { net.peer(1).push_blocks(1, false); net.run_until_connected().await; + // Peer 0 is on 2-block fork which is announced with is_best=false let fork_hash = net .peer(0) @@ -516,15 +515,13 @@ async fn can_sync_explicit_forks() { assert!(net.peer(1).client().header(small_hash).unwrap().is_none()); // poll until the two nodes connect, otherwise announcing the block will not work - futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 { - Poll::Pending - } else { + while net.peer(0).num_peers().await == 0 || net.peer(1).num_peers().await == 0 { + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); Poll::Ready(()) - } - }) - .await; + }) + .await; + } // synchronization: 0 synced to longer chain and 1 didn't sync to small chain. @@ -613,15 +610,14 @@ async fn full_sync_requires_block_body() { net.peer(0).push_headers(1); // Wait for nodes to connect - futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 { - Poll::Pending - } else { + while net.peer(0).num_peers().await == 0 || net.peer(1).num_peers().await == 0 { + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); Poll::Ready(()) - } - }) - .await; + }) + .await; + } + net.run_until_idle().await; assert_eq!(net.peer(1).client.info().best_number, 0); } @@ -917,18 +913,16 @@ async fn block_announce_data_is_propagated() { }); // Wait until peer 1 is connected to both nodes. - futures::future::poll_fn::<(), _>(|cx| { - net.poll(cx); - if net.peer(1).num_peers() == 2 && - net.peer(0).num_peers() == 1 && - net.peer(2).num_peers() == 1 - { + while net.peer(1).num_peers().await != 2 || + net.peer(0).num_peers().await != 1 || + net.peer(2).num_peers().await != 1 + { + futures::future::poll_fn::<(), _>(|cx| { + net.poll(cx); Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; + }) + .await; + } let block_hash = net .peer(0) @@ -1010,7 +1004,7 @@ async fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() { tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; net.peer(0).push_blocks(1, false); net.run_until_sync().await; - assert_eq!(1, net.peer(0).num_peers()); + assert_eq!(1, net.peer(0).num_peers().await); } let hashof10 = hashes[9]; diff --git a/substrate/client/network/transactions/src/lib.rs b/substrate/client/network/transactions/src/lib.rs index b46733d42723..835efe0e6db7 100644 --- a/substrate/client/network/transactions/src/lib.rs +++ b/substrate/client/network/transactions/src/lib.rs @@ -21,8 +21,8 @@ //! Usage: //! //! - Use [`TransactionsHandlerPrototype::new`] to create a prototype. -//! - Pass the return value of [`TransactionsHandlerPrototype::set_config`] to the network -//! configuration as an extra peers set. +//! - Pass the `NonDefaultSetConfig` returned from [`TransactionsHandlerPrototype::new`] to the +//! network configuration as an extra peers set. //! - Use [`TransactionsHandlerPrototype::build`] then [`TransactionsHandler::run`] to obtain a //! `Future` that processes transactions. @@ -37,7 +37,7 @@ use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network::{ config::{NonDefaultSetConfig, NonReservedPeerMode, ProtocolId, SetConfig}, error, - event::Event, + service::traits::{NotificationEvent, NotificationService, ValidationResult}, types::ProtocolName, utils::{interval, LruHashSet}, NetworkEventStream, NetworkNotification, NetworkPeers, @@ -118,8 +118,11 @@ impl Future for PendingTransaction { /// Prototype for a [`TransactionsHandler`]. pub struct TransactionsHandlerPrototype { + /// Name of the transaction protocol. protocol_name: ProtocolName, - fallback_protocol_names: Vec, + + /// Handle that is used to communicate with `sc_network::Notifications`. + notification_service: Box, } impl TransactionsHandlerPrototype { @@ -128,35 +131,28 @@ impl TransactionsHandlerPrototype { protocol_id: ProtocolId, genesis_hash: Hash, fork_id: Option<&str>, - ) -> Self { + ) -> (Self, NonDefaultSetConfig) { let genesis_hash = genesis_hash.as_ref(); - let protocol_name = if let Some(fork_id) = fork_id { + let protocol_name: ProtocolName = if let Some(fork_id) = fork_id { format!("/{}/{}/transactions/1", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { format!("/{}/transactions/1", array_bytes::bytes2hex("", genesis_hash)) - }; - let legacy_protocol_name = format!("/{}/transactions/1", protocol_id.as_ref()); - - Self { - protocol_name: protocol_name.into(), - fallback_protocol_names: iter::once(legacy_protocol_name.into()).collect(), } - } - - /// Returns the configuration of the set to put in the network configuration. - pub fn set_config(&self) -> NonDefaultSetConfig { - NonDefaultSetConfig { - notifications_protocol: self.protocol_name.clone(), - fallback_names: self.fallback_protocol_names.clone(), - max_notification_size: MAX_TRANSACTIONS_SIZE, - handshake: None, - set_config: SetConfig { + .into(); + let (config, notification_service) = NonDefaultSetConfig::new( + protocol_name.clone(), + vec![format!("/{}/transactions/1", protocol_id.as_ref()).into()], + MAX_TRANSACTIONS_SIZE, + None, + SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), non_reserved_mode: NonReservedPeerMode::Deny, }, - } + ); + + (Self { protocol_name, notification_service }, config) } /// Turns the prototype into the actual handler. Returns a controller that allows controlling @@ -176,12 +172,12 @@ impl TransactionsHandlerPrototype { transaction_pool: Arc>, metrics_registry: Option<&Registry>, ) -> error::Result<(TransactionsHandler, TransactionsHandlerController)> { - let net_event_stream = network.event_stream("transactions-handler-net"); let sync_event_stream = sync.event_stream("transactions-handler-sync"); let (to_handler, from_controller) = tracing_unbounded("mpsc_transactions_handler", 100_000); let handler = TransactionsHandler { protocol_name: self.protocol_name, + notification_service: self.notification_service, propagate_timeout: (Box::pin(interval(PROPAGATE_TIMEOUT)) as Pin + Send>>) .fuse(), @@ -189,7 +185,6 @@ impl TransactionsHandlerPrototype { pending_transactions_peers: HashMap::new(), network, sync, - net_event_stream: net_event_stream.fuse(), sync_event_stream: sync_event_stream.fuse(), peers: HashMap::new(), transaction_pool, @@ -256,8 +251,6 @@ pub struct TransactionsHandler< network: N, /// Syncing service. sync: S, - /// Stream of networking events. - net_event_stream: stream::Fuse + Send>>>, /// Receiver for syncing-related events. sync_event_stream: stream::Fuse + Send>>>, // All connected peers @@ -266,6 +259,8 @@ pub struct TransactionsHandler< from_controller: TracingUnboundedReceiver>, /// Prometheus metrics. metrics: Option, + /// Handle that is used to communicate with `sc_network::Notifications`. + notification_service: Box, } /// Peer information @@ -298,14 +293,6 @@ where warn!(target: "sub-libp2p", "Inconsistent state, no peers for pending transaction!"); } }, - network_event = self.net_event_stream.next() => { - if let Some(network_event) = network_event { - self.handle_network_event(network_event).await; - } else { - // Networking has seemingly closed. Closing as well. - return; - } - }, sync_event = self.sync_event_stream.next() => { if let Some(sync_event) = sync_event { self.handle_sync_event(sync_event); @@ -320,10 +307,56 @@ where ToHandler::PropagateTransactions => self.propagate_transactions(), } }, + event = self.notification_service.next_event().fuse() => { + if let Some(event) = event { + self.handle_notification_event(event) + } else { + // `Notifications` has seemingly closed. Closing as well. + return + } + } } } } + fn handle_notification_event(&mut self, event: NotificationEvent) { + match event { + NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + let _ = result_tx.send(ValidationResult::Accept); + }, + NotificationEvent::NotificationStreamOpened { peer, handshake, .. } => { + let Some(role) = self.network.peer_role(peer, handshake) else { + log::debug!(target: "sub-libp2p", "role for {peer} couldn't be determined"); + return + }; + + let _was_in = self.peers.insert( + peer, + Peer { + known_transactions: LruHashSet::new( + NonZeroUsize::new(MAX_KNOWN_TRANSACTIONS).expect("Constant is nonzero"), + ), + role, + }, + ); + debug_assert!(_was_in.is_none()); + }, + NotificationEvent::NotificationStreamClosed { peer } => { + let _peer = self.peers.remove(&peer); + debug_assert!(_peer.is_some()); + }, + NotificationEvent::NotificationReceived { peer, notification } => { + if let Ok(m) = + as Decode>::decode(&mut notification.as_ref()) + { + self.on_transactions(peer, m); + } else { + warn!(target: "sub-libp2p", "Failed to decode transactions list"); + } + }, + } + } + fn handle_sync_event(&mut self, event: SyncEvent) { match event { SyncEvent::PeerConnected(remote) => { @@ -349,51 +382,6 @@ where } } - async fn handle_network_event(&mut self, event: Event) { - match event { - Event::Dht(_) => {}, - Event::NotificationStreamOpened { remote, protocol, role, .. } - if protocol == self.protocol_name => - { - let _was_in = self.peers.insert( - remote, - Peer { - known_transactions: LruHashSet::new( - NonZeroUsize::new(MAX_KNOWN_TRANSACTIONS).expect("Constant is nonzero"), - ), - role, - }, - ); - debug_assert!(_was_in.is_none()); - }, - Event::NotificationStreamClosed { remote, protocol } - if protocol == self.protocol_name => - { - let _peer = self.peers.remove(&remote); - debug_assert!(_peer.is_some()); - }, - - Event::NotificationsReceived { remote, messages } => { - for (protocol, message) in messages { - if protocol != self.protocol_name { - continue - } - - if let Ok(m) = - as Decode>::decode(&mut message.as_ref()) - { - self.on_transactions(remote, m); - } else { - warn!(target: "sub-libp2p", "Failed to decode transactions list"); - } - } - }, - - // Not our concern. - Event::NotificationStreamOpened { .. } | Event::NotificationStreamClosed { .. } => {}, - } - } - /// Called when peer sends us new transactions fn on_transactions(&mut self, who: PeerId, transactions: Transactions) { // Accept transactions only when node is not major syncing @@ -485,8 +473,7 @@ where propagated_to.entry(hash).or_default().push(who.to_base58()); } trace!(target: "sync", "Sending {} transactions to {}", to_send.len(), who); - self.network - .write_notification(*who, self.protocol_name.clone(), to_send.encode()); + let _ = self.notification_service.send_sync_notification(who, to_send.encode()); } } diff --git a/substrate/client/offchain/src/api.rs b/substrate/client/offchain/src/api.rs index c7df5784d329..2901bab2f267 100644 --- a/substrate/client/offchain/src/api.rs +++ b/substrate/client/offchain/src/api.rs @@ -223,7 +223,7 @@ mod tests { use sc_client_db::offchain::LocalStorage; use sc_network::{ config::MultiaddrWithPeerId, types::ProtocolName, NetworkPeers, NetworkStateInfo, - ReputationChange, + ObservedRole, ReputationChange, }; use sp_core::offchain::{storage::OffchainDb, DbExternalities, Externalities, StorageKind}; use std::time::SystemTime; @@ -294,6 +294,10 @@ mod tests { fn sync_num_connected(&self) -> usize { unimplemented!(); } + + fn peer_role(&self, _peer_id: PeerId, _handshake: Vec) -> Option { + None + } } impl NetworkStateInfo for TestNetwork { diff --git a/substrate/client/offchain/src/lib.rs b/substrate/client/offchain/src/lib.rs index a11ac7d86ecb..704999aa334c 100644 --- a/substrate/client/offchain/src/lib.rs +++ b/substrate/client/offchain/src/lib.rs @@ -330,7 +330,9 @@ mod tests { use libp2p::{Multiaddr, PeerId}; use sc_block_builder::BlockBuilderProvider as _; use sc_client_api::Backend as _; - use sc_network::{config::MultiaddrWithPeerId, types::ProtocolName, ReputationChange}; + use sc_network::{ + config::MultiaddrWithPeerId, types::ProtocolName, ObservedRole, ReputationChange, + }; use sc_transaction_pool::BasicPool; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; use sp_consensus::BlockOrigin; @@ -422,6 +424,10 @@ mod tests { fn sync_num_connected(&self) -> usize { unimplemented!(); } + + fn peer_role(&self, _peer_id: PeerId, _handshake: Vec) -> Option { + None + } } #[test] diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index fe18d1d002d5..9e80483954bd 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -834,17 +834,17 @@ where } // create transactions protocol and add it to the list of supported protocols of - // `network_params` - let transactions_handler_proto = sc_network_transactions::TransactionsHandlerPrototype::new( - protocol_id.clone(), - client - .block_hash(0u32.into()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), - config.chain_spec.fork_id(), - ); - net_config.add_notification_protocol(transactions_handler_proto.set_config()); + let (transactions_handler_proto, transactions_config) = + sc_network_transactions::TransactionsHandlerPrototype::new( + protocol_id.clone(), + client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + config.chain_spec.fork_id(), + ); + net_config.add_notification_protocol(transactions_config); // Create `PeerStore` and initialize it with bootnode peer ids. let peer_store = PeerStore::new( @@ -858,7 +858,6 @@ where let peer_store_handle = peer_store.handle(); spawn_handle.spawn("peer-store", Some("networking"), peer_store.run()); - let (tx, rx) = sc_utils::mpsc::tracing_unbounded("mpsc_syncing_engine_protocol", 100_000); let (chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new(); let (engine, sync_service, block_announce_config) = SyncingEngine::new( Roles::from(&config.role), @@ -874,7 +873,7 @@ where block_request_protocol_name, state_request_protocol_name, warp_request_protocol_name, - rx, + peer_store_handle.clone(), )?; let sync_service_import_queue = sync_service.clone(); let sync_service = Arc::new(sync_service); @@ -895,7 +894,6 @@ where fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_announce_config, - tx, }; let has_bootnodes = !network_params.network_config.network_config.boot_nodes.is_empty(); From 026466cab7b5a0da4782ae222510fdcf2cc1242f Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Sun, 3 Sep 2023 16:50:04 +0300 Subject: [PATCH 02/32] Fix clippy --- substrate/client/network/sync/src/engine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 71abbcdd7f21..8bc20339fce9 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -1258,7 +1258,7 @@ mod tests { let (mut handle, _) = config.take_protocol_handle().split(); let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - let genesis = engine.genesis_hash.clone(); + let genesis = engine.genesis_hash; let handshake = BlockAnnouncesHandshake::::build( engine.roles, *block.header().number(), From 229197e7d4ba235b1537c093e56fb212b6d5487c Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 4 Sep 2023 12:53:48 +0300 Subject: [PATCH 03/32] Fix warnings --- polkadot/node/network/bridge/src/rx/tests.rs | 6 ++++-- polkadot/node/network/bridge/src/tx/tests.rs | 20 -------------------- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 3161801aa2c2..67c85c21f300 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -25,7 +25,6 @@ use parking_lot::Mutex; use std::{ collections::HashSet, sync::atomic::{AtomicBool, Ordering}, - task::Poll, }; use sc_network::{ @@ -51,7 +50,7 @@ use polkadot_node_subsystem_test_helpers::{ SingleItemSink, SingleItemStream, TestSubsystemContextHandle, }; use polkadot_node_subsystem_util::metered; -use polkadot_primitives::{AuthorityDiscoveryId, CandidateHash, Hash}; +use polkadot_primitives::{AuthorityDiscoveryId, Hash}; use sp_keyring::Sr25519Keyring; @@ -1495,6 +1494,9 @@ fn network_protocol_versioning_view_update() { #[test] #[cfg(feature = "network-protocol-staging")] fn network_protocol_versioning_subsystem_msg() { + use polkadot_primitives::CandidateHash; + use std::task::Poll; + let (oracle, _handle) = make_sync_oracle(false); test_harness(Box::new(oracle), |test_harness| async move { let TestHarness { mut network_handle, mut virtual_overseer, shared } = test_harness; diff --git a/polkadot/node/network/bridge/src/tx/tests.rs b/polkadot/node/network/bridge/src/tx/tests.rs index a19df51dc575..1de5a8be4c16 100644 --- a/polkadot/node/network/bridge/src/tx/tests.rs +++ b/polkadot/node/network/bridge/src/tx/tests.rs @@ -138,26 +138,6 @@ fn new_test_network( ) } -// wait until all needed validation and collation peers have connected. -async fn await_peer_connections( - shared: &Shared, - num_validation_peers: usize, - num_collation_peers: usize, -) { - loop { - { - let shared = shared.0.lock(); - if shared.validation_peers.len() == num_validation_peers && - shared.collation_peers.len() == num_collation_peers - { - break - } - } - - futures_timer::Delay::new(std::time::Duration::from_millis(100)).await; - } -} - #[async_trait] impl Network for TestNetwork { async fn set_reserved_peers( From 208fe221ee71bea52502b4c52b5c048ac1a2de76 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 4 Sep 2023 17:08:44 +0300 Subject: [PATCH 04/32] Report notification metrics in `NotificationService`/`NotificationSink` --- .../src/protocol/notifications/handler.rs | 59 +++++-------------- .../protocol/notifications/service/metrics.rs | 8 ++- .../src/protocol/notifications/service/mod.rs | 51 ++++++++++++---- 3 files changed, 62 insertions(+), 56 deletions(-) diff --git a/substrate/client/network/src/protocol/notifications/handler.rs b/substrate/client/network/src/protocol/notifications/handler.rs index c2adcbc96f14..d244307f25c6 100644 --- a/substrate/client/network/src/protocol/notifications/handler.rs +++ b/substrate/client/network/src/protocol/notifications/handler.rs @@ -109,28 +109,6 @@ const OPEN_TIMEOUT: Duration = Duration::from_secs(10); /// open substreams. const INITIAL_KEEPALIVE_TIME: Duration = Duration::from_secs(5); -/// Metrics-related information. -#[derive(Debug)] -pub struct MetricsInfo { - /// Protocol name. - protocol: ProtocolName, - - /// Metrics. - metrics: Option, -} - -impl MetricsInfo { - /// Create new [`MetricsInfo`]. - pub fn new(protocol: ProtocolName, metrics: Option) -> Self { - Self { protocol, metrics } - } - - /// Create new empty [`MetricsInfo`]. - pub fn new_empty() -> Self { - Self { protocol: ProtocolName::from(""), metrics: None } - } -} - /// The actual handler once the connection has been established. /// /// See the documentation at the module level for more information. @@ -152,8 +130,8 @@ pub struct NotifsHandler { ConnectionHandlerEvent, >, - /// Metrics-related information. - metrics_info: Vec>, + /// Metrics. + metrics: Option>, } impl NotifsHandler { @@ -164,11 +142,6 @@ impl NotifsHandler { protocols: Vec, metrics: Option, ) -> Self { - let metrics_info = protocols - .iter() - .map(|config| Arc::new(MetricsInfo::new(config.name.clone(), metrics.clone()))) - .collect(); - Self { protocols: protocols .into_iter() @@ -186,7 +159,7 @@ impl NotifsHandler { endpoint, when_connection_open: Instant::now(), events_queue: VecDeque::with_capacity(16), - metrics_info, + metrics: metrics.map_or(None, |metrics| Some(Arc::new(metrics))), } } } @@ -372,11 +345,12 @@ pub enum NotifsHandlerOut { #[derive(Debug, Clone)] pub struct NotificationsSink { inner: Arc, + metrics: Option>, } -// NOTE: only used for testing but must be `pub` as other crates in `client/network` use this. impl NotificationsSink { /// Create new + /// NOTE: only used for testing but must be `pub` as other crates in `client/network` use this. pub fn new( peer_id: PeerId, ) -> (Self, mpsc::Receiver, mpsc::Receiver) @@ -389,13 +363,18 @@ impl NotificationsSink { peer_id, async_channel: FuturesMutex::new(async_tx), sync_channel: Mutex::new(Some(sync_tx)), - metrics_info: Arc::new(MetricsInfo::new_empty()), }), + metrics: None, }, async_rx, sync_rx, ) } + + /// Get reference to metrics. + pub fn metrics(&self) -> &Option> { + &self.metrics + } } #[derive(Debug)] @@ -411,8 +390,6 @@ struct NotificationsSinkInner { /// back-pressure cannot be properly exerted. /// It will be removed in a future version. sync_channel: Mutex>>, - /// Metrics-related information. - metrics_info: Arc, } /// Message emitted through the [`NotificationsSink`] and processed by the background task @@ -447,12 +424,6 @@ impl NotificationsSink { if let Some(tx) = lock.as_mut() { let message = message.into(); - metrics::register_notification_sent( - &self.inner.metrics_info.metrics, - &self.inner.metrics_info.protocol, - message.len(), - ); - let result = tx.try_send(NotificationsSinkMessage::Notification { message }); if result.is_err() { @@ -606,8 +577,8 @@ impl ConnectionHandler for NotifsHandler { peer_id: self.peer_id, async_channel: FuturesMutex::new(async_tx), sync_channel: Mutex::new(Some(sync_tx)), - metrics_info: self.metrics_info[protocol_index].clone(), }), + metrics: self.metrics.clone(), }; self.protocols[protocol_index].state = State::Open { @@ -957,8 +928,8 @@ pub mod tests { peer_id: peer, async_channel: FuturesMutex::new(async_tx), sync_channel: Mutex::new(Some(sync_tx)), - metrics_info: Arc::new(MetricsInfo::new_empty()), }), + metrics: None, }; let (in_substream, out_substream) = MockSubstream::new(); @@ -1118,7 +1089,7 @@ pub mod tests { }, peer_id: PeerId::random(), events_queue: VecDeque::new(), - metrics_info: vec![Arc::new(MetricsInfo::new_empty())], + metrics: None, } } @@ -1623,8 +1594,8 @@ pub mod tests { peer_id: PeerId::random(), async_channel: FuturesMutex::new(async_tx), sync_channel: Mutex::new(Some(sync_tx)), - metrics_info: Arc::new(MetricsInfo::new_empty()), }), + metrics: None, }; handler.protocols[0].state = State::Open { diff --git a/substrate/client/network/src/protocol/notifications/service/metrics.rs b/substrate/client/network/src/protocol/notifications/service/metrics.rs index 65ccedac0762..7d2dd8a818a0 100644 --- a/substrate/client/network/src/protocol/notifications/service/metrics.rs +++ b/substrate/client/network/src/protocol/notifications/service/metrics.rs @@ -23,6 +23,8 @@ use prometheus_endpoint::{ U64, }; +use std::sync::Arc; + /// Notification metrics. #[derive(Debug, Clone)] pub struct Metrics { @@ -100,7 +102,11 @@ pub fn register_substream_closed(metrics: &Option, protocol: &ProtocolN } /// Register sent notification to Prometheus. -pub fn register_notification_sent(metrics: &Option, protocol: &ProtocolName, size: usize) { +pub fn register_notification_sent( + metrics: &Option>, + protocol: &ProtocolName, + size: usize, +) { if let Some(metrics) = metrics { metrics .notifications_sizes diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs index 05aa8fc41615..aea56651770a 100644 --- a/substrate/client/network/src/protocol/notifications/service/mod.rs +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -54,15 +54,19 @@ const COMMAND_QUEUE_SIZE: usize = 64; type Subscribers = Arc>>>; /// Type represending a distributable message sink. +/// Detached message sink must carry the protocol name for registering metrics. /// /// See documentation for [`PeerContext`] for more details. -type NotificationSink = Arc>; +type NotificationSink = Arc>; #[async_trait::async_trait] impl MessageSink for NotificationSink { /// Send synchronous `notification` to the peer associated with this [`MessageSink`]. fn send_sync_notification(&self, notification: Vec) { - self.lock().send_sync_notification(notification); + let sink = self.lock(); + + metrics::register_notification_sent(&sink.0.metrics(), &sink.1, notification.len()); + sink.0.send_sync_notification(notification); } /// Send an asynchronous `notification` to to the peer associated with this [`MessageSink`], @@ -73,9 +77,18 @@ impl MessageSink for NotificationSink { // notification sink must be cloned because the lock cannot be held across `.await` // this makes the implementation less efficient but not prohibitively so as the same // method is also used by `NetworkService` when sending notifications. + let notification_len = notification.len(); let sink = self.lock().clone(); - let sink = sink.reserve_notification().await.map_err(|_| error::Error::ConnectionClosed)?; - sink.send(notification).map_err(|_| error::Error::ChannelClosed) + let permit = sink + .0 + .reserve_notification() + .await + .map_err(|_| error::Error::ConnectionClosed)?; + + permit.send(notification).map_err(|_| error::Error::ChannelClosed).map(|res| { + metrics::register_notification_sent(&sink.0.metrics(), &sink.1, notification_len); + res + }) } } @@ -218,6 +231,12 @@ impl NotificationService for NotificationHandle { log::trace!(target: LOG_TARGET, "{}: send sync notification to {peer:?}", self.protocol); if let Some(info) = self.peers.get(&peer) { + metrics::register_notification_sent( + &info.sink.metrics(), + &self.protocol, + notification.len(), + ); + let _ = info.sink.send_sync_notification(notification); } } @@ -230,15 +249,22 @@ impl NotificationService for NotificationHandle { ) -> Result<(), error::Error> { log::trace!(target: LOG_TARGET, "{}: send async notification to {peer:?}", self.protocol); - self.peers - .get(&peer) - .ok_or_else(|| error::Error::PeerDoesntExist(*peer))? - .sink - .reserve_notification() + let notification_len = notification.len(); + let sink = &self.peers.get(&peer).ok_or_else(|| error::Error::PeerDoesntExist(*peer))?.sink; + + sink.reserve_notification() .await .map_err(|_| error::Error::ConnectionClosed)? .send(notification) .map_err(|_| error::Error::ChannelClosed) + .map(|res| { + metrics::register_notification_sent( + &sink.metrics(), + &self.protocol, + notification_len, + ); + res + }) } /// Set handshake for the notification protocol replacing the old handshake. @@ -267,7 +293,10 @@ impl NotificationService for NotificationHandle { } => { self.peers.insert( peer, - PeerContext { sink: sink.clone(), shared_sink: Arc::new(Mutex::new(sink)) }, + PeerContext { + sink: sink.clone(), + shared_sink: Arc::new(Mutex::new((sink, self.protocol.clone()))), + }, ); return Some(NotificationEvent::NotificationStreamOpened { peer, @@ -290,7 +319,7 @@ impl NotificationService for NotificationHandle { ), Some(context) => { context.sink = sink.clone(); - *context.shared_sink.lock() = sink.clone(); + *context.shared_sink.lock() = (sink.clone(), self.protocol.clone()); }, } }, From 00611e043ed621bb35f7663aea3a0195298c1864 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 4 Sep 2023 21:01:33 +0300 Subject: [PATCH 05/32] Remove notifications sinks on `NotificationStreamClosed` --- polkadot/node/network/bridge/src/rx/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 378fbd3a1a2b..3e9b6a8bdf00 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -320,6 +320,8 @@ async fn handle_validation_message( w }; + notification_sinks.lock().remove(&(peer_set, peer)); + if was_connected && version == peer_set.get_main_version() { dispatch_validation_event_to_all( NetworkBridgeEvent::PeerDisconnected(peer), @@ -563,6 +565,8 @@ async fn handle_collation_message( w }; + notification_sinks.lock().remove(&(peer_set, peer)); + if was_connected && version == peer_set.get_main_version() { dispatch_collation_event_to_all(NetworkBridgeEvent::PeerDisconnected(peer), sender) .await; From b6174e362b4de89e9da45faa76c40fe80149c519 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Tue, 5 Sep 2023 14:09:30 +0300 Subject: [PATCH 06/32] Update substrate/client/network/src/service/traits.rs Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> --- substrate/client/network/src/service/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/network/src/service/traits.rs b/substrate/client/network/src/service/traits.rs index a62283155166..953572823dad 100644 --- a/substrate/client/network/src/service/traits.rs +++ b/substrate/client/network/src/service/traits.rs @@ -730,7 +730,7 @@ pub enum NotificationEvent { /// protocols that can do it. /// /// Both local and remote peer can close the substream at any time. Local peer can do so by calling -/// [`NotificationService::close_substream()`] which instrucs `Notifications` to close the +/// [`NotificationService::close_substream()`] which instructs `Notifications` to close the /// substream. Remote closing the substream is indicated to the local peer by receiving /// [`NotificationEvent::NotificationStreamClosed`] event. /// From 120f4291a0dfafb6e285a838c706f7e60eb798a9 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Tue, 5 Sep 2023 21:13:03 +0300 Subject: [PATCH 07/32] Implement `NotificationService::try_set_handshake()` --- polkadot/node/network/bridge/src/rx/tests.rs | 4 ++++ .../grandpa/src/communication/tests.rs | 4 ++++ substrate/client/network-gossip/src/bridge.rs | 4 ++++ .../src/protocol/notifications/service/mod.rs | 5 +++++ .../protocol/notifications/service/tests.rs | 21 +++++++++++++++++++ .../client/network/src/service/traits.rs | 3 +++ substrate/client/network/sync/src/engine.rs | 21 +++++++------------ 7 files changed, 49 insertions(+), 13 deletions(-) diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 67c85c21f300..f08a9f0c0e4a 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -386,6 +386,10 @@ impl NotificationService for TestNotificationService { unimplemented!(); } + fn try_set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + /// Get next event from the `Notifications` event stream. async fn next_event(&mut self) -> Option { self.rx.next().await diff --git a/substrate/client/consensus/grandpa/src/communication/tests.rs b/substrate/client/consensus/grandpa/src/communication/tests.rs index 3fbc954d89cf..c14e8374a9b3 100644 --- a/substrate/client/consensus/grandpa/src/communication/tests.rs +++ b/substrate/client/consensus/grandpa/src/communication/tests.rs @@ -256,6 +256,10 @@ impl NotificationService for TestNotificationService { unimplemented!(); } + fn try_set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + /// Get next event from the `Notifications` event stream. async fn next_event(&mut self) -> Option { self.rx.next().await diff --git a/substrate/client/network-gossip/src/bridge.rs b/substrate/client/network-gossip/src/bridge.rs index 595cca9b773b..f91c206ed599 100644 --- a/substrate/client/network-gossip/src/bridge.rs +++ b/substrate/client/network-gossip/src/bridge.rs @@ -537,6 +537,10 @@ mod tests { unimplemented!(); } + fn try_set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + async fn next_event(&mut self) -> Option { self.rx.next().await } diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs index aea56651770a..54c2ac60f8b3 100644 --- a/substrate/client/network/src/protocol/notifications/service/mod.rs +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -274,6 +274,11 @@ impl NotificationService for NotificationHandle { self.tx.send(NotificationCommand::SetHandshake(handshake)).await.map_err(|_| ()) } + /// Non-blocking variant of `set_handshake()` that + fn try_set_handshake(&mut self, handshake: Vec) -> Result<(), ()> { + self.tx.try_send(NotificationCommand::SetHandshake(handshake)).map_err(|_| ()) + } + /// Get next event from the `Notifications` event stream. async fn next_event(&mut self) -> Option { loop { diff --git a/substrate/client/network/src/protocol/notifications/service/tests.rs b/substrate/client/network/src/protocol/notifications/service/tests.rs index 72e97b79b50f..615ba8bcf96e 100644 --- a/substrate/client/network/src/protocol/notifications/service/tests.rs +++ b/substrate/client/network/src/protocol/notifications/service/tests.rs @@ -768,3 +768,24 @@ async fn notification_sink_replaced() { Some(NotificationsSinkMessage::Notification { message: vec![1, 3, 3, 7] }), ); } + +#[tokio::test] +async fn set_handshake() { + let (proto, mut notif) = notification_service("/proto/1".into()); + let (_handle, mut stream) = proto.split(); + + assert!(notif.try_set_handshake(vec![1, 3, 3, 7]).is_ok()); + + match stream.next().await { + Some(NotificationCommand::SetHandshake(handshake)) => { + assert_eq!(handshake, vec![1, 3, 3, 7]); + }, + _ => panic!("invalid event received"), + } + + for _ in 0..COMMAND_QUEUE_SIZE { + assert!(notif.try_set_handshake(vec![1, 3, 3, 7]).is_ok()); + } + + assert!(notif.try_set_handshake(vec![1, 3, 3, 7]).is_err()); +} diff --git a/substrate/client/network/src/service/traits.rs b/substrate/client/network/src/service/traits.rs index 953572823dad..c609262158f1 100644 --- a/substrate/client/network/src/service/traits.rs +++ b/substrate/client/network/src/service/traits.rs @@ -772,6 +772,9 @@ pub trait NotificationService: Debug + Send { /// Set handshake for the notification protocol replacing the old handshake. async fn set_handshake(&mut self, handshake: Vec) -> Result<(), ()>; + /// Non-blocking variant of `set_handshake()` that + fn try_set_handshake(&mut self, handshake: Vec) -> Result<(), ()>; + /// Get next event from the `Notifications` event stream. async fn next_event(&mut self) -> Option; diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index be36190488fe..07e3389aef7e 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -703,20 +703,15 @@ where log::debug!(target: "sync", "New best block imported {:?}/#{}", hash, number); self.chain_sync.update_chain_info(&hash, number); - // TODO: remove once `SyncingEngine` is refactored - while let Poll::Pending = self - .notification_service - .set_handshake( - BlockAnnouncesHandshake::::build( - self.roles, - number, - hash, - self.genesis_hash, - ) - .encode(), + let _ = self.notification_service.try_set_handshake( + BlockAnnouncesHandshake::::build( + self.roles, + number, + hash, + self.genesis_hash, ) - .poll_unpin(cx) - {} + .encode(), + ); }, ToServiceCommand::Status(tx) => { let mut status = self.chain_sync.status(); From fa7156b4abcfcc6959bbe6173bc68acb034319b9 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Thu, 7 Sep 2023 15:41:58 +0300 Subject: [PATCH 08/32] Apply review comments --- polkadot/node/service/src/lib.rs | 6 +- substrate/client/network/src/event.rs | 49 +-- substrate/client/network/src/lib.rs | 6 +- substrate/client/network/src/protocol.rs | 3 +- .../network/src/protocol/notifications.rs | 2 +- .../src/protocol/notifications/behaviour.rs | 3 +- .../src/protocol/notifications/service/mod.rs | 11 +- substrate/client/network/src/service.rs | 2 +- .../client/network/src/service/traits.rs | 6 +- substrate/client/network/sync/src/engine.rs | 329 ------------------ substrate/client/service/src/builder.rs | 17 +- 11 files changed, 32 insertions(+), 402 deletions(-) diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 5ef7828e7459..33e08b3ce5f7 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -1190,15 +1190,15 @@ pub fn new_full( // need a keystore, regardless of which protocol we use below. let keystore_opt = if role.is_authority() { Some(keystore_container.keystore()) } else { None }; - if enable_beefy { + // beefy is enabled if its notification service exists + if let Some(notification_service) = beefy_notification_service { let justifications_protocol_name = beefy_on_demand_justifications_handler.protocol_name(); let network_params = beefy::BeefyNetworkParams { network: network.clone(), sync: sync_service.clone(), gossip_protocol_name: beefy_gossip_proto_name, justifications_protocol_name, - notification_service: beefy_notification_service - .expect("BEEFY was enabled so `NotificationService` exists; qed"), + notification_service, _phantom: core::marker::PhantomData::, }; let payload_provider = beefy_primitives::mmr::MmrRootProvider::new(client.clone()); diff --git a/substrate/client/network/src/event.rs b/substrate/client/network/src/event.rs index 2913f0b55225..dc4fd53a49aa 100644 --- a/substrate/client/network/src/event.rs +++ b/substrate/client/network/src/event.rs @@ -19,14 +19,12 @@ //! Network event types. These are are not the part of the protocol, but rather //! events that happen on the network like DHT get/put results received. -use crate::{types::ProtocolName, NotificationsSink}; +use crate::types::ProtocolName; use bytes::Bytes; -use futures::channel::oneshot; use libp2p::{kad::record::Key, PeerId}; -use sc_network_common::{role::ObservedRole, sync::message::BlockAnnouncesHandshake}; -use sp_runtime::traits::Block as BlockT; +use sc_network_common::role::ObservedRole; /// Events generated by DHT as a response to get_value and put_value requests. #[derive(Debug, Clone)] @@ -92,46 +90,3 @@ pub enum Event { messages: Vec<(ProtocolName, Bytes)>, }, } - -/// Event sent to `SyncingEngine` -// TODO: remove once `NotificationService` is implemented. -pub enum SyncEvent { - /// Opened a substream with the given node with the given notifications protocol. - /// - /// The protocol is always one of the notification protocols that have been registered. - NotificationStreamOpened { - /// Node we opened the substream with. - remote: PeerId, - /// Received handshake. - received_handshake: BlockAnnouncesHandshake, - /// Notification sink. - sink: NotificationsSink, - /// Is the connection inbound. - inbound: bool, - /// Channel for reporting accept/reject of the substream. - tx: oneshot::Sender, - }, - - /// Closed a substream with the given node. Always matches a corresponding previous - /// `NotificationStreamOpened` message. - NotificationStreamClosed { - /// Node we closed the substream with. - remote: PeerId, - }, - - /// Notification sink was replaced. - NotificationSinkReplaced { - /// Node we closed the substream with. - remote: PeerId, - /// Notification sink. - sink: NotificationsSink, - }, - - /// Received one or more messages from the given node using the given protocol. - NotificationsReceived { - /// Node we received the message from. - remote: PeerId, - /// Concerned protocol and associated message. - messages: Vec, - }, -} diff --git a/substrate/client/network/src/lib.rs b/substrate/client/network/src/lib.rs index 2f297f45ccc6..d7e8cb2855bd 100644 --- a/substrate/client/network/src/lib.rs +++ b/substrate/client/network/src/lib.rs @@ -262,7 +262,7 @@ pub mod transport; pub mod types; pub mod utils; -pub use event::{DhtEvent, Event, SyncEvent}; +pub use event::{DhtEvent, Event}; #[doc(inline)] pub use libp2p::{multiaddr, Multiaddr, PeerId}; pub use request_responses::{Config, IfDisconnected, RequestFailure}; @@ -283,8 +283,8 @@ pub use service::{ NotificationSender as NotificationSenderT, NotificationSenderError, NotificationSenderReady, NotificationService, }, - DecodingError, Keypair, NetworkService, NetworkWorker, NotificationCommand, NotificationSender, - NotificationsSink, OutboundFailure, ProtocolHandle, PublicKey, + DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, OutboundFailure, + PublicKey, }; pub use types::ProtocolName; diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index c78dfebdcb52..5588cebcbd89 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -52,8 +52,7 @@ use std::{ use notifications::{Notifications, NotificationsOut}; pub use notifications::{ - notification_service, NotificationCommand, NotificationsSink, NotifsHandlerError, - ProtocolHandle, ProtocolHandlePair, Ready, + notification_service, NotificationsSink, NotifsHandlerError, ProtocolHandlePair, Ready, }; mod notifications; diff --git a/substrate/client/network/src/protocol/notifications.rs b/substrate/client/network/src/protocol/notifications.rs index b5b8b697456e..1a53df2cdf78 100644 --- a/substrate/client/network/src/protocol/notifications.rs +++ b/substrate/client/network/src/protocol/notifications.rs @@ -22,7 +22,7 @@ pub use self::{ behaviour::{Notifications, NotificationsOut, ProtocolConfig}, handler::{NotificationsSink, NotifsHandlerError, Ready}, - service::{notification_service, NotificationCommand, ProtocolHandle, ProtocolHandlePair}, + service::{notification_service, ProtocolHandlePair}, }; mod behaviour; diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index 1ae8c35b4921..76413e29b3a0 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -17,10 +17,9 @@ // along with this program. If not, see . use crate::{ - config::ProtocolHandlePair, protocol::notifications::{ handler::{self, NotificationsSink, NotifsHandler, NotifsHandlerIn, NotifsHandlerOut}, - service::{metrics, NotificationCommand, ProtocolHandle}, + service::{metrics, NotificationCommand, ProtocolHandle, ProtocolHandlePair}, }, protocol_controller::{self, IncomingIndex, Message, SetId}, service::traits::{Direction, ValidationResult}, diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs index 54c2ac60f8b3..4c9a3cce38e3 100644 --- a/substrate/client/network/src/protocol/notifications/service/mod.rs +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -41,6 +41,7 @@ use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnbound use std::{collections::HashMap, fmt::Debug, sync::Arc}; pub(crate) mod metrics; + #[cfg(test)] mod tests; @@ -274,7 +275,11 @@ impl NotificationService for NotificationHandle { self.tx.send(NotificationCommand::SetHandshake(handshake)).await.map_err(|_| ()) } - /// Non-blocking variant of `set_handshake()` that + /// Non-blocking variant of `set_handshake()` that attempts to update the handshake + /// and returns an error if the channel is blocked. + /// + /// Technically the function can return an error if the channel to `Notifications` is closed + /// but that doesn't happen under normal operation. fn try_set_handshake(&mut self, handshake: Vec) -> Result<(), ()> { self.tx.try_send(NotificationCommand::SetHandshake(handshake)).map_err(|_| ()) } @@ -386,7 +391,7 @@ impl ProtocolHandlePair { /// Consume `self` and split [`ProtocolHandlePair`] into a handle which allows it to send events /// to the protocol and a stream of commands received from the protocol. - pub fn split( + pub(crate) fn split( self, ) -> (ProtocolHandle, Box + Send + Unpin>) { ( @@ -399,7 +404,7 @@ impl ProtocolHandlePair { /// Handle that is passed on to `Notifications` and allows it to directly communicate /// with the protocol. #[derive(Debug)] -pub struct ProtocolHandle { +pub(crate) struct ProtocolHandle { /// Protocol name. protocol: ProtocolName, diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index 16ef1d1cd7df..aca9bf64707b 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -98,7 +98,7 @@ use std::{ pub use behaviour::{InboundFailure, OutboundFailure, ResponseFailure}; pub use libp2p::identity::{DecodingError, Keypair, PublicKey}; -pub use protocol::{NotificationCommand, NotificationsSink, ProtocolHandle}; +pub use protocol::NotificationsSink; mod metrics; mod out_events; diff --git a/substrate/client/network/src/service/traits.rs b/substrate/client/network/src/service/traits.rs index c609262158f1..c8e206170bba 100644 --- a/substrate/client/network/src/service/traits.rs +++ b/substrate/client/network/src/service/traits.rs @@ -772,7 +772,11 @@ pub trait NotificationService: Debug + Send { /// Set handshake for the notification protocol replacing the old handshake. async fn set_handshake(&mut self, handshake: Vec) -> Result<(), ()>; - /// Non-blocking variant of `set_handshake()` that + /// Non-blocking variant of `set_handshake()` that attempts to update the handshake + /// and returns an error if the channel is blocked. + /// + /// Technically the function can return an error if the channel to `Notifications` is closed + /// but that doesn't happen under normal operation. fn try_set_handshake(&mut self, handshake: Vec) -> Result<(), ()>; /// Get next event from the `Notifications` event stream. diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 07e3389aef7e..6f5f0a95fb84 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -752,7 +752,6 @@ where } } - // <<<<<<< HEAD loop { let Poll::Ready(Some(event)) = self.notification_service.next_event().poll_unpin(cx) else { @@ -1057,331 +1056,3 @@ where Ok(()) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::service::network::NetworkServiceProvider; - use sc_block_builder::BlockBuilderProvider; - use sc_network::{ - config::NetworkConfiguration, peer_store::PeerStore, service::traits::Direction, - NetworkBlock, NotificationCommand, NotificationsSink, - }; - use sp_consensus::block_validation::DefaultBlockAnnounceValidator; - use substrate_test_runtime_client::{ - runtime::Block, DefaultTestClientBuilderExt, TestClient, TestClientBuilder, - TestClientBuilderExt, - }; - - fn make_syncing_engine() -> ( - Arc, - SyncingEngine, - SyncingService, - NonDefaultSetConfig, - ) { - let mut net_config = NetworkConfiguration::new_local(); - - // 8 outbound full nodes, 32 inbound full nodes and 100 inbound light nodes - net_config.default_peers_set_num_full = 40; - net_config.default_peers_set.in_peers = 132; - net_config.default_peers_set.out_peers = 8; - - let full_config = FullNetworkConfiguration::new(&net_config); - let client = Arc::new(TestClientBuilder::new().build()); - let block_announce_validator = Box::new(DefaultBlockAnnounceValidator); - let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new()); - let (_chain_sync_network_provider, chain_sync_network_handle) = - NetworkServiceProvider::new(); - let peer_store = PeerStore::new(vec![]); - let handle = peer_store.handle(); - - let (engine, service, config) = SyncingEngine::new( - Roles::FULL, - client.clone(), - None, - &full_config, - ProtocolId::from("test-protocol-name"), - &None, - block_announce_validator, - None, - chain_sync_network_handle, - import_queue, - ProtocolName::from("/block-request/1"), - ProtocolName::from("/state-request/1"), - None, - handle, - ) - .unwrap(); - - (client, engine, service, config) - } - - #[tokio::test] - async fn reject_invalid_handshake() { - let (_client, engine, _service, config) = make_syncing_engine(); - let (handle, _) = config.take_protocol_handle().split(); - - tokio::spawn(engine.run()); - - let rx = handle.report_incoming_substream(PeerId::random(), vec![1, 2, 3, 4]).unwrap(); - - assert_eq!(rx.await, Ok(ValidationResult::Reject)); - } - - #[tokio::test] - async fn accept_valid_peer() { - let (client, engine, _service, config) = make_syncing_engine(); - let (handle, _) = config.take_protocol_handle().split(); - - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - let handshake = BlockAnnouncesHandshake::::build( - engine.roles, - *block.header().number(), - block.hash(), - engine.genesis_hash, - ) - .encode(); - - tokio::spawn(engine.run()); - - let rx = handle.report_incoming_substream(PeerId::random(), handshake).unwrap(); - - assert_eq!(rx.await, Ok(ValidationResult::Accept)); - } - - #[tokio::test] - async fn valid_peer_included_into_peers() { - let (client, engine, service, config) = make_syncing_engine(); - let (mut handle, _) = config.take_protocol_handle().split(); - - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - let handshake = BlockAnnouncesHandshake::::build( - engine.roles, - *block.header().number(), - block.hash(), - engine.genesis_hash, - ) - .encode(); - - tokio::spawn(engine.run()); - - let peer_id = PeerId::random(); - let rx = handle.report_incoming_substream(peer_id, handshake.clone()).unwrap(); - assert_eq!(rx.await, Ok(ValidationResult::Accept)); - let (sink, _, _) = NotificationsSink::new(peer_id); - - handle - .report_substream_opened(peer_id, Direction::Inbound, handshake, None, sink) - .unwrap(); - - if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { - loop { - if service.num_sync_peers().await.unwrap() == 1 { - break - } - } - }) - .await - { - panic!("failed to add sync peer"); - } - } - - #[tokio::test] - async fn syncing_engine_full_of_inbound_peers() { - let (client, engine, service, config) = make_syncing_engine(); - let (mut handle, _) = config.take_protocol_handle().split(); - - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - let handshake = BlockAnnouncesHandshake::::build( - engine.roles, - *block.header().number(), - block.hash(), - engine.genesis_hash, - ) - .encode(); - - tokio::spawn(engine.run()); - - // add maximum number of allowed full inbound peers to `SyncingEngine` - let num_in_peers = 32; - for i in 0..num_in_peers { - let peer_id = PeerId::random(); - let rx = handle.report_incoming_substream(peer_id, handshake.clone()).unwrap(); - assert_eq!(rx.await, Ok(ValidationResult::Accept)); - let (sink, _, _) = NotificationsSink::new(peer_id); - - handle - .report_substream_opened(peer_id, Direction::Inbound, handshake.clone(), None, sink) - .unwrap(); - let sync_service = service.clone(); - - if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { - loop { - if sync_service.num_sync_peers().await.unwrap() == i + 1 { - break - } - } - }) - .await - { - panic!("failed to add sync peer"); - } - } - - // try to add one more peer and verify the peer is rejected during handshake validation - let peer_id = PeerId::random(); - let rx = handle.report_incoming_substream(peer_id, handshake.clone()).unwrap(); - assert_eq!(rx.await, Ok(ValidationResult::Reject)); - } - - #[tokio::test] - async fn syncing_engine_full_of_inbound_peers_outbound_accepted() { - let (client, engine, service, config) = make_syncing_engine(); - let (mut handle, _) = config.take_protocol_handle().split(); - - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - let handshake = BlockAnnouncesHandshake::::build( - engine.roles, - *block.header().number(), - block.hash(), - engine.genesis_hash, - ) - .encode(); - - tokio::spawn(engine.run()); - - // add maximum number of allowed inbound peers to `SyncingEngine` - let num_in_peers = 32; - for i in 0..num_in_peers { - let peer_id = PeerId::random(); - let rx = handle.report_incoming_substream(peer_id, handshake.clone()).unwrap(); - assert_eq!(rx.await, Ok(ValidationResult::Accept)); - let (sink, _, _) = NotificationsSink::new(peer_id); - - handle - .report_substream_opened(peer_id, Direction::Inbound, handshake.clone(), None, sink) - .unwrap(); - let sync_service = service.clone(); - - if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { - loop { - if sync_service.num_sync_peers().await.unwrap() == i + 1 { - break - } - } - }) - .await - { - panic!("failed to add sync peer"); - } - } - - // try to add one more peer, this time outbound and verify it's accepted - let peer_id = PeerId::random(); - let (sink, _, _) = NotificationsSink::new(peer_id); - handle - .report_substream_opened(peer_id, Direction::Outbound, handshake.clone(), None, sink) - .unwrap(); - let sync_service = service.clone(); - - if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { - loop { - if sync_service.num_sync_peers().await.unwrap() == num_in_peers + 1 { - break - } - } - }) - .await - { - panic!("failed to add sync peer"); - } - } - - #[tokio::test] - async fn syncing_engine_full_of_inbound_full_peers_but_not_light_peers() { - let (client, engine, service, config) = make_syncing_engine(); - let (mut handle, _) = config.take_protocol_handle().split(); - - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - let genesis = engine.genesis_hash; - let handshake = BlockAnnouncesHandshake::::build( - engine.roles, - *block.header().number(), - block.hash(), - engine.genesis_hash, - ) - .encode(); - - tokio::spawn(engine.run()); - - // add maximum number of allowed inbound peers to `SyncingEngine` - let num_in_peers = 32; - for i in 0..num_in_peers { - let peer_id = PeerId::random(); - let rx = handle.report_incoming_substream(peer_id, handshake.clone()).unwrap(); - assert_eq!(rx.await, Ok(ValidationResult::Accept)); - let (sink, _, _) = NotificationsSink::new(peer_id); - - handle - .report_substream_opened(peer_id, Direction::Inbound, handshake.clone(), None, sink) - .unwrap(); - let sync_service = service.clone(); - - if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { - loop { - if sync_service.num_sync_peers().await.unwrap() == i + 1 { - break - } - } - }) - .await - { - panic!("failed to add sync peer"); - } - } - - // try to add one more peer, this time outbound and verify it's accepted - let handshake = BlockAnnouncesHandshake::::build( - Roles::LIGHT, - *block.header().number(), - block.hash(), - genesis, - ) - .encode(); - let peer_id = PeerId::random(); - let (sink, _, _) = NotificationsSink::new(peer_id); - handle - .report_substream_opened(peer_id, Direction::Inbound, handshake.clone(), None, sink) - .unwrap(); - let sync_service = service.clone(); - - if let Err(_) = tokio::time::timeout(Duration::from_secs(10), async move { - loop { - if sync_service.status().await.unwrap().num_connected_peers == num_in_peers + 1 { - break - } - } - }) - .await - { - panic!("failed to add sync peer"); - } - } - - #[tokio::test] - async fn best_block_import_updates_handshake() { - let (client, engine, service, config) = make_syncing_engine(); - let (_handle, mut commands) = config.take_protocol_handle().split(); - - tokio::spawn(engine.run()); - - let block = client.new_block(Default::default()).unwrap().build().unwrap().block; - service.new_best_block_imported(block.hash(), *block.header().number()); - - assert!(std::matches!( - commands.next().await.unwrap(), - NotificationCommand::SetHandshake(_) - )); - } -} diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index 55d233b9e2ef..3c079d8c0466 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -750,6 +750,11 @@ where } let protocol_id = config.protocol_id(); + let genesis_hash = client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"); let block_announce_validator = if let Some(f) = block_announce_validator_builder { f(client.clone()) @@ -792,11 +797,7 @@ where // Allow both outgoing and incoming requests. let (handler, protocol_config) = WarpSyncRequestHandler::new( protocol_id.clone(), - client - .block_hash(0u32.into()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), + genesis_hash, config.chain_spec.fork_id(), warp_with_provider.clone(), ); @@ -838,11 +839,7 @@ where let (transactions_handler_proto, transactions_config) = sc_network_transactions::TransactionsHandlerPrototype::new( protocol_id.clone(), - client - .block_hash(0u32.into()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), + genesis_hash, config.chain_spec.fork_id(), ); net_config.add_notification_protocol(transactions_config); From 2d4bddaae45169b0a039995606fc818653ce82ab Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Sat, 23 Sep 2023 14:47:11 +0300 Subject: [PATCH 09/32] Fix warnings --- polkadot/node/network/bridge/src/rx/mod.rs | 1 - .../client/network/src/protocol/notifications/service/mod.rs | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index ea178f9dfbc0..ac83fe03aba4 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -20,7 +20,6 @@ use super::*; use always_assert::never; use bytes::Bytes; -use futures::stream::{BoxStream, StreamExt}; use parity_scale_codec::{Decode, DecodeAll}; use parking_lot::Mutex; diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs index 4c9a3cce38e3..2d2b414dcfd5 100644 --- a/substrate/client/network/src/protocol/notifications/service/mod.rs +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -158,9 +158,11 @@ enum InnerNotificationEvent { #[derive(Debug)] pub enum NotificationCommand { /// Instruct `Notifications` to open a substream to peer. + #[allow(unused)] OpenSubstream(PeerId), /// Instruct `Notifications` to close the substream to peer. + #[allow(unused)] CloseSubstream(PeerId), /// Set handshake for the notifications protocol. From f4286dac0e6c275eebcddf5dd91f87a7a442c08f Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Tue, 17 Oct 2023 14:22:13 +0300 Subject: [PATCH 10/32] Fix mixnet --- substrate/client/mixnet/Cargo.toml | 1 + .../client/mixnet/src/packet_dispatcher.rs | 36 +++++------ substrate/client/mixnet/src/protocol.rs | 25 ++++++-- substrate/client/mixnet/src/run.rs | 60 ++++++++++--------- .../src/protocol/notifications/service/mod.rs | 2 +- 5 files changed, 71 insertions(+), 53 deletions(-) diff --git a/substrate/client/mixnet/Cargo.toml b/substrate/client/mixnet/Cargo.toml index 86c5a37754af..d11cb1805ff0 100644 --- a/substrate/client/mixnet/Cargo.toml +++ b/substrate/client/mixnet/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = "4.1" arrayvec = "0.7.2" blake2 = "0.10.4" +bytes = "1" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } futures = "0.3.25" futures-timer = "3.0.2" diff --git a/substrate/client/mixnet/src/packet_dispatcher.rs b/substrate/client/mixnet/src/packet_dispatcher.rs index 856208ecb342..420e0c68847d 100644 --- a/substrate/client/mixnet/src/packet_dispatcher.rs +++ b/substrate/client/mixnet/src/packet_dispatcher.rs @@ -24,7 +24,7 @@ use libp2p_identity::PeerId; use log::{debug, warn}; use mixnet::core::{AddressedPacket, NetworkStatus, Packet, PeerId as CorePeerId}; use parking_lot::Mutex; -use sc_network::{NetworkNotification, ProtocolName}; +use sc_network::NotificationService; use std::{collections::HashMap, future::Future, sync::Arc}; const LOG_TARGET: &str = "mixnet"; @@ -77,41 +77,37 @@ pub struct ReadyPeer { } impl ReadyPeer { - /// If a future is returned, and if that future returns `Some`, this function should be called - /// again to send the next packet queued for the peer; `self` is placed in the `Some` to make - /// this straightforward. Otherwise, we have either sent or dropped all packets queued for the - /// peer, and it can be forgotten about for the time being. + /// If a future is returned, and if that future returns `Some`, this function should be + /// called again to send the next packet queued for the peer; `self` is placed in the `Some` + /// to make this straightforward. Otherwise, we have either sent or dropped all packets + /// queued for the peer, and it can be forgotten about for the time being. pub fn send_packet( self, - network: &impl NetworkNotification, - protocol_name: ProtocolName, + notification_service: &Box, ) -> Option>> { - match network.notification_sender(self.id, protocol_name) { - Err(err) => { + match notification_service.message_sink(&self.id) { + None => { debug!( target: LOG_TARGET, - "Failed to get notification sender for peer ID {}: {err}", self.id + "Failed to get message sink for peer ID {}", self.id, ); self.queue.clear(); None }, - Ok(sender) => Some(async move { - match sender.ready().await.and_then(|mut ready| { - let (packet, more_packets) = self.queue.pop(); - let packet = - packet.expect("Should only be called if there is a packet to send"); - ready.send((packet as Box<[_]>).into())?; - Ok(more_packets) - }) { + Some(sink) => Some(async move { + let (packet, more_packets) = self.queue.pop(); + let packet = packet.expect("Should only be called if there is a packet to send"); + + match sink.send_async_notification((packet as Box<[_]>).into()).await { + Ok(_) => more_packets.then_some(self), Err(err) => { debug!( target: LOG_TARGET, - "Notification sender for peer ID {} failed: {err}", self.id + "Failed to send packet to peer ID {}: {err}", self.id, ); self.queue.clear(); None }, - Ok(more_packets) => more_packets.then(|| self), } }), } diff --git a/substrate/client/mixnet/src/protocol.rs b/substrate/client/mixnet/src/protocol.rs index 555c267b86e0..955502a4856a 100644 --- a/substrate/client/mixnet/src/protocol.rs +++ b/substrate/client/mixnet/src/protocol.rs @@ -18,7 +18,10 @@ use super::config::Config; use mixnet::core::PACKET_SIZE; -use sc_network::{config::NonDefaultSetConfig, ProtocolName}; +use sc_network::{ + config::{NonDefaultSetConfig, NonReservedPeerMode, SetConfig}, + NotificationService, ProtocolName, +}; /// Returns the protocol name to use for the mixnet controlled by the given chain. pub fn protocol_name(genesis_hash: &[u8], fork_id: Option<&str>) -> ProtocolName { @@ -31,12 +34,26 @@ pub fn protocol_name(genesis_hash: &[u8], fork_id: Option<&str>) -> ProtocolName } /// Returns the peers set configuration for the mixnet protocol. -pub fn peers_set_config(name: ProtocolName, config: &Config) -> NonDefaultSetConfig { - let mut set_config = NonDefaultSetConfig::new(name, PACKET_SIZE as u64); +pub fn peers_set_config( + name: ProtocolName, + config: &Config, +) -> (NonDefaultSetConfig, Box) { + let (mut set_config, service) = NonDefaultSetConfig::new( + name, + Vec::new(), + PACKET_SIZE as u64, + None, + SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + ); if config.substrate.num_gateway_slots != 0 { // out_peers is always 0; we are only interested in connecting to mixnodes, which we do by // setting them as reserved nodes set_config.allow_non_reserved(config.substrate.num_gateway_slots, 0); } - set_config + (set_config, service) } diff --git a/substrate/client/mixnet/src/run.rs b/substrate/client/mixnet/src/run.rs index 09020469d5ee..14d188df0977 100644 --- a/substrate/client/mixnet/src/run.rs +++ b/substrate/client/mixnet/src/run.rs @@ -29,11 +29,12 @@ use super::{ request::{extrinsic_delay, Request, SUBMIT_EXTRINSIC}, sync_with_runtime::sync_with_runtime, }; +use bytes::Bytes; use codec::{Decode, DecodeAll, Encode}; use futures::{ future::{pending, Either}, stream::FuturesUnordered, - StreamExt, + FutureExt, StreamExt, }; use log::{debug, error, trace, warn}; use mixnet::{ @@ -43,8 +44,8 @@ use mixnet::{ }; use sc_client_api::{BlockchainEvents, HeaderBackend}; use sc_network::{ - Event::{NotificationStreamClosed, NotificationStreamOpened, NotificationsReceived}, - NetworkEventStream, NetworkNotification, NetworkPeers, NetworkStateInfo, ProtocolName, + service::traits::{NotificationEvent, ValidationResult}, + NetworkNotification, NetworkPeers, NetworkStateInfo, NotificationService, ProtocolName, }; use sc_transaction_pool_api::{ LocalTransactionPool, OffchainTransactionPoolFactory, TransactionPool, @@ -154,12 +155,13 @@ pub async fn run( protocol_name: ProtocolName, transaction_pool: Arc

, keystore: Option, + mut notification_service: Box, ) where B: Block, C: BlockchainEvents + ProvideRuntimeApi + HeaderBackend, C::Api: MixnetApi, S: SyncOracle, - N: NetworkStateInfo + NetworkEventStream + NetworkNotification + NetworkPeers, + N: NetworkStateInfo + NetworkNotification + NetworkPeers, P: TransactionPool + LocalTransactionPool + 'static, { let local_peer_id = network.local_peer_id(); @@ -189,7 +191,6 @@ pub async fn run( } else { None }; - let mut network_events = network.event_stream("mixnet").fuse(); let mut next_forward_packet_delay = MaybeInfDelay::new(None); let mut next_authored_packet_delay = MaybeInfDelay::new(None); let mut ready_peers = FuturesUnordered::new(); @@ -248,33 +249,36 @@ pub async fn run( } } - event = network_events.select_next_some() => match event { - NotificationStreamOpened { remote, protocol, .. } - if protocol == protocol_name => packet_dispatcher.add_peer(&remote), - NotificationStreamClosed { remote, protocol } - if protocol == protocol_name => packet_dispatcher.remove_peer(&remote), - NotificationsReceived { remote, messages } => { - for message in messages { - if message.0 == protocol_name { - match message.1.as_ref().try_into() { - Ok(packet) => handle_packet(packet, - &mut mixnet, &mut request_manager, &mut reply_manager, - &mut extrinsic_queue, &config.substrate), - Err(_) => debug!(target: LOG_TARGET, - "Dropped incorrectly sized packet ({} bytes) from {remote}", - message.1.len(), - ), - } - } + event = notification_service.next_event().fuse() => match event { + None => todo!(), + Some(NotificationEvent::ValidateInboundSubstream { result_tx, .. }) => { + let _ = result_tx.send(ValidationResult::Accept); + }, + Some(NotificationEvent::NotificationStreamOpened { peer, .. }) => { + packet_dispatcher.add_peer(&peer); + }, + Some(NotificationEvent::NotificationStreamClosed { peer }) => { + packet_dispatcher.remove_peer(&peer); + }, + Some(NotificationEvent::NotificationReceived { peer, notification }) => { + let notification: Bytes = notification.into(); + + match notification.as_ref().try_into() { + Ok(packet) => handle_packet(packet, + &mut mixnet, &mut request_manager, &mut reply_manager, + &mut extrinsic_queue, &config.substrate), + Err(_) => debug!(target: LOG_TARGET, + "Dropped incorrectly sized packet ({} bytes) from {peer}", + notification.len(), + ), } - } - _ => () + }, }, _ = next_forward_packet_delay => { if let Some(packet) = mixnet.pop_next_forward_packet() { if let Some(ready_peer) = packet_dispatcher.dispatch(packet) { - if let Some(fut) = ready_peer.send_packet(&*network, protocol_name.clone()) { + if let Some(fut) = ready_peer.send_packet(¬ification_service) { ready_peers.push(fut); } } @@ -288,7 +292,7 @@ pub async fn run( _ = next_authored_packet_delay => { if let Some(packet) = mixnet.pop_next_authored_packet(&packet_dispatcher) { if let Some(ready_peer) = packet_dispatcher.dispatch(packet) { - if let Some(fut) = ready_peer.send_packet(&*network, protocol_name.clone()) { + if let Some(fut) = ready_peer.send_packet(¬ification_service) { ready_peers.push(fut); } } @@ -297,7 +301,7 @@ pub async fn run( ready_peer = ready_peers.select_next_some() => { if let Some(ready_peer) = ready_peer { - if let Some(fut) = ready_peer.send_packet(&*network, protocol_name.clone()) { + if let Some(fut) = ready_peer.send_packet(¬ification_service) { ready_peers.push(fut); } } diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs index 2d2b414dcfd5..e15232f6b032 100644 --- a/substrate/client/network/src/protocol/notifications/service/mod.rs +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -70,7 +70,7 @@ impl MessageSink for NotificationSink { sink.0.send_sync_notification(notification); } - /// Send an asynchronous `notification` to to the peer associated with this [`MessageSink`], + /// Send an asynchronous `notification` to the peer associated with this [`MessageSink`], /// allowing sender to exercise backpressure. /// /// Returns an error if the peer does not exist. From ff10bfb22eb41cd28082b9e30db7b1c2a9679fc9 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Tue, 17 Oct 2023 17:49:37 +0300 Subject: [PATCH 11/32] Add `Sync` --- substrate/client/network/src/service/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/network/src/service/traits.rs b/substrate/client/network/src/service/traits.rs index c8e206170bba..f66e810be11a 100644 --- a/substrate/client/network/src/service/traits.rs +++ b/substrate/client/network/src/service/traits.rs @@ -804,7 +804,7 @@ pub trait NotificationService: Debug + Send { /// [`NotificationService`] due to synchronization required to keep the underlying notification /// sink up to date with possible sink replacement events. #[async_trait::async_trait] -pub trait MessageSink: Send { +pub trait MessageSink: Send + Sync { /// Send synchronous `notification` to the peer associated with this [`MessageSink`]. fn send_sync_notification(&self, notification: Vec); From 6451147289d17096242482d1d1fbf3554b9856ae Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Wed, 1 Nov 2023 11:56:03 +0200 Subject: [PATCH 12/32] Use `NotificationService` in `ConsensusGossip` --- substrate/client/network-gossip/src/bridge.rs | 22 ++- .../network-gossip/src/state_machine.rs | 162 ++++++++++++++---- 2 files changed, 141 insertions(+), 43 deletions(-) diff --git a/substrate/client/network-gossip/src/bridge.rs b/substrate/client/network-gossip/src/bridge.rs index f91c206ed599..862c373f8b9d 100644 --- a/substrate/client/network-gossip/src/bridge.rs +++ b/substrate/client/network-gossip/src/bridge.rs @@ -129,7 +129,7 @@ impl GossipEngine { /// Broadcast all messages with given topic. pub fn broadcast_topic(&mut self, topic: B::Hash, force: bool) { - self.state_machine.broadcast_topic(&mut *self.network, topic, force); + self.state_machine.broadcast_topic(&mut self.notification_service, topic, force); } /// Get data of valid, incoming messages for a topic (but might have expired meanwhile). @@ -154,19 +154,21 @@ impl GossipEngine { /// Send all messages with given topic to a peer. pub fn send_topic(&mut self, who: &PeerId, topic: B::Hash, force: bool) { - self.state_machine.send_topic(&mut *self.network, who, topic, force) + self.state_machine.send_topic(&mut self.notification_service, who, topic, force) } /// Multicast a message to all peers. pub fn gossip_message(&mut self, topic: B::Hash, message: Vec, force: bool) { - self.state_machine.multicast(&mut *self.network, topic, message, force) + self.state_machine + .multicast(&mut self.notification_service, topic, message, force) } /// Send addressed message to the given peers. The message is not kept or multicast /// later on. pub fn send_message(&mut self, who: Vec, data: Vec) { for who in &who { - self.state_machine.send_message(&mut *self.network, who, data.clone()); + self.state_machine + .send_message(&mut self.notification_service, who, data.clone()); } } @@ -214,14 +216,20 @@ impl Future for GossipEngine { continue }; - this.state_machine.new_peer(&mut *this.network, peer, role); + this.state_machine.new_peer( + &mut this.notification_service, + peer, + role, + ); }, NotificationEvent::NotificationStreamClosed { peer } => { - this.state_machine.peer_disconnected(&mut *this.network, peer); + this.state_machine + .peer_disconnected(&mut this.notification_service, peer); }, NotificationEvent::NotificationReceived { peer, notification } => { let to_forward = this.state_machine.on_incoming( &mut *this.network, + &mut this.notification_service, peer, vec![notification], ); @@ -309,7 +317,7 @@ impl Future for GossipEngine { while let Poll::Ready(()) = this.periodic_maintenance_interval.poll_unpin(cx) { this.periodic_maintenance_interval.reset(PERIODIC_MAINTENANCE_INTERVAL); - this.state_machine.tick(&mut *this.network); + this.state_machine.tick(&mut this.notification_service); this.message_sinks.retain(|_, sinks| { sinks.retain(|sink| !sink.is_closed()); diff --git a/substrate/client/network-gossip/src/state_machine.rs b/substrate/client/network-gossip/src/state_machine.rs index 724a4e3e07b8..91b56b0f097e 100644 --- a/substrate/client/network-gossip/src/state_machine.rs +++ b/substrate/client/network-gossip/src/state_machine.rs @@ -23,7 +23,7 @@ use libp2p::PeerId; use schnellru::{ByLength, LruMap}; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; -use sc_network::types::ProtocolName; +use sc_network::{types::ProtocolName, NotificationService}; use sc_network_common::role::ObservedRole; use sp_runtime::traits::{Block as BlockT, Hash, HashingFor}; use std::{collections::HashMap, iter, sync::Arc, time, time::Instant}; @@ -74,33 +74,33 @@ struct MessageEntry { /// Local implementation of `ValidatorContext`. struct NetworkContext<'g, 'p, B: BlockT> { gossip: &'g mut ConsensusGossip, - network: &'p mut dyn Network, + notification_service: &'p mut Box, } impl<'g, 'p, B: BlockT> ValidatorContext for NetworkContext<'g, 'p, B> { /// Broadcast all messages with given topic to peers that do not have it yet. fn broadcast_topic(&mut self, topic: B::Hash, force: bool) { - self.gossip.broadcast_topic(self.network, topic, force); + self.gossip.broadcast_topic(self.notification_service, topic, force); } /// Broadcast a message to all peers that have not received it previously. fn broadcast_message(&mut self, topic: B::Hash, message: Vec, force: bool) { - self.gossip.multicast(self.network, topic, message, force); + self.gossip.multicast(self.notification_service, topic, message, force); } /// Send addressed message to a peer. fn send_message(&mut self, who: &PeerId, message: Vec) { - self.network.write_notification(*who, self.gossip.protocol.clone(), message); + self.notification_service.send_sync_notification(who, message); } /// Send all messages with given topic to a peer. fn send_topic(&mut self, who: &PeerId, topic: B::Hash, force: bool) { - self.gossip.send_topic(self.network, who, topic, force); + self.gossip.send_topic(self.notification_service, who, topic, force); } } fn propagate<'a, B: BlockT, I>( - network: &mut dyn Network, + notification_service: &mut Box, protocol: ProtocolName, messages: I, intent: MessageIntent, @@ -147,7 +147,7 @@ where ?message, "Propagating message", ); - network.write_notification(*id, protocol.clone(), message.clone()); + notification_service.send_sync_notification(id, message.clone()); } } } @@ -191,7 +191,12 @@ impl ConsensusGossip { } /// Handle new connected peer. - pub fn new_peer(&mut self, network: &mut dyn Network, who: PeerId, role: ObservedRole) { + pub fn new_peer( + &mut self, + notification_service: &mut Box, + who: PeerId, + role: ObservedRole, + ) { tracing::trace!( target:"gossip", %who, @@ -202,7 +207,7 @@ impl ConsensusGossip { self.peers.insert(who, PeerConsensus { known_messages: Default::default() }); let validator = self.validator.clone(); - let mut context = NetworkContext { gossip: self, network }; + let mut context = NetworkContext { gossip: self, notification_service }; validator.new_peer(&mut context, &who, role); } @@ -233,30 +238,35 @@ impl ConsensusGossip { } /// Call when a peer has been disconnected to stop tracking gossip status. - pub fn peer_disconnected(&mut self, network: &mut dyn Network, who: PeerId) { + pub fn peer_disconnected( + &mut self, + notification_service: &mut Box, + who: PeerId, + ) { let validator = self.validator.clone(); - let mut context = NetworkContext { gossip: self, network }; + let mut context = NetworkContext { gossip: self, notification_service }; validator.peer_disconnected(&mut context, &who); self.peers.remove(&who); } /// Perform periodic maintenance - pub fn tick(&mut self, network: &mut dyn Network) { + pub fn tick(&mut self, notification_service: &mut Box) { self.collect_garbage(); if Instant::now() >= self.next_broadcast { - self.rebroadcast(network); + self.rebroadcast(notification_service); self.next_broadcast = Instant::now() + REBROADCAST_INTERVAL; } } /// Rebroadcast all messages to all peers. - fn rebroadcast(&mut self, network: &mut dyn Network) { + fn rebroadcast(&mut self, notification_service: &mut Box) { let messages = self .messages .iter() .map(|entry| (&entry.message_hash, &entry.topic, &entry.message)); + propagate( - network, + notification_service, self.protocol.clone(), messages, MessageIntent::PeriodicRebroadcast, @@ -266,7 +276,12 @@ impl ConsensusGossip { } /// Broadcast all messages with given topic. - pub fn broadcast_topic(&mut self, network: &mut dyn Network, topic: B::Hash, force: bool) { + pub fn broadcast_topic( + &mut self, + notification_service: &mut Box, + topic: B::Hash, + force: bool, + ) { let messages = self.messages.iter().filter_map(|entry| { if entry.topic == topic { Some((&entry.message_hash, &entry.topic, &entry.message)) @@ -276,7 +291,7 @@ impl ConsensusGossip { }); let intent = if force { MessageIntent::ForcedBroadcast } else { MessageIntent::Broadcast }; propagate( - network, + notification_service, self.protocol.clone(), messages, intent, @@ -327,6 +342,7 @@ impl ConsensusGossip { pub fn on_incoming( &mut self, network: &mut dyn Network, + notification_service: &mut Box, who: PeerId, messages: Vec>, ) -> Vec<(B::Hash, TopicNotification)> { @@ -367,7 +383,7 @@ impl ConsensusGossip { // validate the message let validation = { let validator = self.validator.clone(); - let mut context = NetworkContext { gossip: self, network }; + let mut context = NetworkContext { gossip: self, notification_service }; validator.validate(&mut context, &who, &message) }; @@ -414,7 +430,7 @@ impl ConsensusGossip { /// Send all messages with given topic to a peer. pub fn send_topic( &mut self, - network: &mut dyn Network, + notification_service: &mut Box, who: &PeerId, topic: B::Hash, force: bool, @@ -443,7 +459,7 @@ impl ConsensusGossip { ?entry.message, "Sending topic message", ); - network.write_notification(*who, self.protocol.clone(), entry.message.clone()); + notification_service.send_sync_notification(who, entry.message.clone()); } } } @@ -451,7 +467,7 @@ impl ConsensusGossip { /// Multicast a message to all peers. pub fn multicast( &mut self, - network: &mut dyn Network, + notification_service: &mut Box, topic: B::Hash, message: Vec, force: bool, @@ -460,7 +476,7 @@ impl ConsensusGossip { self.register_message_hashed(message_hash, topic, message.clone(), None); let intent = if force { MessageIntent::ForcedBroadcast } else { MessageIntent::Broadcast }; propagate( - network, + notification_service, self.protocol.clone(), iter::once((&message_hash, &topic, &message)), intent, @@ -471,7 +487,12 @@ impl ConsensusGossip { /// Send addressed message to a peer. The message is not kept or multicast /// later on. - pub fn send_message(&mut self, network: &mut dyn Network, who: &PeerId, message: Vec) { + pub fn send_message( + &mut self, + notification_service: &mut Box, + who: &PeerId, + message: Vec, + ) { let peer = match self.peers.get_mut(who) { None => return, Some(peer) => peer, @@ -488,7 +509,7 @@ impl ConsensusGossip { ); peer.known_messages.insert(message_hash); - network.write_notification(*who, self.protocol.clone(), message); + notification_service.send_sync_notification(who, message) } } @@ -524,9 +545,9 @@ mod tests { use crate::multiaddr::Multiaddr; use futures::prelude::*; use sc_network::{ - config::MultiaddrWithPeerId, event::Event, NetworkBlock, NetworkEventStream, - NetworkNotification, NetworkPeers, NotificationSenderError, - NotificationSenderT as NotificationSender, ReputationChange, + config::MultiaddrWithPeerId, event::Event, service::traits::NotificationEvent, MessageSink, + NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, + NotificationSenderError, NotificationSenderT as NotificationSender, ReputationChange, }; use sp_runtime::{ testing::{Block as RawBlock, ExtrinsicWrapper, H256}, @@ -695,6 +716,62 @@ mod tests { } } + #[derive(Debug, Default)] + struct NoOpNotificationService {} + + #[async_trait::async_trait] + impl NotificationService for NoOpNotificationService { + /// Instruct `Notifications` to open a new substream for `peer`. + async fn open_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Instruct `Notifications` to close substream for `peer`. + async fn close_substream(&mut self, _peer: PeerId) -> Result<(), ()> { + unimplemented!(); + } + + /// Send synchronous `notification` to `peer`. + fn send_sync_notification(&self, _peer: &PeerId, _notification: Vec) { + unimplemented!(); + } + + /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure. + async fn send_async_notification( + &self, + _peer: &PeerId, + _notification: Vec, + ) -> Result<(), sc_network::error::Error> { + unimplemented!(); + } + + /// Set handshake for the notification protocol replacing the old handshake. + async fn set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + fn try_set_handshake(&mut self, _handshake: Vec) -> Result<(), ()> { + unimplemented!(); + } + + /// Get next event from the `Notifications` event stream. + async fn next_event(&mut self) -> Option { + None + } + + fn clone(&mut self) -> Result, ()> { + unimplemented!(); + } + + fn protocol(&self) -> &ProtocolName { + unimplemented!(); + } + + fn message_sink(&self, _peer: &PeerId) -> Option> { + unimplemented!(); + } + } + #[test] fn collects_garbage() { struct AllowOne; @@ -777,20 +854,28 @@ mod tests { fn peer_is_removed_on_disconnect() { let mut consensus = ConsensusGossip::::new(Arc::new(AllowAll), "/foo".into(), None); - let mut network = NoOpNetwork::default(); + let mut notification_service: Box = + Box::new(NoOpNotificationService::default()); let peer_id = PeerId::random(); - consensus.new_peer(&mut network, peer_id, ObservedRole::Full); + consensus.new_peer(&mut notification_service, peer_id, ObservedRole::Full); assert!(consensus.peers.contains_key(&peer_id)); - consensus.peer_disconnected(&mut network, peer_id); + consensus.peer_disconnected(&mut notification_service, peer_id); assert!(!consensus.peers.contains_key(&peer_id)); } #[test] fn on_incoming_ignores_discarded_messages() { + let mut notification_service: Box = + Box::new(NoOpNotificationService::default()); let to_forward = ConsensusGossip::::new(Arc::new(DiscardAll), "/foo".into(), None) - .on_incoming(&mut NoOpNetwork::default(), PeerId::random(), vec![vec![1, 2, 3]]); + .on_incoming( + &mut NoOpNetwork::default(), + &mut notification_service, + PeerId::random(), + vec![vec![1, 2, 3]], + ); assert!( to_forward.is_empty(), @@ -802,11 +887,14 @@ mod tests { #[test] fn on_incoming_ignores_unregistered_peer() { let mut network = NoOpNetwork::default(); + let mut notification_service: Box = + Box::new(NoOpNotificationService::default()); let remote = PeerId::random(); let to_forward = ConsensusGossip::::new(Arc::new(AllowAll), "/foo".into(), None) .on_incoming( &mut network, + &mut notification_service, // Unregistered peer. remote, vec![vec![1, 2, 3]], @@ -826,18 +914,20 @@ mod tests { let mut consensus = ConsensusGossip::::new(Arc::new(AllowAll), "/foo".into(), None); let mut network = NoOpNetwork::default(); + let mut notification_service: Box = + Box::new(NoOpNotificationService::default()); let peer_id = PeerId::random(); - consensus.new_peer(&mut network, peer_id, ObservedRole::Full); + consensus.new_peer(&mut notification_service, peer_id, ObservedRole::Full); assert!(consensus.peers.contains_key(&peer_id)); let peer_id2 = PeerId::random(); - consensus.new_peer(&mut network, peer_id2, ObservedRole::Full); + consensus.new_peer(&mut notification_service, peer_id2, ObservedRole::Full); assert!(consensus.peers.contains_key(&peer_id2)); let message = vec![vec![1, 2, 3]]; - consensus.on_incoming(&mut network, peer_id, message.clone()); - consensus.on_incoming(&mut network, peer_id2, message.clone()); + consensus.on_incoming(&mut network, &mut notification_service, peer_id, message.clone()); + consensus.on_incoming(&mut network, &mut notification_service, peer_id2, message.clone()); assert_eq!( vec![(peer_id, rep::GOSSIP_SUCCESS)], From fd3a6ced20d28e5695d9f04c96a92273e23aea43 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 16 Oct 2023 10:55:33 +0300 Subject: [PATCH 13/32] Fix stuff --- .../client/executor/wasmtime/src/tests.rs | 8 ++- .../client/mixnet/src/sync_with_runtime.rs | 1 + .../account_reentrance_count_call.wat | 2 +- .../add_remove_delegate_dependency.wat | 16 ++--- .../frame/contracts/fixtures/balance.wat | 2 +- substrate/frame/contracts/fixtures/call.wat | 2 +- .../fixtures/call_runtime_and_call.wat | 2 +- .../contracts/fixtures/caller_contract.wat | 66 +++++++++---------- .../contracts/fixtures/chain_extension.wat | 2 +- .../fixtures/chain_extension_temp_storage.wat | 2 +- .../fixtures/create_storage_and_call.wat | 2 +- .../create_storage_and_instantiate.wat | 2 +- .../contracts/fixtures/crypto_hashes.wat | 6 +- .../fixtures/debug_message_invalid_utf8.wat | 2 +- .../debug_message_logging_disabled.wat | 2 +- .../fixtures/debug_message_works.wat | 2 +- .../contracts/fixtures/delegate_call.wat | 6 +- .../contracts/fixtures/delegate_call_lib.wat | 2 +- .../fixtures/delegate_call_simple.wat | 2 +- .../fixtures/destroy_and_transfer.wat | 2 +- substrate/frame/contracts/fixtures/drain.wat | 2 +- .../contracts/fixtures/ecdsa_recover.wat | 2 +- .../frame/contracts/fixtures/event_size.wat | 2 +- .../frame/contracts/fixtures/multi_store.wat | 2 +- .../fixtures/reentrance_count_call.wat | 10 +-- .../reentrance_count_delegated_call.wat | 12 ++-- .../contracts/fixtures/self_destruct.wat | 2 +- .../fixtures/self_destructing_constructor.wat | 2 +- .../contracts/fixtures/set_code_hash.wat | 6 +- .../frame/contracts/fixtures/storage_size.wat | 2 +- .../frame/contracts/fixtures/store_call.wat | 2 +- .../frame/contracts/fixtures/store_deploy.wat | 2 +- substrate/frame/contracts/src/wasm/mod.rs | 54 +++++++-------- 33 files changed, 119 insertions(+), 112 deletions(-) diff --git a/substrate/client/executor/wasmtime/src/tests.rs b/substrate/client/executor/wasmtime/src/tests.rs index e185754b0769..1c06da1e3c14 100644 --- a/substrate/client/executor/wasmtime/src/tests.rs +++ b/substrate/client/executor/wasmtime/src/tests.rs @@ -384,7 +384,9 @@ fn test_max_memory_pages( ) (i32.const -1) ) - (unreachable) + (then + (unreachable) + ) ) (i64.const 0) @@ -421,7 +423,9 @@ fn test_max_memory_pages( ) (i32.const -1) ) - (unreachable) + (then + (unreachable) + ) ) (i64.const 0) diff --git a/substrate/client/mixnet/src/sync_with_runtime.rs b/substrate/client/mixnet/src/sync_with_runtime.rs index 4a80b3c75f43..f3be96025410 100644 --- a/substrate/client/mixnet/src/sync_with_runtime.rs +++ b/substrate/client/mixnet/src/sync_with_runtime.rs @@ -196,6 +196,7 @@ where #[cfg(test)] mod tests { use super::*; + use multiaddr::multiaddr; #[test] fn fixup_empty_external_addresses() { diff --git a/substrate/frame/contracts/fixtures/account_reentrance_count_call.wat b/substrate/frame/contracts/fixtures/account_reentrance_count_call.wat index ab6789066487..e6d6ba8bb814 100644 --- a/substrate/frame/contracts/fixtures/account_reentrance_count_call.wat +++ b/substrate/frame/contracts/fixtures/account_reentrance_count_call.wat @@ -14,7 +14,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/add_remove_delegate_dependency.wat b/substrate/frame/contracts/fixtures/add_remove_delegate_dependency.wat index ef456b6d620a..dac7736244da 100644 --- a/substrate/frame/contracts/fixtures/add_remove_delegate_dependency.wat +++ b/substrate/frame/contracts/fixtures/add_remove_delegate_dependency.wat @@ -16,7 +16,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -44,8 +44,8 @@ ;; [0..4) - size of the call ;; [4..8) - action to perform ;; [8..42) - code hash of the callee - (set_local $action (i32.load (i32.const 4))) - (set_local $code_hash_ptr (i32.const 8)) + (local.set $action (i32.load (i32.const 4))) + (local.set $code_hash_ptr (i32.const 8)) ;; Assert input size == 36 (4 for action + 32 for code_hash). (call $assert @@ -56,25 +56,25 @@ ) ;; Call add_delegate_dependency when action == 1. - (if (i32.eq (get_local $action) (i32.const 1)) + (if (i32.eq (local.get $action) (i32.const 1)) (then - (call $add_delegate_dependency (get_local $code_hash_ptr)) + (call $add_delegate_dependency (local.get $code_hash_ptr)) ) (else) ) ;; Call remove_delegate_dependency when action == 2. - (if (i32.eq (get_local $action) (i32.const 2)) + (if (i32.eq (local.get $action) (i32.const 2)) (then (call $remove_delegate_dependency - (get_local $code_hash_ptr) + (local.get $code_hash_ptr) ) ) (else) ) ;; Call terminate when action == 3. - (if (i32.eq (get_local $action) (i32.const 3)) + (if (i32.eq (local.get $action) (i32.const 3)) (then (call $terminate (i32.const 100) ;; Pointer to beneficiary address diff --git a/substrate/frame/contracts/fixtures/balance.wat b/substrate/frame/contracts/fixtures/balance.wat index d86d5c4b1c60..d7970c92e414 100644 --- a/substrate/frame/contracts/fixtures/balance.wat +++ b/substrate/frame/contracts/fixtures/balance.wat @@ -12,7 +12,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/call.wat b/substrate/frame/contracts/fixtures/call.wat index 4558b2c6409b..43b32049c88a 100644 --- a/substrate/frame/contracts/fixtures/call.wat +++ b/substrate/frame/contracts/fixtures/call.wat @@ -7,7 +7,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/call_runtime_and_call.wat b/substrate/frame/contracts/fixtures/call_runtime_and_call.wat index 3320922d9e2c..5d76e19a74c7 100644 --- a/substrate/frame/contracts/fixtures/call_runtime_and_call.wat +++ b/substrate/frame/contracts/fixtures/call_runtime_and_call.wat @@ -7,7 +7,7 @@ (func $assert (param i32) (block $ok - (br_if $ok (get_local 0)) + (br_if $ok (local.get 0)) (unreachable) ) ) diff --git a/substrate/frame/contracts/fixtures/caller_contract.wat b/substrate/frame/contracts/fixtures/caller_contract.wat index 929171b9a26f..43eb8ccfd54f 100644 --- a/substrate/frame/contracts/fixtures/caller_contract.wat +++ b/substrate/frame/contracts/fixtures/caller_contract.wat @@ -10,7 +10,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -37,10 +37,10 @@ ) ;; Read current balance into local variable. - (set_local $sp (i32.const 1024)) + (local.set $sp (i32.const 1024)) ;; Fail to deploy the contract since it returns a non-zero exit status. - (set_local $exit_code + (local.set $exit_code (call $seal_instantiate (i32.const 24) ;; Pointer to the code hash. (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. @@ -60,11 +60,11 @@ ;; Check non-zero exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted + (i32.eq (local.get $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted ) ;; Fail to deploy the contract due to insufficient ref_time weight. - (set_local $exit_code + (local.set $exit_code (call $seal_instantiate (i32.const 24) ;; Pointer to the code hash. (i64.const 1) ;; Supply too little ref_time weight @@ -85,11 +85,11 @@ ;; Check for special trap exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped + (i32.eq (local.get $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped ) ;; Fail to deploy the contract due to insufficient ref_time weight. - (set_local $exit_code + (local.set $exit_code (call $seal_instantiate (i32.const 24) ;; Pointer to the code hash. (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. @@ -110,17 +110,17 @@ ;; Check for special trap exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped + (i32.eq (local.get $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped ) ;; Length of the output buffer (i32.store - (i32.sub (get_local $sp) (i32.const 4)) + (i32.sub (local.get $sp) (i32.const 4)) (i32.const 256) ) ;; Deploy the contract successfully. - (set_local $exit_code + (local.set $exit_code (call $seal_instantiate (i32.const 24) ;; Pointer to the code hash. (i64.const 0) ;; How much ref_time weight to devote for the execution. 0 = all. @@ -130,7 +130,7 @@ (i32.const 8) ;; Pointer to input data buffer address (i32.const 8) ;; Length of input data buffer (i32.const 16) ;; Pointer to the address output buffer - (i32.sub (get_local $sp) (i32.const 4)) ;; Pointer to the address buffer length + (i32.sub (local.get $sp) (i32.const 4)) ;; Pointer to the address buffer length (i32.const 4294967295) ;; u32 max sentinel value: do not copy output (i32.const 0) ;; Length is ignored in this case (i32.const 0) ;; salt_ptr @@ -141,28 +141,28 @@ ;; Check for success exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + (i32.eq (local.get $exit_code) (i32.const 0)) ;; ReturnCode::Success ) ;; Check that address has the expected length (call $assert - (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 4))) (i32.const 32)) + (i32.eq (i32.load (i32.sub (local.get $sp) (i32.const 4))) (i32.const 32)) ) ;; Zero out destination buffer of output (i32.store - (i32.sub (get_local $sp) (i32.const 4)) + (i32.sub (local.get $sp) (i32.const 4)) (i32.const 0) ) ;; Length of the output buffer (i32.store - (i32.sub (get_local $sp) (i32.const 8)) + (i32.sub (local.get $sp) (i32.const 8)) (i32.const 4) ) ;; Call the new contract and expect it to return failing exit code. - (set_local $exit_code + (local.set $exit_code (call $seal_call (i32.const 0) ;; Set no flag (i32.const 16) ;; Pointer to "callee" address. @@ -172,29 +172,29 @@ (i32.const 0) ;; Pointer to the buffer with value to transfer (i32.const 9) ;; Pointer to input data buffer address (i32.const 7) ;; Length of input data buffer - (i32.sub (get_local $sp) (i32.const 4)) ;; Ptr to output buffer - (i32.sub (get_local $sp) (i32.const 8)) ;; Ptr to output buffer len + (i32.sub (local.get $sp) (i32.const 4)) ;; Ptr to output buffer + (i32.sub (local.get $sp) (i32.const 8)) ;; Ptr to output buffer len ) ) ;; Check non-zero exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted + (i32.eq (local.get $exit_code) (i32.const 2)) ;; ReturnCode::CalleeReverted ) ;; Check that output buffer contains the expected return data. (call $assert - (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 8))) (i32.const 3)) + (i32.eq (i32.load (i32.sub (local.get $sp) (i32.const 8))) (i32.const 3)) ) (call $assert (i32.eq - (i32.load (i32.sub (get_local $sp) (i32.const 4))) + (i32.load (i32.sub (local.get $sp) (i32.const 4))) (i32.const 0x00776655) ) ) ;; Fail to call the contract due to insufficient ref_time weight. - (set_local $exit_code + (local.set $exit_code (call $seal_call (i32.const 0) ;; Set no flag (i32.const 16) ;; Pointer to "callee" address. @@ -211,11 +211,11 @@ ;; Check for special trap exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped + (i32.eq (local.get $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped ) ;; Fail to call the contract due to insufficient proof_size weight. - (set_local $exit_code + (local.set $exit_code (call $seal_call (i32.const 0) ;; Set no flag (i32.const 16) ;; Pointer to "callee" address. @@ -232,23 +232,23 @@ ;; Check for special trap exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped + (i32.eq (local.get $exit_code) (i32.const 1)) ;; ReturnCode::CalleeTrapped ) ;; Zero out destination buffer of output (i32.store - (i32.sub (get_local $sp) (i32.const 4)) + (i32.sub (local.get $sp) (i32.const 4)) (i32.const 0) ) ;; Length of the output buffer (i32.store - (i32.sub (get_local $sp) (i32.const 8)) + (i32.sub (local.get $sp) (i32.const 8)) (i32.const 4) ) ;; Call the contract successfully. - (set_local $exit_code + (local.set $exit_code (call $seal_call (i32.const 0) ;; Set no flag (i32.const 16) ;; Pointer to "callee" address. @@ -258,23 +258,23 @@ (i32.const 0) ;; Pointer to the buffer with value to transfer (i32.const 8) ;; Pointer to input data buffer address (i32.const 8) ;; Length of input data buffer - (i32.sub (get_local $sp) (i32.const 4)) ;; Ptr to output buffer - (i32.sub (get_local $sp) (i32.const 8)) ;; Ptr to output buffer len + (i32.sub (local.get $sp) (i32.const 4)) ;; Ptr to output buffer + (i32.sub (local.get $sp) (i32.const 8)) ;; Ptr to output buffer len ) ) ;; Check for success exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + (i32.eq (local.get $exit_code) (i32.const 0)) ;; ReturnCode::Success ) ;; Check that the output buffer contains the expected return data. (call $assert - (i32.eq (i32.load (i32.sub (get_local $sp) (i32.const 8))) (i32.const 4)) + (i32.eq (i32.load (i32.sub (local.get $sp) (i32.const 8))) (i32.const 4)) ) (call $assert (i32.eq - (i32.load (i32.sub (get_local $sp) (i32.const 4))) + (i32.load (i32.sub (local.get $sp) (i32.const 4))) (i32.const 0x77665544) ) ) diff --git a/substrate/frame/contracts/fixtures/chain_extension.wat b/substrate/frame/contracts/fixtures/chain_extension.wat index 670f8e70172e..c24ca286ff8c 100644 --- a/substrate/frame/contracts/fixtures/chain_extension.wat +++ b/substrate/frame/contracts/fixtures/chain_extension.wat @@ -9,7 +9,7 @@ (func $assert (param i32) (block $ok - (br_if $ok (get_local 0)) + (br_if $ok (local.get 0)) (unreachable) ) ) diff --git a/substrate/frame/contracts/fixtures/chain_extension_temp_storage.wat b/substrate/frame/contracts/fixtures/chain_extension_temp_storage.wat index b481abb5bc7c..504646df1b0e 100644 --- a/substrate/frame/contracts/fixtures/chain_extension_temp_storage.wat +++ b/substrate/frame/contracts/fixtures/chain_extension_temp_storage.wat @@ -11,7 +11,7 @@ (func $assert (param i32) (block $ok - (br_if $ok (get_local 0)) + (br_if $ok (local.get 0)) (unreachable) ) ) diff --git a/substrate/frame/contracts/fixtures/create_storage_and_call.wat b/substrate/frame/contracts/fixtures/create_storage_and_call.wat index 5592e7e96a98..2bff53b638fd 100644 --- a/substrate/frame/contracts/fixtures/create_storage_and_call.wat +++ b/substrate/frame/contracts/fixtures/create_storage_and_call.wat @@ -8,7 +8,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/create_storage_and_instantiate.wat b/substrate/frame/contracts/fixtures/create_storage_and_instantiate.wat index cd7202478437..00c9a657f39f 100644 --- a/substrate/frame/contracts/fixtures/create_storage_and_instantiate.wat +++ b/substrate/frame/contracts/fixtures/create_storage_and_instantiate.wat @@ -14,7 +14,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/crypto_hashes.wat b/substrate/frame/contracts/fixtures/crypto_hashes.wat index c2b4d6b81edb..9d86b02f4192 100644 --- a/substrate/frame/contracts/fixtures/crypto_hashes.wat +++ b/substrate/frame/contracts/fixtures/crypto_hashes.wat @@ -59,8 +59,10 @@ (call $seal_input (local.get $input_ptr) (local.get $input_len_ptr)) (local.set $chosen_hash_fn (i32.load8_u (local.get $input_ptr))) (if (i32.gt_u (local.get $chosen_hash_fn) (i32.const 7)) - ;; We check that the chosen hash fn identifier is within bounds: [0,7] - (unreachable) + (then + ;; We check that the chosen hash fn identifier is within bounds: [0,7] + (unreachable) + ) ) (local.set $input_ptr (i32.add (local.get $input_ptr) (i32.const 1))) (local.set $input_len (i32.sub (i32.load (local.get $input_len_ptr)) (i32.const 1))) diff --git a/substrate/frame/contracts/fixtures/debug_message_invalid_utf8.wat b/substrate/frame/contracts/fixtures/debug_message_invalid_utf8.wat index e8c447b42fca..dae0de884189 100644 --- a/substrate/frame/contracts/fixtures/debug_message_invalid_utf8.wat +++ b/substrate/frame/contracts/fixtures/debug_message_invalid_utf8.wat @@ -8,7 +8,7 @@ (func $assert_eq (param i32 i32) (block $ok (br_if $ok - (i32.eq (get_local 0) (get_local 1)) + (i32.eq (local.get 0) (local.get 1)) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/debug_message_logging_disabled.wat b/substrate/frame/contracts/fixtures/debug_message_logging_disabled.wat index fc6ee72df8b0..e9ce20ba42b2 100644 --- a/substrate/frame/contracts/fixtures/debug_message_logging_disabled.wat +++ b/substrate/frame/contracts/fixtures/debug_message_logging_disabled.wat @@ -8,7 +8,7 @@ (func $assert_eq (param i32 i32) (block $ok (br_if $ok - (i32.eq (get_local 0) (get_local 1)) + (i32.eq (local.get 0) (local.get 1)) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/debug_message_works.wat b/substrate/frame/contracts/fixtures/debug_message_works.wat index 61933c232961..44a7b6db1bef 100644 --- a/substrate/frame/contracts/fixtures/debug_message_works.wat +++ b/substrate/frame/contracts/fixtures/debug_message_works.wat @@ -8,7 +8,7 @@ (func $assert_eq (param i32 i32) (block $ok (br_if $ok - (i32.eq (get_local 0) (get_local 1)) + (i32.eq (local.get 0) (local.get 1)) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/delegate_call.wat b/substrate/frame/contracts/fixtures/delegate_call.wat index 7fe422af4551..b8d4f0d47f0f 100644 --- a/substrate/frame/contracts/fixtures/delegate_call.wat +++ b/substrate/frame/contracts/fixtures/delegate_call.wat @@ -24,7 +24,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -70,7 +70,7 @@ ) ;; Call deployed library contract code. - (set_local $exit_code + (local.set $exit_code (call $seal_delegate_call (i32.const 0) ;; Set no call flags (i32.const 64) ;; Pointer to "callee" code_hash. @@ -83,7 +83,7 @@ ;; Check for success exit status. (call $assert - (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + (i32.eq (local.get $exit_code) (i32.const 0)) ;; ReturnCode::Success ) (call $assert diff --git a/substrate/frame/contracts/fixtures/delegate_call_lib.wat b/substrate/frame/contracts/fixtures/delegate_call_lib.wat index 340b9699f875..62eea32800a4 100644 --- a/substrate/frame/contracts/fixtures/delegate_call_lib.wat +++ b/substrate/frame/contracts/fixtures/delegate_call_lib.wat @@ -20,7 +20,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/delegate_call_simple.wat b/substrate/frame/contracts/fixtures/delegate_call_simple.wat index 24ae5a13e33e..ba0a8fcc8ae3 100644 --- a/substrate/frame/contracts/fixtures/delegate_call_simple.wat +++ b/substrate/frame/contracts/fixtures/delegate_call_simple.wat @@ -12,7 +12,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/destroy_and_transfer.wat b/substrate/frame/contracts/fixtures/destroy_and_transfer.wat index 255547955527..2afd3b2fbacf 100644 --- a/substrate/frame/contracts/fixtures/destroy_and_transfer.wat +++ b/substrate/frame/contracts/fixtures/destroy_and_transfer.wat @@ -33,7 +33,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/drain.wat b/substrate/frame/contracts/fixtures/drain.wat index cb8ff0aed61f..18a21cca803d 100644 --- a/substrate/frame/contracts/fixtures/drain.wat +++ b/substrate/frame/contracts/fixtures/drain.wat @@ -19,7 +19,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/ecdsa_recover.wat b/substrate/frame/contracts/fixtures/ecdsa_recover.wat index d694b3215e86..4910e706069e 100644 --- a/substrate/frame/contracts/fixtures/ecdsa_recover.wat +++ b/substrate/frame/contracts/fixtures/ecdsa_recover.wat @@ -12,7 +12,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/event_size.wat b/substrate/frame/contracts/fixtures/event_size.wat index 4bd6158d72fb..1c1f34b24d72 100644 --- a/substrate/frame/contracts/fixtures/event_size.wat +++ b/substrate/frame/contracts/fixtures/event_size.wat @@ -9,7 +9,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/multi_store.wat b/substrate/frame/contracts/fixtures/multi_store.wat index 2592baf61835..c334ed54c4eb 100644 --- a/substrate/frame/contracts/fixtures/multi_store.wat +++ b/substrate/frame/contracts/fixtures/multi_store.wat @@ -19,7 +19,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/reentrance_count_call.wat b/substrate/frame/contracts/fixtures/reentrance_count_call.wat index c6b529e2aff8..44db8d041b1d 100644 --- a/substrate/frame/contracts/fixtures/reentrance_count_call.wat +++ b/substrate/frame/contracts/fixtures/reentrance_count_call.wat @@ -20,7 +20,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -36,11 +36,11 @@ (call $seal_input (i32.const 32) (i32.const 36)) ;; reading manually passed reentrant count - (set_local $expected_reentrance_count (i32.load (i32.const 32))) + (local.set $expected_reentrance_count (i32.load (i32.const 32))) ;; reentrance count is calculated correctly (call $assert - (i32.eq (call $reentrance_count) (get_local $expected_reentrance_count)) + (i32.eq (call $reentrance_count) (local.get $expected_reentrance_count)) ) ;; re-enter 5 times in a row and assert that the reentrant counter works as expected @@ -52,7 +52,7 @@ (i32.store (i32.const 32) (i32.add (i32.load (i32.const 32)) (i32.const 1))) ;; Call to itself - (set_local $seal_call_exit_code + (local.set $seal_call_exit_code (call $seal_call (i32.const 8) ;; Allow reentrancy flag set (i32.const 0) ;; Pointer to "callee" address @@ -66,7 +66,7 @@ ) (call $assert - (i32.eq (get_local $seal_call_exit_code) (i32.const 0)) + (i32.eq (local.get $seal_call_exit_code) (i32.const 0)) ) ) ) diff --git a/substrate/frame/contracts/fixtures/reentrance_count_delegated_call.wat b/substrate/frame/contracts/fixtures/reentrance_count_delegated_call.wat index b8219a8462ee..49e0193bcdb1 100644 --- a/substrate/frame/contracts/fixtures/reentrance_count_delegated_call.wat +++ b/substrate/frame/contracts/fixtures/reentrance_count_delegated_call.wat @@ -17,7 +17,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -30,7 +30,7 @@ (call $seal_input (i32.const 0) (i32.const 36)) ;; reading passed callstack height - (set_local $callstack_height (i32.load (i32.const 32))) + (local.set $callstack_height (i32.load (i32.const 32))) ;; incrementing callstack height (i32.store (i32.const 32) (i32.add (i32.load (i32.const 32)) (i32.const 1))) @@ -40,12 +40,12 @@ (i32.eq (call $reentrance_count) (i32.const 0)) ) - (i32.eq (get_local $callstack_height) (i32.const 5)) + (i32.eq (local.get $callstack_height) (i32.const 5)) (if (then) ;; exit recursion case (else ;; Call to itself - (set_local $delegate_call_exit_code + (local.set $delegate_call_exit_code (call $seal_delegate_call (i32.const 0) ;; Set no call flags (i32.const 0) ;; Pointer to "callee" code_hash. @@ -57,13 +57,13 @@ ) (call $assert - (i32.eq (get_local $delegate_call_exit_code) (i32.const 0)) + (i32.eq (local.get $delegate_call_exit_code) (i32.const 0)) ) ) ) (call $assert - (i32.le_s (get_local $callstack_height) (i32.const 5)) + (i32.le_s (local.get $callstack_height) (i32.const 5)) ) ) diff --git a/substrate/frame/contracts/fixtures/self_destruct.wat b/substrate/frame/contracts/fixtures/self_destruct.wat index b8a37306e201..00c3895fdded 100644 --- a/substrate/frame/contracts/fixtures/self_destruct.wat +++ b/substrate/frame/contracts/fixtures/self_destruct.wat @@ -26,7 +26,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/self_destructing_constructor.wat b/substrate/frame/contracts/fixtures/self_destructing_constructor.wat index 85fce511e21b..628f283a19fd 100644 --- a/substrate/frame/contracts/fixtures/self_destructing_constructor.wat +++ b/substrate/frame/contracts/fixtures/self_destructing_constructor.wat @@ -5,7 +5,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/set_code_hash.wat b/substrate/frame/contracts/fixtures/set_code_hash.wat index b4df1b133186..c0a9557b4d00 100644 --- a/substrate/frame/contracts/fixtures/set_code_hash.wat +++ b/substrate/frame/contracts/fixtures/set_code_hash.wat @@ -16,7 +16,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -27,11 +27,11 @@ (call $seal_input (i32.const 0) (i32.const 32)) - (set_local $exit_code + (local.set $exit_code (call $seal_set_code_hash (i32.const 0)) ;; Pointer to the input data. ) (call $assert - (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + (i32.eq (local.get $exit_code) (i32.const 0)) ;; ReturnCode::Success ) ;; we return 1 after setting new code_hash diff --git a/substrate/frame/contracts/fixtures/storage_size.wat b/substrate/frame/contracts/fixtures/storage_size.wat index 293a656d4f6e..728bb4fcf3c0 100644 --- a/substrate/frame/contracts/fixtures/storage_size.wat +++ b/substrate/frame/contracts/fixtures/storage_size.wat @@ -20,7 +20,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/store_call.wat b/substrate/frame/contracts/fixtures/store_call.wat index 9e090d31801f..746b7a48b551 100644 --- a/substrate/frame/contracts/fixtures/store_call.wat +++ b/substrate/frame/contracts/fixtures/store_call.wat @@ -15,7 +15,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/store_deploy.wat b/substrate/frame/contracts/fixtures/store_deploy.wat index cc428e9623bf..7f115cba977c 100644 --- a/substrate/frame/contracts/fixtures/store_deploy.wat +++ b/substrate/frame/contracts/fixtures/store_deploy.wat @@ -15,7 +15,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/src/wasm/mod.rs b/substrate/frame/contracts/src/wasm/mod.rs index 77e94b16777b..f73655e99203 100644 --- a/substrate/frame/contracts/src/wasm/mod.rs +++ b/substrate/frame/contracts/src/wasm/mod.rs @@ -1506,7 +1506,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1531,7 +1531,7 @@ mod tests { ) ;; Find out the size of the buffer - (set_local $buf_size + (local.set $buf_size (i32.load (i32.const 32)) ) @@ -1539,7 +1539,7 @@ mod tests { (call $seal_return (i32.const 0) (i32.const 36) - (get_local $buf_size) + (local.get $buf_size) ) ;; env:seal_return doesn't return, so this is effectively unreachable. @@ -1575,7 +1575,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1633,7 +1633,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1680,7 +1680,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1726,7 +1726,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1773,7 +1773,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1836,7 +1836,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1925,7 +1925,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -1966,7 +1966,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -2013,7 +2013,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -2067,7 +2067,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -2137,7 +2137,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -2327,7 +2327,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -2995,7 +2995,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -3047,7 +3047,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) @@ -3162,18 +3162,18 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) ) (func (export "call") (local $exit_code i32) - (set_local $exit_code + (local.set $exit_code (call $seal_set_code_hash (i32.const 0)) ) (call $assert - (i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success + (i32.eq (local.get $exit_code) (i32.const 0)) ;; ReturnCode::Success ) ) @@ -3202,18 +3202,18 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) ) (func (export "call") (local $return_val i32) - (set_local $return_val + (local.set $return_val (call $reentrance_count) ) (call $assert - (i32.eq (get_local $return_val) (i32.const 12)) + (i32.eq (local.get $return_val) (i32.const 12)) ) ) @@ -3234,18 +3234,18 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) ) (func (export "call") (local $return_val i32) - (set_local $return_val + (local.set $return_val (call $account_reentrance_count (i32.const 0)) ) (call $assert - (i32.eq (get_local $return_val) (i32.const 12)) + (i32.eq (local.get $return_val) (i32.const 12)) ) ) @@ -3267,7 +3267,7 @@ mod tests { (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) From bc9d6cfb1e098bd53bfcae70eb6f413451d1e0ed Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Sat, 4 Nov 2023 20:22:17 +0200 Subject: [PATCH 14/32] Fix tests --- polkadot/node/network/bridge/src/rx/tests.rs | 41 ++++++++----------- .../grandpa/src/communication/tests.rs | 7 ++-- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 1a8008fea092..5e31078919bb 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -198,28 +198,10 @@ impl TestNetworkHandle { v } - // async fn connect_peer( - // &mut self, - // peer: PeerId, - // protocol_version: ValidationVersion, - // peer_set: PeerSet, - // role: ObservedRole, - // ) { - // // let protocol_version = ProtocolVersion::from(protocol_version); - // // self.send_network_event(NetworkEvent::NotificationStreamOpened { - // // remote: peer, - // // protocol: self.protocol_names.get_name(peer_set, protocol_version), - // // negotiated_fallback: None, - // // role: role.into(), - // // received_handshake: vec![], - // // }) - // // .await; - // } - async fn connect_peer( &mut self, peer: PeerId, - _protocol_version: ValidationVersion, + protocol_version: ValidationVersion, peer_set: PeerSet, role: ObservedRole, ) { @@ -231,6 +213,19 @@ impl TestNetworkHandle { } } + // because of how protocol negotiation works, if two peers support at least one common + // protocol, the protocol is negotiated over the main protocol (`ValidationVersion::V2`) but + // if either one of the peers used a fallback protocol for the negotiation (meaning they + // don't support the main protocol but some older version of it ), `negotiated_fallback` is + // set to that protocol. + let negotiated_fallback = match protocol_version { + ValidationVersion::V2 => None, + ValidationVersion::V1 => match peer_set { + PeerSet::Validation => Some(ProtocolName::from("/polkadot/validation/1")), + PeerSet::Collation => Some(ProtocolName::from("/polkadot/collation/1")), + }, + }; + match peer_set { PeerSet::Validation => { self.validation_tx @@ -238,7 +233,7 @@ impl TestNetworkHandle { peer, direction: Direction::Inbound, handshake: observed_role_to_handshake(&role), - negotiated_fallback: None, + negotiated_fallback, }) .await .expect("subsystem concluded early"); @@ -249,7 +244,7 @@ impl TestNetworkHandle { peer, direction: Direction::Inbound, handshake: observed_role_to_handshake(&role), - negotiated_fallback: None, + negotiated_fallback, }) .await .expect("subsystem concluded early"); @@ -506,8 +501,6 @@ fn test_harness>( let fork_id = None; let peerset_protocol_names = PeerSetProtocolNames::new(genesis_hash, fork_id); - println!("protocol names: {peerset_protocol_names:#?}"); - let pool = sp_core::testing::TaskExecutor::new(); let (network, network_handle, discovery, validation_service, collation_service) = new_test_network(peerset_protocol_names.clone()); @@ -1449,9 +1442,7 @@ fn network_protocol_versioning_view_update() { }); } -// TODO: discuss with parachains engineering #[test] -#[cfg(feature = "network-protocol-staging")] fn network_protocol_versioning_subsystem_msg() { use polkadot_primitives::CandidateHash; use std::task::Poll; diff --git a/substrate/client/consensus/grandpa/src/communication/tests.rs b/substrate/client/consensus/grandpa/src/communication/tests.rs index 6c3eb6bcaf5e..b76b1af93dac 100644 --- a/substrate/client/consensus/grandpa/src/communication/tests.rs +++ b/substrate/client/consensus/grandpa/src/communication/tests.rs @@ -220,6 +220,7 @@ impl NetworkSyncForkRequest> for TestSync { #[derive(Debug)] pub(crate) struct TestNotificationService { + sender: TracingUnboundedSender, rx: TracingUnboundedReceiver, } @@ -236,8 +237,8 @@ impl NotificationService for TestNotificationService { } /// Send synchronous `notification` to `peer`. - fn send_sync_notification(&self, _peer: &PeerId, _notification: Vec) { - unimplemented!(); + fn send_sync_notification(&self, peer: &PeerId, notification: Vec) { + let _ = self.sender.unbounded_send(Event::WriteNotification(*peer, notification)); } /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure. @@ -347,7 +348,7 @@ pub(crate) fn make_test_network() -> (impl Future, TestNetwork) let (tx, rx) = tracing_unbounded("test", 100_000); let (notification_tx, notification_rx) = tracing_unbounded("test-notification", 100_000); - let notification_service = TestNotificationService { rx: notification_rx }; + let notification_service = TestNotificationService { rx: notification_rx, sender: tx.clone() }; let net = TestNetwork { sender: tx }; let sync = TestSync {}; From aa78cf6d8d719f9a4b03bb99ac28366c6f664e41 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 6 Nov 2023 10:22:21 +0200 Subject: [PATCH 15/32] Fix UI test --- .../construct_runtime_ui/deprecated_where_block.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr index 08954bb6ab5c..a791c313b4a8 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr @@ -97,7 +97,7 @@ note: required because it appears within the type `RuntimeEvent` | ||_- in this macro invocation ... | note: required by a bound in `EncodeLike` - --> $CARGO/parity-scale-codec-3.6.4/src/encode_like.rs + --> $CARGO/parity-scale-codec-3.6.5/src/encode_like.rs | | pub trait EncodeLike: Sized + Encode {} | ^^^^^ required by this bound in `EncodeLike` @@ -129,7 +129,7 @@ note: required because it appears within the type `RuntimeEvent` | ||_- in this macro invocation ... | note: required by a bound in `Decode` - --> $CARGO/parity-scale-codec-3.6.4/src/codec.rs + --> $CARGO/parity-scale-codec-3.6.5/src/codec.rs | | pub trait Decode: Sized { | ^^^^^ required by this bound in `Decode` @@ -301,7 +301,7 @@ note: required because it appears within the type `RuntimeCall` | ||_- in this macro invocation ... | note: required by a bound in `EncodeLike` - --> $CARGO/parity-scale-codec-3.6.4/src/encode_like.rs + --> $CARGO/parity-scale-codec-3.6.5/src/encode_like.rs | | pub trait EncodeLike: Sized + Encode {} | ^^^^^ required by this bound in `EncodeLike` @@ -334,7 +334,7 @@ note: required because it appears within the type `RuntimeCall` | ||_- in this macro invocation ... | note: required by a bound in `Decode` - --> $CARGO/parity-scale-codec-3.6.4/src/codec.rs + --> $CARGO/parity-scale-codec-3.6.5/src/codec.rs | | pub trait Decode: Sized { | ^^^^^ required by this bound in `Decode` From 81b5997ac55356636b9b89a01b4f17a488b42d34 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Tue, 7 Nov 2023 11:49:33 +0200 Subject: [PATCH 16/32] Ignore missing `NotificationService` --- substrate/client/network/src/protocol.rs | 5 +---- .../network/src/protocol/notifications/behaviour.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index 5588cebcbd89..2ef334a0e40e 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -364,10 +364,7 @@ impl NetworkBehaviour for Protocol { } }, (Err(err), _) => { - debug!(target: "sync", "Failed to parse remote handshake: {}", err); - self.bad_handshake_substreams.insert((peer_id, set_id)); - self.behaviour.disconnect_peer(&peer_id, set_id); - self.peer_store_handle.report_peer(peer_id, rep::BAD_MESSAGE); + debug!(target: "sync", "Failed to parse remote handshake: {} {set_id:?}", err); CustomMessageOutcome::None }, } diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index b39c5771dd48..971d68c3716b 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -908,8 +908,14 @@ impl Notifications { .pending_inbound_validations .push(Box::pin(async move { (rx.await, index) })), Err(err) => { - error!(target: LOG_TARGET, "protocol has exited: {err:?}"); - debug_assert!(false); + // parachain collators enable the syncing protocol but `NotificationService` for + // `SyncingEngine` is not created which causes `report_incoming_substream()` to + // fail. This is not a fatal error and should be ignored even though in typical + // cases the `NotificationService` not existing is a fatal error and indicates that + // the protocol has exited. Until the parachain collator issue is fixed, just report + // and error and reject the peer. + debug!(target: LOG_TARGET, "protocol has exited: {err:?} {:?}", incoming.set_id); + self.protocol_report_reject(index); }, } } From 11b0dac94080601763c9209413dbc0d974225811 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Thu, 9 Nov 2023 10:02:55 +0200 Subject: [PATCH 17/32] Fix stuff --- polkadot/node/network/bridge/src/network.rs | 16 ++-------------- polkadot/node/network/bridge/src/rx/mod.rs | 12 ++++++------ polkadot/node/network/bridge/src/rx/tests.rs | 4 ++++ polkadot/node/network/bridge/src/tx/mod.rs | 4 ++-- polkadot/node/network/bridge/src/tx/tests.rs | 2 +- substrate/client/network/src/protocol.rs | 20 ++++++++++---------- substrate/client/network/sync/src/engine.rs | 1 - 7 files changed, 25 insertions(+), 34 deletions(-) diff --git a/polkadot/node/network/bridge/src/network.rs b/polkadot/node/network/bridge/src/network.rs index a5be3e71af75..a9339a5c443c 100644 --- a/polkadot/node/network/bridge/src/network.rs +++ b/polkadot/node/network/bridge/src/network.rs @@ -31,9 +31,7 @@ use sc_network::{ }; use polkadot_node_network_protocol::{ - peer_set::{ - CollationVersion, PeerSet, PeerSetProtocolNames, ProtocolVersion, ValidationVersion, - }, + peer_set::{CollationVersion, PeerSet, ProtocolVersion, ValidationVersion}, request_response::{OutgoingRequest, Recipient, ReqProtocolNames, Requests}, v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, PeerId, }; @@ -47,7 +45,6 @@ const LOG_TARGET: &'static str = "parachain::network-bridge-net"; // Helper function to send a validation v1 message to a list of peers. // Messages are always sent via the main protocol, even legacy protocol messages. pub(crate) fn send_validation_message_v1( - net: &mut impl Network, peers: Vec, message: WireMessage, metrics: &Metrics, @@ -56,7 +53,6 @@ pub(crate) fn send_validation_message_v1( gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation v1 message to peers",); send_message( - net, peers, PeerSet::Validation, ValidationVersion::V1.into(), @@ -69,7 +65,6 @@ pub(crate) fn send_validation_message_v1( // Helper function to send a validation vstaging message to a list of peers. // Messages are always sent via the main protocol, even legacy protocol messages. pub(crate) fn send_validation_message_vstaging( - net: &mut impl Network, peers: Vec, message: WireMessage, metrics: &Metrics, @@ -78,7 +73,6 @@ pub(crate) fn send_validation_message_vstaging( gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation vstaging message to peers",); send_message( - net, peers, PeerSet::Validation, ValidationVersion::VStaging.into(), @@ -91,14 +85,12 @@ pub(crate) fn send_validation_message_vstaging( // Helper function to send a validation v2 message to a list of peers. // Messages are always sent via the main protocol, even legacy protocol messages. pub(crate) fn send_validation_message_v2( - net: &mut impl Network, peers: Vec, message: WireMessage, metrics: &Metrics, notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Validation, ValidationVersion::V2.into(), @@ -111,14 +103,12 @@ pub(crate) fn send_validation_message_v2( // Helper function to send a collation v1 message to a list of peers. // Messages are always sent via the main protocol, even legacy protocol messages. pub(crate) fn send_collation_message_v1( - net: &mut impl Network, peers: Vec, message: WireMessage, metrics: &Metrics, notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Collation, CollationVersion::V1.into(), @@ -131,14 +121,12 @@ pub(crate) fn send_collation_message_v1( // Helper function to send a collation v2 message to a list of peers. // Messages are always sent via the main protocol, even legacy protocol messages. pub(crate) fn send_collation_message_v2( - net: &mut impl Network, peers: Vec, message: WireMessage, metrics: &Metrics, notification_sinks: &Arc>>>, ) { send_message( - net, peers, PeerSet::Collation, CollationVersion::V2.into(), @@ -179,7 +167,7 @@ fn send_message( gum::trace!( target: LOG_TARGET, ?peers, - ?peerset, + ?peer_set, ?version, ?message, "Sending message to peers", diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 8d89136923c9..f9338eee81e0 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -276,7 +276,7 @@ async fn handle_validation_message( NetworkBridgeEvent::PeerConnected(peer, role, version, maybe_authority), NetworkBridgeEvent::PeerViewChange(peer, View::default()), ], - &mut sender, + sender, &metrics, ) .await; @@ -331,7 +331,7 @@ async fn handle_validation_message( if was_connected && version == peer_set.get_main_version() { dispatch_validation_event_to_all( NetworkBridgeEvent::PeerDisconnected(peer), - &mut sender, + sender, &metrics, ) .await; @@ -375,8 +375,8 @@ async fn handle_validation_message( vec![notification.into()], metrics, ) - } else if expected_version[PeerSet::Validation] == - Some(ValidationVersion::VStaging::into()) + } else if expected_versions[PeerSet::Validation] == + Some(ValidationVersion::VStaging.into()) { handle_peer_messages::( peer, @@ -403,7 +403,7 @@ async fn handle_validation_message( network_service.report_peer(peer, report.into()); } - dispatch_validation_events_to_all(events, &mut sender, &metrics).await; + dispatch_validation_events_to_all(events, sender, &metrics).await; }, } } @@ -535,7 +535,7 @@ async fn handle_collation_message( NetworkBridgeEvent::PeerConnected(peer, role, version, maybe_authority), NetworkBridgeEvent::PeerViewChange(peer, View::default()), ], - &mut sender, + sender, ) .await; diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 810bf1bc32a1..2f5cbb1a67ee 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -224,6 +224,10 @@ impl TestNetworkHandle { PeerSet::Validation => Some(ProtocolName::from("/polkadot/validation/1")), PeerSet::Collation => Some(ProtocolName::from("/polkadot/collation/1")), }, + ValidationVersion::VStaging => match peer_set { + PeerSet::Validation => Some(ProtocolName::from("/polkadot/validation/3")), + PeerSet::Collation => unreachable!(), + }, }; match peer_set { diff --git a/polkadot/node/network/bridge/src/tx/mod.rs b/polkadot/node/network/bridge/src/tx/mod.rs index 582842296219..bdcd1574e335 100644 --- a/polkadot/node/network/bridge/src/tx/mod.rs +++ b/polkadot/node/network/bridge/src/tx/mod.rs @@ -207,9 +207,9 @@ where ), Versioned::VStaging(msg) => send_validation_message_vstaging( peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::V2(msg) => send_validation_message_v2( peers, @@ -237,9 +237,9 @@ where ), Versioned::VStaging(msg) => send_validation_message_vstaging( peers, - peerset_protocol_names, WireMessage::ProtocolMessage(msg), &metrics, + notification_sinks, ), Versioned::V2(msg) => send_validation_message_v2( peers, diff --git a/polkadot/node/network/bridge/src/tx/tests.rs b/polkadot/node/network/bridge/src/tx/tests.rs index 0bfdc0c370f7..0f730d2efbec 100644 --- a/polkadot/node/network/bridge/src/tx/tests.rs +++ b/polkadot/node/network/bridge/src/tx/tests.rs @@ -30,7 +30,7 @@ use parity_scale_codec::DecodeAll; use polkadot_node_network_protocol::{ peer_set::{PeerSetProtocolNames, ValidationVersion}, request_response::{outgoing::Requests, ReqProtocolNames}, - v1 as protocol_v1, v2 as protocol_v2, ObservedRole, Versioned, + v1 as protocol_v1, ObservedRole, Versioned, }; use polkadot_node_subsystem::{FromOrchestra, OverseerSignal}; use polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle; diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index 2ef334a0e40e..c98eb2c9b9bc 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -18,7 +18,7 @@ use crate::{ config, error, - peer_store::{PeerStoreHandle, PeerStoreProvider}, + peer_store::PeerStoreHandle, protocol_controller::{self, SetId}, types::ProtocolName, }; @@ -66,19 +66,19 @@ pub(crate) const BLOCK_ANNOUNCES_TRANSACTIONS_SUBSTREAM_SIZE: u64 = 16 * 1024 * /// Identifier of the peerset for the block announces protocol. const HARDCODED_PEERSETS_SYNC: SetId = SetId::from(0); -mod rep { - use crate::ReputationChange as Rep; - /// We received a message that failed to decode. - pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); -} +// mod rep { +// use crate::ReputationChange as Rep; +// /// We received a message that failed to decode. +// pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); +// } type PendingSyncSubstreamValidation = Pin> + Send>>; // Lock must always be taken in order declared here. pub struct Protocol { - /// Used to report reputation changes. - peer_store_handle: PeerStoreHandle, + // /// Used to report reputation changes. + // peer_store_handle: PeerStoreHandle, /// Handles opening the unique substream and sending and receiving raw messages. behaviour: Notifications, /// List of notifications protocols that have been registered. @@ -103,7 +103,7 @@ impl Protocol { registry: &Option, notification_protocols: Vec, block_announces_protocol: config::NonDefaultSetConfig, - peer_store_handle: PeerStoreHandle, + _peer_store_handle: PeerStoreHandle, protocol_controller_handles: Vec, from_protocol_controllers: TracingUnboundedReceiver, ) -> error::Result { @@ -156,7 +156,7 @@ impl Protocol { }; let protocol = Self { - peer_store_handle, + // peer_store_handle, behaviour, notification_protocols, bad_handshake_substreams: Default::default(), diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index cdb1ea4cb4eb..a58afb9cc788 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -454,7 +454,6 @@ where .flatten() .expect("Genesis block exists; qed"), ); - let block_announce_protocol_name = block_announce_config.protocol_name().clone(); let chain_sync = ChainSync::new( mode, From 633f4815cfe531cb28e4743efec506176a4cb914 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Thu, 16 Nov 2023 16:24:03 +0200 Subject: [PATCH 18/32] Reject peers with unknown roles --- polkadot/node/network/bridge/src/rx/mod.rs | 16 +++++++++++++--- substrate/client/network-gossip/src/bridge.rs | 7 ++++++- substrate/client/network/transactions/src/lib.rs | 9 +++++++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index f9338eee81e0..3649fc5e945f 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -165,8 +165,13 @@ async fn handle_validation_message( AD: validator_discovery::AuthorityDiscovery + Send, { match event { - NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { - let _ = result_tx.send(ValidationResult::Accept); + NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx, .. } => { + // only accept peers whose role can be determined + let result = self + .network + .peer_role(peer, handshake) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + let _ = result_tx.send(result); }, NotificationEvent::NotificationStreamOpened { peer, @@ -424,7 +429,12 @@ async fn handle_collation_message( { match event { NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { - let _ = result_tx.send(ValidationResult::Accept); + // only accept peers whose role can be determined + let result = self + .network + .peer_role(peer, handshake) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + let _ = result_tx.send(result); }, NotificationEvent::NotificationStreamOpened { peer, diff --git a/substrate/client/network-gossip/src/bridge.rs b/substrate/client/network-gossip/src/bridge.rs index 80fce717070e..e2d1f73da5b7 100644 --- a/substrate/client/network-gossip/src/bridge.rs +++ b/substrate/client/network-gossip/src/bridge.rs @@ -206,7 +206,12 @@ impl Future for GossipEngine { match next_notification_event { Poll::Ready(Some(event)) => match event { NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { - let _ = result_tx.send(ValidationResult::Accept); + // only accept peers whose role can be determined + let result = self + .network + .peer_role(peer, handshake) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + let _ = result_tx.send(result); }, NotificationEvent::NotificationStreamOpened { peer, handshake, .. diff --git a/substrate/client/network/transactions/src/lib.rs b/substrate/client/network/transactions/src/lib.rs index 265d70630e69..9758ea4c4fcb 100644 --- a/substrate/client/network/transactions/src/lib.rs +++ b/substrate/client/network/transactions/src/lib.rs @@ -318,8 +318,13 @@ where fn handle_notification_event(&mut self, event: NotificationEvent) { match event { - NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { - let _ = result_tx.send(ValidationResult::Accept); + NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx, .. } => { + // only accept peers whose role can be determined + let result = self + .network + .peer_role(peer, handshake) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + let _ = result_tx.send(result); }, NotificationEvent::NotificationStreamOpened { peer, handshake, .. } => { let Some(role) = self.network.peer_role(peer, handshake) else { From 8dec27665360c5789fe32d5af85ed6475222c6c4 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Thu, 16 Nov 2023 17:16:58 +0200 Subject: [PATCH 19/32] Update Cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 57319b14282c..60b086cab52d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8772,7 +8772,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "libc", ] From 6dfef05ba6f779b73492fd7c2d3f9b10194738a8 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Fri, 17 Nov 2023 16:13:26 +0200 Subject: [PATCH 20/32] Fix more stuff --- polkadot/node/network/bridge/src/rx/mod.rs | 8 +++----- substrate/client/network-gossip/src/bridge.rs | 9 +++++++-- substrate/frame/contracts/fixtures/data/xcm_execute.wat | 2 +- substrate/frame/contracts/fixtures/data/xcm_send.wat | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 3649fc5e945f..40cd167a968b 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -167,8 +167,7 @@ async fn handle_validation_message( match event { NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx, .. } => { // only accept peers whose role can be determined - let result = self - .network + let result = network_service .peer_role(peer, handshake) .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); let _ = result_tx.send(result); @@ -428,10 +427,9 @@ async fn handle_collation_message( AD: validator_discovery::AuthorityDiscovery + Send, { match event { - NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx, .. } => { // only accept peers whose role can be determined - let result = self - .network + let result = network_service .peer_role(peer, handshake) .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); let _ = result_tx.send(result); diff --git a/substrate/client/network-gossip/src/bridge.rs b/substrate/client/network-gossip/src/bridge.rs index e2d1f73da5b7..c1bc414c3a34 100644 --- a/substrate/client/network-gossip/src/bridge.rs +++ b/substrate/client/network-gossip/src/bridge.rs @@ -205,9 +205,14 @@ impl Future for GossipEngine { match next_notification_event { Poll::Ready(Some(event)) => match event { - NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { + NotificationEvent::ValidateInboundSubstream { + peer, + handshake, + result_tx, + .. + } => { // only accept peers whose role can be determined - let result = self + let result = this .network .peer_role(peer, handshake) .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); diff --git a/substrate/frame/contracts/fixtures/data/xcm_execute.wat b/substrate/frame/contracts/fixtures/data/xcm_execute.wat index b3459996a2e8..72ef14ed82c7 100644 --- a/substrate/frame/contracts/fixtures/data/xcm_execute.wat +++ b/substrate/frame/contracts/fixtures/data/xcm_execute.wat @@ -12,7 +12,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) diff --git a/substrate/frame/contracts/fixtures/data/xcm_send.wat b/substrate/frame/contracts/fixtures/data/xcm_send.wat index 9eec6388de9b..fe29ddf0f141 100644 --- a/substrate/frame/contracts/fixtures/data/xcm_send.wat +++ b/substrate/frame/contracts/fixtures/data/xcm_send.wat @@ -12,7 +12,7 @@ (func $assert (param i32) (block $ok (br_if $ok - (get_local 0) + (local.get 0) ) (unreachable) ) From 65ece1632168e1b41dbae01edc53aa0716552b5e Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 20 Nov 2023 18:30:15 +0200 Subject: [PATCH 21/32] Fix stuff more --- substrate/client/network/src/behaviour.rs | 54 ++--- substrate/client/network/src/protocol.rs | 225 +++++++----------- .../network/src/protocol/notifications.rs | 2 + .../src/protocol/notifications/behaviour.rs | 88 ++++--- .../src/protocol/notifications/service/mod.rs | 2 +- .../src/protocol/notifications/tests.rs | 5 +- substrate/client/network/src/service.rs | 79 ++---- 7 files changed, 185 insertions(+), 270 deletions(-) diff --git a/substrate/client/network/src/behaviour.rs b/substrate/client/network/src/behaviour.rs index 0aa724818e02..b5df93a31741 100644 --- a/substrate/client/network/src/behaviour.rs +++ b/substrate/client/network/src/behaviour.rs @@ -22,12 +22,13 @@ use crate::{ peer_info, peer_store::PeerStoreHandle, protocol::{CustomMessageOutcome, NotificationsSink, Protocol}, + protocol_controller::SetId, request_responses::{self, IfDisconnected, ProtocolConfig, RequestFailure}, + service::traits::Direction, types::ProtocolName, ReputationChange, }; -use bytes::Bytes; use futures::channel::oneshot; use libp2p::{ core::Multiaddr, identify::Info as IdentifyInfo, identity::PublicKey, kad::RecordKey, @@ -97,8 +98,10 @@ pub enum BehaviourOut { NotificationStreamOpened { /// Node we opened the substream with. remote: PeerId, - /// The concerned protocol. Each protocol uses a different substream. - protocol: ProtocolName, + /// Set ID. + set_id: SetId, + /// Direction of the stream. + direction: Direction, /// If the negotiation didn't use the main name of the protocol (the one in /// `notifications_protocol`), then this field contains which name has actually been /// used. @@ -106,8 +109,6 @@ pub enum BehaviourOut { negotiated_fallback: Option, /// Object that permits sending notifications to the peer. notifications_sink: NotificationsSink, - /// Role of the remote. - role: ObservedRole, /// Received handshake. received_handshake: Vec, }, @@ -120,8 +121,8 @@ pub enum BehaviourOut { NotificationStreamReplaced { /// Id of the peer we are connected to. remote: PeerId, - /// The concerned protocol. Each protocol uses a different substream. - protocol: ProtocolName, + /// Set ID. + set_id: SetId, /// Replacement for the previous [`NotificationsSink`]. notifications_sink: NotificationsSink, }, @@ -131,16 +132,18 @@ pub enum BehaviourOut { NotificationStreamClosed { /// Node we closed the substream with. remote: PeerId, - /// The concerned protocol. Each protocol uses a different substream. - protocol: ProtocolName, + /// Set ID. + set_id: SetId, }, /// Received one or more messages from the given node using the given protocol. NotificationsReceived { /// Node we received the message from. remote: PeerId, + /// Set ID. + set_id: SetId, /// Concerned protocol and associated message. - messages: Vec<(ProtocolName, Bytes)>, + notification: Vec, }, /// We have obtained identity information from a peer, including the addresses it is listening @@ -272,44 +275,33 @@ impl Behaviour { } } -fn reported_roles_to_observed_role(roles: Roles) -> ObservedRole { - if roles.is_authority() { - ObservedRole::Authority - } else if roles.is_full() { - ObservedRole::Full - } else { - ObservedRole::Light - } -} - impl From for BehaviourOut { fn from(event: CustomMessageOutcome) -> Self { match event { CustomMessageOutcome::NotificationStreamOpened { remote, - protocol, + set_id, + direction, negotiated_fallback, - roles, received_handshake, notifications_sink, } => BehaviourOut::NotificationStreamOpened { remote, - protocol, + set_id, + direction, negotiated_fallback, - role: reported_roles_to_observed_role(roles), received_handshake, notifications_sink, }, CustomMessageOutcome::NotificationStreamReplaced { remote, - protocol, + set_id, notifications_sink, - } => BehaviourOut::NotificationStreamReplaced { remote, protocol, notifications_sink }, - CustomMessageOutcome::NotificationStreamClosed { remote, protocol } => - BehaviourOut::NotificationStreamClosed { remote, protocol }, - CustomMessageOutcome::NotificationsReceived { remote, messages } => - BehaviourOut::NotificationsReceived { remote, messages }, - CustomMessageOutcome::None => BehaviourOut::None, + } => BehaviourOut::NotificationStreamReplaced { remote, set_id, notifications_sink }, + CustomMessageOutcome::NotificationStreamClosed { remote, set_id } => + BehaviourOut::NotificationStreamClosed { remote, set_id }, + CustomMessageOutcome::NotificationsReceived { remote, set_id, notification } => + BehaviourOut::NotificationsReceived { remote, set_id, notification }, } } } diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index c98eb2c9b9bc..f7bb9b4bd205 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -20,11 +20,11 @@ use crate::{ config, error, peer_store::PeerStoreHandle, protocol_controller::{self, SetId}, + service::traits::Direction, types::ProtocolName, }; -use bytes::Bytes; -use codec::{DecodeAll, Encode}; +use codec::Encode; use futures::{stream::FuturesUnordered, StreamExt}; use libp2p::{ core::Endpoint, @@ -34,7 +34,7 @@ use libp2p::{ }, Multiaddr, PeerId, }; -use log::{debug, error, warn}; +use log::{error, warn}; use prometheus_endpoint::Registry; use sc_network_common::role::Roles; @@ -51,6 +51,8 @@ use std::{ use notifications::{Notifications, NotificationsOut}; +pub(crate) use notifications::ProtocolHandle; + pub use notifications::{ notification_service, NotificationsSink, NotifsHandlerError, ProtocolHandlePair, Ready, }; @@ -66,12 +68,6 @@ pub(crate) const BLOCK_ANNOUNCES_TRANSACTIONS_SUBSTREAM_SIZE: u64 = 16 * 1024 * /// Identifier of the peerset for the block announces protocol. const HARDCODED_PEERSETS_SYNC: SetId = SetId::from(0); -// mod rep { -// use crate::ReputationChange as Rep; -// /// We received a message that failed to decode. -// pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); -// } - type PendingSyncSubstreamValidation = Pin> + Send>>; @@ -83,13 +79,6 @@ pub struct Protocol { behaviour: Notifications, /// List of notifications protocols that have been registered. notification_protocols: Vec, - /// If we receive a new "substream open" event that contains an invalid handshake, we ask the - /// inner layer to force-close the substream. Force-closing the substream will generate a - /// "substream closed" event. This is a problem: since we can't propagate the "substream open" - /// event to the outer layers, we also shouldn't propagate this "substream closed" event. To - /// solve this, an entry is added to this map whenever an invalid handshake is received. - /// Entries are removed when the corresponding "substream closed" is later received. - bad_handshake_substreams: HashSet<(PeerId, SetId)>, /// Connected peers on sync protocol. peers: HashMap, sync_substream_validations: FuturesUnordered, @@ -98,7 +87,7 @@ pub struct Protocol { impl Protocol { /// Create a new instance. - pub fn new( + pub(crate) fn new( roles: Roles, registry: &Option, notification_protocols: Vec, @@ -106,67 +95,64 @@ impl Protocol { _peer_store_handle: PeerStoreHandle, protocol_controller_handles: Vec, from_protocol_controllers: TracingUnboundedReceiver, - ) -> error::Result { - let (behaviour, notification_protocols) = { + ) -> error::Result<(Self, Vec)> { + let (behaviour, notification_protocols, handles) = { let installed_protocols = iter::once(block_announces_protocol.protocol_name().clone()) .chain(notification_protocols.iter().map(|p| p.protocol_name().clone())) .collect::>(); + // NOTE: Block announcement protocol is still very much hardcoded into + // `Protocol`. This protocol must be the first notification protocol given to + // `Notifications` + let (protocol_configs, handles): (Vec<_>, Vec<_>) = iter::once({ + let config = notifications::ProtocolConfig { + name: block_announces_protocol.protocol_name().clone(), + fallback_names: block_announces_protocol.fallback_names().cloned().collect(), + handshake: block_announces_protocol.handshake().as_ref().unwrap().to_vec(), + max_notification_size: block_announces_protocol.max_notification_size(), + }; + + let (handle, command_stream) = + block_announces_protocol.take_protocol_handle().split(); + + ((config, handle.clone(), command_stream), handle) + }) + .chain(notification_protocols.into_iter().map(|s| { + let config = notifications::ProtocolConfig { + name: s.protocol_name().clone(), + fallback_names: s.fallback_names().cloned().collect(), + handshake: s.handshake().as_ref().map_or(roles.encode(), |h| (*h).to_vec()), + max_notification_size: s.max_notification_size(), + }; + + let (handle, command_stream) = s.take_protocol_handle().split(); + + ((config, handle.clone(), command_stream), handle) + })) + .unzip(); + ( Notifications::new( protocol_controller_handles, from_protocol_controllers, registry, - // NOTE: Block announcement protocol is still very much hardcoded into - // `Protocol`. This protocol must be the first notification protocol given to - // `Notifications` - iter::once(( - notifications::ProtocolConfig { - name: block_announces_protocol.protocol_name().clone(), - fallback_names: block_announces_protocol - .fallback_names() - .cloned() - .collect(), - handshake: block_announces_protocol - .handshake() - .as_ref() - .unwrap() - .to_vec(), - max_notification_size: block_announces_protocol.max_notification_size(), - }, - block_announces_protocol.take_protocol_handle(), - )) - .chain(notification_protocols.into_iter().map(|s| { - ( - notifications::ProtocolConfig { - name: s.protocol_name().clone(), - fallback_names: s.fallback_names().cloned().collect(), - handshake: s - .handshake() - .as_ref() - .map_or(roles.encode(), |h| (*h).to_vec()), - max_notification_size: s.max_notification_size(), - }, - s.take_protocol_handle(), - ) - })), + protocol_configs.into_iter(), ), installed_protocols, + handles, ) }; let protocol = Self { - // peer_store_handle, behaviour, notification_protocols, - bad_handshake_substreams: Default::default(), peers: HashMap::new(), sync_substream_validations: FuturesUnordered::new(), // TODO: remove when `BlockAnnouncesHandshake` is moved away from `Protocol` _marker: Default::default(), }; - Ok(protocol) + Ok((protocol, handles)) } /// Returns the list of all the peers we have an open channel to. @@ -213,25 +199,36 @@ pub enum CustomMessageOutcome { /// Notification protocols have been opened with a remote. NotificationStreamOpened { remote: PeerId, - protocol: ProtocolName, + // protocol: ProtocolName, + set_id: SetId, + /// Direction of the stream. + direction: Direction, /// See [`crate::Event::NotificationStreamOpened::negotiated_fallback`]. negotiated_fallback: Option, - roles: Roles, + // roles: Roles, received_handshake: Vec, notifications_sink: NotificationsSink, }, /// The [`NotificationsSink`] of some notification protocols need an update. NotificationStreamReplaced { remote: PeerId, - protocol: ProtocolName, + set_id: SetId, + // protocol: ProtocolName, notifications_sink: NotificationsSink, }, /// Notification protocols have been closed with a remote. - NotificationStreamClosed { remote: PeerId, protocol: ProtocolName }, + NotificationStreamClosed { + remote: PeerId, + set_id: SetId, + // protocol: ProtocolName, + }, /// Messages have been received on one or more notifications protocols. - NotificationsReceived { remote: PeerId, messages: Vec<(ProtocolName, Bytes)> }, - /// Now connected to a new peer for syncing purposes. - None, + NotificationsReceived { + remote: PeerId, + set_id: SetId, + notification: Vec, + // messages: Vec<(ProtocolName, Bytes)>, + }, } impl NetworkBehaviour for Protocol { @@ -331,97 +328,35 @@ impl NetworkBehaviour for Protocol { NotificationsOut::CustomProtocolOpen { peer_id, set_id, + direction, received_handshake, notifications_sink, negotiated_fallback, .. - } => { - if set_id != HARDCODED_PEERSETS_SYNC { - match ( - Roles::decode_all(&mut &received_handshake[..]), - self.peers.get(&peer_id), - ) { - (Ok(roles), _) => CustomMessageOutcome::NotificationStreamOpened { - remote: peer_id, - protocol: self.notification_protocols[usize::from(set_id)].clone(), - negotiated_fallback, - roles, - received_handshake, - notifications_sink, - }, - (Err(_), Some(roles)) if received_handshake.is_empty() => { - // As a convenience, we allow opening substreams for "external" - // notification protocols with an empty handshake. This fetches the - // roles from the locally-known roles. - // TODO: remove this after https://github.com/paritytech/substrate/issues/5685 - CustomMessageOutcome::NotificationStreamOpened { - remote: peer_id, - protocol: self.notification_protocols[usize::from(set_id)].clone(), - negotiated_fallback, - roles: *roles, - received_handshake, - notifications_sink, - } - }, - (Err(err), _) => { - debug!(target: "sync", "Failed to parse remote handshake: {} {set_id:?}", err); - CustomMessageOutcome::None - }, - } - } else { - CustomMessageOutcome::None - } + } => CustomMessageOutcome::NotificationStreamOpened { + remote: peer_id, + set_id, + direction, + negotiated_fallback, + received_handshake, + notifications_sink, }, NotificationsOut::CustomProtocolReplaced { peer_id, notifications_sink, set_id } => - if self.bad_handshake_substreams.contains(&(peer_id, set_id)) { - CustomMessageOutcome::None - } else if set_id == HARDCODED_PEERSETS_SYNC { - CustomMessageOutcome::None - } else { - CustomMessageOutcome::NotificationStreamReplaced { - remote: peer_id, - protocol: self.notification_protocols[usize::from(set_id)].clone(), - notifications_sink, - } + CustomMessageOutcome::NotificationStreamReplaced { + remote: peer_id, + set_id, + notifications_sink, + }, + NotificationsOut::CustomProtocolClosed { peer_id, set_id } => + CustomMessageOutcome::NotificationStreamClosed { remote: peer_id, set_id }, + NotificationsOut::Notification { peer_id, set_id, message } => + CustomMessageOutcome::NotificationsReceived { + remote: peer_id, + set_id, + notification: message.freeze().into(), }, - NotificationsOut::CustomProtocolClosed { peer_id, set_id } => { - if self.bad_handshake_substreams.remove(&(peer_id, set_id)) { - // The substream that has just been closed had been opened with a bad - // handshake. The outer layers have never received an opening event about this - // substream, and consequently shouldn't receive a closing event either. - CustomMessageOutcome::None - } else if set_id == HARDCODED_PEERSETS_SYNC { - CustomMessageOutcome::None - } else { - CustomMessageOutcome::NotificationStreamClosed { - remote: peer_id, - protocol: self.notification_protocols[usize::from(set_id)].clone(), - } - } - }, - NotificationsOut::Notification { peer_id, set_id, message } => { - if self.bad_handshake_substreams.contains(&(peer_id, set_id)) { - CustomMessageOutcome::None - } else if set_id == HARDCODED_PEERSETS_SYNC { - CustomMessageOutcome::None - } else { - let protocol_name = self.notification_protocols[usize::from(set_id)].clone(); - CustomMessageOutcome::NotificationsReceived { - remote: peer_id, - messages: vec![(protocol_name, message.freeze())], - } - } - }, }; - if !matches!(outcome, CustomMessageOutcome::None) { - return Poll::Ready(ToSwarm::GenerateEvent(outcome)) - } - - // This block can only be reached if an event was pulled from the behaviour and that - // resulted in `CustomMessageOutcome::None`. Since there might be another pending - // message from the behaviour, the task is scheduled again. - cx.waker().wake_by_ref(); - Poll::Pending + return Poll::Ready(ToSwarm::GenerateEvent(outcome)) } } diff --git a/substrate/client/network/src/protocol/notifications.rs b/substrate/client/network/src/protocol/notifications.rs index 1a53df2cdf78..10fa329097d1 100644 --- a/substrate/client/network/src/protocol/notifications.rs +++ b/substrate/client/network/src/protocol/notifications.rs @@ -25,6 +25,8 @@ pub use self::{ service::{notification_service, ProtocolHandlePair}, }; +pub(crate) use self::service::ProtocolHandle; + mod behaviour; mod handler; mod service; diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index 971d68c3716b..f05660354d73 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -19,7 +19,7 @@ use crate::{ protocol::notifications::{ handler::{self, NotificationsSink, NotifsHandler, NotifsHandlerIn, NotifsHandlerOut}, - service::{metrics, NotificationCommand, ProtocolHandle, ProtocolHandlePair}, + service::{metrics, NotificationCommand, ProtocolHandle}, }, protocol_controller::{self, IncomingIndex, Message, SetId}, service::traits::{Direction, ValidationResult}, @@ -347,6 +347,8 @@ pub enum NotificationsOut { peer_id: PeerId, /// Peerset set ID the substream is tied to. set_id: SetId, + /// Direction of the stream. + direction: Direction, /// If `Some`, a fallback protocol name has been used rather the main protocol name. /// Always matches one of the fallback names passed at initialization. negotiated_fallback: Option, @@ -397,14 +399,20 @@ pub enum NotificationsOut { impl Notifications { /// Creates a `CustomProtos`. - pub fn new( + pub(crate) fn new( protocol_controller_handles: Vec, from_protocol_controllers: TracingUnboundedReceiver, registry: &Option, - notif_protocols: impl Iterator, + notif_protocols: impl Iterator< + Item = ( + ProtocolConfig, + ProtocolHandle, + Box + Send + Unpin>, + ), + >, ) -> Self { - let (notif_protocols, protocol_handle_pairs): (Vec<_>, Vec<_>) = notif_protocols - .map(|(cfg, protocol_handle_pair)| { + let (notif_protocols, protocol_handles): (Vec<_>, Vec<_>) = notif_protocols + .map(|(cfg, protocol_handle, command_stream)| { ( handler::ProtocolConfig { name: cfg.name, @@ -412,18 +420,17 @@ impl Notifications { handshake: Arc::new(RwLock::new(cfg.handshake)), max_notification_size: cfg.max_notification_size, }, - protocol_handle_pair, + (protocol_handle, command_stream), ) }) .unzip(); assert!(!notif_protocols.is_empty()); let metrics = registry.as_ref().and_then(|registry| metrics::register(®istry).ok()); - let (protocol_handles, command_streams): (Vec<_>, Vec<_>) = protocol_handle_pairs + let (protocol_handles, command_streams): (Vec<_>, Vec<_>) = protocol_handles .into_iter() .enumerate() - .map(|(set_id, protocol_handle_pair)| { - let (mut protocol_handle, command_stream) = protocol_handle_pair.split(); + .map(|(set_id, (mut protocol_handle, command_stream))| { protocol_handle.set_metrics(metrics.clone()); (protocol_handle, (set_id, command_stream)) @@ -517,8 +524,8 @@ impl Notifications { let event = NotificationsOut::CustomProtocolClosed { peer_id: *peer_id, set_id }; self.events.push_back(ToSwarm::GenerateEvent(event)); - let _ = self.protocol_handles[usize::from(set_id)] - .report_substream_closed(*peer_id); + // let _ = self.protocol_handles[usize::from(set_id)] + // .report_substream_closed(*peer_id); } for (connec_id, connec_state) in @@ -820,8 +827,8 @@ impl Notifications { let event = NotificationsOut::CustomProtocolClosed { peer_id: entry.key().0, set_id }; self.events.push_back(ToSwarm::GenerateEvent(event)); - let _ = self.protocol_handles[usize::from(set_id)] - .report_substream_closed(entry.key().0); + // let _ = self.protocol_handles[usize::from(set_id)] + // .report_substream_closed(entry.key().0); } for (connec_id, connec_state) in @@ -1437,11 +1444,11 @@ impl NetworkBehaviour for Notifications { notifications_sink: replacement_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); - let _ = self.protocol_handles[usize::from(set_id)] - .report_notification_sink_replaced( - peer_id, - replacement_sink, - ); + // let _ = self.protocol_handles[usize::from(set_id)] + // .report_notification_sink_replaced( + // peer_id, + // replacement_sink, + // ); } } else { trace!( @@ -1453,8 +1460,8 @@ impl NetworkBehaviour for Notifications { set_id, }; self.events.push_back(ToSwarm::GenerateEvent(event)); - let _ = self.protocol_handles[usize::from(set_id)] - .report_substream_closed(peer_id); + // let _ = self.protocol_handles[usize::from(set_id)] + // .report_substream_closed(peer_id); } } } else { @@ -1857,8 +1864,8 @@ impl NetworkBehaviour for Notifications { notifications_sink: replacement_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); - let _ = self.protocol_handles[usize::from(set_id)] - .report_notification_sink_replaced(peer_id, replacement_sink); + // let _ = self.protocol_handles[usize::from(set_id)] + // .report_notification_sink_replaced(peer_id, replacement_sink); } *entry.into_mut() = PeerState::Enabled { connections }; @@ -1880,8 +1887,8 @@ impl NetworkBehaviour for Notifications { trace!(target: "sub-libp2p", "External API <= Closed({}, {:?})", peer_id, set_id); let event = NotificationsOut::CustomProtocolClosed { peer_id, set_id }; self.events.push_back(ToSwarm::GenerateEvent(event)); - let _ = self.protocol_handles[usize::from(set_id)] - .report_substream_closed(peer_id); + // let _ = self.protocol_handles[usize::from(set_id)] + // .report_substream_closed(peer_id); } }, @@ -1963,21 +1970,26 @@ impl NetworkBehaviour for Notifications { peer_id, set_id, inbound, + direction: if inbound { + Direction::Inbound + } else { + Direction::Outbound + }, received_handshake: received_handshake.clone(), negotiated_fallback: negotiated_fallback.clone(), notifications_sink: notifications_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); - let direction = - if inbound { Direction::Inbound } else { Direction::Outbound }; - let _ = self.protocol_handles[protocol_index] - .report_substream_opened( - peer_id, - direction, - received_handshake, - negotiated_fallback, - notifications_sink.clone(), - ); + // let direction = + // if inbound { Direction::Inbound } else { Direction::Outbound }; + // let _ = self.protocol_handles[protocol_index] + // .report_substream_opened( + // peer_id, + // direction, + // received_handshake, + // negotiated_fallback, + // notifications_sink.clone(), + // ); } *connec_state = ConnectionState::Open(notifications_sink); } else if let Some((_, connec_state)) = @@ -2128,8 +2140,8 @@ impl NetworkBehaviour for Notifications { message: message.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); - let _ = self.protocol_handles[protocol_index] - .report_notification_received(peer_id, message.to_vec()); + // let _ = self.protocol_handles[protocol_index] + // .report_notification_received(peer_id, message.to_vec()); } else { trace!( target: "sub-libp2p", @@ -2357,6 +2369,7 @@ mod tests { Box::new(MockPeerStore {}), ); + let (notif_handle, command_stream) = protocol_handle_pair.split(); ( Notifications::new( vec![handle], @@ -2369,7 +2382,8 @@ mod tests { handshake: vec![1, 2, 3, 4], max_notification_size: u64::MAX, }, - protocol_handle_pair, + notif_handle, + command_stream, )), ), controller, diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs index e15232f6b032..b5f627e966a2 100644 --- a/substrate/client/network/src/protocol/notifications/service/mod.rs +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -405,7 +405,7 @@ impl ProtocolHandlePair { /// Handle that is passed on to `Notifications` and allows it to directly communicate /// with the protocol. -#[derive(Debug)] +#[derive(Debug, Clone)] pub(crate) struct ProtocolHandle { /// Protocol name. protocol: ProtocolName, diff --git a/substrate/client/network/src/protocol/notifications/tests.rs b/substrate/client/network/src/protocol/notifications/tests.rs index 30bbe0275054..f3ad0e2f34ee 100644 --- a/substrate/client/network/src/protocol/notifications/tests.rs +++ b/substrate/client/network/src/protocol/notifications/tests.rs @@ -94,6 +94,7 @@ fn build_nodes() -> (Swarm, Swarm) { Box::new(peer_store.handle()), ); + let (notif_handle, command_stream) = protocol_handle_pair.split(); let behaviour = CustomProtoWithAddr { inner: Notifications::new( vec![controller_handle], @@ -106,7 +107,9 @@ fn build_nodes() -> (Swarm, Swarm) { handshake: Vec::new(), max_notification_size: 1024 * 1024, }, - protocol_handle_pair, + notif_handle, + command_stream, + // protocol_handle_pair, )), ), peer_store_future: peer_store.run().boxed(), diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index aca9bf64707b..8ed291771559 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -383,7 +383,7 @@ where let num_connected = Arc::new(AtomicUsize::new(0)); let external_addresses = Arc::new(Mutex::new(HashSet::new())); - let protocol = Protocol::new( + let (protocol, notif_protocol_handles) = Protocol::new( From::from(¶ms.role), ¶ms.metrics_registry, notification_protocols, @@ -546,6 +546,7 @@ where reported_invalid_boot_nodes: Default::default(), peers_notifications_sinks, peer_store_handle: params.peer_store, + notif_protocol_handles, _marker: Default::default(), _block: Default::default(), }) @@ -1259,6 +1260,8 @@ where peers_notifications_sinks: Arc>>, /// Peer reputation store handle. peer_store_handle: PeerStoreHandle, + /// Notification protocol handles. + notif_protocol_handles: Vec, /// Marker to pin the `H` generic. Serves no purpose except to not break backwards /// compatibility. _marker: PhantomData, @@ -1487,47 +1490,27 @@ where }, SwarmEvent::Behaviour(BehaviourOut::NotificationStreamOpened { remote, - protocol, + set_id, + direction, negotiated_fallback, notifications_sink, - role, received_handshake, }) => { - if let Some(metrics) = self.metrics.as_ref() { - metrics - .notifications_streams_opened_total - .with_label_values(&[&protocol]) - .inc(); - } - { - let mut peers_notifications_sinks = self.peers_notifications_sinks.lock(); - let _previous_value = peers_notifications_sinks - .insert((remote, protocol.clone()), notifications_sink); - debug_assert!(_previous_value.is_none()); - } - self.event_streams.send(Event::NotificationStreamOpened { + let _ = self.notif_protocol_handles[usize::from(set_id)].report_substream_opened( remote, - protocol, - negotiated_fallback, - role, + direction, received_handshake, - }); + negotiated_fallback, + notifications_sink, + ); }, SwarmEvent::Behaviour(BehaviourOut::NotificationStreamReplaced { remote, - protocol, + set_id, notifications_sink, }) => { - let mut peers_notifications_sinks = self.peers_notifications_sinks.lock(); - if let Some(s) = peers_notifications_sinks.get_mut(&(remote, protocol)) { - *s = notifications_sink; - } else { - error!( - target: "sub-libp2p", - "NotificationStreamReplaced for non-existing substream" - ); - debug_assert!(false); - } + let _ = self.notif_protocol_handles[usize::from(set_id)] + .report_notification_sink_replaced(remote, notifications_sink); // TODO: Notifications might have been lost as a result of the previous // connection being dropped, and as a result it would be preferable to notify @@ -1550,31 +1533,17 @@ where // role, // }); }, - SwarmEvent::Behaviour(BehaviourOut::NotificationStreamClosed { remote, protocol }) => { - if let Some(metrics) = self.metrics.as_ref() { - metrics - .notifications_streams_closed_total - .with_label_values(&[&protocol[..]]) - .inc(); - } - self.event_streams - .send(Event::NotificationStreamClosed { remote, protocol: protocol.clone() }); - { - let mut peers_notifications_sinks = self.peers_notifications_sinks.lock(); - let _previous_value = peers_notifications_sinks.remove(&(remote, protocol)); - debug_assert!(_previous_value.is_some()); - } + SwarmEvent::Behaviour(BehaviourOut::NotificationStreamClosed { remote, set_id }) => { + let _ = self.notif_protocol_handles[usize::from(set_id)] + .report_substream_closed(remote); }, - SwarmEvent::Behaviour(BehaviourOut::NotificationsReceived { remote, messages }) => { - if let Some(metrics) = self.metrics.as_ref() { - for (protocol, message) in &messages { - metrics - .notifications_sizes - .with_label_values(&["in", protocol]) - .observe(message.len() as f64); - } - } - self.event_streams.send(Event::NotificationsReceived { remote, messages }); + SwarmEvent::Behaviour(BehaviourOut::NotificationsReceived { + remote, + set_id, + notification, + }) => { + let _ = self.notif_protocol_handles[usize::from(set_id)] + .report_notification_received(remote, notification); }, SwarmEvent::Behaviour(BehaviourOut::Dht(event, duration)) => { if let Some(metrics) = self.metrics.as_ref() { From 77704771e29ba01891fb5e44345ffaa88963d842 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 20 Nov 2023 19:57:26 +0200 Subject: [PATCH 22/32] Fix warnings --- substrate/client/network/src/behaviour.rs | 1 - substrate/client/network/src/protocol.rs | 23 +----- substrate/client/network/src/service.rs | 86 +++-------------------- 3 files changed, 11 insertions(+), 99 deletions(-) diff --git a/substrate/client/network/src/behaviour.rs b/substrate/client/network/src/behaviour.rs index b5df93a31741..9f770bc3ba74 100644 --- a/substrate/client/network/src/behaviour.rs +++ b/substrate/client/network/src/behaviour.rs @@ -36,7 +36,6 @@ use libp2p::{ }; use parking_lot::Mutex; -use sc_network_common::role::{ObservedRole, Roles}; use sp_runtime::traits::Block as BlockT; use std::{collections::HashSet, sync::Arc, time::Duration}; diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index f7bb9b4bd205..f2628c298722 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -34,20 +34,14 @@ use libp2p::{ }, Multiaddr, PeerId, }; -use log::{error, warn}; +use log::warn; use prometheus_endpoint::Registry; use sc_network_common::role::Roles; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_runtime::traits::Block as BlockT; -use std::{ - collections::{HashMap, HashSet}, - future::Future, - iter, - pin::Pin, - task::Poll, -}; +use std::{collections::HashMap, future::Future, iter, pin::Pin, task::Poll}; use notifications::{Notifications, NotificationsOut}; @@ -177,19 +171,6 @@ impl Protocol { pub fn num_connected_peers(&self) -> usize { self.behaviour.num_connected_peers(HARDCODED_PEERSETS_SYNC) } - - /// Set handshake for the notification protocol. - pub fn set_notification_handshake(&mut self, protocol: ProtocolName, handshake: Vec) { - if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.behaviour.set_notif_protocol_handshake(SetId::from(index), handshake); - } else { - error!( - target: "sub-libp2p", - "set_notification_handshake with unknown protocol: {}", - protocol - ); - } - } } /// Outcome of an incoming custom message. diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index 8ed291771559..f2b5a5f76f4f 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -72,7 +72,7 @@ use libp2p::{ Multiaddr, PeerId, }; use log::{debug, error, info, trace, warn}; -use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; +use metrics::{Histogram, MetricSources, Metrics}; use parking_lot::Mutex; use sc_network_common::{ @@ -122,12 +122,6 @@ pub struct NetworkService { bandwidth: Arc, /// Channel that sends messages to the actual worker. to_worker: TracingUnboundedSender, - /// For each peer and protocol combination, an object that allows sending notifications to - /// that peer. Updated by the [`NetworkWorker`]. - peers_notifications_sinks: Arc>>, - /// Field extracted from the [`Metrics`] struct and necessary to report the - /// notifications-related metrics. - notifications_sizes_metric: Option, /// Protocol name -> `SetId` mapping for notification protocols. The map never changes after /// initialization. notification_protocol_ids: HashMap, @@ -512,7 +506,6 @@ where } let listen_addresses = Arc::new(Mutex::new(HashSet::new())); - let peers_notifications_sinks = Arc::new(Mutex::new(HashMap::new())); let service = Arc::new(NetworkService { bandwidth, @@ -522,10 +515,6 @@ where local_peer_id, local_identity, to_worker, - peers_notifications_sinks: peers_notifications_sinks.clone(), - notifications_sizes_metric: metrics - .as_ref() - .map(|metrics| metrics.notifications_sizes.clone()), notification_protocol_ids, protocol_handles, sync_protocol_handle, @@ -544,7 +533,6 @@ where metrics, boot_node_ids, reported_invalid_boot_nodes: Default::default(), - peers_notifications_sinks, peer_store_handle: params.peer_store, notif_protocol_handles, _marker: Default::default(), @@ -1021,73 +1009,26 @@ where } } +// TODO(aaro): remove this trait impl NetworkNotification for NetworkService where B: BlockT + 'static, H: ExHashT, { - fn write_notification(&self, target: PeerId, protocol: ProtocolName, message: Vec) { - // We clone the `NotificationsSink` in order to be able to unlock the network-wide - // `peers_notifications_sinks` mutex as soon as possible. - let sink = { - let peers_notifications_sinks = self.peers_notifications_sinks.lock(); - if let Some(sink) = peers_notifications_sinks.get(&(target, protocol.clone())) { - sink.clone() - } else { - // Notification silently discarded, as documented. - debug!( - target: "sub-libp2p", - "Attempted to send notification on missing or closed substream: {}, {:?}", - target, protocol, - ); - return - } - }; - - if let Some(notifications_sizes_metric) = self.notifications_sizes_metric.as_ref() { - notifications_sizes_metric - .with_label_values(&["out", &protocol]) - .observe(message.len() as f64); - } - - // Sending is communicated to the `NotificationsSink`. - trace!( - target: "sub-libp2p", - "External API => Notification({:?}, {:?}, {} bytes)", - target, protocol, message.len() - ); - trace!(target: "sub-libp2p", "Handler({:?}) <= Sync notification", target); - sink.send_sync_notification(message); + fn write_notification(&self, _target: PeerId, _protocol: ProtocolName, _message: Vec) { + unimplemented!(); } fn notification_sender( &self, - target: PeerId, - protocol: ProtocolName, + _target: PeerId, + _protocol: ProtocolName, ) -> Result, NotificationSenderError> { - // We clone the `NotificationsSink` in order to be able to unlock the network-wide - // `peers_notifications_sinks` mutex as soon as possible. - let sink = { - let peers_notifications_sinks = self.peers_notifications_sinks.lock(); - if let Some(sink) = peers_notifications_sinks.get(&(target, protocol.clone())) { - sink.clone() - } else { - return Err(NotificationSenderError::Closed) - } - }; - - let notification_size_metric = self - .notifications_sizes_metric - .as_ref() - .map(|histogram| histogram.with_label_values(&["out", &protocol])); - - Ok(Box::new(NotificationSender { sink, protocol_name: protocol, notification_size_metric })) + unimplemented!(); } - fn set_notification_handshake(&self, protocol: ProtocolName, handshake: Vec) { - let _ = self - .to_worker - .unbounded_send(ServiceToWorkerMsg::SetNotificationHandshake(protocol, handshake)); + fn set_notification_handshake(&self, _protocol: ProtocolName, _handshake: Vec) { + unimplemented!(); } } @@ -1225,7 +1166,6 @@ enum ServiceToWorkerMsg { pending_response: oneshot::Sender>, }, DisconnectPeer(PeerId, ProtocolName), - SetNotificationHandshake(ProtocolName, Vec), } /// Main network worker. Must be polled in order for the network to advance. @@ -1255,9 +1195,6 @@ where boot_node_ids: Arc>>, /// Boot nodes that we already have reported as invalid. reported_invalid_boot_nodes: HashSet, - /// For each peer and protocol combination, an object that allows sending notifications to - /// that peer. Shared with the [`NetworkService`]. - peers_notifications_sinks: Arc>>, /// Peer reputation store handle. peer_store_handle: PeerStoreHandle, /// Notification protocol handles. @@ -1371,11 +1308,6 @@ where .behaviour_mut() .user_protocol_mut() .disconnect_peer(&who, protocol_name), - ServiceToWorkerMsg::SetNotificationHandshake(protocol, handshake) => self - .network_service - .behaviour_mut() - .user_protocol_mut() - .set_notification_handshake(protocol, handshake), } } From eeab2fdf2a98c88b7b7168f863abd48b54841eef Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 20 Nov 2023 21:23:00 +0200 Subject: [PATCH 23/32] Use `ProtocolHandle` for fetching peer counts --- substrate/client/network/src/protocol.rs | 5 ----- substrate/client/network/src/service.rs | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index f2628c298722..148755af921f 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -166,11 +166,6 @@ impl Protocol { warn!(target: "sub-libp2p", "disconnect_peer() with invalid protocol name") } } - - /// Returns the number of peers we're connected to on sync protocol. - pub fn num_connected_peers(&self) -> usize { - self.behaviour.num_connected_peers(HARDCODED_PEERSETS_SYNC) - } } /// Outcome of an incoming custom message. diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index f2b5a5f76f4f..0411942ce2e0 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -561,7 +561,7 @@ where /// Returns the number of peers we're connected to. pub fn num_connected_peers(&self) -> usize { - self.network_service.behaviour().user_protocol().num_connected_peers() + self.notif_protocol_handles.get(0).map_or(0usize, |handle| handle.num_peers()) } /// Adds an address for a node. @@ -1238,7 +1238,7 @@ where // Update the `num_connected` count shared with the `NetworkService`. let num_connected_peers = - self.network_service.behaviour_mut().user_protocol_mut().num_connected_peers(); + self.notif_protocol_handles.get(0).map_or(0usize, |handle| handle.num_peers()); self.num_connected.store(num_connected_peers, Ordering::Relaxed); if let Some(metrics) = self.metrics.as_ref() { From 5049ade294fe333a3e1a3c4006bef7e9ba549723 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 20 Nov 2023 23:17:54 +0200 Subject: [PATCH 24/32] zzz --- .../client/network/src/protocol/notifications/behaviour.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index f05660354d73..b6196b1a13d6 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -468,11 +468,6 @@ impl Notifications { } } - /// Get the number of connected peers for a given set. - pub fn num_connected_peers(&self, set_id: SetId) -> usize { - self.protocol_handles[usize::from(set_id)].num_peers() - } - /// Returns the list of all the peers we have an open channel to. pub fn open_peers(&self) -> impl Iterator { self.peers.iter().filter(|(_, state)| state.is_open()).map(|((id, _), _)| id) From befd2d9a9dad309ca2a5d9342e365f4121ac2284 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Tue, 21 Nov 2023 11:38:38 +0200 Subject: [PATCH 25/32] Prioritize validation events over other events GRANDPA and transactions follow syncing protocol for peers while they're still required to validate inbound peers. Peer might be accepted over GRANDPA and after `ProtocolController` has accepted the peer, the peer is sent to the protocol for validation. While it was being validated, syncing protocol may have disconnected from the peer, instructing GRANDPA to disconnect as well. If the validation result from GRANDPA is not processed before the disconnection request is received from --- .../src/protocol/notifications/behaviour.rs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index b6196b1a13d6..93c3be0310b9 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -2160,6 +2160,23 @@ impl NetworkBehaviour for Notifications { return Poll::Ready(event) } + while let Poll::Ready(Some((result, index))) = + self.pending_inbound_validations.poll_next_unpin(cx) + { + match result { + Ok(ValidationResult::Accept) => { + self.protocol_report_accept(index); + }, + Ok(ValidationResult::Reject) => { + self.protocol_report_reject(index); + }, + Err(_) => { + error!(target: LOG_TARGET, "Protocol has shut down"); + break + }, + } + } + // Poll for instructions from the protocol controllers. loop { match futures::Stream::poll_next(Pin::new(&mut self.from_protocol_controllers), cx) { @@ -2206,23 +2223,6 @@ impl NetworkBehaviour for Notifications { } } - while let Poll::Ready(Some((result, index))) = - self.pending_inbound_validations.poll_next_unpin(cx) - { - match result { - Ok(ValidationResult::Accept) => { - self.protocol_report_accept(index); - }, - Ok(ValidationResult::Reject) => { - self.protocol_report_reject(index); - }, - Err(_) => { - error!(target: LOG_TARGET, "Protocol has shut down"); - break - }, - } - } - while let Poll::Ready(Some((delay_id, peer_id, set_id))) = Pin::new(&mut self.delays).poll_next(cx) { From cd94277beab872ca2d0f4383c677c00b9c907001 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Wed, 22 Nov 2023 16:59:10 +0200 Subject: [PATCH 26/32] Improve validation --- .../src/protocol/notifications/behaviour.rs | 522 +++++++++++++----- .../src/protocol/notifications/service/mod.rs | 29 +- .../protocol/notifications/service/tests.rs | 74 ++- 3 files changed, 483 insertions(+), 142 deletions(-) diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index 93c3be0310b9..4c628949911a 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -19,7 +19,7 @@ use crate::{ protocol::notifications::{ handler::{self, NotificationsSink, NotifsHandler, NotifsHandlerIn, NotifsHandlerOut}, - service::{metrics, NotificationCommand, ProtocolHandle}, + service::{metrics, NotificationCommand, ProtocolHandle, ValidationCallResult}, }, protocol_controller::{self, IncomingIndex, Message, SetId}, service::traits::{Direction, ValidationResult}, @@ -38,7 +38,7 @@ use libp2p::{ }, PeerId, }; -use log::{debug, error, info, trace, warn}; +use log::{debug, error, trace, warn}; use parking_lot::RwLock; use prometheus_endpoint::Registry; use rand::distributions::{Distribution as _, Uniform}; @@ -266,6 +266,9 @@ enum PeerState { /// Incoming index tracking this connection. incoming_index: IncomingIndex, + /// Peerset has signaled it wants the substream closed. + peerset_rejected: bool, + /// List of connections with this peer, and their state. connections: SmallVec<[(ConnectionId, ConnectionState); crate::MAX_CONNECTIONS_PER_PEER]>, }, @@ -427,7 +430,7 @@ impl Notifications { assert!(!notif_protocols.is_empty()); let metrics = registry.as_ref().and_then(|registry| metrics::register(®istry).ok()); - let (protocol_handles, command_streams): (Vec<_>, Vec<_>) = protocol_handles + let (mut protocol_handles, command_streams): (Vec<_>, Vec<_>) = protocol_handles .into_iter() .enumerate() .map(|(set_id, (mut protocol_handle, command_stream))| { @@ -437,6 +440,10 @@ impl Notifications { }) .unzip(); + protocol_handles.iter_mut().skip(1).for_each(|handle| { + handle.delegate_to_peerset(true); + }); + Self { notif_protocols, protocol_handles, @@ -519,8 +526,6 @@ impl Notifications { let event = NotificationsOut::CustomProtocolClosed { peer_id: *peer_id, set_id }; self.events.push_back(ToSwarm::GenerateEvent(event)); - // let _ = self.protocol_handles[usize::from(set_id)] - // .report_substream_closed(*peer_id); } for (connec_id, connec_state) in @@ -822,8 +827,6 @@ impl Notifications { let event = NotificationsOut::CustomProtocolClosed { peer_id: entry.key().0, set_id }; self.events.push_back(ToSwarm::GenerateEvent(event)); - // let _ = self.protocol_handles[usize::from(set_id)] - // .report_substream_closed(entry.key().0); } for (connec_id, connec_state) in @@ -872,14 +875,21 @@ impl Notifications { *entry.into_mut() = PeerState::Backoff { timer, timer_deadline } }, - // Invalid state transitions. - st @ PeerState::Incoming { .. } => { - info!( + // `ProtocolController` disconnected peer while it was still being validated by the + // protocol, mark the connection as rejected and once the validation is received from + // the protocol, reject the substream + PeerState::Incoming { backoff_until, connections, incoming_index, .. } => { + debug!( target: "sub-libp2p", "PSM => Drop({}, {:?}): Ignoring obsolete disconnect, we are awaiting accept/reject.", entry.key().0, set_id, ); - *entry.into_mut() = st; + *entry.into_mut() = PeerState::Incoming { + backoff_until, + connections, + incoming_index, + peerset_rejected: true, + }; }, PeerState::Poisoned => { error!(target: "sub-libp2p", "State of {:?} is poisoned", entry.key()); @@ -906,9 +916,13 @@ impl Notifications { match self.protocol_handles[usize::from(incoming.set_id)] .report_incoming_substream(incoming.peer_id, incoming.handshake.clone()) { - Ok(rx) => self - .pending_inbound_validations - .push(Box::pin(async move { (rx.await, index) })), + Ok(ValidationCallResult::Delegated) => { + self.protocol_report_accept(index); + }, + Ok(ValidationCallResult::WaitForValidation(rx)) => { + self.pending_inbound_validations + .push(Box::pin(async move { (rx.await, index) })); + }, Err(err) => { // parachain collators enable the syncing protocol but `NotificationService` for // `SyncingEngine` is not created which causes `report_incoming_substream()` to @@ -917,6 +931,7 @@ impl Notifications { // the protocol has exited. Until the parachain collator issue is fixed, just report // and error and reject the peer. debug!(target: LOG_TARGET, "protocol has exited: {err:?} {:?}", incoming.set_id); + self.protocol_report_reject(index); }, } @@ -925,17 +940,29 @@ impl Notifications { /// Function that is called when the peerset wants us to accept a connection /// request from a peer. fn protocol_report_accept(&mut self, index: IncomingIndex) { - let incoming = if let Some(pos) = self.incoming.iter().position(|i| i.incoming_id == index) - { - self.incoming.remove(pos) - } else { - error!(target: "sub-libp2p", "PSM => Accept({:?}): Invalid index", index); - return + let (pos, incoming) = + if let Some(pos) = self.incoming.iter().position(|i| i.incoming_id == index) { + (pos, self.incoming.get(pos)) + } else { + error!(target: "sub-libp2p", "PSM => Accept({:?}): Invalid index", index); + return + }; + + let Some(incoming) = incoming else { + error!(target: "sub-libp2p", "Incoming connection ({:?}) doesn't exist", index); + debug_assert!(false); + return; }; if !incoming.alive { - trace!(target: "sub-libp2p", "PSM => Accept({:?}, {}, {:?}): Obsolete incoming", - index, incoming.peer_id, incoming.set_id); + trace!( + target: "sub-libp2p", + "PSM => Accept({:?}, {}, {:?}): Obsolete incoming", + index, + incoming.peer_id, + incoming.set_id, + ); + match self.peers.get_mut(&(incoming.peer_id, incoming.set_id)) { Some(PeerState::DisabledPendingEnable { .. }) | Some(PeerState::Enabled { .. }) => { }, @@ -946,26 +973,42 @@ impl Notifications { .dropped(incoming.peer_id); }, } + + self.incoming.remove(pos); return } let state = match self.peers.get_mut(&(incoming.peer_id, incoming.set_id)) { Some(s) => s, None => { - debug_assert!(false); + log::debug!( + target: "sub-libp2p", + "Connection to {:?} closed, ({:?} {:?}), ignoring accept", + incoming.peer_id, + incoming.set_id, + index, + ); + self.incoming.remove(pos); return }, }; match mem::replace(state, PeerState::Poisoned) { // Incoming => Enabled - PeerState::Incoming { mut connections, incoming_index, .. } => { + PeerState::Incoming { + mut connections, + incoming_index, + peerset_rejected, + backoff_until, + } => { if index < incoming_index { warn!( target: "sub-libp2p", "PSM => Accept({:?}, {}, {:?}): Ignoring obsolete incoming index, we are already awaiting {:?}.", index, incoming.peer_id, incoming.set_id, incoming_index ); + + self.incoming.remove(pos); return } else if index > incoming_index { error!( @@ -973,12 +1016,39 @@ impl Notifications { "PSM => Accept({:?}, {}, {:?}): Ignoring incoming index from the future, we are awaiting {:?}.", index, incoming.peer_id, incoming.set_id, incoming_index ); + + self.incoming.remove(pos); debug_assert!(false); return } - trace!(target: "sub-libp2p", "PSM => Accept({:?}, {}, {:?}): Enabling connections.", - index, incoming.peer_id, incoming.set_id); + // while the substream was being validated by the protocol, `Peerset` had request + // for the it to be closed so reject the substream now + if peerset_rejected { + trace!( + target: "sub-libp2p", + "Protocol accepted ({:?} {:?} {:?}) but Peerset had request disconnection, rejecting", + index, + incoming.peer_id, + incoming.set_id + ); + + *state = PeerState::Incoming { + connections, + backoff_until, + peerset_rejected, + incoming_index, + }; + return self.report_reject(index).map_or((), |_| ()); + } + + trace!( + target: "sub-libp2p", + "PSM => Accept({:?}, {}, {:?}): Enabling connections.", + index, + incoming.peer_id, + incoming.set_id + ); debug_assert!(connections .iter() @@ -997,14 +1067,22 @@ impl Notifications { *connec_state = ConnectionState::Opening; } + self.incoming.remove(pos); *state = PeerState::Enabled { connections }; }, - + st @ PeerState::Disabled { .. } | st @ PeerState::Backoff { .. } => { + self.incoming.remove(pos); + *state = st; + }, // Any state other than `Incoming` is invalid. peer => { - error!(target: "sub-libp2p", + error!( + target: "sub-libp2p", "State mismatch in libp2p: Expected alive incoming. Got {:?}.", - peer); + peer + ); + + self.incoming.remove(pos); debug_assert!(false); }, } @@ -1033,15 +1111,27 @@ impl Notifications { }; if !incoming.alive { - trace!(target: "sub-libp2p", "PSM => Reject({:?}, {}, {:?}): Obsolete incoming, \ - ignoring", index, incoming.peer_id, incoming.set_id); + trace!( + target: "sub-libp2p", + "PSM => Reject({:?}, {}, {:?}): Obsolete incoming, ignoring", + index, + incoming.peer_id, + incoming.set_id, + ); + return None } let state = match self.peers.get_mut(&(incoming.peer_id, incoming.set_id)) { Some(s) => s, None => { - debug_assert!(false); + log::debug!( + target: "sub-libp2p", + "Connection to {:?} closed, ({:?} {:?}), ignoring accept", + incoming.peer_id, + incoming.set_id, + index, + ); return None }, }; @@ -1089,6 +1179,11 @@ impl Notifications { *state = PeerState::Disabled { connections, backoff_until }; Some((incoming.set_id, incoming.peer_id)) }, + // connection to peer may have been closed already + st @ PeerState::Disabled { .. } | st @ PeerState::Backoff { .. } => { + *state = st; + None + }, peer => { error!( target: LOG_TARGET, @@ -1317,7 +1412,7 @@ impl NetworkBehaviour for Notifications { mut connections, backoff_until, incoming_index, - .. + peerset_rejected, } => { trace!( target: "sub-libp2p", @@ -1397,6 +1492,7 @@ impl NetworkBehaviour for Notifications { connections, backoff_until, incoming_index, + peerset_rejected, }; } }, @@ -1439,11 +1535,6 @@ impl NetworkBehaviour for Notifications { notifications_sink: replacement_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); - // let _ = self.protocol_handles[usize::from(set_id)] - // .report_notification_sink_replaced( - // peer_id, - // replacement_sink, - // ); } } else { trace!( @@ -1455,8 +1546,6 @@ impl NetworkBehaviour for Notifications { set_id, }; self.events.push_back(ToSwarm::GenerateEvent(event)); - // let _ = self.protocol_handles[usize::from(set_id)] - // .report_substream_closed(peer_id); } } } else { @@ -1625,7 +1714,12 @@ impl NetworkBehaviour for Notifications { match mem::replace(entry.get_mut(), PeerState::Poisoned) { // Incoming => Incoming - PeerState::Incoming { mut connections, backoff_until, incoming_index } => { + PeerState::Incoming { + mut connections, + backoff_until, + incoming_index, + peerset_rejected, + } => { debug_assert!(connections .iter() .any(|(_, s)| matches!(s, ConnectionState::OpenDesiredByRemote))); @@ -1653,8 +1747,12 @@ impl NetworkBehaviour for Notifications { debug_assert!(false); } - *entry.into_mut() = - PeerState::Incoming { connections, backoff_until, incoming_index }; + *entry.into_mut() = PeerState::Incoming { + connections, + backoff_until, + incoming_index, + peerset_rejected, + }; }, PeerState::Enabled { mut connections } => { @@ -1724,6 +1822,7 @@ impl NetworkBehaviour for Notifications { *entry.into_mut() = PeerState::Incoming { connections, backoff_until, + peerset_rejected: false, incoming_index: incoming_id, }; } else { @@ -1859,8 +1958,6 @@ impl NetworkBehaviour for Notifications { notifications_sink: replacement_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); - // let _ = self.protocol_handles[usize::from(set_id)] - // .report_notification_sink_replaced(peer_id, replacement_sink); } *entry.into_mut() = PeerState::Enabled { connections }; @@ -1882,8 +1979,6 @@ impl NetworkBehaviour for Notifications { trace!(target: "sub-libp2p", "External API <= Closed({}, {:?})", peer_id, set_id); let event = NotificationsOut::CustomProtocolClosed { peer_id, set_id }; self.events.push_back(ToSwarm::GenerateEvent(event)); - // let _ = self.protocol_handles[usize::from(set_id)] - // .report_substream_closed(peer_id); } }, @@ -1975,16 +2070,6 @@ impl NetworkBehaviour for Notifications { notifications_sink: notifications_sink.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); - // let direction = - // if inbound { Direction::Inbound } else { Direction::Outbound }; - // let _ = self.protocol_handles[protocol_index] - // .report_substream_opened( - // peer_id, - // direction, - // received_handshake, - // negotiated_fallback, - // notifications_sink.clone(), - // ); } *connec_state = ConnectionState::Open(notifications_sink); } else if let Some((_, connec_state)) = @@ -2135,8 +2220,6 @@ impl NetworkBehaviour for Notifications { message: message.clone(), }; self.events.push_back(ToSwarm::GenerateEvent(event)); - // let _ = self.protocol_handles[protocol_index] - // .report_notification_received(peer_id, message.to_vec()); } else { trace!( target: "sub-libp2p", @@ -2160,23 +2243,6 @@ impl NetworkBehaviour for Notifications { return Poll::Ready(event) } - while let Poll::Ready(Some((result, index))) = - self.pending_inbound_validations.poll_next_unpin(cx) - { - match result { - Ok(ValidationResult::Accept) => { - self.protocol_report_accept(index); - }, - Ok(ValidationResult::Reject) => { - self.protocol_report_reject(index); - }, - Err(_) => { - error!(target: LOG_TARGET, "Protocol has shut down"); - break - }, - } - } - // Poll for instructions from the protocol controllers. loop { match futures::Stream::poll_next(Pin::new(&mut self.from_protocol_controllers), cx) { @@ -2223,6 +2289,23 @@ impl NetworkBehaviour for Notifications { } } + while let Poll::Ready(Some((result, index))) = + self.pending_inbound_validations.poll_next_unpin(cx) + { + match result { + Ok(ValidationResult::Accept) => { + self.protocol_report_accept(index); + }, + Ok(ValidationResult::Reject) => { + self.protocol_report_reject(index); + }, + Err(_) => { + error!(target: LOG_TARGET, "Protocol has shut down"); + break + }, + } + } + while let Poll::Ready(Some((delay_id, peer_id, set_id))) = Pin::new(&mut self.delays).poll_next(cx) { @@ -4311,13 +4394,68 @@ mod tests { } #[test] - #[should_panic] #[cfg(debug_assertions)] - fn protocol_report_accept_incoming_peer() { + fn peerset_report_disconnect_with_incoming_peer_protocol_accepts() { let (mut notif, _controller, _notif_service) = development_notifs(); let peer = PeerId::random(); + let set_id = SetId::from(0); let conn = ConnectionId::new_unchecked(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + // `Peerset` wants to disconnect the peer but since it's still under validation, + // it won't be disabled automatically + notif.peerset_report_disconnect(peer, set_id); + + let incoming_index = match notif.peers.get(&(peer, set_id)) { + Some(&PeerState::Incoming { peerset_rejected, incoming_index, .. }) => { + assert!(peerset_rejected); + incoming_index + }, + state => panic!("invalid state: {state:?}"), + }; + + // protocol accepted peer but since `Peerset` wanted to disconnect it, the peer will be + // disabled + notif.protocol_report_accept(incoming_index); + + match notif.peers.get(&(peer, set_id)) { + Some(&PeerState::Disabled { .. }) => {}, + state => panic!("invalid state: {state:?}"), + }; + } + + #[test] + #[cfg(debug_assertions)] + fn peer_disconnected_protocol_accepts() { + let (mut notif, _controller, _notif_service) = development_notifs(); + let peer = PeerId::random(); let set_id = SetId::from(0); + let conn = ConnectionId::new_unchecked(0); let connected = ConnectedPoint::Listener { local_addr: Multiaddr::empty(), send_back_addr: Multiaddr::empty(), @@ -4345,13 +4483,190 @@ mod tests { ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); - assert!(std::matches!( - notif.incoming[0], - IncomingPeer { alive: true, incoming_id: IncomingIndex(0), .. }, + assert!(notif + .incoming + .iter() + .find(|entry| entry.incoming_id == IncomingIndex(0)) + .is_some()); + notif.disconnect_peer(&peer, set_id); + + // since the connection was closed, nothing happens for the peer state because + // there is nothing actionable + notif.protocol_report_accept(IncomingIndex(0)); + + match notif.peers.get(&(peer, set_id)) { + Some(&PeerState::Disabled { .. }) => {}, + state => panic!("invalid state: {state:?}"), + }; + + assert!(notif + .incoming + .iter() + .find(|entry| entry.incoming_id == IncomingIndex(0)) + .is_none()); + } + + #[test] + #[cfg(debug_assertions)] + fn connection_closed_protocol_accepts() { + let (mut notif, _controller, _notif_service) = development_notifs(); + let peer = PeerId::random(); + let set_id = SetId::from(0); + let conn = ConnectionId::new_unchecked(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new_unchecked(0), + endpoint: &connected.clone(), + handler: NotifsHandler::new(peer, connected, vec![], None), + remaining_established: 0usize, + }, )); - notif.peers.remove(&(peer, set_id)); + // connection closed, nothing to do notif.protocol_report_accept(IncomingIndex(0)); + + match notif.peers.get(&(peer, set_id)) { + None => {}, + state => panic!("invalid state: {state:?}"), + }; + } + + #[test] + #[cfg(debug_assertions)] + fn peer_disconnected_protocol_reject() { + let (mut notif, _controller, _notif_service) = development_notifs(); + let peer = PeerId::random(); + let set_id = SetId::from(0); + let conn = ConnectionId::new_unchecked(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + assert!(notif + .incoming + .iter() + .find(|entry| entry.incoming_id == IncomingIndex(0)) + .is_some()); + notif.disconnect_peer(&peer, set_id); + + // since the connection was closed, nothing happens for the peer state because + // there is nothing actionable + notif.protocol_report_reject(IncomingIndex(0)); + + match notif.peers.get(&(peer, set_id)) { + Some(&PeerState::Disabled { .. }) => {}, + state => panic!("invalid state: {state:?}"), + }; + + assert!(notif + .incoming + .iter() + .find(|entry| entry.incoming_id == IncomingIndex(0)) + .is_none()); + } + + #[test] + #[cfg(debug_assertions)] + fn connection_closed_protocol_rejects() { + let (mut notif, _controller, _notif_service) = development_notifs(); + let peer = PeerId::random(); + let set_id = SetId::from(0); + let conn = ConnectionId::new_unchecked(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { + protocol_index: 0, + handshake: vec![1, 3, 3, 7], + }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new_unchecked(0), + endpoint: &connected.clone(), + handler: NotifsHandler::new(peer, connected, vec![], None), + remaining_established: 0usize, + }, + )); + + // connection closed, nothing to do + notif.protocol_report_reject(IncomingIndex(0)); + + match notif.peers.get(&(peer, set_id)) { + None => {}, + state => panic!("invalid state: {state:?}"), + }; } #[test] @@ -4499,49 +4814,6 @@ mod tests { assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); } - #[test] - #[should_panic] - #[cfg(debug_assertions)] - fn reject_non_existent_peer_but_alive_connection() { - let (mut notif, _controller, _notif_service) = development_notifs(); - let peer = PeerId::random(); - let conn = ConnectionId::new_unchecked(0); - let set_id = SetId::from(0); - let connected = ConnectedPoint::Listener { - local_addr: Multiaddr::empty(), - send_back_addr: Multiaddr::empty(), - }; - - notif.on_swarm_event(FromSwarm::ConnectionEstablished( - libp2p::swarm::behaviour::ConnectionEstablished { - peer_id: peer, - connection_id: conn, - endpoint: &connected, - failed_addresses: &[], - other_established: 0usize, - }, - )); - assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); - - // remote opens a substream, verify that peer state is updated to `Incoming` - notif.on_connection_handler_event( - peer, - conn, - NotifsHandlerOut::OpenDesiredByRemote { - protocol_index: 0, - handshake: vec![1, 3, 3, 7], - }, - ); - assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); - assert!(std::matches!( - notif.incoming[0], - IncomingPeer { alive: true, incoming_id: IncomingIndex(0), .. }, - )); - - notif.peers.remove(&(peer, set_id)); - notif.protocol_report_reject(0.into()); - } - #[test] #[should_panic] #[cfg(debug_assertions)] diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs index b5f627e966a2..e7bc8255b515 100644 --- a/substrate/client/network/src/protocol/notifications/service/mod.rs +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -416,14 +416,22 @@ pub(crate) struct ProtocolHandle { /// Number of connected peers. num_peers: usize, + /// Delegate validation to `Peerset`. + delegate_to_peerset: bool, + /// Prometheus metrics. metrics: Option, } +pub(crate) enum ValidationCallResult { + WaitForValidation(oneshot::Receiver), + Delegated, +} + impl ProtocolHandle { /// Create new [`ProtocolHandle`]. fn new(protocol: ProtocolName, subscribers: Subscribers) -> Self { - Self { protocol, subscribers, num_peers: 0usize, metrics: None } + Self { protocol, subscribers, num_peers: 0usize, metrics: None, delegate_to_peerset: false } } /// Set metrics. @@ -431,6 +439,15 @@ impl ProtocolHandle { self.metrics = metrics; } + /// Delegate validation to `Peerset`. + /// + /// Protocols that do not do any validation themselves and only rely on `Peerset` handling + /// validation can disable protocol-side validation entirely by delegating all validation to + /// `Peerset`. + pub fn delegate_to_peerset(&mut self, delegate: bool) { + self.delegate_to_peerset = delegate; + } + /// Report to the protocol that a substream has been opened and it must be validated by the /// protocol. /// @@ -440,7 +457,7 @@ impl ProtocolHandle { &self, peer: PeerId, handshake: Vec, - ) -> Result, ()> { + ) -> Result { let subscribers = self.subscribers.lock(); log::trace!( @@ -449,6 +466,10 @@ impl ProtocolHandle { self.protocol ); + if self.delegate_to_peerset { + return Ok(ValidationCallResult::Delegated) + } + // if there is only one subscriber, `Notifications` can wait directly on the // `oneshot::channel()`'s RX half without indirection if subscribers.len() == 1 { @@ -459,7 +480,7 @@ impl ProtocolHandle { handshake, result_tx, }) - .map(|_| rx) + .map(|_| ValidationCallResult::WaitForValidation(rx)) .map_err(|_| ()) } @@ -494,7 +515,7 @@ impl ProtocolHandle { return tx.send(ValidationResult::Accept) }); - Ok(rx) + Ok(ValidationCallResult::WaitForValidation(rx)) } /// Report to the protocol that a substream has been opened and that it can now use the handle diff --git a/substrate/client/network/src/protocol/notifications/service/tests.rs b/substrate/client/network/src/protocol/notifications/service/tests.rs index 615ba8bcf96e..02ba9e1711c3 100644 --- a/substrate/client/network/src/protocol/notifications/service/tests.rs +++ b/substrate/client/network/src/protocol/notifications/service/tests.rs @@ -29,7 +29,11 @@ async fn validate_and_accept_substream() { let (handle, _stream) = proto.split(); let peer_id = PeerId::random(); - let rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = notif.next_event().await @@ -41,7 +45,7 @@ async fn validate_and_accept_substream() { panic!("invalid event received"); } - assert_eq!(rx.await.unwrap(), ValidationResult::Accept); + assert_eq!(result_rx.await.unwrap(), ValidationResult::Accept); } #[tokio::test] @@ -79,7 +83,11 @@ async fn send_sync_notification() { let peer_id = PeerId::random(); // validate inbound substream - let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = notif.next_event().await @@ -127,7 +135,11 @@ async fn send_async_notification() { let peer_id = PeerId::random(); // validate inbound substream - let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = notif.next_event().await @@ -202,7 +214,11 @@ async fn receive_notification() { let peer_id = PeerId::random(); // validate inbound substream - let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = notif.next_event().await @@ -256,7 +272,11 @@ async fn backpressure_works() { let peer_id = PeerId::random(); // validate inbound substream - let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = notif.next_event().await @@ -316,7 +336,11 @@ async fn peer_disconnects_then_sync_notification_is_sent() { let peer_id = PeerId::random(); // validate inbound substream - let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = notif.next_event().await @@ -366,7 +390,11 @@ async fn peer_disconnects_then_async_notification_is_sent() { let peer_id = PeerId::random(); // validate inbound substream - let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = notif.next_event().await @@ -422,7 +450,11 @@ async fn cloned_service_opening_substream_works() { let peer_id = PeerId::random(); // validate inbound substream - let mut result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(mut result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; // verify that `notif1` gets the event if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = @@ -463,7 +495,11 @@ async fn cloned_service_one_service_rejects_substream() { let peer_id = PeerId::random(); // validate inbound substream - let mut result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(mut result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; for notif in vec![&mut notif1, &mut notif2] { if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = @@ -502,7 +538,11 @@ async fn cloned_service_opening_substream_sending_and_receiving_notifications_wo let peer_id = PeerId::random(); // validate inbound substream - let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; for notif in vec![&mut notif1, &mut notif2, &mut notif3] { // accept the inbound substream for all services @@ -583,7 +623,11 @@ async fn sending_notifications_using_notifications_sink_works() { let peer_id = PeerId::random(); // validate inbound substream - let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = notif.next_event().await @@ -660,7 +704,11 @@ async fn notification_sink_replaced() { let peer_id = PeerId::random(); // validate inbound substream - let result_rx = handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap(); + let ValidationCallResult::WaitForValidation(result_rx) = + handle.report_incoming_substream(peer_id, vec![1, 3, 3, 7]).unwrap() + else { + panic!("peerset not enabled"); + }; if let Some(NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx }) = notif.next_event().await From baf44b20793e5bd05ccb5c31e813cfe1477dfa2d Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Wed, 22 Nov 2023 19:20:26 +0200 Subject: [PATCH 27/32] Fix clippy --- .../src/protocol/notifications/behaviour.rs | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index 4c628949911a..ef0c6540eee5 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -4483,11 +4483,7 @@ mod tests { ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); - assert!(notif - .incoming - .iter() - .find(|entry| entry.incoming_id == IncomingIndex(0)) - .is_some()); + assert!(notif.incoming.iter().any(|entry| entry.incoming_id == IncomingIndex(0))); notif.disconnect_peer(&peer, set_id); // since the connection was closed, nothing happens for the peer state because @@ -4499,11 +4495,7 @@ mod tests { state => panic!("invalid state: {state:?}"), }; - assert!(notif - .incoming - .iter() - .find(|entry| entry.incoming_id == IncomingIndex(0)) - .is_none()); + assert!(!notif.incoming.iter().any(|entry| entry.incoming_id == IncomingIndex(0))); } #[test] @@ -4593,11 +4585,7 @@ mod tests { ); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); - assert!(notif - .incoming - .iter() - .find(|entry| entry.incoming_id == IncomingIndex(0)) - .is_some()); + assert!(notif.incoming.iter().any(|entry| entry.incoming_id == IncomingIndex(0))); notif.disconnect_peer(&peer, set_id); // since the connection was closed, nothing happens for the peer state because @@ -4609,11 +4597,7 @@ mod tests { state => panic!("invalid state: {state:?}"), }; - assert!(notif - .incoming - .iter() - .find(|entry| entry.incoming_id == IncomingIndex(0)) - .is_none()); + assert!(!notif.incoming.iter().any(|entry| entry.incoming_id == IncomingIndex(0))); } #[test] From ac76424ff4cf55c86e5ab554bc7755989fb78ade Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Thu, 23 Nov 2023 11:49:35 +0200 Subject: [PATCH 28/32] Clean up things --- substrate/client/network/src/protocol.rs | 48 +++++-------------- .../src/protocol/notifications/handler.rs | 2 +- .../protocol/notifications/service/metrics.rs | 6 +-- .../src/protocol/notifications/service/mod.rs | 6 +-- .../src/protocol/notifications/tests.rs | 1 - substrate/client/network/src/service.rs | 2 - .../client/network/src/service/metrics.rs | 28 ----------- substrate/client/network/statement/src/lib.rs | 9 +++- 8 files changed, 24 insertions(+), 78 deletions(-) diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index 148755af921f..e9ce2d6f4564 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -18,14 +18,12 @@ use crate::{ config, error, - peer_store::PeerStoreHandle, protocol_controller::{self, SetId}, service::traits::Direction, types::ProtocolName, }; use codec::Encode; -use futures::{stream::FuturesUnordered, StreamExt}; use libp2p::{ core::Endpoint, swarm::{ @@ -41,7 +39,7 @@ use sc_network_common::role::Roles; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_runtime::traits::Block as BlockT; -use std::{collections::HashMap, future::Future, iter, pin::Pin, task::Poll}; +use std::{iter, task::Poll}; use notifications::{Notifications, NotificationsOut}; @@ -60,22 +58,14 @@ pub mod message; pub(crate) const BLOCK_ANNOUNCES_TRANSACTIONS_SUBSTREAM_SIZE: u64 = 16 * 1024 * 1024; /// Identifier of the peerset for the block announces protocol. -const HARDCODED_PEERSETS_SYNC: SetId = SetId::from(0); - -type PendingSyncSubstreamValidation = - Pin> + Send>>; +const _HARDCODED_PEERSETS_SYNC: SetId = SetId::from(0); // Lock must always be taken in order declared here. pub struct Protocol { - // /// Used to report reputation changes. - // peer_store_handle: PeerStoreHandle, /// Handles opening the unique substream and sending and receiving raw messages. behaviour: Notifications, /// List of notifications protocols that have been registered. notification_protocols: Vec, - /// Connected peers on sync protocol. - peers: HashMap, - sync_substream_validations: FuturesUnordered, _marker: std::marker::PhantomData, } @@ -86,7 +76,6 @@ impl Protocol { registry: &Option, notification_protocols: Vec, block_announces_protocol: config::NonDefaultSetConfig, - _peer_store_handle: PeerStoreHandle, protocol_controller_handles: Vec, from_protocol_controllers: TracingUnboundedReceiver, ) -> error::Result<(Self, Vec)> { @@ -140,8 +129,6 @@ impl Protocol { let protocol = Self { behaviour, notification_protocols, - peers: HashMap::new(), - sync_substream_validations: FuturesUnordered::new(), // TODO: remove when `BlockAnnouncesHandshake` is moved away from `Protocol` _marker: Default::default(), }; @@ -181,29 +168,35 @@ pub enum CustomMessageOutcome { direction: Direction, /// See [`crate::Event::NotificationStreamOpened::negotiated_fallback`]. negotiated_fallback: Option, - // roles: Roles, + /// Received handshake. received_handshake: Vec, + /// Notification sink. notifications_sink: NotificationsSink, }, /// The [`NotificationsSink`] of some notification protocols need an update. NotificationStreamReplaced { + // Peer ID. remote: PeerId, + /// Set ID. set_id: SetId, - // protocol: ProtocolName, + /// New notification sink. notifications_sink: NotificationsSink, }, /// Notification protocols have been closed with a remote. NotificationStreamClosed { + // Peer ID. remote: PeerId, + /// Set ID. set_id: SetId, - // protocol: ProtocolName, }, /// Messages have been received on one or more notifications protocols. NotificationsReceived { + // Peer ID. remote: PeerId, + /// Set ID. set_id: SetId, + /// Received notification. notification: Vec, - // messages: Vec<(ProtocolName, Bytes)>, }, } @@ -271,23 +264,6 @@ impl NetworkBehaviour for Protocol { cx: &mut std::task::Context, params: &mut impl PollParameters, ) -> Poll>> { - while let Poll::Ready(Some(validation_result)) = - self.sync_substream_validations.poll_next_unpin(cx) - { - match validation_result { - Ok((peer, roles)) => { - self.peers.insert(peer, roles); - }, - Err(peer) => { - log::debug!( - target: "sub-libp2p", - "`SyncingEngine` rejected stream" - ); - self.behaviour.disconnect_peer(&peer, HARDCODED_PEERSETS_SYNC); - }, - } - } - let event = match self.behaviour.poll(cx, params) { Poll::Pending => return Poll::Pending, Poll::Ready(ToSwarm::GenerateEvent(ev)) => ev, diff --git a/substrate/client/network/src/protocol/notifications/handler.rs b/substrate/client/network/src/protocol/notifications/handler.rs index d244307f25c6..28662be29fee 100644 --- a/substrate/client/network/src/protocol/notifications/handler.rs +++ b/substrate/client/network/src/protocol/notifications/handler.rs @@ -349,7 +349,7 @@ pub struct NotificationsSink { } impl NotificationsSink { - /// Create new + /// Create new [`NotificationsSink`]. /// NOTE: only used for testing but must be `pub` as other crates in `client/network` use this. pub fn new( peer_id: PeerId, diff --git a/substrate/client/network/src/protocol/notifications/service/metrics.rs b/substrate/client/network/src/protocol/notifications/service/metrics.rs index 7d2dd8a818a0..2a57d57c1757 100644 --- a/substrate/client/network/src/protocol/notifications/service/metrics.rs +++ b/substrate/client/network/src/protocol/notifications/service/metrics.rs @@ -45,7 +45,7 @@ impl Metrics { HistogramVec::new( HistogramOpts { common_opts: Opts::new( - "substrate_sub_libp2p_notification_service_total_sizes", + "substrate_sub_libp2p_notifications_sizes", "Sizes of the notifications send to and received from all nodes", ), buckets: prometheus::exponential_buckets(64.0, 4.0, 8) @@ -58,7 +58,7 @@ impl Metrics { notifications_streams_closed_total: prometheus::register( CounterVec::new( Opts::new( - "substrate_sub_libp2p_notification_service_streams_closed_total", + "substrate_sub_libp2p_notifications_streams_closed_total", "Total number of notification substreams that have been closed", ), &["protocol"], @@ -68,7 +68,7 @@ impl Metrics { notifications_streams_opened_total: prometheus::register( CounterVec::new( Opts::new( - "substrate_sub_libp2p_notification_service_streams_opened_total", + "substrate_sub_libp2p_notifications_streams_opened_total", "Total number of notification substreams that have been opened", ), &["protocol"], diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs index e7bc8255b515..62e6d88a3d5a 100644 --- a/substrate/client/network/src/protocol/notifications/service/mod.rs +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -46,7 +46,7 @@ pub(crate) mod metrics; mod tests; /// Logging target for the file. -const LOG_TARGET: &str = "notification-service"; +const LOG_TARGET: &str = "sub-libp2p"; /// Default command queue size. const COMMAND_QUEUE_SIZE: usize = 64; @@ -231,8 +231,6 @@ impl NotificationService for NotificationHandle { /// Send synchronous `notification` to `peer`. fn send_sync_notification(&self, peer: &PeerId, notification: Vec) { - log::trace!(target: LOG_TARGET, "{}: send sync notification to {peer:?}", self.protocol); - if let Some(info) = self.peers.get(&peer) { metrics::register_notification_sent( &info.sink.metrics(), @@ -250,8 +248,6 @@ impl NotificationService for NotificationHandle { peer: &PeerId, notification: Vec, ) -> Result<(), error::Error> { - log::trace!(target: LOG_TARGET, "{}: send async notification to {peer:?}", self.protocol); - let notification_len = notification.len(); let sink = &self.peers.get(&peer).ok_or_else(|| error::Error::PeerDoesntExist(*peer))?.sink; diff --git a/substrate/client/network/src/protocol/notifications/tests.rs b/substrate/client/network/src/protocol/notifications/tests.rs index f3ad0e2f34ee..92d269f89c31 100644 --- a/substrate/client/network/src/protocol/notifications/tests.rs +++ b/substrate/client/network/src/protocol/notifications/tests.rs @@ -109,7 +109,6 @@ fn build_nodes() -> (Swarm, Swarm) { }, notif_handle, command_stream, - // protocol_handle_pair, )), ), peer_store_future: peer_store.run().boxed(), diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index 0411942ce2e0..fd3bcd72878e 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -382,7 +382,6 @@ where ¶ms.metrics_registry, notification_protocols, params.block_announce_config, - params.peer_store.clone(), protocol_handles.clone(), from_protocol_controllers, )?; @@ -1009,7 +1008,6 @@ where } } -// TODO(aaro): remove this trait impl NetworkNotification for NetworkService where B: BlockT + 'static, diff --git a/substrate/client/network/src/service/metrics.rs b/substrate/client/network/src/service/metrics.rs index 13bc4b4e7aff..c349fd98c76b 100644 --- a/substrate/client/network/src/service/metrics.rs +++ b/substrate/client/network/src/service/metrics.rs @@ -61,9 +61,6 @@ pub struct Metrics { pub kbuckets_num_nodes: GaugeVec, pub listeners_local_addresses: Gauge, pub listeners_errors_total: Counter, - pub notifications_sizes: HistogramVec, - pub notifications_streams_closed_total: CounterVec, - pub notifications_streams_opened_total: CounterVec, pub peerset_num_discovered: Gauge, pub pending_connections: Gauge, pub pending_connections_errors_total: CounterVec, @@ -153,31 +150,6 @@ impl Metrics { "substrate_sub_libp2p_listeners_errors_total", "Total number of non-fatal errors reported by a listener" )?, registry)?, - notifications_sizes: prometheus::register(HistogramVec::new( - HistogramOpts { - common_opts: Opts::new( - "substrate_sub_libp2p_notifications_sizes", - "Sizes of the notifications send to and received from all nodes" - ), - buckets: prometheus::exponential_buckets(64.0, 4.0, 8) - .expect("parameters are always valid values; qed"), - }, - &["direction", "protocol"] - )?, registry)?, - notifications_streams_closed_total: prometheus::register(CounterVec::new( - Opts::new( - "substrate_sub_libp2p_notifications_streams_closed_total", - "Total number of notification substreams that have been closed" - ), - &["protocol"] - )?, registry)?, - notifications_streams_opened_total: prometheus::register(CounterVec::new( - Opts::new( - "substrate_sub_libp2p_notifications_streams_opened_total", - "Total number of notification substreams that have been opened" - ), - &["protocol"] - )?, registry)?, peerset_num_discovered: prometheus::register(Gauge::new( "substrate_sub_libp2p_peerset_num_discovered", "Number of nodes stored in the peerset manager", diff --git a/substrate/client/network/statement/src/lib.rs b/substrate/client/network/statement/src/lib.rs index abbe4d90498b..5187e681d83c 100644 --- a/substrate/client/network/statement/src/lib.rs +++ b/substrate/client/network/statement/src/lib.rs @@ -308,8 +308,13 @@ where fn handle_notification_event(&mut self, event: NotificationEvent) { match event { - NotificationEvent::ValidateInboundSubstream { result_tx, .. } => { - let _ = result_tx.send(ValidationResult::Accept); + NotificationEvent::ValidateInboundSubstream { peer, handshake, result_tx, .. } => { + // only accept peers whose role can be determined + let result = self + .network + .peer_role(peer, handshake) + .map_or(ValidationResult::Reject, |_| ValidationResult::Accept); + let _ = result_tx.send(result); }, NotificationEvent::NotificationStreamOpened { peer, handshake, .. } => { let Some(role) = self.network.peer_role(peer, handshake) else { From 20395c67499695ccb9abf85fd0b29c58bf29ed9f Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Thu, 23 Nov 2023 12:06:55 +0200 Subject: [PATCH 29/32] Updates --- substrate/client/network/src/protocol.rs | 121 ++++++++++++++++++----- substrate/client/network/src/service.rs | 6 +- 2 files changed, 101 insertions(+), 26 deletions(-) diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index e9ce2d6f4564..ea7977cc9ae2 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -18,6 +18,7 @@ use crate::{ config, error, + peer_store::{PeerStoreHandle, PeerStoreProvider}, protocol_controller::{self, SetId}, service::traits::Direction, types::ProtocolName, @@ -34,12 +35,13 @@ use libp2p::{ }; use log::warn; +use codec::DecodeAll; use prometheus_endpoint::Registry; use sc_network_common::role::Roles; use sc_utils::mpsc::TracingUnboundedReceiver; use sp_runtime::traits::Block as BlockT; -use std::{iter, task::Poll}; +use std::{collections::HashSet, iter, task::Poll}; use notifications::{Notifications, NotificationsOut}; @@ -58,7 +60,7 @@ pub mod message; pub(crate) const BLOCK_ANNOUNCES_TRANSACTIONS_SUBSTREAM_SIZE: u64 = 16 * 1024 * 1024; /// Identifier of the peerset for the block announces protocol. -const _HARDCODED_PEERSETS_SYNC: SetId = SetId::from(0); +const HARDCODED_PEERSETS_SYNC: SetId = SetId::from(0); // Lock must always be taken in order declared here. pub struct Protocol { @@ -66,6 +68,11 @@ pub struct Protocol { behaviour: Notifications, /// List of notifications protocols that have been registered. notification_protocols: Vec, + /// Handle to `PeerStore`. + peer_store_handle: PeerStoreHandle, + /// Streams for peers whose handshake couldn't be determined. + bad_handshake_streams: HashSet, + sync_handle: ProtocolHandle, _marker: std::marker::PhantomData, } @@ -76,6 +83,7 @@ impl Protocol { registry: &Option, notification_protocols: Vec, block_announces_protocol: config::NonDefaultSetConfig, + peer_store_handle: PeerStoreHandle, protocol_controller_handles: Vec, from_protocol_controllers: TracingUnboundedReceiver, ) -> error::Result<(Self, Vec)> { @@ -128,7 +136,10 @@ impl Protocol { let protocol = Self { behaviour, + sync_handle: handles[0].clone(), + peer_store_handle, notification_protocols, + bad_handshake_streams: HashSet::new(), // TODO: remove when `BlockAnnouncesHandshake` is moved away from `Protocol` _marker: Default::default(), }; @@ -136,6 +147,10 @@ impl Protocol { Ok((protocol, handles)) } + pub fn num_sync_peers(&self) -> usize { + self.sync_handle.num_peers() + } + /// Returns the list of all the peers we have an open channel to. pub fn open_peers(&self) -> impl Iterator { self.behaviour.open_peers() @@ -153,6 +168,15 @@ impl Protocol { warn!(target: "sub-libp2p", "disconnect_peer() with invalid protocol name") } } + + /// Check if role is available for `peer_id` by attempt to decode the handshake to roles and if + /// that fails, check if the role has been registered to `PeerStore`. + fn role_available(&self, peer_id: &PeerId, handshake: &Vec) -> bool { + match Roles::decode_all(&mut &handshake[..]) { + Ok(_) => true, + Err(_) => self.peer_store_handle.peer_role(&peer_id).is_some(), + } + } } /// Outcome of an incoming custom message. @@ -285,30 +309,81 @@ impl NetworkBehaviour for Protocol { notifications_sink, negotiated_fallback, .. - } => CustomMessageOutcome::NotificationStreamOpened { - remote: peer_id, - set_id, - direction, - negotiated_fallback, - received_handshake, - notifications_sink, - }, - NotificationsOut::CustomProtocolReplaced { peer_id, notifications_sink, set_id } => - CustomMessageOutcome::NotificationStreamReplaced { - remote: peer_id, - set_id, - notifications_sink, + } => + if set_id == HARDCODED_PEERSETS_SYNC { + let _ = self.sync_handle.report_substream_opened( + peer_id, + direction, + received_handshake, + negotiated_fallback, + notifications_sink, + ); + None + } else { + match self.role_available(&peer_id, &received_handshake) { + true => Some(CustomMessageOutcome::NotificationStreamOpened { + remote: peer_id, + set_id, + direction, + negotiated_fallback, + received_handshake, + notifications_sink, + }), + false => { + self.bad_handshake_streams.insert(peer_id); + None + }, + } }, - NotificationsOut::CustomProtocolClosed { peer_id, set_id } => - CustomMessageOutcome::NotificationStreamClosed { remote: peer_id, set_id }, - NotificationsOut::Notification { peer_id, set_id, message } => - CustomMessageOutcome::NotificationsReceived { - remote: peer_id, - set_id, - notification: message.freeze().into(), + NotificationsOut::CustomProtocolReplaced { peer_id, notifications_sink, set_id } => + if set_id == HARDCODED_PEERSETS_SYNC { + let _ = self + .sync_handle + .report_notification_sink_replaced(peer_id, notifications_sink); + None + } else { + (!self.bad_handshake_streams.contains(&peer_id)).then_some( + CustomMessageOutcome::NotificationStreamReplaced { + remote: peer_id, + set_id, + notifications_sink, + }, + ) }, + NotificationsOut::CustomProtocolClosed { peer_id, set_id } => { + if set_id == HARDCODED_PEERSETS_SYNC { + let _ = self.sync_handle.report_substream_closed(peer_id); + None + } else { + (!self.bad_handshake_streams.remove(&peer_id)).then_some( + CustomMessageOutcome::NotificationStreamClosed { remote: peer_id, set_id }, + ) + } + }, + NotificationsOut::Notification { peer_id, set_id, message } => { + if set_id == HARDCODED_PEERSETS_SYNC { + let _ = self + .sync_handle + .report_notification_received(peer_id, message.freeze().into()); + None + } else { + (!self.bad_handshake_streams.contains(&peer_id)).then_some( + CustomMessageOutcome::NotificationsReceived { + remote: peer_id, + set_id, + notification: message.freeze().into(), + }, + ) + } + }, }; - return Poll::Ready(ToSwarm::GenerateEvent(outcome)) + match outcome { + Some(event) => Poll::Ready(ToSwarm::GenerateEvent(event)), + None => { + cx.waker().wake_by_ref(); + Poll::Pending + }, + } } } diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index fd3bcd72878e..43a3ab09115c 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -382,6 +382,7 @@ where ¶ms.metrics_registry, notification_protocols, params.block_announce_config, + params.peer_store.clone(), protocol_handles.clone(), from_protocol_controllers, )?; @@ -560,7 +561,7 @@ where /// Returns the number of peers we're connected to. pub fn num_connected_peers(&self) -> usize { - self.notif_protocol_handles.get(0).map_or(0usize, |handle| handle.num_peers()) + self.network_service.behaviour().user_protocol().num_sync_peers() } /// Adds an address for a node. @@ -1235,8 +1236,7 @@ where }; // Update the `num_connected` count shared with the `NetworkService`. - let num_connected_peers = - self.notif_protocol_handles.get(0).map_or(0usize, |handle| handle.num_peers()); + let num_connected_peers = self.network_service.behaviour().user_protocol().num_sync_peers(); self.num_connected.store(num_connected_peers, Ordering::Relaxed); if let Some(metrics) = self.metrics.as_ref() { From e791de23fc2a0ba96b2bec42007cf01ce691b896 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 27 Nov 2023 11:48:05 +0200 Subject: [PATCH 30/32] Fix networkbridge test --- Cargo.lock | 2 +- polkadot/node/network/bridge/src/rx/tests.rs | 2 -- polkadot/node/network/bridge/src/tx/tests.rs | 14 +++++++------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15e06a87b222..d5d3f5642bbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13080,7 +13080,7 @@ dependencies = [ "hex-literal", "jsonrpsee", "log", - "nix 0.26.2", + "nix 0.26.4", "pallet-transaction-payment", "pallet-transaction-payment-rpc", "pallet-transaction-payment-rpc-runtime-api", diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 2f5cbb1a67ee..e0b86feb6442 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -353,7 +353,6 @@ impl MessageSink for TestMessageSink { } } -// TODO: how to implement this? #[async_trait::async_trait] impl NotificationService for TestNotificationService { /// Instruct `Notifications` to open a new substream for `peer`. @@ -406,7 +405,6 @@ impl NotificationService for TestNotificationService { /// Get notification sink of the peer. fn message_sink(&self, peer: &PeerId) -> Option> { - // TODO: verify that peer exists? Some(Box::new(TestMessageSink::new(*peer, self.peer_set, self.action_tx.clone()))) } } diff --git a/polkadot/node/network/bridge/src/tx/tests.rs b/polkadot/node/network/bridge/src/tx/tests.rs index 0f730d2efbec..c3cf0f322f68 100644 --- a/polkadot/node/network/bridge/src/tx/tests.rs +++ b/polkadot/node/network/bridge/src/tx/tests.rs @@ -30,7 +30,7 @@ use parity_scale_codec::DecodeAll; use polkadot_node_network_protocol::{ peer_set::{PeerSetProtocolNames, ValidationVersion}, request_response::{outgoing::Requests, ReqProtocolNames}, - v1 as protocol_v1, ObservedRole, Versioned, + v1 as protocol_v1, v2 as protocol_v2, ObservedRole, Versioned, }; use polkadot_node_subsystem::{FromOrchestra, OverseerSignal}; use polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle; @@ -368,9 +368,7 @@ fn send_messages_to_peers() { }); } -// TODO: discuss with parachains engineering #[test] -#[cfg(feature = "network-protocol-staging")] fn network_protocol_versioning_send() { test_harness(|test_harness| async move { let TestHarness { mut network_handle, mut virtual_overseer } = test_harness; @@ -400,9 +398,9 @@ fn network_protocol_versioning_send() { approval_distribution_message.clone(), ); - // Note that bridge doesn't ensure neither peer's protocol version - // or peer set match the message. - let receivers = vec![peer_ids[0], peer_ids[3]]; + // only `peer_ids[0]` opened the validation protocol v2 + // so only they will be sent a notification + let receivers = vec![peer_ids[0]]; virtual_overseer .send(FromOrchestra::Communication { msg: NetworkBridgeTxMessage::SendValidationMessage( @@ -442,7 +440,9 @@ fn network_protocol_versioning_send() { let msg = protocol_v2::CollationProtocol::CollatorProtocol(collator_protocol_message.clone()); - let receivers = vec![peer_ids[1], peer_ids[2]]; + // only `peer_ids[0]` opened the collation protocol v2 + // so only they will be sent a notification + let receivers = vec![peer_ids[1]]; virtual_overseer .send(FromOrchestra::Communication { From 691f4c821defa3ff5b9fffb5c45fc80060377f4f Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 27 Nov 2023 19:06:15 +0200 Subject: [PATCH 31/32] Update Cargo.lock --- Cargo.lock | 2026 +++++++++++++++++++++++++--------------------------- 1 file changed, 981 insertions(+), 1045 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 14eb87ed3945..4fa9e83a1736 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,33 +155,32 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.10", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", - "getrandom 0.2.11", + "getrandom 0.2.10", "once_cell", "version_check", - "zerocopy", ] [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" dependencies = [ "memchr", ] @@ -244,15 +243,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" [[package]] name = "anstyle-parse" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" dependencies = [ "utf8parse", ] @@ -307,9 +306,9 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" [[package]] name = "arc-swap" @@ -612,9 +611,9 @@ checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" [[package]] name = "array-bytes" -version = "6.2.0" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de17a919934ad8c5cc99a1a74de4e2dab95d6121a8f27f94755ff525b630382c" +checksum = "d9b1c5a481ec30a5abd8dfbd94ab5cf1bb4e9a66be7f1b3b322f2f1170c200fd" [[package]] name = "arrayref" @@ -656,7 +655,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time", + "time 0.3.27", ] [[package]] @@ -672,7 +671,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time", + "time 0.3.27", ] [[package]] @@ -719,7 +718,7 @@ dependencies = [ "anstyle", "bstr", "doc-comment", - "predicates 3.0.4", + "predicates 3.0.3", "predicates-core", "predicates-tree", "wait-timeout", @@ -1183,34 +1182,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37875bd9915b7d67c2f117ea2c30a0989874d0b2cb694fe25403c85763c0c9e" -dependencies = [ - "concurrent-queue", - "event-listener 3.1.0", - "event-listener-strategy", + "event-listener", "futures-core", - "pin-project-lite 0.2.13", ] [[package]] name = "async-executor" -version = "1.7.2" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc5ea910c42e5ab19012bab31f53cb4d63d54c3a27730f9a833a88efcf4bb52d" +checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" dependencies = [ - "async-lock 3.1.1", + "async-lock", "async-task", "concurrent-queue", - "fastrand 2.0.1", - "futures-lite 2.0.1", + "fastrand 1.9.0", + "futures-lite", "slab", ] @@ -1220,10 +1206,10 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" dependencies = [ - "async-lock 2.8.0", + "async-lock", "autocfg", "blocking", - "futures-lite 1.13.0", + "futures-lite", ] [[package]] @@ -1232,38 +1218,18 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ - "async-lock 2.8.0", + "async-lock", "autocfg", "cfg-if", "concurrent-queue", - "futures-lite 1.13.0", + "futures-lite", "log", "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2 0.4.10", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9d5715c2d329bf1b4da8d60455b99b187f27ba726df2883799af9af60997" -dependencies = [ - "async-lock 3.1.1", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite 2.0.1", - "parking", - "polling 3.3.0", - "rustix 0.38.25", + "polling", + "rustix 0.37.23", "slab", - "tracing", + "socket2 0.4.9", "waker-fn", - "windows-sys 0.48.0", ] [[package]] @@ -1272,63 +1238,36 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener 2.5.3", -] - -[[package]] -name = "async-lock" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655b9c7fe787d3b25cc0f804a1a8401790f0c5bc395beb5a64dc77d8de079105" -dependencies = [ - "event-listener 3.1.0", - "event-listener-strategy", - "pin-project-lite 0.2.13", + "event-listener", ] [[package]] name = "async-net" -version = "1.8.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f" +checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f" dependencies = [ - "async-io 1.13.0", + "async-io", + "autocfg", "blocking", - "futures-lite 1.13.0", + "futures-lite", ] [[package]] name = "async-process" -version = "1.8.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" dependencies = [ - "async-io 1.13.0", - "async-lock 2.8.0", - "async-signal", + "async-io", + "async-lock", + "autocfg", "blocking", "cfg-if", - "event-listener 3.1.0", - "futures-lite 1.13.0", - "rustix 0.38.25", - "windows-sys 0.48.0", -] - -[[package]] -name = "async-signal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" -dependencies = [ - "async-io 2.2.0", - "async-lock 2.8.0", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 0.38.25", - "signal-hook-registry", - "slab", + "event-listener", + "futures-lite", + "rustix 0.37.23", + "signal-hook", "windows-sys 0.48.0", ] @@ -1340,7 +1279,7 @@ checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", ] [[package]] @@ -1351,24 +1290,24 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] name = "async-task" -version = "4.5.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" +checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -1381,7 +1320,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", ] [[package]] @@ -1392,9 +1331,9 @@ checksum = "a8ab6b55fe97976e46f91ddbed8d147d966475dc29b2032757ba47e02376fbc3" [[package]] name = "atomic-waker" -version = "1.1.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" [[package]] name = "atty" @@ -1424,7 +1363,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.32.1", + "object 0.32.0", "rustc-demangle", ] @@ -1445,7 +1384,7 @@ dependencies = [ "rand_chacha 0.3.1", "rand_core 0.6.4", "ring 0.1.0", - "sha2 0.10.8", + "sha2 0.10.7", "sp-ark-bls12-381", "sp-ark-ed-on-bls12-381-bandersnatch", "zeroize", @@ -1477,9 +1416,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "base64ct" @@ -1489,9 +1428,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "basic-toml" -version = "0.1.7" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f2139706359229bfa8f19142ac1155b4b80beafb7a60471ac5dd109d4a19778" +checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" dependencies = [ "serde", ] @@ -1509,7 +1448,7 @@ dependencies = [ name = "binary-merkle-tree" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "env_logger 0.9.3", "hash-db", "log", @@ -1538,13 +1477,13 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "prettyplease 0.2.15", + "prettyplease 0.2.12", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -1574,9 +1513,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bitvec" @@ -1624,24 +1563,24 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", "arrayvec 0.7.4", - "constant_time_eq 0.3.0", + "constant_time_eq 0.2.6", ] [[package]] name = "blake2s_simd" -version = "1.0.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" +checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" dependencies = [ "arrayref", "arrayvec 0.7.4", - "constant_time_eq 0.3.0", + "constant_time_eq 0.2.6", ] [[package]] @@ -1714,25 +1653,24 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "blocking" -version = "1.5.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" dependencies = [ - "async-channel 2.1.0", - "async-lock 3.1.1", + "async-channel", + "async-lock", "async-task", - "fastrand 2.0.1", - "futures-io", - "futures-lite 2.0.1", - "piper", - "tracing", + "atomic-waker", + "fastrand 1.9.0", + "futures-lite", + "log", ] [[package]] name = "bounded-collections" -version = "0.1.9" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca548b6163b872067dc5eb82fd130c56881435e30367d2073594a3d9744120dd" +checksum = "eb5b05133427c07c4776906f673ccf36c21b102c9829c641a5b56bd151d44fd6" dependencies = [ "log", "parity-scale-codec", @@ -2501,12 +2439,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.8.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" +checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", - "regex-automata 0.4.3", + "regex-automata 0.3.6", "serde", ] @@ -2521,9 +2459,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byte-slice-cast" @@ -2539,21 +2477,21 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.14.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" -version = "1.5.0" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.5.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "bzip2-sys" @@ -2587,9 +2525,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.5" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34637b3140142bdf929fb439e8aa4ebad7651ebf7b1080b3930aa16ac1459ff" +checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" dependencies = [ "serde", ] @@ -2602,7 +2540,7 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver 1.0.20", + "semver 1.0.18", "serde", "serde_json", "thiserror", @@ -2675,6 +2613,18 @@ dependencies = [ "keystream", ] +[[package]] +name = "chacha20" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +dependencies = [ + "cfg-if", + "cipher 0.3.0", + "cpufeatures", + "zeroize", +] + [[package]] name = "chacha20" version = "0.9.1" @@ -2688,27 +2638,28 @@ dependencies = [ [[package]] name = "chacha20poly1305" -version = "0.10.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" dependencies = [ - "aead 0.5.2", - "chacha20", - "cipher 0.4.4", - "poly1305", + "aead 0.4.3", + "chacha20 0.8.2", + "cipher 0.3.0", + "poly1305 0.7.2", "zeroize", ] [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "f56b4c72906975ca04becb8a30e102dfecddd0c06181e3e95ddc444be28881f8" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", + "time 0.1.45", "wasm-bindgen", "windows-targets 0.48.5", ] @@ -2779,7 +2730,6 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", - "zeroize", ] [[package]] @@ -2821,34 +2771,34 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.8" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" dependencies = [ "clap_builder", - "clap_derive 4.4.7", + "clap_derive 4.4.2", ] [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" dependencies = [ "anstream", "anstyle", - "clap_lex 0.6.0", + "clap_lex 0.5.1", "strsim", "terminal_size", ] [[package]] name = "clap_complete" -version = "4.4.4" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae" +checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", ] [[package]] @@ -2866,14 +2816,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -2887,15 +2837,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "coarsetime" -version = "0.1.33" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71367d3385c716342014ad17e3d19f7788ae514885a1f4c24f500260fb365e1a" +checksum = "a90d114103adbc625300f346d4d09dfb4ab1c4a8df6868435dd903392ecf4354" dependencies = [ "libc", "once_cell", @@ -3074,18 +3024,18 @@ dependencies = [ [[package]] name = "color-print" -version = "0.3.5" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a858372ff14bab9b1b30ea504f2a4bc534582aee3e42ba2d41d2a7baba63d5d" +checksum = "f2a5e6504ed8648554968650feecea00557a3476bc040d0ffc33080e66b646d0" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.5" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e37866456a721d0a404439a1adae37a31be4e0055590d053dfe6981e05003f" +checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" dependencies = [ "nom", "proc-macro2", @@ -3101,12 +3051,12 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "comfy-table" -version = "7.1.0" +version = "7.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c64043d6c7b7a4c58e39e7efccfdea7b93d885a795d0c054a69dbbf4dd52686" +checksum = "9ab77dbd8adecaf3f0db40581631b995f312a8a5ae3aa9993188bb8f23d83a5b" dependencies = [ - "strum 0.25.0", - "strum_macros 0.25.3", + "strum", + "strum_macros", "unicode-width", ] @@ -3133,9 +3083,9 @@ checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" [[package]] name = "concurrent-queue" -version = "2.3.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" dependencies = [ "crossbeam-utils", ] @@ -3161,21 +3111,23 @@ checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "const-random" -version = "0.1.17" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" +checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e" dependencies = [ "const-random-macro", + "proc-macro-hack", ] [[package]] name = "const-random-macro" -version = "0.1.16" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.10", "once_cell", + "proc-macro-hack", "tiny-keccak", ] @@ -3185,6 +3137,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "constant_time_eq" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" + [[package]] name = "constant_time_eq" version = "0.3.0" @@ -3193,9 +3151,9 @@ checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "constcat" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08" +checksum = "f272d0c4cf831b4fa80ee529c7707f76585986e910e1fbce1d7921970bc1a241" [[package]] name = "contracts-rococo-runtime" @@ -3323,9 +3281,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -3439,9 +3397,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.4.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" [[package]] name = "crc32fast" @@ -3489,7 +3447,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.8", + "clap 4.4.6", "criterion-plot", "futures", "is-terminal", @@ -3518,6 +3476,16 @@ dependencies = [ "itertools 0.10.5", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -3581,9 +3549,9 @@ dependencies = [ [[package]] name = "crypto-bigint" -version = "0.5.5" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", @@ -3654,7 +3622,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.1.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3984,7 +3952,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -4203,7 +4171,7 @@ dependencies = [ name = "cumulus-relay-chain-minimal-node" version = "0.1.0" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "async-trait", "cumulus-primitives-core", "cumulus-relay-chain-interface", @@ -4359,7 +4327,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.4.8", + "clap 4.4.6", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -4459,9 +4427,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.1.1" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +checksum = "f711ade317dd348950a9910f81c5947e3d8907ebd2b83f76203ff1807e6a2bc2" dependencies = [ "cfg-if", "cpufeatures", @@ -4476,13 +4444,13 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -4500,9 +4468,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.110" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7129e341034ecb940c9072817cd9007974ea696844fc4dd582dc1653a7fbe2e8" +checksum = "28403c86fc49e3401fdf45499ba37fad6493d9329449d6449d7f0e10f4654d28" dependencies = [ "cc", "cxxbridge-flags", @@ -4512,9 +4480,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.110" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a24f3f5f8eed71936f21e570436f024f5c2e25628f7496aa7ccd03b90109d5" +checksum = "78da94fef01786dc3e0c76eafcd187abcaa9972c78e05ff4041e24fdf059c285" dependencies = [ "cc", "codespan-reporting", @@ -4522,24 +4490,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] name = "cxxbridge-flags" -version = "1.0.110" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06fdd177fc61050d63f67f5bd6351fac6ab5526694ea8e359cd9cd3b75857f44" +checksum = "e2a6f5e1dfb4b34292ad4ea1facbfdaa1824705b231610087b00b17008641809" [[package]] name = "cxxbridge-macro" -version = "1.0.110" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f" +checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -4579,28 +4547,28 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.5.3" +version = "5.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "edd72493923899c6f10c641bdbdeddc7183d6396641d99c1a0d1597f37f92e28" dependencies = [ "cfg-if", - "hashbrown 0.14.2", + "hashbrown 0.14.0", "lock_api", "once_cell", - "parking_lot_core 0.9.9", + "parking_lot_core 0.9.8", ] [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "data-encoding-macro" -version = "0.1.14" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20c01c06f5f429efdf2bae21eb67c28b3df3cf85b7dd2d8ef09c0838dac5d33e" +checksum = "c904b33cc60130e1aeea4956ab803d08a3f4a0ca82d64ed757afac3891f2bb99" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -4608,9 +4576,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.12" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0047d07f2c89b17dd631c80450d69841a6b5d7fb17278cbc43d7e4cfcf2576f3" +checksum = "8fdf3fce3ce863539ec1d7fd1b6dcc3c645663376b43ed376bbf887733e4f772" dependencies = [ "data-encoding", "syn 1.0.109", @@ -4676,12 +4644,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" -dependencies = [ - "powerfmt", -] +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" [[package]] name = "derivative" @@ -4841,7 +4806,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -4903,9 +4868,9 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.39", + "syn 2.0.38", "termcolor", - "toml 0.7.8", + "toml 0.7.6", "walkdir", ] @@ -4950,9 +4915,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.16" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" +checksum = "bbfc4744c1b8f2a09adc0e55242f60b1af195d88596bd8700be74418c056c555" [[package]] name = "ecdsa" @@ -4968,40 +4933,39 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.16.9" +version = "0.16.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" dependencies = [ "der 0.7.8", "digest 0.10.7", - "elliptic-curve 0.13.8", + "elliptic-curve 0.13.5", "rfc6979 0.4.0", - "signature 2.2.0", + "signature 2.1.0", "spki 0.7.2", ] [[package]] name = "ed25519" -version = "2.2.3" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" dependencies = [ "pkcs8 0.10.2", - "signature 2.2.0", + "signature 2.1.0", ] [[package]] name = "ed25519-dalek" -version = "2.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" +checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.0.0", "ed25519", "rand_core 0.6.4", "serde", - "sha2 0.10.8", - "subtle 2.4.1", + "sha2 0.10.7", "zeroize", ] @@ -5021,16 +4985,16 @@ dependencies = [ [[package]] name = "ed25519-zebra" -version = "4.0.3" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" +checksum = "4e83e509bcd060ca4b54b72bde5bb306cb2088cb01e14797ebae90a24f70f5f7" dependencies = [ - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.0.0", "ed25519", - "hashbrown 0.14.2", + "hashbrown 0.14.0", "hex", "rand_core 0.6.4", - "sha2 0.10.8", + "sha2 0.10.7", "zeroize", ] @@ -5064,12 +5028,12 @@ dependencies = [ [[package]] name = "elliptic-curve" -version = "0.13.8" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" dependencies = [ "base16ct 0.2.0", - "crypto-bigint 0.5.5", + "crypto-bigint 0.5.2", "digest 0.10.7", "ff 0.13.0", "generic-array 0.14.7", @@ -5144,22 +5108,22 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.7.8" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5998b4f30320c9d93aed72f63af821bfdac50465b75428fce77b48ec482c3939" +checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.7.8" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" +checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -5170,7 +5134,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -5188,9 +5152,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ "humantime", "is-terminal", @@ -5213,9 +5177,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "erased-serde" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" +checksum = "837c0466252947ada828b975e12daf82e18bb5444e4df87be6038d4469e2a3d2" dependencies = [ "serde", ] @@ -5232,14 +5196,25 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.7" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ + "errno-dragonfly", "libc", "windows-sys 0.48.0", ] +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "ethbloom" version = "0.13.0" @@ -5273,27 +5248,6 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" -[[package]] -name = "event-listener" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite 0.2.13", -] - -[[package]] -name = "event-listener-strategy" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160" -dependencies = [ - "event-listener 3.1.0", - "pin-project-lite 0.2.13", -] - [[package]] name = "exit-future" version = "0.2.0" @@ -5325,14 +5279,14 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] name = "eyre" -version = "0.6.9" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" dependencies = [ "indenter", "once_cell", @@ -5361,9 +5315,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "fatality" @@ -5451,9 +5405,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.5" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" [[package]] name = "file-per-thread-logger" @@ -5461,7 +5415,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger 0.10.1", + "env_logger 0.10.0", "log", ] @@ -5526,9 +5480,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", "libz-sys", @@ -5616,7 +5570,7 @@ dependencies = [ name = "frame-benchmarking" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "frame-support", "frame-support-procedural", "frame-system", @@ -5644,9 +5598,9 @@ name = "frame-benchmarking-cli" version = "4.0.0-dev" dependencies = [ "Inflector", - "array-bytes 6.2.0", + "array-bytes 6.1.0", "chrono", - "clap 4.4.8", + "clap 4.4.6", "comfy-table", "frame-benchmarking", "frame-support", @@ -5712,7 +5666,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.39", + "syn 2.0.38", "trybuild", ] @@ -5738,7 +5692,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -5755,7 +5709,7 @@ dependencies = [ name = "frame-executive" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "frame-support", "frame-system", "frame-try-runtime", @@ -5811,7 +5765,7 @@ name = "frame-support" version = "4.0.0-dev" dependencies = [ "aquamarine", - "array-bytes 6.2.0", + "array-bytes 6.1.0", "assert_matches", "bitflags 1.3.2", "docify", @@ -5864,7 +5818,7 @@ dependencies = [ "proc-macro2", "quote", "sp-core-hashing", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -5875,7 +5829,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -5884,7 +5838,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -6009,12 +5963,9 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.11.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" -dependencies = [ - "autocfg", -] +checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" [[package]] name = "fs2" @@ -6032,7 +5983,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47" dependencies = [ - "rustix 0.38.25", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -6050,9 +6001,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.29" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -6065,9 +6016,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -6075,15 +6026,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -6093,9 +6044,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-lite" @@ -6108,33 +6059,19 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "waker-fn", ] -[[package]] -name = "futures-lite" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" -dependencies = [ - "fastrand 2.0.1", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite 0.2.13", -] - [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -6144,21 +6081,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls 0.20.9", - "webpki 0.22.4", + "rustls 0.20.8", + "webpki 0.22.0", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-timer" @@ -6168,9 +6105,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -6179,7 +6116,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "pin-utils", "slab", ] @@ -6249,9 +6186,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -6428,9 +6365,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.22" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ "bytes", "fnv", @@ -6438,7 +6375,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.1.0", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -6453,9 +6390,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "handlebars" -version = "4.5.0" +version = "4.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225" +checksum = "83c3372087601b532857d332f5957cbae686da52bb7810bf038c3e3c3cc2fa0d" dependencies = [ "log", "pest", @@ -6486,7 +6423,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.6", ] [[package]] @@ -6495,16 +6432,16 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.3", ] [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.3", "allocator-api2", "serde", ] @@ -6515,7 +6452,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.2", + "hashbrown 0.14.0", ] [[package]] @@ -6535,9 +6472,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -6600,15 +6537,6 @@ dependencies = [ "hmac 0.8.1", ] -[[package]] -name = "home" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" -dependencies = [ - "windows-sys 0.48.0", -] - [[package]] name = "honggfuzz" version = "0.5.55" @@ -6617,7 +6545,7 @@ checksum = "848e9c511092e0daa0a35a63e8e6e475a3e8f870741448b9f6028d69b142f18e" dependencies = [ "arbitrary", "lazy_static", - "memmap2 0.5.10", + "memmap2", "rustc_version 0.4.0", ] @@ -6634,9 +6562,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", @@ -6651,7 +6579,7 @@ checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", ] [[package]] @@ -6694,8 +6622,8 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.13", - "socket2 0.4.10", + "pin-project-lite 0.2.12", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -6704,33 +6632,33 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ "futures-util", "http", "hyper", "log", - "rustls 0.21.9", + "rustls 0.21.6", "rustls-native-certs", "tokio", "tokio-rustls", - "webpki-roots 0.25.2", + "webpki-roots 0.23.1", ] [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows 0.48.0", ] [[package]] @@ -6771,21 +6699,21 @@ dependencies = [ [[package]] name = "if-addrs" -version = "0.10.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" +checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" dependencies = [ "libc", - "windows-sys 0.48.0", + "winapi", ] [[package]] name = "if-watch" -version = "3.2.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" +checksum = "a9465340214b296cd17a0009acdb890d6160010b8adf8f78a00d0d7ab270f79f" dependencies = [ - "async-io 2.2.0", + "async-io", "core-foundation", "fnv", "futures", @@ -6795,7 +6723,7 @@ dependencies = [ "rtnetlink", "system-configuration", "tokio", - "windows", + "windows 0.34.0", ] [[package]] @@ -6885,12 +6813,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown 0.14.0", ] [[package]] @@ -6901,9 +6829,9 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "indicatif" -version = "0.17.7" +version = "0.17.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" dependencies = [ "console", "instant", @@ -6970,7 +6898,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi 0.3.2", "libc", "windows-sys 0.48.0", ] @@ -6987,7 +6915,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.5", + "socket2 0.5.3", "widestring", "windows-sys 0.48.0", "winreg", @@ -6995,9 +6923,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" @@ -7005,8 +6933,8 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.3", - "rustix 0.38.25", + "hermit-abi 0.3.2", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -7045,18 +6973,18 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -7069,9 +6997,9 @@ checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" [[package]] name = "json-patch" -version = "1.2.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ff1e1486799e3f64129f8ccad108b38290df9cd7015cd31bed17239f0789d6" +checksum = "1f54898088ccb91df1b492cc80029a6fdf1c48ca0db7c6822a8babad69c94658" dependencies = [ "serde", "serde_json", @@ -7122,7 +7050,7 @@ checksum = "2b5dde66c53d6dcdc8caea1874a45632ec0fcf5b437789f1e45766a1512ce803" dependencies = [ "anyhow", "arrayvec 0.7.4", - "async-lock 2.8.0", + "async-lock", "async-trait", "beef", "futures-channel", @@ -7224,15 +7152,15 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if", - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", + "ecdsa 0.16.8", + "elliptic-curve 0.13.5", "once_cell", - "sha2 0.10.8", + "sha2 0.10.7", ] [[package]] @@ -7461,9 +7389,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libflate" @@ -7508,9 +7436,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "libp2p" @@ -7521,7 +7449,7 @@ dependencies = [ "bytes", "futures", "futures-timer", - "getrandom 0.2.11", + "getrandom 0.2.10", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -7647,7 +7575,7 @@ dependencies = [ "multihash", "quick-protobuf", "rand 0.8.5", - "sha2 0.10.8", + "sha2 0.10.7", "thiserror", "zeroize", ] @@ -7672,7 +7600,7 @@ dependencies = [ "log", "quick-protobuf", "rand 0.8.5", - "sha2 0.10.8", + "sha2 0.10.7", "smallvec", "thiserror", "uint", @@ -7695,7 +7623,7 @@ dependencies = [ "log", "rand 0.8.5", "smallvec", - "socket2 0.4.10", + "socket2 0.4.9", "tokio", "trust-dns-proto", "void", @@ -7730,7 +7658,7 @@ dependencies = [ "once_cell", "quick-protobuf", "rand 0.8.5", - "sha2 0.10.8", + "sha2 0.10.7", "snow", "static_assertions", "thiserror", @@ -7772,7 +7700,7 @@ dependencies = [ "parking_lot 0.12.1", "quinn-proto", "rand 0.8.5", - "rustls 0.20.9", + "rustls 0.20.8", "thiserror", "tokio", ] @@ -7837,7 +7765,7 @@ dependencies = [ "libc", "libp2p-core", "log", - "socket2 0.4.10", + "socket2 0.4.9", "tokio", ] @@ -7853,9 +7781,9 @@ dependencies = [ "libp2p-identity", "rcgen 0.10.0", "ring 0.16.20", - "rustls 0.20.9", + "rustls 0.20.8", "thiserror", - "webpki 0.22.4", + "webpki 0.22.0", "x509-parser 0.14.0", "yasna", ] @@ -7937,17 +7865,6 @@ dependencies = [ "yamux", ] -[[package]] -name = "libredox" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" -dependencies = [ - "bitflags 2.4.1", - "libc", - "redox_syscall 0.4.1", -] - [[package]] name = "librocksdb-sys" version = "0.11.0+8.1.1" @@ -8048,9 +7965,9 @@ dependencies = [ [[package]] name = "linregress" -version = "0.5.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de04dcecc58d366391f9920245b85ffa684558a5ef6e7736e754347c3aea9c2" +checksum = "4de0b5f52a9f84544d268f5fabb71b38962d6aa3c6600b8bcd27d44ccf9c9c45" dependencies = [ "nalgebra", ] @@ -8069,9 +7986,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "lioness" @@ -8105,9 +8022,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -8143,9 +8060,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.11.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" +checksum = "eedb2bdbad7e0634f83989bf596f497b070130daaa398ab22d84c39e266deec5" [[package]] name = "lru-cache" @@ -8194,7 +8111,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -8208,7 +8125,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -8219,7 +8136,7 @@ checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -8230,7 +8147,7 @@ checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -8262,9 +8179,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matrixmultiply" -version = "0.3.8" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" dependencies = [ "autocfg", "rawpointer", @@ -8272,11 +8189,10 @@ dependencies = [ [[package]] name = "md-5" -version = "0.10.6" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" dependencies = [ - "cfg-if", "digest 0.10.7", ] @@ -8288,11 +8204,11 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memfd" -version = "0.6.4" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" dependencies = [ - "rustix 0.38.25", + "rustix 0.37.23", ] [[package]] @@ -8305,21 +8221,12 @@ dependencies = [ ] [[package]] -name = "memmap2" -version = "0.8.0" +name = "memoffset" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", + "autocfg", ] [[package]] @@ -8409,7 +8316,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" name = "minimal-node" version = "4.0.0-dev" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "frame", "futures", "futures-timer", @@ -8468,9 +8375,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -8488,7 +8395,7 @@ dependencies = [ "bitflags 1.3.2", "blake2 0.10.6", "c2-chacha", - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.0.0", "either", "hashlink", "lioness", @@ -8610,7 +8517,7 @@ dependencies = [ "core2", "digest 0.10.7", "multihash-derive", - "sha2 0.10.8", + "sha2 0.10.7", "sha3", "unsigned-varint", ] @@ -8781,15 +8688,16 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.4" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", "memoffset 0.7.1", "pin-utils", + "static_assertions", ] [[package]] @@ -8798,7 +8706,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.0", "cfg-if", "libc", ] @@ -8813,8 +8721,8 @@ checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" name = "node-bench" version = "0.9.0-dev" dependencies = [ - "array-bytes 6.2.0", - "clap 4.4.8", + "array-bytes 6.1.0", + "clap 4.4.6", "derive_more", "fs_extra", "futures", @@ -8889,7 +8797,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "generate-bags", "kitchensink-runtime", ] @@ -8898,7 +8806,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -8942,7 +8850,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "flate2", "fs_extra", "glob", @@ -9135,9 +9043,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", "libm", @@ -9149,7 +9057,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi 0.3.2", "libc", ] @@ -9173,9 +9081,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" dependencies = [ "memchr", ] @@ -9260,7 +9168,7 @@ dependencies = [ "anyhow", "expander 2.0.0", "fs-err", - "indexmap 2.1.0", + "indexmap 2.0.0", "itertools 0.11.0", "layout-rs", "petgraph", @@ -9291,9 +9199,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.6.1" +version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" [[package]] name = "owo-colors" @@ -9309,7 +9217,7 @@ checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ "ecdsa 0.14.8", "elliptic-curve 0.12.3", - "sha2 0.10.8", + "sha2 0.10.7", ] [[package]] @@ -9320,14 +9228,14 @@ checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa" dependencies = [ "ecdsa 0.14.8", "elliptic-curve 0.12.3", - "sha2 0.10.8", + "sha2 0.10.7", ] [[package]] name = "pallet-alliance" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "frame-benchmarking", "frame-support", "frame-system", @@ -9630,7 +9538,7 @@ dependencies = [ name = "pallet-beefy-mmr" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "binary-merkle-tree", "frame-support", "frame-system", @@ -9851,7 +9759,7 @@ dependencies = [ name = "pallet-contracts" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "assert_matches", "bitflags 1.3.2", "env_logger 0.9.3", @@ -9957,7 +9865,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -10094,7 +10002,7 @@ dependencies = [ "sp-runtime", "sp-std 8.0.0", "sp-tracing 10.0.0", - "strum 0.24.1", + "strum", ] [[package]] @@ -10439,7 +10347,7 @@ dependencies = [ name = "pallet-mmr" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "env_logger 0.9.3", "frame-benchmarking", "frame-support", @@ -11071,7 +10979,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -11252,7 +11160,7 @@ dependencies = [ name = "pallet-transaction-storage" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "frame-benchmarking", "frame-support", "frame-system", @@ -11452,7 +11360,7 @@ dependencies = [ name = "parachain-template-node" version = "0.1.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -11633,9 +11541,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.12" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e9ab494af9e6e813c72170f0d3c1de1500990d62c97cc05cc7576f91aa402f" +checksum = "78f19d20a0d2cc52327a88d131fa1c4ea81ea4a04714aedcfeca2dd410049cf8" dependencies = [ "blake2 0.10.6", "crc32fast", @@ -11644,7 +11552,7 @@ dependencies = [ "libc", "log", "lz4", - "memmap2 0.5.10", + "memmap2", "parking_lot 0.12.1", "rand 0.8.5", "siphasher", @@ -11653,9 +11561,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.5" +version = "3.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" +checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" dependencies = [ "arrayvec 0.7.4", "bitvec", @@ -11668,9 +11576,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.5" +version = "3.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" +checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11721,9 +11629,9 @@ checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" [[package]] name = "parking" -version = "2.2.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" [[package]] name = "parking_lot" @@ -11743,7 +11651,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.9", + "parking_lot_core 0.9.8", ] [[package]] @@ -11762,13 +11670,13 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall 0.3.5", "smallvec", "windows-targets 0.48.5", ] @@ -11912,20 +11820,19 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.5" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" dependencies = [ - "memchr", "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.5" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" +checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" dependencies = [ "pest", "pest_generator", @@ -11933,26 +11840,26 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.5" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" +checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] name = "pest_meta" -version = "2.7.5" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" +checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" dependencies = [ "once_cell", "pest", - "sha2 0.10.8", + "sha2 0.10.7", ] [[package]] @@ -11962,7 +11869,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.0.0", ] [[package]] @@ -11982,7 +11889,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -11993,9 +11900,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" [[package]] name = "pin-utils" @@ -12003,17 +11910,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "piper" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" -dependencies = [ - "atomic-waker", - "fastrand 2.0.1", - "futures-io", -] - [[package]] name = "pkcs8" version = "0.9.0" @@ -12042,9 +11938,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" -version = "3.2.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" [[package]] name = "plotters" @@ -12080,7 +11976,7 @@ version = "1.1.0" dependencies = [ "assert_cmd", "color-eyre", - "nix 0.26.4", + "nix 0.26.2", "polkadot-cli", "polkadot-core-primitives", "polkadot-node-core-pvf", @@ -12214,7 +12110,7 @@ dependencies = [ name = "polkadot-cli" version = "1.1.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "frame-benchmarking-cli", "futures", "log", @@ -12284,7 +12180,7 @@ name = "polkadot-dispute-distribution" version = "1.0.0" dependencies = [ "assert_matches", - "async-channel 1.9.0", + "async-channel", "async-trait", "derive_more", "fatality", @@ -12874,7 +12770,7 @@ dependencies = [ name = "polkadot-node-network-protocol" version = "1.0.0" dependencies = [ - "async-channel 1.9.0", + "async-channel", "async-trait", "bitvec", "derive_more", @@ -12889,7 +12785,7 @@ dependencies = [ "rand_chacha 0.3.1", "sc-authority-discovery", "sc-network", - "strum 0.24.1", + "strum", "thiserror", "tracing-gum", ] @@ -13055,7 +12951,7 @@ dependencies = [ "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", "bridge-hub-westend-runtime", - "clap 4.4.8", + "clap 4.4.6", "collectives-polkadot-runtime", "collectives-westend-runtime", "color-print", @@ -13082,7 +12978,7 @@ dependencies = [ "hex-literal", "jsonrpsee", "log", - "nix 0.26.4", + "nix 0.26.2", "pallet-transaction-payment", "pallet-transaction-payment-rpc", "pallet-transaction-payment-rpc-runtime-api", @@ -13478,7 +13374,7 @@ version = "1.0.0" dependencies = [ "arrayvec 0.7.4", "assert_matches", - "async-channel 1.9.0", + "async-channel", "bitvec", "fatality", "futures", @@ -13551,7 +13447,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.4.8", + "clap 4.4.6", "color-eyre", "futures", "futures-timer", @@ -13698,7 +13594,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "1.0.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "generate-bags", "sp-io", "westend-runtime", @@ -13716,22 +13612,19 @@ dependencies = [ "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "windows-sys 0.48.0", ] [[package]] -name = "polling" -version = "3.3.0" +name = "poly1305" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53b6af1f60f36f8c2ac2aad5459d75a5a9b4be1e8cdd40264f315d78193e531" +checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ - "cfg-if", - "concurrent-queue", - "pin-project-lite 0.2.13", - "rustix 0.38.25", - "tracing", - "windows-sys 0.48.0", + "cpufeatures", + "opaque-debug 0.3.0", + "universal-hash 0.4.1", ] [[package]] @@ -13771,9 +13664,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.5.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" +checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" [[package]] name = "portpicker" @@ -13784,12 +13677,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "pprof" version = "0.12.1" @@ -13801,7 +13688,7 @@ dependencies = [ "findshlibs", "libc", "log", - "nix 0.26.4", + "nix 0.26.2", "once_cell", "parking_lot 0.12.1", "smallvec", @@ -13832,13 +13719,13 @@ dependencies = [ [[package]] name = "predicates" -version = "3.0.4" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0" +checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" dependencies = [ "anstyle", "difflib", - "itertools 0.11.0", + "itertools 0.10.5", "predicates-core", ] @@ -13880,19 +13767,19 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.15" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] name = "primitive-types" -version = "0.12.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" dependencies = [ "fixed-hash", "impl-codec", @@ -13953,6 +13840,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro-warning" version = "1.0.0" @@ -13961,7 +13854,7 @@ checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -13979,13 +13872,13 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.0", "chrono", "flate2", "hex", "lazy_static", "procfs-core", - "rustix 0.38.25", + "rustix 0.38.21", ] [[package]] @@ -13994,7 +13887,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.0", "chrono", "hex", ] @@ -14033,7 +13926,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -14191,20 +14084,20 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.9.6" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b0b33c13a79f669c85defaf4c275dc86a0c0372807d0ca3d78e0bb87274863" +checksum = "c956be1b23f4261676aed05a0046e204e8a6836e50203902683a718af0797989" dependencies = [ "bytes", "rand 0.8.5", "ring 0.16.20", "rustc-hash", - "rustls 0.20.9", + "rustls 0.20.8", "slab", "thiserror", "tinyvec", "tracing", - "webpki 0.22.4", + "webpki 0.22.0", ] [[package]] @@ -14281,7 +14174,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.10", ] [[package]] @@ -14320,9 +14213,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.8.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", @@ -14330,12 +14223,14 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ + "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", + "num_cpus", ] [[package]] @@ -14346,7 +14241,7 @@ checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", "ring 0.16.20", - "time", + "time 0.3.27", "x509-parser 0.13.2", "yasna", ] @@ -14359,7 +14254,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring 0.16.20", - "time", + "time 0.3.27", "yasna", ] @@ -14381,36 +14276,27 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.11", - "libredox", + "getrandom 0.2.10", + "redox_syscall 0.2.16", "thiserror", ] [[package]] name = "reed-solomon-novelpoly" -version = "1.0.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58130877ca403ab42c864fbac74bb319a0746c07a634a92a5cfc7f54af272582" +checksum = "3bd8f48b2066e9f69ab192797d66da804d1935bf22763204ed3675740cb0f221" dependencies = [ "derive_more", "fs-err", - "itertools 0.11.0", - "static_init", + "itertools 0.10.5", + "static_init 0.5.2", "thiserror", ] @@ -14431,7 +14317,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -14467,6 +14353,12 @@ dependencies = [ "regex-syntax 0.6.29", ] +[[package]] +name = "regex-automata" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" + [[package]] name = "regex-automata" version = "0.4.3" @@ -14494,7 +14386,7 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "frame-system", "log", "pallet-bags-list-remote-tests", @@ -14507,11 +14399,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ - "base64 0.21.5", + "base64 0.21.2", "bytes", "encoding_rs", "futures-core", @@ -14527,13 +14419,12 @@ dependencies = [ "mime", "once_cell", "percent-encoding", - "pin-project-lite 0.2.13", - "rustls 0.21.9", + "pin-project-lite 0.2.12", + "rustls 0.21.6", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", - "system-configuration", "tokio", "tokio-rustls", "tower-service", @@ -14602,25 +14493,11 @@ dependencies = [ "libc", "once_cell", "spin 0.5.2", - "untrusted 0.7.1", + "untrusted", "web-sys", "winapi", ] -[[package]] -name = "ring" -version = "0.17.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" -dependencies = [ - "cc", - "getrandom 0.2.11", - "libc", - "spin 0.9.8", - "untrusted 0.9.0", - "windows-sys 0.48.0", -] - [[package]] name = "rle-decode-fast" version = "1.0.3" @@ -14860,13 +14737,13 @@ dependencies = [ [[package]] name = "rpassword" -version = "7.3.1" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" dependencies = [ "libc", "rtoolbox", - "windows-sys 0.48.0", + "winapi", ] [[package]] @@ -14897,12 +14774,12 @@ dependencies = [ [[package]] name = "rtoolbox" -version = "0.0.2" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" dependencies = [ "libc", - "windows-sys 0.48.0", + "winapi", ] [[package]] @@ -14952,7 +14829,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.20", + "semver 1.0.18", ] [[package]] @@ -14966,9 +14843,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.17" +version = "0.36.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" +checksum = "c37f1bd5ef1b5422177b7646cba67430579cfe2ace80f284fee876bca52ad941" dependencies = [ "bitflags 1.3.2", "errno", @@ -14980,9 +14857,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.27" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ "bitflags 1.3.2", "errno", @@ -14994,14 +14871,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.25" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys 0.4.11", + "linux-raw-sys 0.4.10", "windows-sys 0.48.0", ] @@ -15020,26 +14897,26 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.9" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring 0.16.20", - "sct 0.7.1", - "webpki 0.22.4", + "sct 0.7.0", + "webpki 0.22.0", ] [[package]] name = "rustls" -version = "0.21.9" +version = "0.21.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" dependencies = [ "log", - "ring 0.17.5", - "rustls-webpki", - "sct 0.7.1", + "ring 0.16.20", + "rustls-webpki 0.101.4", + "sct 0.7.0", ] [[package]] @@ -15056,21 +14933,31 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.4" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +dependencies = [ + "base64 0.21.2", +] + +[[package]] +name = "rustls-webpki" +version = "0.100.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "e98ff011474fa39949b7e5c0428f9b4937eda7da7848bbb947786b7be0b27dab" dependencies = [ - "base64 0.21.5", + "ring 0.16.20", + "untrusted", ] [[package]] name = "rustls-webpki" -version = "0.101.7" +version = "0.101.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" dependencies = [ - "ring 0.17.5", - "untrusted 0.9.0", + "ring 0.16.20", + "untrusted", ] [[package]] @@ -15230,10 +15117,10 @@ dependencies = [ name = "sc-chain-spec" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "docify", "log", - "memmap2 0.5.10", + "memmap2", "parity-scale-codec", "sc-chain-spec-derive", "sc-client-api", @@ -15261,17 +15148,17 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] name = "sc-cli" version = "0.10.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "bip39", "chrono", - "clap 4.4.8", + "clap 4.4.6", "fdlimit", "futures", "futures-timer", @@ -15340,7 +15227,7 @@ dependencies = [ name = "sc-client-db" version = "0.10.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "criterion 0.4.0", "hash-db", "kitchensink-runtime", @@ -15505,8 +15392,8 @@ dependencies = [ name = "sc-consensus-beefy" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", - "async-channel 1.9.0", + "array-bytes 6.1.0", + "async-channel", "async-trait", "fnv", "futures", @@ -15580,8 +15467,8 @@ dependencies = [ name = "sc-consensus-grandpa" version = "0.10.0-dev" dependencies = [ - "ahash 0.8.6", - "array-bytes 6.2.0", + "ahash 0.8.3", + "array-bytes 6.1.0", "assert_matches", "async-trait", "dyn-clone", @@ -15737,7 +15624,7 @@ dependencies = [ name = "sc-executor" version = "0.10.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "assert_matches", "criterion 0.4.0", "env_logger 0.9.3", @@ -15794,7 +15681,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", "paste", - "rustix 0.36.17", + "rustix 0.36.15", "sc-allocator", "sc-executor-common", "sc-runtime-test", @@ -15826,7 +15713,7 @@ dependencies = [ name = "sc-keystore" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "parking_lot 0.12.1", "serde_json", "sp-application-crypto", @@ -15868,9 +15755,9 @@ dependencies = [ name = "sc-network" version = "0.10.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "assert_matches", - "async-channel 1.9.0", + "async-channel", "async-trait", "asynchronous-codec", "bytes", @@ -15921,7 +15808,7 @@ dependencies = [ name = "sc-network-bitswap" version = "0.10.0-dev" dependencies = [ - "async-channel 1.9.0", + "async-channel", "cid", "futures", "libp2p-identity", @@ -15964,7 +15851,7 @@ dependencies = [ name = "sc-network-gossip" version = "0.10.0-dev" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.3", "async-trait", "futures", "futures-timer", @@ -15987,8 +15874,8 @@ dependencies = [ name = "sc-network-light" version = "0.10.0-dev" dependencies = [ - "array-bytes 6.2.0", - "async-channel 1.9.0", + "array-bytes 6.1.0", + "async-channel", "futures", "libp2p-identity", "log", @@ -16007,8 +15894,8 @@ dependencies = [ name = "sc-network-statement" version = "0.10.0-dev" dependencies = [ - "array-bytes 6.2.0", - "async-channel 1.9.0", + "array-bytes 6.1.0", + "async-channel", "futures", "libp2p", "log", @@ -16025,8 +15912,8 @@ dependencies = [ name = "sc-network-sync" version = "0.10.0-dev" dependencies = [ - "array-bytes 6.2.0", - "async-channel 1.9.0", + "array-bytes 6.1.0", + "async-channel", "async-trait", "fork-tree", "futures", @@ -16095,7 +15982,7 @@ dependencies = [ name = "sc-network-transactions" version = "0.10.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "futures", "libp2p", "log", @@ -16113,7 +16000,7 @@ dependencies = [ name = "sc-offchain" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "bytes", "fnv", "futures", @@ -16235,7 +16122,7 @@ dependencies = [ name = "sc-rpc-spec-v2" version = "0.10.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "assert_matches", "futures", "futures-util", @@ -16334,7 +16221,7 @@ dependencies = [ "sp-transaction-storage-proof", "sp-trie", "sp-version", - "static_init", + "static_init 1.0.3", "substrate-prometheus-endpoint", "substrate-test-runtime", "substrate-test-runtime-client", @@ -16349,8 +16236,8 @@ dependencies = [ name = "sc-service-test" version = "2.0.0" dependencies = [ - "array-bytes 6.2.0", - "async-channel 1.9.0", + "array-bytes 6.1.0", + "async-channel", "fdlimit", "futures", "log", @@ -16415,7 +16302,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "fs4", "log", "sc-client-db", @@ -16517,14 +16404,14 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "assert_matches", "async-trait", "criterion 0.4.0", @@ -16573,7 +16460,7 @@ dependencies = [ name = "sc-utils" version = "4.0.0-dev" dependencies = [ - "async-channel 1.9.0", + "async-channel", "futures", "futures-timer", "lazy_static", @@ -16625,7 +16512,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.3", "cfg-if", "hashbrown 0.13.2", ] @@ -16683,17 +16570,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" dependencies = [ "ring 0.16.20", - "untrusted 0.7.1", + "untrusted", ] [[package]] name = "sct" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring 0.17.5", - "untrusted 0.9.0", + "ring 0.16.20", + "untrusted", ] [[package]] @@ -16850,9 +16737,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" dependencies = [ "serde", ] @@ -16871,22 +16758,22 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -16911,9 +16798,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.4" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -16952,7 +16839,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -16981,9 +16868,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.6" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", "cpufeatures", @@ -17017,9 +16904,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -17038,9 +16925,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.7" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" dependencies = [ "lazy_static", ] @@ -17084,9 +16971,19 @@ dependencies = [ [[package]] name = "shlex" -version = "1.2.0" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "signal-hook" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] [[package]] name = "signal-hook-registry" @@ -17109,9 +17006,9 @@ dependencies = [ [[package]] name = "signature" -version = "2.2.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest 0.10.7", "rand_core 0.6.4", @@ -17178,9 +17075,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "smol" @@ -17188,15 +17085,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1" dependencies = [ - "async-channel 1.9.0", + "async-channel", "async-executor", "async-fs", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io", + "async-lock", "async-net", "async-process", "blocking", - "futures-lite 1.13.0", + "futures-lite", ] [[package]] @@ -17206,22 +17103,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0bb30cf57b7b5f6109ce17c3164445e2d6f270af2cb48f6e4d31c2967c9a9f5" dependencies = [ "arrayvec 0.7.4", - "async-lock 2.8.0", + "async-lock", "atomic-take", - "base64 0.21.5", + "base64 0.21.2", "bip39", "blake2-rfc", "bs58 0.5.0", - "chacha20", + "chacha20 0.9.1", "crossbeam-queue", "derive_more", - "ed25519-zebra 4.0.3", + "ed25519-zebra 4.0.2", "either", - "event-listener 2.5.3", + "event-listener", "fnv", - "futures-lite 1.13.0", + "futures-lite", "futures-util", - "hashbrown 0.14.2", + "hashbrown 0.14.0", "hex", "hmac 0.12.1", "itertools 0.11.0", @@ -17234,14 +17131,14 @@ dependencies = [ "num-traits", "pbkdf2 0.12.2", "pin-project", - "poly1305", + "poly1305 0.8.0", "rand 0.8.5", "rand_chacha 0.3.1", "ruzstd", "schnorrkel 0.10.2", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.7", "sha3", "siphasher", "slab", @@ -17259,22 +17156,22 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "256b5bad1d6b49045e95fe87492ce73d5af81545d8b4d8318a872d2007024c33" dependencies = [ - "async-channel 1.9.0", - "async-lock 2.8.0", - "base64 0.21.5", + "async-channel", + "async-lock", + "base64 0.21.2", "blake2-rfc", "derive_more", "either", - "event-listener 2.5.3", + "event-listener", "fnv", "futures-channel", - "futures-lite 1.13.0", + "futures-lite", "futures-util", - "hashbrown 0.14.2", + "hashbrown 0.14.0", "hex", "itertools 0.11.0", "log", - "lru 0.11.1", + "lru 0.11.0", "no-std-net", "parking_lot 0.12.1", "pin-project", @@ -17297,26 +17194,26 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58021967fd0a5eeeb23b08df6cc244a4d4a5b4aec1d27c9e02fad1a58b4cd74e" +checksum = "0c9d1425eb528a21de2755c75af4c9b5d57f50a0d4c3b7f1828a4cd03f8ba155" dependencies = [ - "aes-gcm 0.10.3", + "aes-gcm 0.9.4", "blake2 0.10.6", "chacha20poly1305", - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.0.0", "rand_core 0.6.4", - "ring 0.17.5", + "ring 0.16.20", "rustc_version 0.4.0", - "sha2 0.10.8", + "sha2 0.10.7", "subtle 2.4.1", ] [[package]] name = "socket2" -version = "0.4.10" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -17324,9 +17221,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" dependencies = [ "libc", "windows-sys 0.48.0", @@ -17381,7 +17278,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -17568,7 +17465,7 @@ dependencies = [ name = "sp-consensus-beefy" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "lazy_static", "parity-scale-codec", "scale-info", @@ -17580,7 +17477,7 @@ dependencies = [ "sp-mmr-primitives", "sp-runtime", "sp-std 8.0.0", - "strum 0.24.1", + "strum", "w3f-bls", ] @@ -17642,7 +17539,7 @@ dependencies = [ name = "sp-core" version = "21.0.0" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "bandersnatch_vrfs", "bip39", "bitflags 1.3.2", @@ -17705,7 +17602,7 @@ dependencies = [ "blake2b_simd", "byteorder", "digest 0.10.7", - "sha2 0.10.8", + "sha2 0.10.7", "sha3", "twox-hash", ] @@ -17716,7 +17613,7 @@ version = "9.0.0" dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -17742,7 +17639,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" version = "0.4.1" -source = "git+https://github.com/paritytech/polkadot-sdk#408af9b32d95acbbac5e18bee66fd1b74230a699" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -17774,17 +17671,17 @@ version = "8.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#408af9b32d95acbbac5e18bee66fd1b74230a699" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -17800,7 +17697,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/polkadot-sdk#408af9b32d95acbbac5e18bee66fd1b74230a699" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "environmental", "parity-scale-codec", @@ -17862,7 +17759,7 @@ dependencies = [ "lazy_static", "sp-core", "sp-runtime", - "strum 0.24.1", + "strum", ] [[package]] @@ -17911,7 +17808,7 @@ dependencies = [ name = "sp-mmr-primitives" version = "4.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "ckb-merkle-mountain-range", "log", "parity-scale-codec", @@ -17944,7 +17841,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "honggfuzz", "rand 0.8.5", "sp-npos-elections", @@ -18032,7 +17929,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#408af9b32d95acbbac5e18bee66fd1b74230a699" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -18055,19 +17952,19 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#408af9b32d95acbbac5e18bee66fd1b74230a699" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "Inflector", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -18139,7 +18036,7 @@ dependencies = [ name = "sp-state-machine" version = "0.28.0" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "assert_matches", "hash-db", "log", @@ -18164,13 +18061,13 @@ name = "sp-statement-store" version = "4.0.0-dev" dependencies = [ "aes-gcm 0.10.3", - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.0.0", "ed25519-dalek", "hkdf", "parity-scale-codec", "rand 0.8.5", "scale-info", - "sha2 0.10.8", + "sha2 0.10.7", "sp-api", "sp-application-crypto", "sp-core", @@ -18189,7 +18086,7 @@ version = "8.0.0" [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#408af9b32d95acbbac5e18bee66fd1b74230a699" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" [[package]] name = "sp-storage" @@ -18206,7 +18103,7 @@ dependencies = [ [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#408af9b32d95acbbac5e18bee66fd1b74230a699" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "impl-serde", "parity-scale-codec", @@ -18255,7 +18152,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#408af9b32d95acbbac5e18bee66fd1b74230a699" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "parity-scale-codec", "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", @@ -18290,8 +18187,8 @@ dependencies = [ name = "sp-trie" version = "22.0.0" dependencies = [ - "ahash 0.8.6", - "array-bytes 6.2.0", + "ahash 0.8.3", + "array-bytes 6.1.0", "criterion 0.4.0", "hash-db", "hashbrown 0.13.2", @@ -18338,7 +18235,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -18356,7 +18253,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#408af9b32d95acbbac5e18bee66fd1b74230a699" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -18394,13 +18291,13 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spinners" -version = "4.1.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ef947f358b9c238923f764c72a4a9d42f2d637c46e059dbd319d6e7cfb4f82" +checksum = "08615eea740067d9899969bc2891c68a19c315cb1f66640af9a9ecb91b13bcab" dependencies = [ "lazy_static", "maplit", - "strum 0.24.1", + "strum", ] [[package]] @@ -18425,9 +18322,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.44.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35935738370302d5e33963665b77541e4b990a3e919ec904c837a56cfc891de1" +checksum = "5e6915280e2d0db8911e5032a5c275571af6bdded2916abd691a659be25d3439" dependencies = [ "Inflector", "num-format", @@ -18448,7 +18345,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "2.0.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "log", "sc-chain-spec", "serde_json", @@ -18459,9 +18356,9 @@ dependencies = [ name = "staging-node-cli" version = "3.0.0-dev" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "assert_cmd", - "clap 4.4.8", + "clap 4.4.6", "clap_complete", "criterion 0.4.0", "frame-benchmarking-cli", @@ -18471,7 +18368,7 @@ dependencies = [ "jsonrpsee", "kitchensink-runtime", "log", - "nix 0.26.4", + "nix 0.26.2", "node-primitives", "node-rpc", "pallet-asset-conversion-tx-payment", @@ -18591,7 +18488,7 @@ dependencies = [ name = "staging-node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -18694,6 +18591,18 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "static_init" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11b73400442027c4adedda20a9f9b7945234a5bd8d5f7e86da22bd5d0622369c" +dependencies = [ + "cfg_aliases", + "libc", + "parking_lot 0.11.2", + "static_init_macro 0.5.0", +] + [[package]] name = "static_init" version = "1.0.3" @@ -18705,10 +18614,23 @@ dependencies = [ "libc", "parking_lot 0.11.2", "parking_lot_core 0.8.6", - "static_init_macro", + "static_init_macro 1.0.2", "winapi", ] +[[package]] +name = "static_init_macro" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2261c91034a1edc3fc4d1b80e89d82714faede0515c14a75da10cb941546bbf" +dependencies = [ + "cfg_aliases", + "memchr", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "static_init_macro" version = "1.0.2" @@ -18734,15 +18656,9 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ - "strum_macros 0.24.3", + "strum_macros", ] -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" - [[package]] name = "strum_macros" version = "0.24.3" @@ -18756,19 +18672,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.39", -] - [[package]] name = "stun" version = "0.4.4" @@ -18792,7 +18695,7 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "sc-cli", ] @@ -18818,9 +18721,9 @@ dependencies = [ [[package]] name = "substrate-bip39" -version = "0.4.5" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e620c7098893ba667438b47169c00aacdd9e7c10e042250ce2b60b087ec97328" +checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c" dependencies = [ "hmac 0.11.0", "pbkdf2 0.8.0", @@ -18839,7 +18742,7 @@ version = "0.1.0" dependencies = [ "assert_cmd", "futures", - "nix 0.26.4", + "nix 0.26.2", "node-primitives", "regex", "sc-cli", @@ -18854,7 +18757,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "frame-support", "frame-system", "sc-cli", @@ -18948,7 +18851,7 @@ dependencies = [ name = "substrate-test-client" version = "2.0.1" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "async-trait", "futures", "parity-scale-codec", @@ -18973,7 +18876,7 @@ dependencies = [ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ - "array-bytes 6.2.0", + "array-bytes 6.1.0", "frame-executive", "frame-support", "frame-system", @@ -19071,9 +18974,9 @@ dependencies = [ "filetime", "parity-wasm", "sp-maybe-compressed-blob", - "strum 0.24.1", + "strum", "tempfile", - "toml 0.7.8", + "toml 0.7.6", "walkdir", "wasm-opt", ] @@ -19107,15 +19010,15 @@ checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" [[package]] name = "sval" -version = "2.10.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15df12a8db7c216a04b4b438f90d50d5335cd38f161b56389c9f5c9d96d0873" +checksum = "8b031320a434d3e9477ccf9b5756d57d4272937b8d22cb88af80b7633a1b78b1" [[package]] name = "sval_buffer" -version = "2.10.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e80556bc8acea0446e574ce542ad6114a76a0237f28a842bc01ca3ea98f479" +checksum = "6bf7e9412af26b342f3f2cc5cc4122b0105e9d16eb76046cd14ed10106cf6028" dependencies = [ "sval", "sval_ref", @@ -19123,18 +19026,18 @@ dependencies = [ [[package]] name = "sval_dynamic" -version = "2.10.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d93d2259edb1d7b4316179f0a98c62e3ffc726f47ab200e07cfe382771f57b8" +checksum = "a0ef628e8a77a46ed3338db8d1b08af77495123cc229453084e47cd716d403cf" dependencies = [ "sval", ] [[package]] name = "sval_fmt" -version = "2.10.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532f7f882226f7a5a4656f5151224aaebf8217e0d539cb1595b831bace921343" +checksum = "7dc09e9364c2045ab5fa38f7b04d077b3359d30c4c2b3ec4bae67a358bd64326" dependencies = [ "itoa", "ryu", @@ -19143,9 +19046,9 @@ dependencies = [ [[package]] name = "sval_json" -version = "2.10.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76e03bd8aa0ae6ee018f7ae95c9714577687a4415bd1a5f19b26e34695f7e072" +checksum = "ada6f627e38cbb8860283649509d87bc4a5771141daa41c78fd31f2b9485888d" dependencies = [ "itoa", "ryu", @@ -19154,18 +19057,18 @@ dependencies = [ [[package]] name = "sval_ref" -version = "2.10.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ed054f2fb8c2a0ab5d36c1ec57b412919700099fc5e32ad8e7a38b23e1a9e1" +checksum = "703ca1942a984bd0d9b5a4c0a65ab8b4b794038d080af4eb303c71bc6bf22d7c" dependencies = [ "sval", ] [[package]] name = "sval_serde" -version = "2.10.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff191c4ff05b67e3844c161021427646cde5d6624597958be158357d9200586" +checksum = "830926cd0581f7c3e5d51efae4d35c6b6fc4db583842652891ba2f1bed8db046" dependencies = [ "serde", "sval", @@ -19175,21 +19078,21 @@ dependencies = [ [[package]] name = "symbolic-common" -version = "12.7.0" +version = "12.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39eac77836da383d35edbd9ff4585b4fc1109929ff641232f2e9a1aefdfc9e91" +checksum = "167a4ffd7c35c143fd1030aa3c2caf76ba42220bd5a6b5f4781896434723b8c3" dependencies = [ "debugid", - "memmap2 0.8.0", + "memmap2", "stable_deref_trait", "uuid", ] [[package]] name = "symbolic-demangle" -version = "12.7.0" +version = "12.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee1608a1d13061fb0e307a316de29f6c6e737b05459fe6bbf5dd8d7837c4fb7" +checksum = "e378c50e80686c1c5c205674e1f86a2858bec3d2a7dfdd690331a8a19330f293" dependencies = [ "cpp_demangle 0.4.3", "rustc-demangle", @@ -19209,9 +19112,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -19270,28 +19173,28 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.12" +version = "0.12.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" +checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" [[package]] name = "tempfile" -version = "3.8.1" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", - "fastrand 2.0.1", - "redox_syscall 0.4.1", - "rustix 0.38.25", + "fastrand 2.0.0", + "redox_syscall 0.3.5", + "rustix 0.38.21", "windows-sys 0.48.0", ] [[package]] name = "termcolor" -version = "1.4.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -19302,7 +19205,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.25", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -19329,7 +19232,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "futures", "futures-timer", "log", @@ -19377,7 +19280,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.4.8", + "clap 4.4.6", "futures", "futures-timer", "log", @@ -19453,22 +19356,22 @@ dependencies = [ [[package]] name = "thiserror-core" -version = "1.0.50" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c001ee18b7e5e3f62cbf58c7fe220119e68d902bb7443179c0c8aef30090e999" +checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" dependencies = [ "thiserror-core-impl", ] [[package]] name = "thiserror-core-impl" -version = "1.0.50" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c60d69f36615a077cc7663b9cb8e42275722d23e58a7fa3d2c7f2915d09d04" +checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 1.0.109", ] [[package]] @@ -19479,7 +19382,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -19553,13 +19456,23 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb39ee79a6d8de55f48f2293a830e040392f1c5f16e336bdd1788cd0aadce07" dependencies = [ "deranged", "itoa", - "powerfmt", "serde", "time-core", "time-macros", @@ -19567,15 +19480,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "733d258752e9303d392b94b75230d07b0b9c489350c69b851fc6c065fde3e8f9" dependencies = [ "time-core", ] @@ -19616,9 +19529,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ "backtrace", "bytes", @@ -19626,22 +19539,22 @@ dependencies = [ "mio", "num_cpus", "parking_lot 0.12.1", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "signal-hook-registry", - "socket2 0.5.5", + "socket2 0.5.3", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -19661,7 +19574,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.9", + "rustls 0.21.6", "tokio", ] @@ -19672,7 +19585,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "tokio", "tokio-util", ] @@ -19704,15 +19617,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "tokio", "tracing", ] @@ -19728,9 +19641,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.8" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ "serde", "serde_spanned", @@ -19740,20 +19653,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.15" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.0.0", "serde", "serde_spanned", "toml_datetime", @@ -19773,18 +19686,18 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.4.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +checksum = "55ae70283aba8d2a8b411c695c437fe25b8b5e44e23e780662002fc72fb47a82" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.0", "bytes", "futures-core", "futures-util", "http", "http-body", "http-range-header", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "tower-layer", "tower-service", ] @@ -19803,32 +19716,33 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ + "cfg-if", "log", - "pin-project-lite 0.2.13", + "pin-project-lite 0.2.12", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -19863,17 +19777,17 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] name = "tracing-log" -version = "0.1.4" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ + "lazy_static", "log", - "once_cell", "tracing-core", ] @@ -19976,7 +19890,7 @@ dependencies = [ "lazy_static", "rand 0.8.5", "smallvec", - "socket2 0.4.10", + "socket2 0.4.9", "thiserror", "tinyvec", "tokio", @@ -20016,7 +19930,7 @@ version = "0.10.0-dev" dependencies = [ "assert_cmd", "async-trait", - "clap 4.4.8", + "clap 4.4.6", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -20053,9 +19967,9 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.85" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196a58260a906cedb9bf6d8034b6379d0c11f552416960452f267402ceeddff1" +checksum = "6df60d81823ed9c520ee897489573da4b1d79ffbe006b8134f46de1a1aa03555" dependencies = [ "basic-toml", "dissimilar", @@ -20125,9 +20039,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" @@ -20155,9 +20069,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -20170,9 +20084,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" @@ -20202,9 +20116,9 @@ dependencies = [ [[package]] name = "unsigned-varint" -version = "0.7.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" +checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836" dependencies = [ "asynchronous-codec", "bytes", @@ -20218,17 +20132,11 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - [[package]] name = "url" -version = "2.4.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna 0.4.0", @@ -20249,11 +20157,11 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.6.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.10", ] [[package]] @@ -20264,9 +20172,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.4.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72e1902dde2bd6441347de2b70b7f5d59bf157c6c62f0c44572607a1d55bbe" +checksum = "d92ccd67fb88503048c01b59152a04effd0782d035a83a6d256ce6085f08f4a3" dependencies = [ "value-bag-serde1", "value-bag-sval2", @@ -20274,9 +20182,9 @@ dependencies = [ [[package]] name = "value-bag-serde1" -version = "1.4.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ba39dc791ecb35baad371a3fc04c6eab688c04937d2e0ac6c22b612c0357bf" +checksum = "b0b9f3feef403a50d4d67e9741a6d8fc688bcbb4e4f31bd4aab72cc690284394" dependencies = [ "erased-serde", "serde", @@ -20285,9 +20193,9 @@ dependencies = [ [[package]] name = "value-bag-sval2" -version = "1.4.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e06c10810a57bbf45778d023d432a50a1daa7d185991ae06bcfb6c654d0945" +checksum = "30b24f4146b6f3361e91cbf527d1fb35e9376c3c0cef72ca5ec5af6d640fad7d" dependencies = [ "sval", "sval_buffer", @@ -20334,7 +20242,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rand_core 0.6.4", - "sha2 0.10.8", + "sha2 0.10.7", "sha3", "thiserror", "zeroize", @@ -20360,15 +20268,15 @@ dependencies = [ [[package]] name = "waker-fn" -version = "1.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", "winapi-util", @@ -20389,6 +20297,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -20397,9 +20311,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.88" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "serde", @@ -20409,24 +20323,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.88" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.38" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -20436,9 +20350,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.88" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -20446,28 +20360,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.88" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.88" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-encoder" -version = "0.38.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b09bc5df933a3dabbdb72ae4b6b71be8ae07f58774d5aa41bd20adcd41a235a" +checksum = "41763f20eafed1399fff1afb466496d3a959f58241436cfdc17e3f5ca954de16" dependencies = [ "leb128", ] @@ -20498,8 +20412,8 @@ checksum = "fc942673e7684671f0c5708fc18993569d184265fd5223bb51fc8e5b9b6cfd52" dependencies = [ "anyhow", "libc", - "strum 0.24.1", - "strum_macros 0.24.3", + "strum", + "strum_macros", "tempfile", "thiserror", "wasm-opt-cxx-sys", @@ -20639,14 +20553,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c86437fa68626fe896e5afc69234bb2b5894949083586535f200385adfd71213" dependencies = [ "anyhow", - "base64 0.21.5", + "base64 0.21.2", "bincode", "directories-next", "file-per-thread-logger", "log", - "rustix 0.36.17", + "rustix 0.36.15", "serde", - "sha2 0.10.8", + "sha2 0.10.7", "toml 0.5.11", "windows-sys 0.45.0", "zstd 0.11.2+zstd.1.5.2", @@ -20740,7 +20654,7 @@ checksum = "6e0554b84c15a27d76281d06838aed94e13a77d7bf604bbbaf548aa20eb93846" dependencies = [ "object 0.30.4", "once_cell", - "rustix 0.36.17", + "rustix 0.36.15", ] [[package]] @@ -20771,7 +20685,7 @@ dependencies = [ "memoffset 0.8.0", "paste", "rand 0.8.5", - "rustix 0.36.17", + "rustix 0.36.15", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", @@ -20792,9 +20706,9 @@ dependencies = [ [[package]] name = "wast" -version = "69.0.0" +version = "63.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa51b5ad1391943d1bfad537e50f28fe938199ee76b115be6bae83802cd5185" +checksum = "2560471f60a48b77fccefaf40796fda61c97ce1e790b59dfcec9dc3995c9f63a" dependencies = [ "leb128", "memchr", @@ -20804,18 +20718,18 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.81" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a4c2488d058326466e086a43f5d4ea448241a8d0975e3eb0642c0828be1eb3" +checksum = "3bdc306c2c4c2f2bf2ba69e083731d0d2a77437fc6a350a19db139636e7e416c" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.65" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -20828,17 +20742,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" dependencies = [ "ring 0.16.20", - "untrusted 0.7.1", + "untrusted", ] [[package]] name = "webpki" -version = "0.22.4" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ - "ring 0.17.5", - "untrusted 0.9.0", + "ring 0.16.20", + "untrusted", ] [[package]] @@ -20847,7 +20761,16 @@ version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ - "webpki 0.22.4", + "webpki 0.22.0", +] + +[[package]] +name = "webpki-roots" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" +dependencies = [ + "rustls-webpki 0.100.2", ] [[package]] @@ -20879,10 +20802,10 @@ dependencies = [ "sdp", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.7", "stun", "thiserror", - "time", + "time 0.3.27", "tokio", "turn", "url", @@ -20941,7 +20864,7 @@ dependencies = [ "sec1 0.3.0", "serde", "sha1", - "sha2 0.10.8", + "sha2 0.10.7", "signature 1.6.4", "subtle 2.4.1", "thiserror", @@ -20983,7 +20906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f08dfd7a6e3987e255c4dbe710dde5d94d0f0574f8a21afa95d171376c143106" dependencies = [ "log", - "socket2 0.4.10", + "socket2 0.4.9", "thiserror", "tokio", "webrtc-util", @@ -21222,21 +21145,20 @@ dependencies = [ [[package]] name = "which" -version = "4.4.2" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", - "home", + "libc", "once_cell", - "rustix 0.38.25", ] [[package]] name = "wide" -version = "0.7.13" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68938b57b33da363195412cfc5fc37c9ed49aa9cfe2156fde64b8d2c9498242" +checksum = "aa469ffa65ef7e0ba0f164183697b89b854253fd31aeb92358b7b6155177d62f" dependencies = [ "bytemuck", "safe_arch", @@ -21266,9 +21188,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] @@ -21281,19 +21203,22 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.51.1" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" dependencies = [ - "windows-core", - "windows-targets 0.48.5", + "windows_aarch64_msvc 0.34.0", + "windows_i686_gnu 0.34.0", + "windows_i686_msvc 0.34.0", + "windows_x86_64_gnu 0.34.0", + "windows_x86_64_msvc 0.34.0", ] [[package]] -name = "windows-core" -version = "0.51.1" +name = "windows" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ "windows-targets 0.48.5", ] @@ -21358,6 +21283,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -21370,6 +21301,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_i686_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -21382,6 +21319,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -21394,6 +21337,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_x86_64_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -21418,6 +21367,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -21432,9 +21387,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.19" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] @@ -21475,7 +21430,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ - "curve25519-dalek 4.1.1", + "curve25519-dalek 4.0.0", "rand_core 0.6.4", "serde", "zeroize", @@ -21497,7 +21452,7 @@ dependencies = [ "ring 0.16.20", "rusticata-macros", "thiserror", - "time", + "time 0.3.27", ] [[package]] @@ -21515,7 +21470,7 @@ dependencies = [ "oid-registry 0.6.1", "rusticata-macros", "thiserror", - "time", + "time 0.3.27", ] [[package]] @@ -21589,7 +21544,7 @@ dependencies = [ "proc-macro2", "quote", "staging-xcm", - "syn 2.0.39", + "syn 2.0.38", "trybuild", ] @@ -21689,34 +21644,14 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "time", -] - -[[package]] -name = "zerocopy" -version = "0.7.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", + "time 0.3.27", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" dependencies = [ "zeroize_derive", ] @@ -21729,7 +21664,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.38", ] [[package]] @@ -21789,10 +21724,11 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.8+zstd.1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" dependencies = [ "cc", + "libc", "pkg-config", ] From b04d65d42edf3f243392936408dcad4918043809 Mon Sep 17 00:00:00 2001 From: Aaro Altonen Date: Mon, 27 Nov 2023 21:17:28 +0200 Subject: [PATCH 32/32] Fix gitlab ui test --- .../construct_runtime_ui/deprecated_where_block.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr index a791c313b4a8..08954bb6ab5c 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr @@ -97,7 +97,7 @@ note: required because it appears within the type `RuntimeEvent` | ||_- in this macro invocation ... | note: required by a bound in `EncodeLike` - --> $CARGO/parity-scale-codec-3.6.5/src/encode_like.rs + --> $CARGO/parity-scale-codec-3.6.4/src/encode_like.rs | | pub trait EncodeLike: Sized + Encode {} | ^^^^^ required by this bound in `EncodeLike` @@ -129,7 +129,7 @@ note: required because it appears within the type `RuntimeEvent` | ||_- in this macro invocation ... | note: required by a bound in `Decode` - --> $CARGO/parity-scale-codec-3.6.5/src/codec.rs + --> $CARGO/parity-scale-codec-3.6.4/src/codec.rs | | pub trait Decode: Sized { | ^^^^^ required by this bound in `Decode` @@ -301,7 +301,7 @@ note: required because it appears within the type `RuntimeCall` | ||_- in this macro invocation ... | note: required by a bound in `EncodeLike` - --> $CARGO/parity-scale-codec-3.6.5/src/encode_like.rs + --> $CARGO/parity-scale-codec-3.6.4/src/encode_like.rs | | pub trait EncodeLike: Sized + Encode {} | ^^^^^ required by this bound in `EncodeLike` @@ -334,7 +334,7 @@ note: required because it appears within the type `RuntimeCall` | ||_- in this macro invocation ... | note: required by a bound in `Decode` - --> $CARGO/parity-scale-codec-3.6.5/src/codec.rs + --> $CARGO/parity-scale-codec-3.6.4/src/codec.rs | | pub trait Decode: Sized { | ^^^^^ required by this bound in `Decode`