From fb263ce3a79bd298ec3523fab0d3f2149a24aa8b Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 30 Aug 2023 17:18:21 +0200 Subject: [PATCH 01/17] jsonrpsee v0.20.3 --- Cargo.lock | 146 +++++++++------- .../client/relay-chain-interface/Cargo.toml | 2 +- .../relay-chain-rpc-interface/Cargo.toml | 2 +- cumulus/pallets/xcmp-queue/src/bridging.rs | 4 +- cumulus/pallets/xcmp-queue/src/tests.rs | 22 ++- cumulus/parachain-template/node/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- cumulus/test/service/Cargo.toml | 2 +- cumulus/test/service/src/lib.rs | 1 + polkadot/node/test/service/src/lib.rs | 1 + polkadot/rpc/Cargo.toml | 2 +- substrate/bin/minimal/node/Cargo.toml | 2 +- substrate/bin/node-template/node/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 2 +- .../bin/node/cli/benches/block_production.rs | 1 + .../bin/node/cli/benches/transaction_pool.rs | 1 + substrate/bin/node/rpc/Cargo.toml | 2 +- substrate/client/cli/src/commands/run_cmd.rs | 16 +- substrate/client/cli/src/config.rs | 11 +- substrate/client/cli/src/runner.rs | 1 + .../client/consensus/babe/rpc/Cargo.toml | 2 +- .../client/consensus/babe/rpc/src/lib.rs | 44 +++-- .../client/consensus/beefy/rpc/Cargo.toml | 2 +- .../client/consensus/beefy/rpc/src/lib.rs | 52 +++--- .../consensus/common/src/block_import.rs | 2 +- .../client/consensus/grandpa/rpc/Cargo.toml | 2 +- .../client/consensus/grandpa/rpc/src/error.rs | 13 +- .../consensus/grandpa/rpc/src/finality.rs | 2 +- .../client/consensus/grandpa/rpc/src/lib.rs | 66 ++++--- .../consensus/grandpa/rpc/src/report.rs | 8 +- .../client/consensus/manual-seal/Cargo.toml | 2 +- .../client/consensus/manual-seal/src/error.rs | 9 +- .../client/consensus/manual-seal/src/rpc.rs | 19 +- .../merkle-mountain-range/rpc/Cargo.toml | 3 +- .../merkle-mountain-range/rpc/src/lib.rs | 34 ++-- substrate/client/rpc-api/Cargo.toml | 2 +- substrate/client/rpc-api/src/author/error.rs | 75 ++++---- substrate/client/rpc-api/src/author/mod.rs | 23 +-- substrate/client/rpc-api/src/chain/error.rs | 14 +- substrate/client/rpc-api/src/chain/mod.rs | 15 +- .../client/rpc-api/src/child_state/mod.rs | 18 +- substrate/client/rpc-api/src/dev/error.rs | 23 +-- substrate/client/rpc-api/src/dev/mod.rs | 5 +- substrate/client/rpc-api/src/lib.rs | 2 +- substrate/client/rpc-api/src/mixnet/error.rs | 6 +- substrate/client/rpc-api/src/mixnet/mod.rs | 5 +- .../client/rpc-api/src/offchain/error.rs | 12 +- substrate/client/rpc-api/src/offchain/mod.rs | 11 +- substrate/client/rpc-api/src/policy.rs | 24 +-- substrate/client/rpc-api/src/state/error.rs | 18 +- substrate/client/rpc-api/src/state/helpers.rs | 2 +- substrate/client/rpc-api/src/state/mod.rs | 38 ++-- .../client/rpc-api/src/statement/error.rs | 12 +- substrate/client/rpc-api/src/system/error.rs | 29 ++-- .../client/rpc-api/src/system/helpers.rs | 8 +- substrate/client/rpc-api/src/system/mod.rs | 46 +++-- substrate/client/rpc-servers/Cargo.toml | 4 +- substrate/client/rpc-servers/src/lib.rs | 40 +++-- .../client/rpc-servers/src/middleware.rs | 8 +- substrate/client/rpc-spec-v2/Cargo.toml | 3 +- .../client/rpc-spec-v2/src/archive/error.rs | 11 +- .../client/rpc-spec-v2/src/archive/tests.rs | 7 +- .../client/rpc-spec-v2/src/chain_head/api.rs | 27 +-- .../rpc-spec-v2/src/chain_head/chain_head.rs | 104 +++++------ .../src/chain_head/chain_head_follow.rs | 39 ++--- .../rpc-spec-v2/src/chain_head/error.rs | 11 +- .../rpc-spec-v2/src/chain_head/tests.rs | 59 +++---- .../rpc-spec-v2/src/chain_spec/tests.rs | 2 +- substrate/client/rpc-spec-v2/src/lib.rs | 2 +- .../src/transaction/transaction.rs | 74 ++++---- substrate/client/rpc/Cargo.toml | 4 +- substrate/client/rpc/src/author/mod.rs | 40 ++--- substrate/client/rpc/src/author/tests.rs | 13 +- substrate/client/rpc/src/chain/chain_full.rs | 30 ++-- substrate/client/rpc/src/chain/mod.rs | 41 +++-- substrate/client/rpc/src/chain/tests.rs | 4 +- substrate/client/rpc/src/dev/mod.rs | 3 +- substrate/client/rpc/src/dev/tests.rs | 2 +- substrate/client/rpc/src/lib.rs | 144 ++++++++++++++++ substrate/client/rpc/src/mixnet/mod.rs | 4 +- substrate/client/rpc/src/offchain/mod.rs | 10 +- substrate/client/rpc/src/offchain/tests.rs | 9 +- substrate/client/rpc/src/state/mod.rs | 101 +++++------ substrate/client/rpc/src/state/state_full.rs | 53 +++--- substrate/client/rpc/src/state/tests.rs | 162 ++++++------------ substrate/client/rpc/src/system/mod.rs | 85 ++++----- substrate/client/rpc/src/system/tests.rs | 7 +- substrate/client/rpc/src/testing.rs | 45 ++++- substrate/client/service/Cargo.toml | 2 +- substrate/client/service/src/config.rs | 2 + substrate/client/service/src/lib.rs | 7 +- substrate/client/service/test/src/lib.rs | 1 + substrate/client/sync-state-rpc/Cargo.toml | 2 +- substrate/client/sync-state-rpc/src/lib.rs | 21 +-- .../procedural/src/pallet/expand/warnings.rs | 8 +- .../frame/transaction-payment/rpc/Cargo.toml | 2 +- .../frame/transaction-payment/rpc/src/lib.rs | 31 ++-- .../frame/transaction-payment/src/types.rs | 2 +- substrate/primitives/rpc/src/list.rs | 2 +- substrate/primitives/storage/src/lib.rs | 2 +- substrate/test-utils/client/Cargo.toml | 1 + substrate/test-utils/client/src/lib.rs | 10 +- .../frame/remote-externalities/Cargo.toml | 2 +- .../frame/remote-externalities/src/lib.rs | 3 +- substrate/utils/frame/rpc/client/Cargo.toml | 2 +- substrate/utils/frame/rpc/client/src/lib.rs | 5 +- .../rpc/state-trie-migration-rpc/Cargo.toml | 2 +- .../rpc/state-trie-migration-rpc/src/lib.rs | 12 +- substrate/utils/frame/rpc/support/Cargo.toml | 4 +- substrate/utils/frame/rpc/system/Cargo.toml | 2 +- substrate/utils/frame/rpc/system/src/lib.rs | 29 ++-- 111 files changed, 1124 insertions(+), 1050 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1183f9204a2d..a3dc5b435262 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5893,19 +5893,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" -[[package]] -name = "globset" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - [[package]] name = "glutton-runtime" version = "1.0.0" @@ -6253,7 +6240,6 @@ dependencies = [ "rustls-native-certs", "tokio", "tokio-rustls", - "webpki-roots 0.23.1", ] [[package]] @@ -6666,9 +6652,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.16.3" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367a292944c07385839818bb71c8d76611138e2dedb0677d035b8da21d29c78b" +checksum = "affdc52f7596ccb2d7645231fc6163bb314630c989b64998f3699a28b4d5d4dc" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -6676,19 +6662,19 @@ dependencies = [ "jsonrpsee-server", "jsonrpsee-types", "jsonrpsee-ws-client", + "tokio", "tracing", ] [[package]] name = "jsonrpsee-client-transport" -version = "0.16.3" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8b3815d9f5d5de348e5f162b316dc9cdf4548305ebb15b4eb9328e66cf27d7a" +checksum = "b5b005c793122d03217da09af68ba9383363caa950b90d3436106df8cabce935" dependencies = [ "futures-util", "http", "jsonrpsee-core", - "jsonrpsee-types", "pin-project", "rustls-native-certs", "soketto", @@ -6697,24 +6683,21 @@ dependencies = [ "tokio-rustls", "tokio-util", "tracing", - "webpki-roots 0.25.2", + "url", ] [[package]] name = "jsonrpsee-core" -version = "0.16.3" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b5dde66c53d6dcdc8caea1874a45632ec0fcf5b437789f1e45766a1512ce803" +checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" dependencies = [ "anyhow", - "arrayvec 0.7.4", "async-lock", "async-trait", "beef", - "futures-channel", "futures-timer", "futures-util", - "globset", "hyper", "jsonrpsee-types", "parking_lot 0.12.1", @@ -6730,28 +6713,29 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.16.3" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5f9fabdd5d79344728521bb65e3106b49ec405a78b66fbff073b72b389fa43" +checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" dependencies = [ "async-trait", "hyper", "hyper-rustls", "jsonrpsee-core", "jsonrpsee-types", - "rustc-hash", "serde", "serde_json", "thiserror", "tokio", + "tower", "tracing", + "url", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.16.3" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e8ab85614a08792b9bff6c8feee23be78c98d0182d4c622c05256ab553892a" +checksum = "29110019693a4fa2dbda04876499d098fa16d70eba06b1e6e2b3f1b251419515" dependencies = [ "heck", "proc-macro-crate", @@ -6762,19 +6746,20 @@ dependencies = [ [[package]] name = "jsonrpsee-server" -version = "0.16.3" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4d945a6008c9b03db3354fb3c83ee02d2faa9f2e755ec1dfb69c3551b8f4ba" +checksum = "82c39a00449c9ef3f50b84fc00fc4acba20ef8f559f07902244abf4c15c5ab9c" dependencies = [ - "futures-channel", "futures-util", "http", "hyper", "jsonrpsee-core", "jsonrpsee-types", + "route-recognizer", "serde", "serde_json", "soketto", + "thiserror", "tokio", "tokio-stream", "tokio-util", @@ -6784,9 +6769,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.16.3" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245ba8e5aa633dd1c1e4fae72bce06e71f42d34c14a2767c6b4d173b57bee5e5" +checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" dependencies = [ "anyhow", "beef", @@ -6798,14 +6783,15 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.16.3" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e1b3975ed5d73f456478681a417128597acd6a2487855fdb7b4a3d4d195bf5e" +checksum = "bca9cb3933ccae417eb6b08c3448eb1cb46e39834e5b503e395e5e5bd08546c0" dependencies = [ "http", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", + "url", ] [[package]] @@ -7816,6 +7802,15 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matches" version = "0.1.10" @@ -8078,7 +8073,6 @@ dependencies = [ name = "mmr-rpc" version = "4.0.0-dev" dependencies = [ - "anyhow", "jsonrpsee", "parity-scale-codec", "serde", @@ -8737,6 +8731,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num" version = "0.4.1" @@ -8966,6 +8970,12 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "owo-colors" version = "3.5.0" @@ -14321,6 +14331,12 @@ dependencies = [ "staging-xcm", ] +[[package]] +name = "route-recognizer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" + [[package]] name = "rpassword" version = "7.2.0" @@ -14501,7 +14517,7 @@ checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" dependencies = [ "log", "ring 0.16.20", - "rustls-webpki 0.101.4", + "rustls-webpki", "sct 0.7.0", ] @@ -14526,16 +14542,6 @@ dependencies = [ "base64 0.21.2", ] -[[package]] -name = "rustls-webpki" -version = "0.100.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e98ff011474fa39949b7e5c0428f9b4937eda7da7848bbb947786b7be0b27dab" -dependencies = [ - "ring 0.16.20", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.101.4" @@ -15228,7 +15234,7 @@ dependencies = [ "substrate-test-runtime", "tempfile", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.2.25", "wat", ] @@ -15649,6 +15655,7 @@ dependencies = [ "sp-version", "substrate-test-runtime-client", "tokio", + "tracing-subscriber 0.3.17", ] [[package]] @@ -15701,6 +15708,7 @@ dependencies = [ "sc-block-builder", "sc-chain-spec", "sc-client-api", + "sc-rpc", "sc-service", "sc-transaction-pool-api", "sc-utils", @@ -15957,7 +15965,7 @@ dependencies = [ "thiserror", "tracing", "tracing-log", - "tracing-subscriber", + "tracing-subscriber 0.2.25", ] [[package]] @@ -17575,7 +17583,7 @@ dependencies = [ "sp-std", "tracing", "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.2.25", ] [[package]] @@ -18097,6 +18105,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-state-machine", + "tokio", ] [[package]] @@ -18912,6 +18921,10 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite 0.2.12", "tower-layer", "tower-service", "tracing", @@ -19044,7 +19057,7 @@ dependencies = [ "ansi_term", "chrono", "lazy_static", - "matchers", + "matchers 0.0.1", "parking_lot 0.11.2", "regex", "serde", @@ -19058,6 +19071,24 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "tracing-subscriber" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +dependencies = [ + "matchers 0.1.0", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "trie-bench" version = "0.38.0" @@ -19998,15 +20029,6 @@ dependencies = [ "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]] name = "webpki-roots" version = "0.25.2" diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index 3da7ab0b0e82..ccad39796a42 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -17,5 +17,5 @@ sc-client-api = { path = "../../../substrate/client/api" } futures = "0.3.28" async-trait = "0.1.73" thiserror = "1.0.48" -jsonrpsee-core = "0.16.2" +jsonrpsee-core = "0.20.3" parity-scale-codec = "3.6.4" diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 0f09377e106c..8c429c39f095 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -28,7 +28,7 @@ tokio-util = { version = "0.7.8", features = ["compat"] } futures = "0.3.28" futures-timer = "3.0.2" parity-scale-codec = "3.6.4" -jsonrpsee = { version = "0.16.2", features = ["ws-client"] } +jsonrpsee = { version = "0.20.3", features = ["ws-client"] } tracing = "0.1.37" async-trait = "0.1.73" url = "2.4.0" diff --git a/cumulus/pallets/xcmp-queue/src/bridging.rs b/cumulus/pallets/xcmp-queue/src/bridging.rs index 0fc3f1f39ea3..53238fe2bf7a 100644 --- a/cumulus/pallets/xcmp-queue/src/bridging.rs +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -55,7 +55,9 @@ impl, Runtime: crate::Config> let sibling_bridge_hub_id: ParaId = SiblingBridgeHubParaId::get(); // let's find the channel's state with the sibling parachain, - let Some((outbound_state, queued_pages)) = pallet::Pallet::::outbound_channel_state(sibling_bridge_hub_id) else { + let Some((outbound_state, queued_pages)) = + pallet::Pallet::::outbound_channel_state(sibling_bridge_hub_id) + else { return false }; // suspended channel => it is congested diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index cf6d947609d2..bab7e92ca2de 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -410,9 +410,11 @@ fn verify_fee_factor_increase_and_decrease() { assert_eq!(DeliveryFeeFactor::::get(sibling_para_id), initial); // Sending the message right now is cheap - let (_, delivery_fees) = validate_send::(destination, xcm.clone()) - .expect("message can be sent; qed"); - let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); }; + let (_, delivery_fees) = + validate_send::(destination, xcm.clone()).expect("message can be sent; qed"); + let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { + unreachable!("asset is fungible; qed"); + }; assert_eq!(delivery_fee_amount, 402_000_000); let smaller_xcm = Xcm(vec![ClearOrigin; 30]); @@ -422,19 +424,23 @@ fn verify_fee_factor_increase_and_decrease() { assert_ok!(send_xcm::(destination, xcm.clone())); // Size 520 assert_eq!(DeliveryFeeFactor::::get(sibling_para_id), FixedU128::from_float(1.05)); - for _ in 0..12 { // We finish at size 929 + for _ in 0..12 { + // We finish at size 929 assert_ok!(send_xcm::(destination, smaller_xcm.clone())); } assert!(DeliveryFeeFactor::::get(sibling_para_id) > FixedU128::from_float(1.88)); // Sending the message right now is expensive - let (_, delivery_fees) = validate_send::(destination, xcm.clone()) - .expect("message can be sent; qed"); - let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); }; + let (_, delivery_fees) = + validate_send::(destination, xcm.clone()).expect("message can be sent; qed"); + let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { + unreachable!("asset is fungible; qed"); + }; assert_eq!(delivery_fee_amount, 758_030_955); // Fee factor only decreases in `take_outbound_messages` - for _ in 0..5 { // We take 5 100 byte pages + for _ in 0..5 { + // We take 5 100 byte pages XcmpQueue::take_outbound_messages(1); } assert!(DeliveryFeeFactor::::get(sibling_para_id) < FixedU128::from_float(1.72)); diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index e73c7b507262..bfe4c9659cc7 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -15,7 +15,7 @@ clap = { version = "4.4.6", features = ["derive"] } log = "0.4.20" codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.188", features = ["derive"] } -jsonrpsee = { version = "0.16.2", features = ["server"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } futures = "0.3.28" # Local diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 3c2069c81ef4..c3e7c3361577 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -35,7 +35,7 @@ bridge-hub-rococo-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge- bridge-hub-kusama-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-kusama" } bridge-hub-polkadot-runtime = { path = "../parachains/runtimes/bridge-hubs/bridge-hub-polkadot" } penpal-runtime = { path = "../parachains/runtimes/testing/penpal" } -jsonrpsee = { version = "0.16.2", features = ["server"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } parachains-common = { path = "../parachains/common" } # Substrate diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index c996a01a12ed..16427700f460 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -14,7 +14,7 @@ async-trait = "0.1.73" clap = { version = "4.4.6", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } criterion = { version = "0.5.1", features = [ "async_tokio" ] } -jsonrpsee = { version = "0.16.2", features = ["server"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } rand = "0.8.5" serde = { version = "1.0.188", features = ["derive"] } tokio = { version = "1.32.0", features = ["macros"] } diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index a721645546af..a7b52f0f4465 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -774,6 +774,7 @@ pub fn node_config( rpc_id_provider: None, rpc_max_subs_per_conn: Default::default(), rpc_port: 9945, + rpc_message_buffer_capacity: Default::default(), prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index be2746daf321..9ccb9d53d6c4 100644 --- a/polkadot/node/test/service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -181,6 +181,7 @@ pub fn node_config( rpc_id_provider: None, rpc_max_subs_per_conn: Default::default(), rpc_port: 9944, + rpc_message_buffer_capacity: Default::default(), prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/polkadot/rpc/Cargo.toml b/polkadot/rpc/Cargo.toml index b5f155b5a658..bc5e922374ff 100644 --- a/polkadot/rpc/Cargo.toml +++ b/polkadot/rpc/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] -jsonrpsee = { version = "0.16.2", features = ["server"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } polkadot-primitives = { path = "../primitives" } sc-client-api = { path = "../../substrate/client/api" } sp-blockchain = { path = "../../substrate/primitives/blockchain" } diff --git a/substrate/bin/minimal/node/Cargo.toml b/substrate/bin/minimal/node/Cargo.toml index 11ce98eec0dd..601e43389401 100644 --- a/substrate/bin/minimal/node/Cargo.toml +++ b/substrate/bin/minimal/node/Cargo.toml @@ -20,7 +20,7 @@ name = "minimal-node" clap = { version = "4.0.9", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" -jsonrpsee = { version = "0.16.2", features = ["server"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } sc-cli = { path = "../../../client/cli" } sc-executor = { path = "../../../client/executor" } diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index 23840cce2229..b34f29ae49cd 100644 --- a/substrate/bin/node-template/node/Cargo.toml +++ b/substrate/bin/node-template/node/Cargo.toml @@ -44,7 +44,7 @@ frame-system = { path = "../../../frame/system" } pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false} # These dependencies are used for the node template's RPCs -jsonrpsee = { version = "0.16.2", features = ["server"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } sp-api = { path = "../../../primitives/api" } sc-rpc-api = { path = "../../../client/rpc-api" } sp-blockchain = { path = "../../../primitives/blockchain" } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 49dc39099be0..d17ffc58fb57 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -41,7 +41,7 @@ array-bytes = "6.1" clap = { version = "4.4.6", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } serde = { version = "1.0.188", features = ["derive"] } -jsonrpsee = { version = "0.16.2", features = ["server"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } futures = "0.3.21" log = "0.4.17" rand = "0.8" diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index 246de8f3e925..ad46bac88225 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -82,6 +82,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { rpc_id_provider: Default::default(), rpc_max_subs_per_conn: Default::default(), rpc_port: 9944, + rpc_message_buffer_capacity: Default::default(), prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index 47f890574151..a3d6c0938d09 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -78,6 +78,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { rpc_id_provider: Default::default(), rpc_max_subs_per_conn: Default::default(), rpc_port: 9944, + rpc_message_buffer_capacity: Default::default(), prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index 43db4ab9d34f..3f1e378c4479 100644 --- a/substrate/bin/node/rpc/Cargo.toml +++ b/substrate/bin/node/rpc/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.16.2", features = ["server"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } node-primitives = { path = "../primitives" } pallet-transaction-payment-rpc = { path = "../../../frame/transaction-payment/rpc" } mmr-rpc = { path = "../../../client/merkle-mountain-range/rpc" } diff --git a/substrate/client/cli/src/commands/run_cmd.rs b/substrate/client/cli/src/commands/run_cmd.rs index bc62dc3324e3..228262a5256f 100644 --- a/substrate/client/cli/src/commands/run_cmd.rs +++ b/substrate/client/cli/src/commands/run_cmd.rs @@ -25,7 +25,7 @@ use crate::{ }, CliConfiguration, PrometheusParams, RuntimeParams, TelemetryParams, RPC_DEFAULT_MAX_CONNECTIONS, RPC_DEFAULT_MAX_REQUEST_SIZE_MB, RPC_DEFAULT_MAX_RESPONSE_SIZE_MB, - RPC_DEFAULT_MAX_SUBS_PER_CONN, + RPC_DEFAULT_MAX_SUBS_PER_CONN, RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN, }; use clap::Parser; use regex::Regex; @@ -102,9 +102,19 @@ pub struct RunCmd { #[arg(long, value_name = "COUNT", default_value_t = RPC_DEFAULT_MAX_CONNECTIONS)] pub rpc_max_connections: u32, - /// Specify browser *origins* allowed to access the HTTP and WS RPC servers. + /// The number of messages the RPC server is allowed to keep in memory. /// - /// A comma-separated list of origins (`protocol://domain` or special `null` + /// If the buffer becomes full then the server will not process + /// new messages until the connected client start reading the + /// underlying messages. + /// + /// This applies per connection which includes both + /// JSON-RPC methods calls and subscriptions. + #[arg(long, default_value_t = RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN)] + pub rpc_message_buffer_capacity_per_connection: u32, + + /// Specify browser Origins allowed to access the HTTP & WS RPC servers. + /// A comma-separated list of origins (protocol://domain or special `null` /// value). Value of `all` will disable origin validation. Default is to /// allow localhost and origins. When running in /// `--dev` mode the default is to allow all origins. diff --git a/substrate/client/cli/src/config.rs b/substrate/client/cli/src/config.rs index 4d218da6aa89..497c4da35307 100644 --- a/substrate/client/cli/src/config.rs +++ b/substrate/client/cli/src/config.rs @@ -52,8 +52,11 @@ pub const RPC_DEFAULT_MAX_SUBS_PER_CONN: u32 = 1024; pub const RPC_DEFAULT_MAX_REQUEST_SIZE_MB: u32 = 15; /// The default max response size in MB. pub const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 15; -/// The default number of connection.. +/// The default concurrent connection limit. pub const RPC_DEFAULT_MAX_CONNECTIONS: u32 = 100; +/// The default number of messages the RPC server +/// is allowed to keep in memory per connection. +pub const RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN: u32 = 64; /// Default configuration values used by Substrate /// @@ -330,6 +333,11 @@ pub trait CliConfiguration: Sized { Ok(RPC_DEFAULT_MAX_SUBS_PER_CONN) } + /// The number of messages the RPC server is allowed to keep in memory per connection. + fn rpc_buffer_capacity_per_connection(&self) -> Result { + Ok(RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN) + } + /// Get the prometheus configuration (`None` if disabled) /// /// By default this is `None`. @@ -501,6 +509,7 @@ pub trait CliConfiguration: Sized { rpc_id_provider: None, rpc_max_subs_per_conn: self.rpc_max_subscriptions_per_connection()?, rpc_port: DCV::rpc_listen_port(), + rpc_message_buffer_capacity: self.rpc_buffer_capacity_per_connection()?, prometheus_config: self .prometheus_config(DCV::prometheus_listen_port(), &chain_spec)?, telemetry_endpoints, diff --git a/substrate/client/cli/src/runner.rs b/substrate/client/cli/src/runner.rs index 59f53200a192..032724bc55a9 100644 --- a/substrate/client/cli/src/runner.rs +++ b/substrate/client/cli/src/runner.rs @@ -273,6 +273,7 @@ mod tests { rpc_max_response_size: Default::default(), rpc_id_provider: Default::default(), rpc_max_subs_per_conn: Default::default(), + rpc_message_buffer_capacity: Default::default(), rpc_port: 9944, prometheus_config: None, telemetry_endpoints: None, diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index f54edb296842..f1c7c24335e7 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.20.3", features = ["client-core", "server", "macros"] } futures = "0.3.21" serde = { version = "1.0.188", features = ["derive"] } thiserror = "1.0" diff --git a/substrate/client/consensus/babe/rpc/src/lib.rs b/substrate/client/consensus/babe/rpc/src/lib.rs index bffe026ea6ef..307b1f955ba2 100644 --- a/substrate/client/consensus/babe/rpc/src/lib.rs +++ b/substrate/client/consensus/babe/rpc/src/lib.rs @@ -22,15 +22,15 @@ use std::{collections::HashMap, sync::Arc}; use futures::TryFutureExt; use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError, RpcResult}, + core::async_trait, proc_macros::rpc, - types::{error::CallError, ErrorObject}, + types::{ErrorObject, ErrorObjectOwned}, }; use serde::{Deserialize, Serialize}; use sc_consensus_babe::{authorship, BabeWorkerHandle}; use sc_consensus_epochs::Epoch as EpochT; -use sc_rpc_api::DenyUnsafe; +use sc_rpc_api::{DenyUnsafe, UnsafeRpcError}; use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppCrypto; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; @@ -48,7 +48,7 @@ pub trait BabeApi { /// Returns data about which slots (primary or secondary) can be claimed in the current epoch /// with the keys in the keystore. #[method(name = "babe_epochAuthorship")] - async fn epoch_authorship(&self) -> RpcResult>; + async fn epoch_authorship(&self) -> Result, Error>; } /// Provides RPC methods for interacting with Babe. @@ -89,7 +89,7 @@ where C::Api: BabeRuntimeApi, SC: SelectChain + Clone + 'static, { - async fn epoch_authorship(&self) -> RpcResult> { + async fn epoch_authorship(&self) -> Result, Error> { self.deny_unsafe.check_if_safe()?; let best_header = self.select_chain.best_chain().map_err(Error::SelectChain).await?; @@ -147,7 +147,7 @@ where } /// Holds information about the `slot`'s that can be claimed by a given key. -#[derive(Default, Debug, Deserialize, Serialize)] +#[derive(Clone, Default, Debug, Deserialize, Serialize)] pub struct EpochAuthorship { /// the array of primary slots that can be claimed primary: Vec, @@ -166,20 +166,26 @@ pub enum Error { /// Failed to fetch epoch data. #[error("Failed to fetch epoch data")] FetchEpoch, + /// Consensus error + #[error(transparent)] + Consensus(#[from] ConsensusError), + /// Errors that can be formatted as a String + #[error("{0}")] + StringError(String), + /// Call to an unsafe RPC was denied. + #[error(transparent)] + UnsafeRpcCalled(#[from] UnsafeRpcError), } -impl From for JsonRpseeError { +impl From for ErrorObjectOwned { fn from(error: Error) -> Self { - let error_code = match error { - Error::SelectChain(_) => 1, - Error::FetchEpoch => 2, - }; - - JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( - BABE_ERROR + error_code, - error.to_string(), - Some(format!("{:?}", error)), - ))) + match error { + Error::SelectChain(e) => ErrorObject::owned(BABE_ERROR + 1, e.to_string(), None::<()>), + Error::FetchEpoch => ErrorObject::owned(BABE_ERROR + 2, error.to_string(), None::<()>), + Error::Consensus(e) => ErrorObject::owned(BABE_ERROR + 3, e.to_string(), None::<()>), + Error::StringError(e) => ErrorObject::owned(BABE_ERROR + 4, e, None::<()>), + Error::UnsafeRpcCalled(e) => e.into(), + } } } @@ -251,7 +257,7 @@ mod tests { let api = babe_rpc.into_rpc(); let request = r#"{"jsonrpc":"2.0","method":"babe_epochAuthorship","params": [],"id":1}"#; - let (response, _) = api.raw_json_request(request).await.unwrap(); + let (response, _) = api.raw_json_request(request, 1).await.unwrap(); let expected = r#"{"jsonrpc":"2.0","result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[1,2,4],"secondary_vrf":[]}},"id":1}"#; assert_eq!(&response.result, expected); @@ -263,7 +269,7 @@ mod tests { let api = babe_rpc.into_rpc(); let request = r#"{"jsonrpc":"2.0","method":"babe_epochAuthorship","params":[],"id":1}"#; - let (response, _) = api.raw_json_request(request).await.unwrap(); + let (response, _) = api.raw_json_request(request, 1).await.unwrap(); let expected = r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"RPC call is unsafe to be called externally"},"id":1}"#; assert_eq!(&response.result, expected); diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index 74733ea9edd9..661bf09746a6 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://substrate.io" [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } futures = "0.3.21" -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.20.3", features = ["client-core", "server", "macros"] } log = "0.4" parking_lot = "0.12.1" serde = { version = "1.0.188", features = ["derive"] } diff --git a/substrate/client/consensus/beefy/rpc/src/lib.rs b/substrate/client/consensus/beefy/rpc/src/lib.rs index f5c0ff32627d..a11c6a2fabc7 100644 --- a/substrate/client/consensus/beefy/rpc/src/lib.rs +++ b/substrate/client/consensus/beefy/rpc/src/lib.rs @@ -23,15 +23,15 @@ use parking_lot::RwLock; use std::sync::Arc; -use sc_rpc::SubscriptionTaskExecutor; +use sc_rpc::{utils::pipe_from_stream, SubscriptionTaskExecutor}; use sp_runtime::traits::Block as BlockT; use futures::{task::SpawnError, FutureExt, StreamExt}; use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError, RpcResult}, + core::async_trait, proc_macros::rpc, - types::{error::CallError, ErrorObject, SubscriptionResult}, - SubscriptionSink, + types::{ErrorObject, ErrorObjectOwned}, + PendingSubscriptionSink, }; use log::warn; @@ -69,15 +69,11 @@ impl From for ErrorCode { } } -impl From for JsonRpseeError { +impl From for ErrorObjectOwned { fn from(error: Error) -> Self { let message = error.to_string(); let code = ErrorCode::from(error); - JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( - code as i32, - message, - None::<()>, - ))) + ErrorObject::owned(code as i32, message, None::<()>) } } @@ -98,7 +94,7 @@ pub trait BeefyApi { /// in the network or if the client is still initializing or syncing with the network. /// In such case an error would be returned. #[method(name = "beefy_getFinalizedHead")] - async fn latest_finalized(&self) -> RpcResult; + async fn latest_finalized(&self) -> Result; } /// Implements the BeefyApi RPC trait for interacting with BEEFY. @@ -138,27 +134,20 @@ impl BeefyApiServer SubscriptionResult { + fn subscribe_justifications(&self, pending: PendingSubscriptionSink) { let stream = self .finality_proof_stream .subscribe(100_000) .map(|vfp| notification::EncodedVersionedFinalityProof::new::(vfp)); - let fut = async move { - sink.pipe_from_stream(stream).await; - }; - - self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); - Ok(()) + sc_rpc::utils::spawn_subscription_task( + &self.executor, + pipe_from_stream(pending, stream, 16), + ); } - async fn latest_finalized(&self) -> RpcResult { - self.beefy_best_block - .read() - .as_ref() - .cloned() - .ok_or(Error::EndpointNotReady) - .map_err(Into::into) + async fn latest_finalized(&self) -> Result { + self.beefy_best_block.read().as_ref().cloned().ok_or(Error::EndpointNotReady) } } @@ -167,7 +156,7 @@ mod tests { use super::*; use codec::{Decode, Encode}; - use jsonrpsee::{types::EmptyServerParams as EmptyParams, RpcModule}; + use jsonrpsee::{core::EmptyServerParams as EmptyParams, RpcModule}; use sc_consensus_beefy::{ communication::notification::BeefyVersionedFinalityProofSender, justification::BeefyVersionedFinalityProof, @@ -199,7 +188,7 @@ mod tests { let (rpc, _) = setup_io_handler(); let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#; let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"BEEFY RPC endpoint not ready"},"id":1}"#.to_string(); - let (response, _) = rpc.raw_json_request(&request).await.unwrap(); + let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); assert_eq!(expected_response, response.result); } @@ -230,13 +219,13 @@ mod tests { let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2); while std::time::Instant::now() < deadline { - let (response, _) = io.raw_json_request(request).await.expect("RPC requests work"); + let (response, _) = io.raw_json_request(request, 1).await.expect("RPC requests work"); if response.result != not_ready { assert_eq!(response.result, expected); // Success return } - std::thread::sleep(std::time::Duration::from_millis(50)) + tokio::time::sleep(std::time::Duration::from_millis(50)).await; } panic!( @@ -249,7 +238,7 @@ mod tests { let (rpc, _) = setup_io_handler(); // Subscribe call. let _sub = rpc - .subscribe("beefy_subscribeJustifications", EmptyParams::new()) + .subscribe_unbounded("beefy_subscribeJustifications", EmptyParams::new()) .await .unwrap(); @@ -257,6 +246,7 @@ mod tests { let (response, _) = rpc .raw_json_request( r#"{"jsonrpc":"2.0","method":"beefy_unsubscribeJustifications","params":["FOO"],"id":1}"#, + 1, ) .await .unwrap(); @@ -284,7 +274,7 @@ mod tests { // Subscribe let mut sub = rpc - .subscribe("beefy_subscribeJustifications", EmptyParams::new()) + .subscribe_unbounded("beefy_subscribeJustifications", EmptyParams::new()) .await .unwrap(); diff --git a/substrate/client/consensus/common/src/block_import.rs b/substrate/client/consensus/common/src/block_import.rs index a451692ad478..d91851aea62c 100644 --- a/substrate/client/consensus/common/src/block_import.rs +++ b/substrate/client/consensus/common/src/block_import.rs @@ -43,7 +43,7 @@ pub enum ImportResult { } /// Auxiliary data associated with an imported block result. -#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct ImportedAux { /// Only the header has been imported. Block body verification was skipped. pub header_only: bool, diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index e2f9e40afb2d..04b4d2bad258 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" [dependencies] finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } futures = "0.3.16" -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.20.3", features = ["client-core", "server", "macros"] } log = "0.4.8" parity-scale-codec = { version = "3.6.1", features = ["derive"] } serde = { version = "1.0.188", features = ["derive"] } diff --git a/substrate/client/consensus/grandpa/rpc/src/error.rs b/substrate/client/consensus/grandpa/rpc/src/error.rs index 4884380cd22d..795077804a4b 100644 --- a/substrate/client/consensus/grandpa/rpc/src/error.rs +++ b/substrate/client/consensus/grandpa/rpc/src/error.rs @@ -16,10 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use jsonrpsee::{ - core::Error as JsonRpseeError, - types::error::{CallError, ErrorObject}, -}; +use jsonrpsee::types::error::{ErrorObject, ErrorObjectOwned}; #[derive(Debug, thiserror::Error)] /// Top-level error type for the RPC handler @@ -61,15 +58,11 @@ impl From for ErrorCode { } } -impl From for JsonRpseeError { +impl From for ErrorObjectOwned { fn from(error: Error) -> Self { let message = error.to_string(); let code = ErrorCode::from(error); - JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( - code as i32, - message, - None::<()>, - ))) + ErrorObject::owned(code as i32, message, None::<()>) } } diff --git a/substrate/client/consensus/grandpa/rpc/src/finality.rs b/substrate/client/consensus/grandpa/rpc/src/finality.rs index f8ec01781ac6..93f6c46e411e 100644 --- a/substrate/client/consensus/grandpa/rpc/src/finality.rs +++ b/substrate/client/consensus/grandpa/rpc/src/finality.rs @@ -21,7 +21,7 @@ use serde::{Deserialize, Serialize}; use sc_consensus_grandpa::FinalityProofProvider; use sp_runtime::traits::{Block as BlockT, NumberFor}; -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] pub struct EncodedFinalityProof(pub sp_core::Bytes); /// Local trait mainly to allow mocking in tests. diff --git a/substrate/client/consensus/grandpa/rpc/src/lib.rs b/substrate/client/consensus/grandpa/rpc/src/lib.rs index c6298bff969b..166be02b4fc3 100644 --- a/substrate/client/consensus/grandpa/rpc/src/lib.rs +++ b/substrate/client/consensus/grandpa/rpc/src/lib.rs @@ -19,15 +19,13 @@ //! RPC API for GRANDPA. #![warn(missing_docs)] -use futures::{FutureExt, StreamExt}; +use futures::StreamExt; use log::warn; use std::sync::Arc; use jsonrpsee::{ - core::{async_trait, RpcResult}, + core::{async_trait, server::PendingSubscriptionSink}, proc_macros::rpc, - types::SubscriptionResult, - SubscriptionSink, }; mod error; @@ -35,13 +33,13 @@ mod finality; mod notification; mod report; -use sc_consensus_grandpa::GrandpaJustificationStream; -use sc_rpc::SubscriptionTaskExecutor; -use sp_runtime::traits::{Block as BlockT, NumberFor}; - +use error::Error; use finality::{EncodedFinalityProof, RpcFinalityProofProvider}; use notification::JustificationNotification; use report::{ReportAuthoritySet, ReportVoterState, ReportedRoundStates}; +use sc_consensus_grandpa::GrandpaJustificationStream; +use sc_rpc::{utils::pipe_from_stream, SubscriptionTaskExecutor}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; /// Provides RPC methods for interacting with GRANDPA. #[rpc(client, server)] @@ -49,7 +47,7 @@ pub trait GrandpaApi { /// Returns the state of the current best round state as well as the /// ongoing background rounds. #[method(name = "grandpa_roundState")] - async fn round_state(&self) -> RpcResult; + async fn round_state(&self) -> Result; /// Returns the block most recently finalized by Grandpa, alongside /// side its justification. @@ -63,7 +61,7 @@ pub trait GrandpaApi { /// Prove finality for the given block number by returning the Justification for the last block /// in the set and all the intermediary headers to link them together. #[method(name = "grandpa_proveFinality")] - async fn prove_finality(&self, block: Number) -> RpcResult>; + async fn prove_finality(&self, block: Number) -> Result, Error>; } /// Provides RPC methods for interacting with GRANDPA. @@ -99,36 +97,31 @@ where Block: BlockT, ProofProvider: RpcFinalityProofProvider + Send + Sync + 'static, { - async fn round_state(&self) -> RpcResult { - ReportedRoundStates::from(&self.authority_set, &self.voter_state).map_err(Into::into) + async fn round_state(&self) -> Result { + ReportedRoundStates::from(&self.authority_set, &self.voter_state) } - fn subscribe_justifications(&self, mut sink: SubscriptionSink) -> SubscriptionResult { + fn subscribe_justifications(&self, pending: PendingSubscriptionSink) { let stream = self.justification_stream.subscribe(100_000).map( |x: sc_consensus_grandpa::GrandpaJustification| { JustificationNotification::from(x) }, ); - let fut = async move { - sink.pipe_from_stream(stream).await; - }; - - self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); - Ok(()) + sc_rpc::utils::spawn_subscription_task( + &self.executor, + pipe_from_stream(pending, stream, 16), + ); } async fn prove_finality( &self, block: NumberFor, - ) -> RpcResult> { - self.finality_proof_provider - .rpc_prove_finality(block) - .map_err(|e| { - warn!("Error proving finality: {}", e); - error::Error::ProveFinalityFailed(e) - }) - .map_err(Into::into) + ) -> Result, Error> { + self.finality_proof_provider.rpc_prove_finality(block).map_err(|e| { + warn!("Error proving finality: {}", e); + error::Error::ProveFinalityFailed(e) + }) } } @@ -137,17 +130,15 @@ mod tests { use super::*; use std::{collections::HashSet, convert::TryInto, sync::Arc}; - use jsonrpsee::{ - types::{EmptyServerParams as EmptyParams, SubscriptionId}, - RpcModule, - }; + use jsonrpsee::{core::EmptyServerParams as EmptyParams, types::SubscriptionId, RpcModule}; use parity_scale_codec::{Decode, Encode}; use sc_block_builder::{BlockBuilder, RecordProof}; use sc_consensus_grandpa::{ report, AuthorityId, FinalityProof, GrandpaJustification, GrandpaJustificationSender, }; + use sc_rpc::testing::test_executor; use sp_blockchain::HeaderBackend; - use sp_core::{crypto::ByteArray, testing::TaskExecutor}; + use sp_core::crypto::ByteArray; use sp_keyring::Ed25519Keyring; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use substrate_test_runtime_client::{ @@ -264,7 +255,7 @@ mod tests { { let (justification_sender, justification_stream) = GrandpaJustificationStream::channel(); let finality_proof_provider = Arc::new(TestFinalityProofProvider { finality_proof }); - let executor = Arc::new(TaskExecutor::default()); + let executor = test_executor(); let rpc = Grandpa::new( executor, @@ -283,7 +274,7 @@ mod tests { let (rpc, _) = setup_io_handler(EmptyVoterState); let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"GRANDPA RPC endpoint not ready"},"id":0}"#.to_string(); let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; - let (response, _) = rpc.raw_json_request(&request).await.unwrap(); + let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); assert_eq!(expected_response, response.result); } @@ -306,7 +297,7 @@ mod tests { },\"id\":0}".to_string(); let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; - let (response, _) = rpc.raw_json_request(&request).await.unwrap(); + let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); assert_eq!(expected_response, response.result); } @@ -315,7 +306,7 @@ mod tests { let (rpc, _) = setup_io_handler(TestVoterState); // Subscribe call. let _sub = rpc - .subscribe("grandpa_subscribeJustifications", EmptyParams::new()) + .subscribe_unbounded("grandpa_subscribeJustifications", EmptyParams::new()) .await .unwrap(); @@ -323,6 +314,7 @@ mod tests { let (response, _) = rpc .raw_json_request( r#"{"jsonrpc":"2.0","method":"grandpa_unsubscribeJustifications","params":["FOO"],"id":1}"#, + 1, ) .await .unwrap(); @@ -390,7 +382,7 @@ mod tests { let (rpc, justification_sender) = setup_io_handler(TestVoterState); let mut sub = rpc - .subscribe("grandpa_subscribeJustifications", EmptyParams::new()) + .subscribe_unbounded("grandpa_subscribeJustifications", EmptyParams::new()) .await .unwrap(); diff --git a/substrate/client/consensus/grandpa/rpc/src/report.rs b/substrate/client/consensus/grandpa/rpc/src/report.rs index ae4fd76d2857..b41d090afac8 100644 --- a/substrate/client/consensus/grandpa/rpc/src/report.rs +++ b/substrate/client/consensus/grandpa/rpc/src/report.rs @@ -57,21 +57,21 @@ impl ReportVoterState for SharedVoterState { } } -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct Prevotes { current_weight: u32, missing: BTreeSet, } -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct Precommits { current_weight: u32, missing: BTreeSet, } -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct RoundState { round: u32, @@ -111,7 +111,7 @@ impl RoundState { /// The state of the current best round, as well as the background rounds in a /// form suitable for serialization. -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ReportedRoundStates { set_id: u32, diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index a6430fdf1dee..8d29b320fd1d 100644 --- a/substrate/client/consensus/manual-seal/Cargo.toml +++ b/substrate/client/consensus/manual-seal/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.20.3", features = ["client-core", "server", "macros"] } assert_matches = "1.3.0" async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.6.1" } diff --git a/substrate/client/consensus/manual-seal/src/error.rs b/substrate/client/consensus/manual-seal/src/error.rs index eeae1d153e81..d7bb00eff6b7 100644 --- a/substrate/client/consensus/manual-seal/src/error.rs +++ b/substrate/client/consensus/manual-seal/src/error.rs @@ -20,10 +20,7 @@ //! This is suitable for a testing environment. use futures::channel::{mpsc::SendError, oneshot}; -use jsonrpsee::{ - core::Error as JsonRpseeError, - types::error::{CallError, ErrorObject}, -}; +use jsonrpsee::types::error::{ErrorObject, ErrorObjectOwned}; use sc_consensus::ImportResult; use sp_blockchain::Error as BlockchainError; use sp_consensus::Error as ConsensusError; @@ -106,8 +103,8 @@ impl Error { } } -impl From for JsonRpseeError { +impl From for ErrorObjectOwned { fn from(err: Error) -> Self { - CallError::Custom(ErrorObject::owned(err.to_code(), err.to_string(), None::<()>)).into() + ErrorObject::owned(err.to_code(), err.to_string(), None::<()>) } } diff --git a/substrate/client/consensus/manual-seal/src/rpc.rs b/substrate/client/consensus/manual-seal/src/rpc.rs index c0b3af69bedf..6018c3ab092a 100644 --- a/substrate/client/consensus/manual-seal/src/rpc.rs +++ b/substrate/client/consensus/manual-seal/src/rpc.rs @@ -23,10 +23,7 @@ use futures::{ channel::{mpsc, oneshot}, SinkExt, }; -use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError, RpcResult}, - proc_macros::rpc, -}; +use jsonrpsee::{core::async_trait, proc_macros::rpc}; use sc_consensus::ImportedAux; use serde::{Deserialize, Serialize}; use sp_runtime::EncodedJustification; @@ -74,7 +71,7 @@ pub trait ManualSealApi { create_empty: bool, finalize: bool, parent_hash: Option, - ) -> RpcResult>; + ) -> Result, Error>; /// Instructs the manual-seal authorship task to finalize a block #[method(name = "engine_finalizeBlock")] @@ -82,7 +79,7 @@ pub trait ManualSealApi { &self, hash: Hash, justification: Option, - ) -> RpcResult; + ) -> Result; } /// A struct that implements the [`ManualSealApiServer`]. @@ -91,7 +88,7 @@ pub struct ManualSeal { } /// return type of `engine_createBlock` -#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] pub struct CreatedBlock { /// hash of the created block. pub hash: Hash, @@ -115,7 +112,7 @@ impl ManualSealApiServer for ManualSeal { create_empty: bool, finalize: bool, parent_hash: Option, - ) -> RpcResult> { + ) -> Result, Error> { let mut sink = self.import_block_channel.clone(); let (sender, receiver) = oneshot::channel(); // NOTE: this sends a Result over the channel. @@ -131,7 +128,7 @@ impl ManualSealApiServer for ManualSeal { match receiver.await { Ok(Ok(rx)) => Ok(rx), Ok(Err(e)) => Err(e.into()), - Err(e) => Err(JsonRpseeError::to_call_error(e)), + Err(e) => Err(e.into()), } } @@ -139,12 +136,12 @@ impl ManualSealApiServer for ManualSeal { &self, hash: Hash, justification: Option, - ) -> RpcResult { + ) -> Result { let mut sink = self.import_block_channel.clone(); let (sender, receiver) = oneshot::channel(); let command = EngineCommand::FinalizeBlock { hash, sender: Some(sender), justification }; sink.send(command).await?; - receiver.await.map(|_| true).map_err(|e| JsonRpseeError::to_call_error(e)) + receiver.await.map(|_| true).map_err(Into::into) } } diff --git a/substrate/client/merkle-mountain-range/rpc/Cargo.toml b/substrate/client/merkle-mountain-range/rpc/Cargo.toml index 05d8547d243f..edeed225fa81 100644 --- a/substrate/client/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/client/merkle-mountain-range/rpc/Cargo.toml @@ -13,14 +13,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.20.3", features = ["client-core", "server", "macros"] } serde = { version = "1.0.188", features = ["derive"] } sp-api = { path = "../../../primitives/api" } sp-blockchain = { path = "../../../primitives/blockchain" } sp-core = { path = "../../../primitives/core" } sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } -anyhow = "1" [dev-dependencies] serde_json = "1.0.107" diff --git a/substrate/client/merkle-mountain-range/rpc/src/lib.rs b/substrate/client/merkle-mountain-range/rpc/src/lib.rs index 5be82b600d91..3d59dbcc3f5a 100644 --- a/substrate/client/merkle-mountain-range/rpc/src/lib.rs +++ b/substrate/client/merkle-mountain-range/rpc/src/lib.rs @@ -26,7 +26,7 @@ use codec::{Codec, Decode, Encode}; use jsonrpsee::{ core::{async_trait, RpcResult}, proc_macros::rpc, - types::error::{CallError, ErrorObject}, + types::{error::ErrorObject, ErrorObjectOwned}, }; use serde::{Deserialize, Serialize}; @@ -189,11 +189,9 @@ where fn verify_proof(&self, proof: LeavesProof<::Hash>) -> RpcResult { let mut api = self.client.runtime_api(); - let leaves = Decode::decode(&mut &proof.leaves.0[..]) - .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; + let leaves = Decode::decode(&mut &proof.leaves.0[..]).map_err(invalid_params)?; - let decoded_proof = Decode::decode(&mut &proof.proof.0[..]) - .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; + let decoded_proof = Decode::decode(&mut &proof.proof.0[..]).map_err(invalid_params)?; api.register_extension(OffchainDbExt::new(self.offchain_db.clone())); @@ -211,11 +209,9 @@ where ) -> RpcResult { let api = self.client.runtime_api(); - let leaves = Decode::decode(&mut &proof.leaves.0[..]) - .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; + let leaves = Decode::decode(&mut &proof.leaves.0[..]).map_err(invalid_params)?; - let decoded_proof = Decode::decode(&mut &proof.proof.0[..]) - .map_err(|e| CallError::InvalidParams(anyhow::Error::new(e)))?; + let decoded_proof = Decode::decode(&mut &proof.proof.0[..]).map_err(invalid_params)?; api.verify_proof_stateless(proof.block_hash, mmr_root, leaves, decoded_proof) .map_err(runtime_error_into_rpc_error)? @@ -226,7 +222,7 @@ where } /// Converts an mmr-specific error into a [`CallError`]. -fn mmr_error_into_rpc_error(err: MmrError) -> CallError { +fn mmr_error_into_rpc_error(err: MmrError) -> ErrorObjectOwned { let error_code = MMR_ERROR + match err { MmrError::LeafNotFound => 1, @@ -237,16 +233,20 @@ fn mmr_error_into_rpc_error(err: MmrError) -> CallError { _ => 0, }; - CallError::Custom(ErrorObject::owned(error_code, err.to_string(), Some(format!("{:?}", err)))) + ErrorObject::owned(error_code, err.to_string(), Some(format!("{:?}", err))) } /// Converts a runtime trap into a [`CallError`]. -fn runtime_error_into_rpc_error(err: impl std::fmt::Debug) -> CallError { - CallError::Custom(ErrorObject::owned( - RUNTIME_ERROR, - "Runtime trapped", - Some(format!("{:?}", err)), - )) +fn runtime_error_into_rpc_error(err: impl std::fmt::Debug) -> ErrorObjectOwned { + ErrorObject::owned(RUNTIME_ERROR, "Runtime trapped", Some(format!("{:?}", err))) +} + +fn invalid_params(e: impl std::error::Error) -> ErrorObjectOwned { + ErrorObject::owned( + jsonrpsee::types::error::ErrorCode::InvalidParams.code(), + e.to_string(), + None::<()>, + ) } #[cfg(test)] diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index e07bdf0d15a1..c26c91829452 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -25,4 +25,4 @@ sp-core = { path = "../../primitives/core" } sp-rpc = { path = "../../primitives/rpc" } sp-runtime = { path = "../../primitives/runtime" } sp-version = { path = "../../primitives/version" } -jsonrpsee = { version = "0.16.2", features = ["server", "client-core", "macros"] } +jsonrpsee = { version = "0.20.3", features = ["server", "client-core", "macros"] } diff --git a/substrate/client/rpc-api/src/author/error.rs b/substrate/client/rpc-api/src/author/error.rs index 648dbb295d8d..0ccd82fc0b64 100644 --- a/substrate/client/rpc-api/src/author/error.rs +++ b/substrate/client/rpc-api/src/author/error.rs @@ -18,10 +18,7 @@ //! Authoring RPC module errors. -use jsonrpsee::{ - core::Error as JsonRpseeError, - types::error::{CallError, ErrorObject}, -}; +use jsonrpsee::types::error::{ErrorObject, ErrorObjectOwned}; use sp_runtime::transaction_validity::InvalidTransaction; /// Author RPC Result type. @@ -86,98 +83,104 @@ const POOL_NO_TAGS: i32 = POOL_INVALID_TX + 9; const POOL_INVALID_BLOCK_ID: i32 = POOL_INVALID_TX + 10; /// The pool is not accepting future transactions. const POOL_FUTURE_TX: i32 = POOL_INVALID_TX + 11; +/// Other error. +const OTHER_ERR: i32 = BASE_ERROR + 40; -impl From for JsonRpseeError { - fn from(e: Error) -> Self { +impl From for ErrorObjectOwned { + fn from(e: Error) -> ErrorObjectOwned { use sc_transaction_pool_api::error::Error as PoolError; match e { - Error::BadFormat(e) => CallError::Custom(ErrorObject::owned( + Error::BadFormat(e) => ErrorObject::owned( BAD_FORMAT, format!("Extrinsic has invalid format: {}", e), None::<()>, - )), - Error::Verification(e) => CallError::Custom(ErrorObject::owned( + ), + Error::Verification(e) => ErrorObject::owned( VERIFICATION_ERROR, format!("Verification Error: {}", e), Some(format!("{:?}", e)), - )), + ), Error::Pool(PoolError::InvalidTransaction(InvalidTransaction::Custom(e))) => { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( POOL_INVALID_TX, "Invalid Transaction", Some(format!("Custom error: {}", e)), - )) + ) }, Error::Pool(PoolError::InvalidTransaction(e)) => { let msg: &str = e.into(); - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( POOL_INVALID_TX, "Invalid Transaction", Some(msg), - )) + ) }, Error::Pool(PoolError::UnknownTransaction(e)) => { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( POOL_UNKNOWN_VALIDITY, "Unknown Transaction Validity", Some(format!("{:?}", e)), - )) + ) }, Error::Pool(PoolError::TemporarilyBanned) => - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( POOL_TEMPORARILY_BANNED, "Transaction is temporarily banned", None::<()>, - )), + ), Error::Pool(PoolError::AlreadyImported(hash)) => - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( POOL_ALREADY_IMPORTED, "Transaction Already Imported", Some(format!("{:?}", hash)), - )), - Error::Pool(PoolError::TooLowPriority { old, new }) => CallError::Custom(ErrorObject::owned( + ), + Error::Pool(PoolError::TooLowPriority { old, new }) => ErrorObject::owned( POOL_TOO_LOW_PRIORITY, format!("Priority is too low: ({} vs {})", old, new), Some("The transaction has too low priority to replace another transaction already in the pool.") - )), + ), Error::Pool(PoolError::CycleDetected) => - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( POOL_CYCLE_DETECTED, "Cycle Detected", None::<()> - )), - Error::Pool(PoolError::ImmediatelyDropped) => CallError::Custom(ErrorObject::owned( + ), + Error::Pool(PoolError::ImmediatelyDropped) => ErrorObject::owned( POOL_IMMEDIATELY_DROPPED, "Immediately Dropped", Some("The transaction couldn't enter the pool because of the limit"), - )), - Error::Pool(PoolError::Unactionable) => CallError::Custom(ErrorObject::owned( + ), + Error::Pool(PoolError::Unactionable) => ErrorObject::owned( POOL_UNACTIONABLE, "Unactionable", Some("The transaction is unactionable since it is not propagable and \ the local node does not author blocks") - )), - Error::Pool(PoolError::NoTagsProvided) => CallError::Custom(ErrorObject::owned( + ), + Error::Pool(PoolError::NoTagsProvided) => ErrorObject::owned( POOL_NO_TAGS, "No tags provided", Some("Transaction does not provide any tags, so the pool can't identify it") - )), + ), Error::Pool(PoolError::InvalidBlockId(_)) => - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( POOL_INVALID_BLOCK_ID, "The provided block ID is not valid", None::<()> - )), + ), Error::Pool(PoolError::RejectedFutureTransaction) => { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( POOL_FUTURE_TX, "The pool is not accepting future transactions", None::<()>, - )) + ) }, Error::UnsafeRpcCalled(e) => e.into(), - e => CallError::Failed(e.into()), - }.into() + other => ErrorObject::owned( + OTHER_ERR, + other.to_string(), + None::<()>, + ) + } } } diff --git a/substrate/client/rpc-api/src/author/mod.rs b/substrate/client/rpc-api/src/author/mod.rs index 55881e62152e..cfc56f4130ab 100644 --- a/substrate/client/rpc-api/src/author/mod.rs +++ b/substrate/client/rpc-api/src/author/mod.rs @@ -18,27 +18,28 @@ //! Substrate block-author/full-node API. -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use sc_transaction_pool_api::TransactionStatus; -use sp_core::Bytes; - pub mod error; pub mod hash; +use error::Error; +use jsonrpsee::proc_macros::rpc; +use sc_transaction_pool_api::TransactionStatus; +use sp_core::Bytes; + /// Substrate authoring RPC API #[rpc(client, server)] pub trait AuthorApi { /// Submit hex-encoded extrinsic for inclusion in block. #[method(name = "author_submitExtrinsic")] - async fn submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult; + async fn submit_extrinsic(&self, extrinsic: Bytes) -> Result; /// Insert a key into the keystore. #[method(name = "author_insertKey")] - fn insert_key(&self, key_type: String, suri: String, public: Bytes) -> RpcResult<()>; + fn insert_key(&self, key_type: String, suri: String, public: Bytes) -> Result<(), Error>; /// Generate new session keys and returns the corresponding public keys. #[method(name = "author_rotateKeys")] - fn rotate_keys(&self) -> RpcResult; + fn rotate_keys(&self) -> Result; /// Checks if the keystore has private keys for the given session public keys. /// @@ -46,24 +47,24 @@ pub trait AuthorApi { /// /// Returns `true` iff all private keys could be found. #[method(name = "author_hasSessionKeys")] - fn has_session_keys(&self, session_keys: Bytes) -> RpcResult; + fn has_session_keys(&self, session_keys: Bytes) -> Result; /// Checks if the keystore has private keys for the given public key and key type. /// /// Returns `true` if a private key could be found. #[method(name = "author_hasKey")] - fn has_key(&self, public_key: Bytes, key_type: String) -> RpcResult; + fn has_key(&self, public_key: Bytes, key_type: String) -> Result; /// Returns all pending extrinsics, potentially grouped by sender. #[method(name = "author_pendingExtrinsics")] - fn pending_extrinsics(&self) -> RpcResult>; + fn pending_extrinsics(&self) -> Result, Error>; /// Remove given extrinsic from the pool and temporarily ban it to prevent reimporting. #[method(name = "author_removeExtrinsic")] fn remove_extrinsic( &self, bytes_or_hash: Vec>, - ) -> RpcResult>; + ) -> Result, Error>; /// Submit an extrinsic to watch. /// diff --git a/substrate/client/rpc-api/src/chain/error.rs b/substrate/client/rpc-api/src/chain/error.rs index 652192942588..ff3593557bdb 100644 --- a/substrate/client/rpc-api/src/chain/error.rs +++ b/substrate/client/rpc-api/src/chain/error.rs @@ -18,10 +18,7 @@ //! Error helpers for Chain RPC module. -use jsonrpsee::{ - core::Error as JsonRpseeError, - types::error::{CallError, ErrorObject}, -}; +use jsonrpsee::types::{error::ErrorObject, ErrorObjectOwned}; /// Chain RPC Result type. pub type Result = std::result::Result; @@ -39,12 +36,11 @@ pub enum Error { /// Base error code for all chain errors. const BASE_ERROR: i32 = crate::error::base::CHAIN; -impl From for JsonRpseeError { - fn from(e: Error) -> Self { +impl From for ErrorObjectOwned { + fn from(e: Error) -> ErrorObjectOwned { match e { - Error::Other(message) => - CallError::Custom(ErrorObject::owned(BASE_ERROR + 1, message, None::<()>)).into(), - e => e.into(), + Error::Other(message) => ErrorObject::owned(BASE_ERROR + 1, message, None::<()>), + e => ErrorObject::owned(BASE_ERROR + 2, e.to_string(), None::<()>), } } } diff --git a/substrate/client/rpc-api/src/chain/mod.rs b/substrate/client/rpc-api/src/chain/mod.rs index f215cd978f03..e53c2bc5510a 100644 --- a/substrate/client/rpc-api/src/chain/mod.rs +++ b/substrate/client/rpc-api/src/chain/mod.rs @@ -18,20 +18,21 @@ //! Substrate blockchain API. -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use sp_rpc::{list::ListOrValue, number::NumberOrHex}; - pub mod error; +use error::Error; +use jsonrpsee::proc_macros::rpc; +use sp_rpc::{list::ListOrValue, number::NumberOrHex}; + #[rpc(client, server)] pub trait ChainApi { /// Get header. #[method(name = "chain_getHeader", blocking)] - fn header(&self, hash: Option) -> RpcResult>; + fn header(&self, hash: Option) -> Result, Error>; /// Get header and body of a block. #[method(name = "chain_getBlock", blocking)] - fn block(&self, hash: Option) -> RpcResult>; + fn block(&self, hash: Option) -> Result, Error>; /// Get hash of the n-th block in the canon chain. /// @@ -40,11 +41,11 @@ pub trait ChainApi { fn block_hash( &self, hash: Option>, - ) -> RpcResult>>; + ) -> Result>, Error>; /// Get hash of the last finalized block in the canon chain. #[method(name = "chain_getFinalizedHead", aliases = ["chain_getFinalisedHead"], blocking)] - fn finalized_head(&self) -> RpcResult; + fn finalized_head(&self) -> Result; /// All head subscription. #[subscription( diff --git a/substrate/client/rpc-api/src/child_state/mod.rs b/substrate/client/rpc-api/src/child_state/mod.rs index a184677a721b..70f304ea8e02 100644 --- a/substrate/client/rpc-api/src/child_state/mod.rs +++ b/substrate/client/rpc-api/src/child_state/mod.rs @@ -17,8 +17,8 @@ // along with this program. If not, see . //! Substrate child state API -use crate::state::ReadProof; -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use crate::state::{Error, ReadProof}; +use jsonrpsee::proc_macros::rpc; use sp_core::storage::{PrefixedStorageKey, StorageData, StorageKey}; /// Substrate child state API @@ -35,7 +35,7 @@ pub trait ChildStateApi { child_storage_key: PrefixedStorageKey, prefix: StorageKey, hash: Option, - ) -> RpcResult>; + ) -> Result, Error>; /// Returns the keys with prefix from a child storage with pagination support. /// Up to `count` keys will be returned. @@ -48,7 +48,7 @@ pub trait ChildStateApi { count: u32, start_key: Option, hash: Option, - ) -> RpcResult>; + ) -> Result, Error>; /// Returns a child storage entry at a specific block's state. #[method(name = "childstate_getStorage", blocking)] @@ -57,7 +57,7 @@ pub trait ChildStateApi { child_storage_key: PrefixedStorageKey, key: StorageKey, hash: Option, - ) -> RpcResult>; + ) -> Result, Error>; /// Returns child storage entries for multiple keys at a specific block's state. #[method(name = "childstate_getStorageEntries", blocking)] @@ -66,7 +66,7 @@ pub trait ChildStateApi { child_storage_key: PrefixedStorageKey, keys: Vec, hash: Option, - ) -> RpcResult>>; + ) -> Result>, Error>; /// Returns the hash of a child storage entry at a block's state. #[method(name = "childstate_getStorageHash", blocking)] @@ -75,7 +75,7 @@ pub trait ChildStateApi { child_storage_key: PrefixedStorageKey, key: StorageKey, hash: Option, - ) -> RpcResult>; + ) -> Result, Error>; /// Returns the size of a child storage entry at a block's state. #[method(name = "childstate_getStorageSize", blocking)] @@ -84,7 +84,7 @@ pub trait ChildStateApi { child_storage_key: PrefixedStorageKey, key: StorageKey, hash: Option, - ) -> RpcResult>; + ) -> Result, Error>; /// Returns proof of storage for child key entries at a specific block's state. #[method(name = "state_getChildReadProof", blocking)] @@ -93,5 +93,5 @@ pub trait ChildStateApi { child_storage_key: PrefixedStorageKey, keys: Vec, hash: Option, - ) -> RpcResult>; + ) -> Result, Error>; } diff --git a/substrate/client/rpc-api/src/dev/error.rs b/substrate/client/rpc-api/src/dev/error.rs index 8e4ddb55e35d..f70e368b8738 100644 --- a/substrate/client/rpc-api/src/dev/error.rs +++ b/substrate/client/rpc-api/src/dev/error.rs @@ -18,10 +18,10 @@ //! Error helpers for Dev RPC module. -use jsonrpsee::{ - core::Error as JsonRpseeError, - types::error::{CallError, ErrorObject}, -}; +use jsonrpsee::types::error::{ErrorObject, ErrorObjectOwned}; + +/// Dev RPC Result type. +pub type Result = std::result::Result; /// Dev RPC errors. #[derive(Debug, thiserror::Error)] @@ -46,21 +46,16 @@ pub enum Error { /// Base error code for all dev errors. const BASE_ERROR: i32 = crate::error::base::DEV; -impl From for JsonRpseeError { +impl From for ErrorObjectOwned { fn from(e: Error) -> Self { let msg = e.to_string(); match e { - Error::BlockQueryError(_) => - CallError::Custom(ErrorObject::owned(BASE_ERROR + 1, msg, None::<()>)), - Error::BlockExecutionFailed => - CallError::Custom(ErrorObject::owned(BASE_ERROR + 3, msg, None::<()>)), - Error::WitnessCompactionFailed => - CallError::Custom(ErrorObject::owned(BASE_ERROR + 4, msg, None::<()>)), - Error::ProofExtractionFailed => - CallError::Custom(ErrorObject::owned(BASE_ERROR + 5, msg, None::<()>)), + Error::BlockQueryError(_) => ErrorObject::owned(BASE_ERROR + 1, msg, None::<()>), + Error::BlockExecutionFailed => ErrorObject::owned(BASE_ERROR + 3, msg, None::<()>), + Error::WitnessCompactionFailed => ErrorObject::owned(BASE_ERROR + 4, msg, None::<()>), + Error::ProofExtractionFailed => ErrorObject::owned(BASE_ERROR + 5, msg, None::<()>), Error::UnsafeRpcCalled(e) => e.into(), } - .into() } } diff --git a/substrate/client/rpc-api/src/dev/mod.rs b/substrate/client/rpc-api/src/dev/mod.rs index bc7216199dd7..5bee6df73ba9 100644 --- a/substrate/client/rpc-api/src/dev/mod.rs +++ b/substrate/client/rpc-api/src/dev/mod.rs @@ -23,7 +23,8 @@ pub mod error; use codec::{Decode, Encode}; -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use error::Error; +use jsonrpsee::proc_macros::rpc; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; @@ -59,5 +60,5 @@ pub trait DevApi { /// at the queried node. If either the specified block or the parent is pruned, /// this function will return `None`. #[method(name = "dev_getBlockStats")] - fn block_stats(&self, block_hash: Hash) -> RpcResult>; + fn block_stats(&self, block_hash: Hash) -> Result, Error>; } diff --git a/substrate/client/rpc-api/src/lib.rs b/substrate/client/rpc-api/src/lib.rs index 32120d37902d..451ebdf7fc00 100644 --- a/substrate/client/rpc-api/src/lib.rs +++ b/substrate/client/rpc-api/src/lib.rs @@ -25,7 +25,7 @@ mod error; mod policy; -pub use policy::DenyUnsafe; +pub use policy::{DenyUnsafe, UnsafeRpcError}; pub mod author; pub mod chain; diff --git a/substrate/client/rpc-api/src/mixnet/error.rs b/substrate/client/rpc-api/src/mixnet/error.rs index 0dde5f32e613..22352256f91e 100644 --- a/substrate/client/rpc-api/src/mixnet/error.rs +++ b/substrate/client/rpc-api/src/mixnet/error.rs @@ -18,7 +18,7 @@ //! Mixnet RPC module errors. -use jsonrpsee::types::error::{CallError, ErrorObject}; +use jsonrpsee::types::error::{ErrorObject, ErrorObjectOwned}; use sc_mixnet::{PostErr, RemoteErr, TopologyErr}; /// Mixnet RPC error type. @@ -27,7 +27,7 @@ pub struct Error(pub sc_mixnet::Error); /// Base code for all mixnet errors. const BASE_ERROR: i32 = crate::error::base::MIXNET; -impl From for jsonrpsee::core::Error { +impl From for ErrorObjectOwned { fn from(err: Error) -> Self { let code = match err.0 { sc_mixnet::Error::ServiceUnavailable => BASE_ERROR + 1, @@ -43,6 +43,6 @@ impl From for jsonrpsee::core::Error { sc_mixnet::Error::Remote(RemoteErr::Other(_)) => BASE_ERROR + 200, sc_mixnet::Error::Remote(RemoteErr::Decode(_)) => BASE_ERROR + 201, }; - CallError::Custom(ErrorObject::owned(code, err.0.to_string(), None::<()>)).into() + ErrorObject::owned(code, err.0.to_string(), None::<()>) } } diff --git a/substrate/client/rpc-api/src/mixnet/mod.rs b/substrate/client/rpc-api/src/mixnet/mod.rs index bc478cf3bf33..8bd3362ca613 100644 --- a/substrate/client/rpc-api/src/mixnet/mod.rs +++ b/substrate/client/rpc-api/src/mixnet/mod.rs @@ -20,12 +20,13 @@ pub mod error; -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use error::Error; +use jsonrpsee::proc_macros::rpc; use sp_core::Bytes; #[rpc(client, server)] pub trait MixnetApi { /// Submit encoded extrinsic over the mixnet for inclusion in block. #[method(name = "mixnet_submitExtrinsic")] - async fn submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult<()>; + async fn submit_extrinsic(&self, extrinsic: Bytes) -> Result<(), Error>; } diff --git a/substrate/client/rpc-api/src/offchain/error.rs b/substrate/client/rpc-api/src/offchain/error.rs index 679e10008973..ae5771981ea9 100644 --- a/substrate/client/rpc-api/src/offchain/error.rs +++ b/substrate/client/rpc-api/src/offchain/error.rs @@ -18,10 +18,7 @@ //! Offchain RPC errors. -use jsonrpsee::{ - core::Error as JsonRpseeError, - types::error::{CallError, ErrorObject}, -}; +use jsonrpsee::types::error::{ErrorObject, ErrorObjectOwned}; /// Offchain RPC Result type. pub type Result = std::result::Result; @@ -40,15 +37,14 @@ pub enum Error { /// Base error code for all offchain errors. const BASE_ERROR: i32 = crate::error::base::OFFCHAIN; -impl From for JsonRpseeError { +impl From for ErrorObjectOwned { fn from(e: Error) -> Self { match e { - Error::UnavailableStorageKind => CallError::Custom(ErrorObject::owned( + Error::UnavailableStorageKind => ErrorObject::owned( BASE_ERROR + 1, "This storage kind is not available yet", None::<()>, - )) - .into(), + ), Error::UnsafeRpcCalled(e) => e.into(), } } diff --git a/substrate/client/rpc-api/src/offchain/mod.rs b/substrate/client/rpc-api/src/offchain/mod.rs index cd42d6db3508..469e22d2b3fa 100644 --- a/substrate/client/rpc-api/src/offchain/mod.rs +++ b/substrate/client/rpc-api/src/offchain/mod.rs @@ -18,19 +18,20 @@ //! Substrate offchain API. -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use sp_core::{offchain::StorageKind, Bytes}; - pub mod error; +use error::Error; +use jsonrpsee::proc_macros::rpc; +use sp_core::{offchain::StorageKind, Bytes}; + /// Substrate offchain RPC API #[rpc(client, server)] pub trait OffchainApi { /// Set offchain local storage under given key and prefix. #[method(name = "offchain_localStorageSet")] - fn set_local_storage(&self, kind: StorageKind, key: Bytes, value: Bytes) -> RpcResult<()>; + fn set_local_storage(&self, kind: StorageKind, key: Bytes, value: Bytes) -> Result<(), Error>; /// Get offchain local storage under given key and prefix. #[method(name = "offchain_localStorageGet")] - fn get_local_storage(&self, kind: StorageKind, key: Bytes) -> RpcResult>; + fn get_local_storage(&self, kind: StorageKind, key: Bytes) -> Result, Error>; } diff --git a/substrate/client/rpc-api/src/policy.rs b/substrate/client/rpc-api/src/policy.rs index 799898fb7cf5..c0847de89d2c 100644 --- a/substrate/client/rpc-api/src/policy.rs +++ b/substrate/client/rpc-api/src/policy.rs @@ -21,13 +21,7 @@ //! Contains a `DenyUnsafe` type that can be used to deny potentially unsafe //! RPC when accessed externally. -use jsonrpsee::{ - core::Error as JsonRpseeError, - types::{ - error::{CallError, ErrorCode}, - ErrorObject, - }, -}; +use jsonrpsee::types::{error::ErrorCode, ErrorObject, ErrorObjectOwned}; /// Signifies whether a potentially unsafe RPC should be denied. #[derive(Clone, Copy, Debug)] @@ -61,18 +55,8 @@ impl std::fmt::Display for UnsafeRpcError { impl std::error::Error for UnsafeRpcError {} -impl From for CallError { - fn from(e: UnsafeRpcError) -> CallError { - CallError::Custom(ErrorObject::owned( - ErrorCode::MethodNotFound.code(), - e.to_string(), - None::<()>, - )) - } -} - -impl From for JsonRpseeError { - fn from(e: UnsafeRpcError) -> JsonRpseeError { - JsonRpseeError::Call(e.into()) +impl From for ErrorObjectOwned { + fn from(e: UnsafeRpcError) -> ErrorObjectOwned { + ErrorObject::owned(ErrorCode::MethodNotFound.code(), e.to_string(), None::<()>) } } diff --git a/substrate/client/rpc-api/src/state/error.rs b/substrate/client/rpc-api/src/state/error.rs index 9857784e3545..f2396c63815c 100644 --- a/substrate/client/rpc-api/src/state/error.rs +++ b/substrate/client/rpc-api/src/state/error.rs @@ -18,10 +18,8 @@ //! State RPC errors. -use jsonrpsee::{ - core::Error as JsonRpseeError, - types::error::{CallError, ErrorObject}, -}; +use jsonrpsee::types::error::{ErrorObject, ErrorObjectOwned}; + /// State RPC Result type. pub type Result = std::result::Result; @@ -57,16 +55,14 @@ pub enum Error { /// Base code for all state errors. const BASE_ERROR: i32 = crate::error::base::STATE; -impl From for JsonRpseeError { - fn from(e: Error) -> Self { +impl From for ErrorObjectOwned { + fn from(e: Error) -> ErrorObjectOwned { match e { Error::InvalidBlockRange { .. } => - CallError::Custom(ErrorObject::owned(BASE_ERROR + 1, e.to_string(), None::<()>)) - .into(), + ErrorObject::owned(BASE_ERROR + 1, e.to_string(), None::<()>), Error::InvalidCount { .. } => - CallError::Custom(ErrorObject::owned(BASE_ERROR + 2, e.to_string(), None::<()>)) - .into(), - e => Self::to_call_error(e), + ErrorObject::owned(BASE_ERROR + 2, e.to_string(), None::<()>), + e => ErrorObject::owned(BASE_ERROR + 3, e.to_string(), None::<()>), } } } diff --git a/substrate/client/rpc-api/src/state/helpers.rs b/substrate/client/rpc-api/src/state/helpers.rs index de20ee6f1bdf..58b79ab64ea3 100644 --- a/substrate/client/rpc-api/src/state/helpers.rs +++ b/substrate/client/rpc-api/src/state/helpers.rs @@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize}; use sp_core::Bytes; /// ReadProof struct returned by the RPC -#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ReadProof { /// Block hash used to generate the proof diff --git a/substrate/client/rpc-api/src/state/mod.rs b/substrate/client/rpc-api/src/state/mod.rs index dbc2a505456a..c99ef3015c20 100644 --- a/substrate/client/rpc-api/src/state/mod.rs +++ b/substrate/client/rpc-api/src/state/mod.rs @@ -18,7 +18,7 @@ //! Substrate state API. -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use jsonrpsee::proc_macros::rpc; use sp_core::{ storage::{StorageChangeSet, StorageData, StorageKey}, Bytes, @@ -29,18 +29,23 @@ pub mod error; pub mod helpers; pub use self::helpers::ReadProof; +pub use error::Error; /// Substrate state API #[rpc(client, server)] pub trait StateApi { /// Call a method from the runtime API at a block's state. #[method(name = "state_call", aliases = ["state_callAt"], blocking)] - fn call(&self, name: String, bytes: Bytes, hash: Option) -> RpcResult; + fn call(&self, name: String, bytes: Bytes, hash: Option) -> Result; /// Returns the keys with prefix, leave empty to get all the keys. #[method(name = "state_getKeys", blocking)] #[deprecated(since = "2.0.0", note = "Please use `getKeysPaged` with proper paging support")] - fn storage_keys(&self, prefix: StorageKey, hash: Option) -> RpcResult>; + fn storage_keys( + &self, + prefix: StorageKey, + hash: Option, + ) -> Result, Error>; /// Returns the keys with prefix, leave empty to get all the keys #[method(name = "state_getPairs", blocking)] @@ -48,7 +53,7 @@ pub trait StateApi { &self, prefix: StorageKey, hash: Option, - ) -> RpcResult>; + ) -> Result, Error>; /// Returns the keys with prefix with pagination support. /// Up to `count` keys will be returned. @@ -60,27 +65,28 @@ pub trait StateApi { count: u32, start_key: Option, hash: Option, - ) -> RpcResult>; + ) -> Result, Error>; /// Returns a storage entry at a specific block's state. #[method(name = "state_getStorage", aliases = ["state_getStorageAt"], blocking)] - fn storage(&self, key: StorageKey, hash: Option) -> RpcResult>; + fn storage(&self, key: StorageKey, hash: Option) -> Result, Error>; /// Returns the hash of a storage entry at a block's state. #[method(name = "state_getStorageHash", aliases = ["state_getStorageHashAt"], blocking)] - fn storage_hash(&self, key: StorageKey, hash: Option) -> RpcResult>; + fn storage_hash(&self, key: StorageKey, hash: Option) -> Result, Error>; /// Returns the size of a storage entry at a block's state. #[method(name = "state_getStorageSize", aliases = ["state_getStorageSizeAt"])] - async fn storage_size(&self, key: StorageKey, hash: Option) -> RpcResult>; + async fn storage_size(&self, key: StorageKey, hash: Option) + -> Result, Error>; /// Returns the runtime metadata as an opaque blob. #[method(name = "state_getMetadata", blocking)] - fn metadata(&self, hash: Option) -> RpcResult; + fn metadata(&self, hash: Option) -> Result; /// Get the runtime version. #[method(name = "state_getRuntimeVersion", aliases = ["chain_getRuntimeVersion"], blocking)] - fn runtime_version(&self, hash: Option) -> RpcResult; + fn runtime_version(&self, hash: Option) -> Result; /// Query historical storage entries (by key) starting from a block given as the second /// parameter. @@ -95,7 +101,7 @@ pub trait StateApi { keys: Vec, block: Hash, hash: Option, - ) -> RpcResult>>; + ) -> Result>, Error>; /// Query storage entries (by key) at a block hash given as the second parameter. /// NOTE: Each StorageChangeSet in the result corresponds to exactly one element -- @@ -105,11 +111,15 @@ pub trait StateApi { &self, keys: Vec, at: Option, - ) -> RpcResult>>; + ) -> Result>, Error>; /// Returns proof of storage entries at a specific block's state. #[method(name = "state_getReadProof", blocking)] - fn read_proof(&self, keys: Vec, hash: Option) -> RpcResult>; + fn read_proof( + &self, + keys: Vec, + hash: Option, + ) -> Result, Error>; /// New runtime version subscription #[subscription( @@ -288,5 +298,5 @@ pub trait StateApi { targets: Option, storage_keys: Option, methods: Option, - ) -> RpcResult; + ) -> Result; } diff --git a/substrate/client/rpc-api/src/statement/error.rs b/substrate/client/rpc-api/src/statement/error.rs index 8438cc3ec9e9..f8041864faca 100644 --- a/substrate/client/rpc-api/src/statement/error.rs +++ b/substrate/client/rpc-api/src/statement/error.rs @@ -18,10 +18,7 @@ //! Statement RPC errors. -use jsonrpsee::{ - core::Error as JsonRpseeError, - types::error::{CallError, ErrorObject}, -}; +use jsonrpsee::types::error::{ErrorObject, ErrorObjectOwned}; /// Statement RPC Result type. pub type Result = std::result::Result; @@ -40,15 +37,14 @@ pub enum Error { /// Base error code for all statement errors. const BASE_ERROR: i32 = crate::error::base::STATEMENT; -impl From for JsonRpseeError { +impl From for ErrorObjectOwned { fn from(e: Error) -> Self { match e { - Error::StatementStore(message) => CallError::Custom(ErrorObject::owned( + Error::StatementStore(message) => ErrorObject::owned( BASE_ERROR + 1, format!("Statement store error: {message}"), None::<()>, - )) - .into(), + ), Error::UnsafeRpcCalled(e) => e.into(), } } diff --git a/substrate/client/rpc-api/src/system/error.rs b/substrate/client/rpc-api/src/system/error.rs index 713ade9210d3..1e826a75ae62 100644 --- a/substrate/client/rpc-api/src/system/error.rs +++ b/substrate/client/rpc-api/src/system/error.rs @@ -19,9 +19,9 @@ //! System RPC module errors. use crate::system::helpers::Health; -use jsonrpsee::{ - core::Error as JsonRpseeError, - types::error::{CallError, ErrorObject}, +use jsonrpsee::types::{ + error::{ErrorCode, ErrorObject}, + ErrorObjectOwned, }; /// System RPC Result type. @@ -36,6 +36,12 @@ pub enum Error { /// Peer argument is malformatted. #[error("{0}")] MalformattedPeerArg(String), + /// Call to an unsafe RPC was denied. + #[error(transparent)] + UnsafeRpcCalled(#[from] crate::policy::UnsafeRpcError), + /// Internal error. + #[error("{0}")] + Internal(String), } // Base code for all system errors. @@ -45,17 +51,16 @@ const NOT_HEALTHY_ERROR: i32 = BASE_ERROR + 1; // Peer argument is malformatted. const MALFORMATTED_PEER_ARG_ERROR: i32 = BASE_ERROR + 2; -impl From for JsonRpseeError { - fn from(e: Error) -> Self { +impl From for ErrorObjectOwned { + fn from(e: Error) -> ErrorObjectOwned { match e { Error::NotHealthy(ref h) => - CallError::Custom(ErrorObject::owned(NOT_HEALTHY_ERROR, e.to_string(), Some(h))), - Error::MalformattedPeerArg(e) => CallError::Custom(ErrorObject::owned( - MALFORMATTED_PEER_ARG_ERROR + 2, - e, - None::<()>, - )), + ErrorObject::owned(NOT_HEALTHY_ERROR, e.to_string(), Some(h)), + Error::MalformattedPeerArg(e) => + ErrorObject::owned(MALFORMATTED_PEER_ARG_ERROR, e, None::<()>), + Error::UnsafeRpcCalled(e) => e.into(), + Error::Internal(e) => + ErrorObjectOwned::owned(ErrorCode::InternalError.code(), e, None::<()>), } - .into() } } diff --git a/substrate/client/rpc-api/src/system/helpers.rs b/substrate/client/rpc-api/src/system/helpers.rs index ad56dc385009..ed642e0679eb 100644 --- a/substrate/client/rpc-api/src/system/helpers.rs +++ b/substrate/client/rpc-api/src/system/helpers.rs @@ -38,7 +38,7 @@ pub struct SystemInfo { } /// Health struct returned by the RPC -#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Health { /// Number of connected peers @@ -58,7 +58,7 @@ impl fmt::Display for Health { } /// Network Peer information -#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PeerInfo { /// Peer ID @@ -72,7 +72,7 @@ pub struct PeerInfo { } /// The role the node is running as -#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum NodeRole { /// The node is a full node Full, @@ -81,7 +81,7 @@ pub enum NodeRole { } /// The state of the syncing of the node. -#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SyncState { /// Height of the block at which syncing started. diff --git a/substrate/client/rpc-api/src/system/mod.rs b/substrate/client/rpc-api/src/system/mod.rs index bf2e92bc27a0..c38fa8f3d817 100644 --- a/substrate/client/rpc-api/src/system/mod.rs +++ b/substrate/client/rpc-api/src/system/mod.rs @@ -18,38 +18,36 @@ //! Substrate system API. -use jsonrpsee::{ - core::{JsonValue, RpcResult}, - proc_macros::rpc, -}; - -pub use self::helpers::{Health, NodeRole, PeerInfo, SyncState, SystemInfo}; - pub mod error; pub mod helpers; +use jsonrpsee::{core::JsonValue, proc_macros::rpc}; + +pub use self::helpers::{Health, NodeRole, PeerInfo, SyncState, SystemInfo}; +pub use error::Error; + /// Substrate system RPC API #[rpc(client, server)] pub trait SystemApi { /// Get the node's implementation name. Plain old string. #[method(name = "system_name")] - fn system_name(&self) -> RpcResult; + fn system_name(&self) -> Result; /// Get the node implementation's version. Should be a semver string. #[method(name = "system_version")] - fn system_version(&self) -> RpcResult; + fn system_version(&self) -> Result; /// Get the chain's name. Given as a string identifier. #[method(name = "system_chain")] - fn system_chain(&self) -> RpcResult; + fn system_chain(&self) -> Result; /// Get the chain's type. #[method(name = "system_chainType")] - fn system_type(&self) -> RpcResult; + fn system_type(&self) -> Result; /// Get a custom set of properties as a JSON object, defined in the chain spec. #[method(name = "system_properties")] - fn system_properties(&self) -> RpcResult; + fn system_properties(&self) -> Result; /// Return health status of the node. /// @@ -57,22 +55,22 @@ pub trait SystemApi { /// - connected to some peers (unless running in dev mode) /// - not performing a major sync #[method(name = "system_health")] - async fn system_health(&self) -> RpcResult; + async fn system_health(&self) -> Result; /// Returns the base58-encoded PeerId of the node. #[method(name = "system_localPeerId")] - async fn system_local_peer_id(&self) -> RpcResult; + async fn system_local_peer_id(&self) -> Result; /// Returns the multi-addresses that the local node is listening on /// /// The addresses include a trailing `/p2p/` with the local PeerId, and are thus suitable to /// be passed to `addReservedPeer` or as a bootnode address for example. #[method(name = "system_localListenAddresses")] - async fn system_local_listen_addresses(&self) -> RpcResult>; + async fn system_local_listen_addresses(&self) -> Result, Error>; /// Returns currently connected peers #[method(name = "system_peers")] - async fn system_peers(&self) -> RpcResult>>; + async fn system_peers(&self) -> Result>, Error>; /// Returns current state of the network. /// @@ -81,7 +79,7 @@ pub trait SystemApi { // TODO: the future of this call is uncertain: https://github.com/paritytech/substrate/issues/1890 // https://github.com/paritytech/substrate/issues/5541 #[method(name = "system_unstable_networkState")] - async fn system_network_state(&self) -> RpcResult; + async fn system_network_state(&self) -> Result; /// Adds a reserved peer. Returns the empty string or an error. The string /// parameter should encode a `p2p` multiaddr. @@ -89,25 +87,25 @@ pub trait SystemApi { /// `/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV` /// is an example of a valid, passing multiaddr with PeerId attached. #[method(name = "system_addReservedPeer")] - async fn system_add_reserved_peer(&self, peer: String) -> RpcResult<()>; + async fn system_add_reserved_peer(&self, peer: String) -> Result<(), Error>; /// Remove a reserved peer. Returns the empty string or an error. The string /// should encode only the PeerId e.g. `QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV`. #[method(name = "system_removeReservedPeer")] - async fn system_remove_reserved_peer(&self, peer_id: String) -> RpcResult<()>; + async fn system_remove_reserved_peer(&self, peer_id: String) -> Result<(), Error>; /// Returns the list of reserved peers #[method(name = "system_reservedPeers")] - async fn system_reserved_peers(&self) -> RpcResult>; + async fn system_reserved_peers(&self) -> Result, Error>; /// Returns the roles the node is running as. #[method(name = "system_nodeRoles")] - async fn system_node_roles(&self) -> RpcResult>; + async fn system_node_roles(&self) -> Result, Error>; /// Returns the state of the syncing of the node: starting block, current best block, highest /// known block. #[method(name = "system_syncState")] - async fn system_sync_state(&self) -> RpcResult>; + async fn system_sync_state(&self) -> Result, Error>; /// Adds the supplied directives to the current log filter /// @@ -115,9 +113,9 @@ pub trait SystemApi { /// /// `sync=debug,state=trace` #[method(name = "system_addLogFilter")] - fn system_add_log_filter(&self, directives: String) -> RpcResult<()>; + fn system_add_log_filter(&self, directives: String) -> Result<(), Error>; /// Resets the log filter to Substrate defaults #[method(name = "system_resetLogFilter")] - fn system_reset_log_filter(&self) -> RpcResult<()>; + fn system_reset_log_filter(&self) -> Result<(), Error>; } diff --git a/substrate/client/rpc-servers/Cargo.toml b/substrate/client/rpc-servers/Cargo.toml index 674a8db39cb5..2e26c949e337 100644 --- a/substrate/client/rpc-servers/Cargo.toml +++ b/substrate/client/rpc-servers/Cargo.toml @@ -13,11 +13,11 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.16.2", features = ["server"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } log = "0.4.17" serde_json = "1.0.107" tokio = { version = "1.22.0", features = ["parking_lot"] } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } tower-http = { version = "0.4.0", features = ["cors"] } -tower = "0.4.13" +tower = { version = "0.4.13", features = ["util"] } http = "0.2.8" diff --git a/substrate/client/rpc-servers/src/lib.rs b/substrate/client/rpc-servers/src/lib.rs index dc625c3d6c4c..9725f6d221d9 100644 --- a/substrate/client/rpc-servers/src/lib.rs +++ b/substrate/client/rpc-servers/src/lib.rs @@ -22,15 +22,13 @@ pub mod middleware; +use std::{error::Error as StdError, net::SocketAddr, time::Duration}; + use http::header::HeaderValue; use jsonrpsee::{ - server::{ - middleware::proxy_get_request::ProxyGetRequestLayer, AllowHosts, ServerBuilder, - ServerHandle, - }, + server::middleware::{HostFilterLayer, ProxyGetRequestLayer}, RpcModule, }; -use std::{error::Error as StdError, net::SocketAddr}; use tower_http::cors::{AllowOrigin, CorsLayer}; pub use crate::middleware::RpcMetrics; @@ -42,7 +40,7 @@ pub use jsonrpsee::core::{ const MEGABYTE: u32 = 1024 * 1024; /// Type alias for the JSON-RPC server. -pub type Server = ServerHandle; +pub type Server = jsonrpsee::server::ServerHandle; /// RPC server configuration. #[derive(Debug)] @@ -61,6 +59,8 @@ pub struct Config<'a, M: Send + Sync + 'static> { pub max_payload_out_mb: u32, /// Metrics. pub metrics: Option, + /// Message buffer size + pub message_buffer_capacity: u32, /// RPC API. pub rpc_api: RpcModule, /// Subscription ID provider. @@ -72,7 +72,7 @@ pub struct Config<'a, M: Send + Sync + 'static> { /// Start RPC server listening on given address. pub async fn start_server( config: Config<'_, M>, -) -> Result> { +) -> Result> { let Config { addrs, cors, @@ -81,6 +81,7 @@ pub async fn start_server( max_connections, max_subs_per_conn, metrics, + message_buffer_capacity, id_provider, tokio_handle, rpc_api, @@ -89,18 +90,19 @@ pub async fn start_server( let host_filter = hosts_filtering(cors.is_some(), &addrs); let middleware = tower::ServiceBuilder::new() + .option_layer(host_filter) // Proxy `GET /health` requests to internal `system_health` method. .layer(ProxyGetRequestLayer::new("/health", "system_health")?) .layer(try_into_cors(cors)?); - let mut builder = ServerBuilder::new() + let mut builder = jsonrpsee::server::Server::builder() .max_request_body_size(max_payload_in_mb.saturating_mul(MEGABYTE)) .max_response_body_size(max_payload_out_mb.saturating_mul(MEGABYTE)) .max_connections(max_connections) .max_subscriptions_per_connection(max_subs_per_conn) - .ping_interval(std::time::Duration::from_secs(30)) - .set_host_filtering(host_filter) + .ping_interval(Duration::from_secs(30)) .set_middleware(middleware) + .set_message_buffer_capacity(message_buffer_capacity) .custom_tokio_runtime(tokio_handle); if let Some(provider) = id_provider { @@ -113,11 +115,11 @@ pub async fn start_server( let (handle, addr) = if let Some(metrics) = metrics { let server = builder.set_logger(metrics).build(&addrs[..]).await?; let addr = server.local_addr(); - (server.start(rpc_api)?, addr) + (server.start(rpc_api), addr) } else { let server = builder.build(&addrs[..]).await?; let addr = server.local_addr(); - (server.start(rpc_api)?, addr) + (server.start(rpc_api), addr) }; log::info!( @@ -129,17 +131,17 @@ pub async fn start_server( Ok(handle) } -fn hosts_filtering(enabled: bool, addrs: &[SocketAddr]) -> AllowHosts { +fn hosts_filtering(enabled: bool, addrs: &[SocketAddr]) -> Option { if enabled { // NOTE The listening addresses are whitelisted by default. let mut hosts = Vec::with_capacity(addrs.len() * 2); for addr in addrs { - hosts.push(format!("localhost:{}", addr.port()).into()); - hosts.push(format!("127.0.0.1:{}", addr.port()).into()); + hosts.push(format!("localhost:{}", addr.port())); + hosts.push(format!("127.0.0.1:{}", addr.port())); } - AllowHosts::Only(hosts) + Some(HostFilterLayer::new(hosts).expect("SockAddr is valid host; qed")) } else { - AllowHosts::Any + None } } @@ -151,9 +153,9 @@ fn build_rpc_api(mut rpc_api: RpcModule) -> RpcModu rpc_api .register_method("rpc_methods", move |_, _| { - Ok(serde_json::json!({ + serde_json::json!({ "methods": available_methods, - })) + }) }) .expect("infallible all other methods have their own address space; qed"); diff --git a/substrate/client/rpc-servers/src/middleware.rs b/substrate/client/rpc-servers/src/middleware.rs index c3e17c7852f1..fabb64eafa79 100644 --- a/substrate/client/rpc-servers/src/middleware.rs +++ b/substrate/client/rpc-servers/src/middleware.rs @@ -18,7 +18,9 @@ //! RPC middleware to collect prometheus metrics on RPC calls. -use jsonrpsee::server::logger::{HttpRequest, Logger, MethodKind, Params, TransportProtocol}; +use jsonrpsee::server::logger::{ + HttpRequest, Logger, MethodKind, Params, SuccessOrError, TransportProtocol, +}; use prometheus_endpoint::{ register, Counter, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError, Registry, U64, @@ -176,7 +178,7 @@ impl Logger for RpcMetrics { fn on_result( &self, name: &str, - success: bool, + success_or_error: SuccessOrError, started_at: Self::Instant, transport: TransportProtocol, ) { @@ -197,7 +199,7 @@ impl Logger for RpcMetrics { name, // the label "is_error", so `success` should be regarded as false // and vice-versa to be registrered correctly. - if success { "false" } else { "true" }, + if success_or_error.is_success() { "false" } else { "true" }, ]) .inc(); } diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index 1eaed65706e0..9aa886c6cea5 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.20.3", features = ["client-core", "server", "macros"] } # Internal chain structures for "chain_spec". sc-chain-spec = { path = "../chain-spec" } # Pool for submitting extrinsics required by "transaction" @@ -25,6 +25,7 @@ sp-blockchain = { path = "../../primitives/blockchain" } sp-version = { path = "../../primitives/version" } sc-client-api = { path = "../api" } sc-utils = { path = "../utils" } +sc-rpc = { path = "../rpc" } codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = "1.0" serde = "1.0" diff --git a/substrate/client/rpc-spec-v2/src/archive/error.rs b/substrate/client/rpc-spec-v2/src/archive/error.rs index b858212399ce..d631c3fb8e89 100644 --- a/substrate/client/rpc-spec-v2/src/archive/error.rs +++ b/substrate/client/rpc-spec-v2/src/archive/error.rs @@ -18,10 +18,7 @@ //! Error helpers for `archive` RPC module. -use jsonrpsee::{ - core::Error as RpcError, - types::error::{CallError, ErrorObject}, -}; +use jsonrpsee::types::error::ErrorObject; /// ChainHead RPC errors. #[derive(Debug, thiserror::Error)] @@ -58,9 +55,3 @@ impl From for ErrorObject<'static> { .into() } } - -impl From for RpcError { - fn from(e: Error) -> Self { - CallError::Custom(e.into()).into() - } -} diff --git a/substrate/client/rpc-spec-v2/src/archive/tests.rs b/substrate/client/rpc-spec-v2/src/archive/tests.rs index 36f7716e393c..a81f9d21da50 100644 --- a/substrate/client/rpc-spec-v2/src/archive/tests.rs +++ b/substrate/client/rpc-spec-v2/src/archive/tests.rs @@ -23,8 +23,7 @@ use super::{archive::Archive, *}; use assert_matches::assert_matches; use codec::{Decode, Encode}; use jsonrpsee::{ - core::error::Error, - types::{error::CallError, EmptyServerParams as EmptyParams}, + core::{EmptyServerParams as EmptyParams, Error}, RpcModule, }; use sc_block_builder::BlockBuilderProvider; @@ -218,7 +217,7 @@ async fn archive_call() { ) .await .unwrap_err(); - assert_matches!(err, Error::Call(CallError::Custom(ref err)) if err.code() == 3001 && err.message().contains("Invalid parameter")); + assert_matches!(err, Error::Call(err) if err.code() == 3001 && err.message().contains("Invalid parameter")); // Pass an invalid parameters that cannot be decode. let err = api @@ -229,7 +228,7 @@ async fn archive_call() { ) .await .unwrap_err(); - assert_matches!(err, Error::Call(CallError::Custom(ref err)) if err.code() == 3001 && err.message().contains("Invalid parameter")); + assert_matches!(err, Error::Call(err) if err.code() == 3001 && err.message().contains("Invalid parameter")); // Invalid hash. let result: MethodResult = api diff --git a/substrate/client/rpc-spec-v2/src/chain_head/api.rs b/substrate/client/rpc-spec-v2/src/chain_head/api.rs index d93c4018b60f..54ebee83d5c8 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/api.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/api.rs @@ -19,8 +19,11 @@ #![allow(non_snake_case)] //! API trait of the chain head. -use crate::chain_head::event::{FollowEvent, MethodResponse, StorageQuery}; -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use crate::chain_head::{ + error::Error, + event::{FollowEvent, MethodResponse, StorageQuery}, +}; +use jsonrpsee::proc_macros::rpc; #[rpc(client, server)] pub trait ChainHeadApi { @@ -52,7 +55,7 @@ pub trait ChainHeadApi { &self, follow_subscription: String, hash: Hash, - ) -> RpcResult; + ) -> Result; /// Retrieves the header of a pinned block. /// @@ -71,7 +74,7 @@ pub trait ChainHeadApi { &self, follow_subscription: String, hash: Hash, - ) -> RpcResult>; + ) -> Result, Error>; /// Get the chain's genesis hash. /// @@ -79,7 +82,7 @@ pub trait ChainHeadApi { /// /// This method is unstable and subject to change in the future. #[method(name = "chainHead_unstable_genesisHash", blocking)] - fn chain_head_unstable_genesis_hash(&self) -> RpcResult; + fn chain_head_unstable_genesis_hash(&self) -> Result; /// Returns storage entries at a specific block's state. /// @@ -93,7 +96,7 @@ pub trait ChainHeadApi { hash: Hash, items: Vec>, child_trie: Option, - ) -> RpcResult; + ) -> Result; /// Call into the Runtime API at a specified block's state. /// @@ -107,7 +110,7 @@ pub trait ChainHeadApi { hash: Hash, function: String, call_parameters: String, - ) -> RpcResult; + ) -> Result; /// Unpin a block reported by the `follow` method. /// @@ -118,7 +121,11 @@ pub trait ChainHeadApi { /// /// This method is unstable and subject to change in the future. #[method(name = "chainHead_unstable_unpin", blocking)] - fn chain_head_unstable_unpin(&self, follow_subscription: String, hash: Hash) -> RpcResult<()>; + fn chain_head_unstable_unpin( + &self, + follow_subscription: String, + hash: Hash, + ) -> Result<(), Error>; /// Resumes a storage fetch started with `chainHead_storage` after it has generated an /// `operationWaitingForContinue` event. @@ -131,7 +138,7 @@ pub trait ChainHeadApi { &self, follow_subscription: String, operation_id: String, - ) -> RpcResult<()>; + ) -> Result<(), Error>; /// Stops an operation started with chainHead_unstable_body, chainHead_unstable_call, or /// chainHead_unstable_storage. If the operation was still in progress, this interrupts it. If @@ -145,5 +152,5 @@ pub trait ChainHeadApi { &self, follow_subscription: String, operation_id: String, - ) -> RpcResult<()>; + ) -> Result<(), Error>; } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index a8c1c4f7e083..23b18efa8a4f 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -36,15 +36,14 @@ use crate::{ use codec::Encode; use futures::future::FutureExt; use jsonrpsee::{ - core::{async_trait, RpcResult}, - types::{SubscriptionEmptyError, SubscriptionId, SubscriptionResult}, - SubscriptionSink, + core::async_trait, types::SubscriptionId, PendingSubscriptionSink, SubscriptionSink, }; use log::debug; use sc_client_api::{ Backend, BlockBackend, BlockchainEvents, CallExecutor, ChildInfo, ExecutorProvider, StorageKey, StorageProvider, }; +use sc_rpc::utils::to_sub_message; use sp_api::CallApiAt; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_core::{traits::CallContext, Bytes}; @@ -140,27 +139,13 @@ impl, Block: BlockT, Client> ChainHead { _phantom: PhantomData, } } +} - /// Accept the subscription and return the subscription ID on success. - fn accept_subscription( - &self, - sink: &mut SubscriptionSink, - ) -> Result { - // The subscription must be accepted before it can provide a valid subscription ID. - sink.accept()?; - - let Some(sub_id) = sink.subscription_id() else { - // This can only happen if the subscription was not accepted. - return Err(SubscriptionEmptyError) - }; - - // Get the string representation for the subscription. - let sub_id = match sub_id { - SubscriptionId::Num(num) => num.to_string(), - SubscriptionId::Str(id) => id.into_owned().into(), - }; - - Ok(sub_id) +/// Helper to convert the `subscription ID` to a string. +pub fn read_subscription_id_as_string(sink: &SubscriptionSink) -> String { + match sink.subscription_id() { + SubscriptionId::Num(n) => n.to_string(), + SubscriptionId::Str(s) => s.into_owned().into(), } } @@ -194,33 +179,28 @@ where + StorageProvider + 'static, { - fn chain_head_unstable_follow( - &self, - mut sink: SubscriptionSink, - with_runtime: bool, - ) -> SubscriptionResult { - let sub_id = match self.accept_subscription(&mut sink) { - Ok(sub_id) => sub_id, - Err(err) => { - sink.close(ChainHeadRpcError::InvalidSubscriptionID); - return Err(err) - }, - }; - // Keep track of the subscription. - let Some(sub_data) = self.subscriptions.insert_subscription(sub_id.clone(), with_runtime) - else { - // Inserting the subscription can only fail if the JsonRPSee - // generated a duplicate subscription ID. - debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription already accepted", sub_id); - let _ = sink.send(&FollowEvent::::Stop); - return Ok(()) - }; - debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription accepted", sub_id); - + fn chain_head_unstable_follow(&self, pending: PendingSubscriptionSink, with_runtime: bool) { let subscriptions = self.subscriptions.clone(); let backend = self.backend.clone(); let client = self.client.clone(); + let fut = async move { + let Ok(sink) = pending.accept().await else { return }; + + let sub_id = read_subscription_id_as_string(&sink); + + // Keep track of the subscription. + let Some(sub_data) = subscriptions.insert_subscription(sub_id.clone(), with_runtime) + else { + // Inserting the subscription can only fail if the JsonRPSee + // generated a duplicate subscription ID. + debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription already accepted", sub_id); + let msg = to_sub_message(&sink, &FollowEvent::::Stop); + let _ = sink.send(msg).await; + return + }; + debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription accepted", sub_id); + let mut chain_head_follow = ChainHeadFollower::new( client, backend, @@ -235,15 +215,15 @@ where debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription removed", sub_id); }; - self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); - Ok(()) + self.executor + .spawn_blocking("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } fn chain_head_unstable_body( &self, follow_subscription: String, hash: Block::Hash, - ) -> RpcResult { + ) -> Result { let mut block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { Ok(block) => block, Err(SubscriptionManagementError::SubscriptionAbsent) | @@ -295,7 +275,7 @@ where &self, follow_subscription: String, hash: Block::Hash, - ) -> RpcResult> { + ) -> Result, ChainHeadRpcError> { let _block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { Ok(block) => block, Err(SubscriptionManagementError::SubscriptionAbsent) | @@ -311,10 +291,9 @@ where .header(hash) .map(|opt_header| opt_header.map(|h| hex_string(&h.encode()))) .map_err(ChainHeadRpcError::FetchBlockHeader) - .map_err(Into::into) } - fn chain_head_unstable_genesis_hash(&self) -> RpcResult { + fn chain_head_unstable_genesis_hash(&self) -> Result { Ok(self.genesis_hash.clone()) } @@ -324,7 +303,7 @@ where hash: Block::Hash, items: Vec>, child_trie: Option, - ) -> RpcResult { + ) -> Result { // Gain control over parameter parsing and returned error. let items = items .into_iter() @@ -369,7 +348,7 @@ where }; self.executor - .spawn_blocking("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + .spawn("rpcV2-chainHead-unstable-storage", Some("rpc"), fut.boxed()); Ok(MethodResponse::Started(MethodResponseStarted { operation_id, discarded_items: Some(discarded), @@ -382,7 +361,7 @@ where hash: Block::Hash, function: String, call_parameters: String, - ) -> RpcResult { + ) -> Result { let call_parameters = Bytes::from(parse_hex_param(call_parameters)?); let mut block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { @@ -426,14 +405,17 @@ where }); let _ = block_guard.response_sender().unbounded_send(event); - Ok(MethodResponse::Started(MethodResponseStarted { operation_id, discarded_items: None })) + Ok(MethodResponse::Started(MethodResponseStarted { + operation_id: operation_id.clone(), + discarded_items: None, + })) } fn chain_head_unstable_unpin( &self, follow_subscription: String, hash: Block::Hash, - ) -> RpcResult<()> { + ) -> Result<(), ChainHeadRpcError> { match self.subscriptions.unpin_block(&follow_subscription, hash) { Ok(()) => Ok(()), Err(SubscriptionManagementError::SubscriptionAbsent) => { @@ -442,9 +424,9 @@ where }, Err(SubscriptionManagementError::BlockHashAbsent) => { // Block is not part of the subscription. - Err(ChainHeadRpcError::InvalidBlock.into()) + Err(ChainHeadRpcError::InvalidBlock) }, - Err(_) => Err(ChainHeadRpcError::InvalidBlock.into()), + Err(_) => Err(ChainHeadRpcError::InvalidBlock), } } @@ -452,7 +434,7 @@ where &self, follow_subscription: String, operation_id: String, - ) -> RpcResult<()> { + ) -> Result<(), ChainHeadRpcError> { let Some(operation) = self.subscriptions.get_operation(&follow_subscription, &operation_id) else { return Ok(()) @@ -470,7 +452,7 @@ where &self, follow_subscription: String, operation_id: String, - ) -> RpcResult<()> { + ) -> Result<(), ChainHeadRpcError> { let Some(operation) = self.subscriptions.get_operation(&follow_subscription, &operation_id) else { return Ok(()) diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs index b981e69f2e47..e94374aebd91 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs @@ -24,7 +24,7 @@ use crate::chain_head::{ BestBlockChanged, Finalized, FollowEvent, Initialized, NewBlock, RuntimeEvent, RuntimeVersionEvent, }, - subscription::{InsertedSubscriptionData, SubscriptionManagement, SubscriptionManagementError}, + subscription::{SubscriptionManagement, SubscriptionManagementError}, }; use futures::{ channel::oneshot, @@ -36,6 +36,7 @@ use log::{debug, error}; use sc_client_api::{ Backend, BlockBackend, BlockImportNotification, BlockchainEvents, FinalityNotification, }; +use sc_rpc::utils::to_sub_message; use sp_api::CallApiAt; use sp_blockchain::{ Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, Info, @@ -43,6 +44,8 @@ use sp_blockchain::{ use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use std::{collections::HashSet, sync::Arc}; +use super::subscription::InsertedSubscriptionData; + /// Generates the events of the `chainHead_follow` method. pub struct ChainHeadFollower, Block: BlockT, Client> { /// Substrate client. @@ -500,7 +503,7 @@ where startup_point: &StartupPoint, mut stream: EventStream, mut to_ignore: HashSet, - mut sink: SubscriptionSink, + sink: SubscriptionSink, rx_stop: oneshot::Receiver<()>, ) where EventStream: Stream> + Unpin, @@ -529,35 +532,23 @@ where self.sub_id, err ); - let _ = sink.send(&FollowEvent::::Stop); + let msg = to_sub_message(&sink, &FollowEvent::::Stop); + let _ = sink.send(msg).await; return }, }; for event in events { - let result = sink.send(&event); - - // Migration note: the new version of jsonrpsee returns Result<(), DisconnectError> - // The logic from `Err(err)` should be moved when building the new - // `SubscriptionMessage`. - - // For now, jsonrpsee returns: - // Ok(true): message sent - // Ok(false): client disconnected or subscription closed - // Err(err): serder serialization error of the event - if let Err(err) = result { + let msg = to_sub_message(&sink, &event); + if let Err(err) = sink.send(msg).await { // Failed to submit event. debug!( target: LOG_TARGET, "[follow][id={:?}] Failed to send event {:?}", self.sub_id, err ); - let _ = sink.send(&FollowEvent::::Stop); - return - } - - if let Ok(false) = result { - // Client disconnected or subscription was closed. + let msg = to_sub_message(&sink, &FollowEvent::::Stop); + let _ = sink.send(msg).await; return } } @@ -568,13 +559,14 @@ where // If we got here either the substrate streams have closed // or the `Stop` receiver was triggered. - let _ = sink.send(&FollowEvent::::Stop); + let msg = to_sub_message(&sink, &FollowEvent::::Stop); + let _ = sink.send(msg).await; } /// Generate the block events for the `chainHead_follow` method. pub async fn generate_events( &mut self, - mut sink: SubscriptionSink, + sink: SubscriptionSink, sub_data: InsertedSubscriptionData, ) { // Register for the new block and finalized notifications. @@ -602,7 +594,8 @@ where self.sub_id, err ); - let _ = sink.send(&FollowEvent::::Stop); + let msg = to_sub_message(&sink, &FollowEvent::::Stop); + let _ = sink.send(msg).await; return }, }; diff --git a/substrate/client/rpc-spec-v2/src/chain_head/error.rs b/substrate/client/rpc-spec-v2/src/chain_head/error.rs index 811666428c5a..6f24d97283a6 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/error.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/error.rs @@ -18,10 +18,7 @@ //! Error helpers for `chainHead` RPC module. -use jsonrpsee::{ - core::Error as RpcError, - types::error::{CallError, ErrorObject}, -}; +use jsonrpsee::types::error::ErrorObject; use sp_blockchain::Error as BlockchainError; /// ChainHead RPC errors. @@ -71,9 +68,3 @@ impl From for ErrorObject<'static> { } } } - -impl From for RpcError { - fn from(e: Error) -> Self { - CallError::Custom(e.into()).into() - } -} diff --git a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs index 8aaeb413cdff..f911eaf40da6 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -26,10 +26,10 @@ use assert_matches::assert_matches; use codec::{Decode, Encode}; use futures::Future; use jsonrpsee::{ - core::{error::Error, server::rpc_module::Subscription as RpcSubscription}, - rpc_params, - types::{error::CallError, EmptyServerParams as EmptyParams}, - RpcModule, + core::{ + error::Error, server::Subscription as RpcSubscription, EmptyServerParams as EmptyParams, + }, + rpc_params, RpcModule, }; use sc_block_builder::BlockBuilderProvider; use sc_client_api::ChildInfo; @@ -121,7 +121,7 @@ async fn setup_api() -> ( ) .into_rpc(); - let mut sub = api.subscribe("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -166,7 +166,7 @@ async fn follow_subscription_produces_blocks() { .into_rpc(); let finalized_hash = client.info().finalized_hash; - let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -228,7 +228,7 @@ async fn follow_with_runtime() { .into_rpc(); let finalized_hash = client.info().finalized_hash; - let mut sub = api.subscribe("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -364,7 +364,7 @@ async fn get_header() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" ); // Obtain the valid header. @@ -393,7 +393,7 @@ async fn get_body() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" ); // Valid call. @@ -474,7 +474,7 @@ async fn call_runtime() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" ); // Pass an invalid parameters that cannot be decode. @@ -487,7 +487,7 @@ async fn call_runtime() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2003 && err.message().contains("Invalid parameter") + Error::Call(err) if err.code() == 2003 && err.message().contains("Invalid parameter") ); // Valid call. @@ -550,7 +550,7 @@ async fn call_runtime_without_flag() { ) .into_rpc(); - let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -584,7 +584,7 @@ async fn call_runtime_without_flag() { .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2003 && err.message().contains("The runtime updates flag must be set") + Error::Call(err) if err.code() == 2003 && err.message().contains("The runtime updates flag must be set") ); } @@ -622,7 +622,7 @@ async fn get_storage_hash() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" ); // Valid call without storage at the key. @@ -882,7 +882,7 @@ async fn get_storage_value() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" ); // Valid call without storage at the key. @@ -1191,11 +1191,12 @@ async fn separate_operation_ids_for_subscriptions() { .into_rpc(); // Create two separate subscriptions. - let mut sub_first = api.subscribe("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub_first = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); let sub_id_first = sub_first.subscription_id(); let sub_id_first = serde_json::to_string(&sub_id_first).unwrap(); - let mut sub_second = api.subscribe("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub_second = + api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); let sub_id_second = sub_second.subscription_id(); let sub_id_second = serde_json::to_string(&sub_id_second).unwrap(); @@ -1300,7 +1301,7 @@ async fn follow_generates_initial_blocks() { let block_3_hash = block_3.header.hash(); client.import(BlockOrigin::Own, block_3.clone()).await.unwrap(); - let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -1403,7 +1404,7 @@ async fn follow_exceeding_pinned_blocks() { ) .into_rpc(); - let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); let block = client.new_block(Default::default()).unwrap().build().unwrap().block; client.import(BlockOrigin::Own, block.clone()).await.unwrap(); @@ -1458,7 +1459,7 @@ async fn follow_with_unpin() { ) .into_rpc(); - let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -1494,7 +1495,7 @@ async fn follow_with_unpin() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash" + Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" ); // To not exceed the number of pinned blocks, we need to unpin before the next import. @@ -1544,7 +1545,7 @@ async fn follow_prune_best_block() { .into_rpc(); let finalized_hash = client.info().finalized_hash; - let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -1753,7 +1754,7 @@ async fn follow_forks_pruned_block() { // Block 4 and 5 are not pruned, pruning happens at height (N - 1). client.finalize_block(block_3_hash, None).unwrap(); - let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -1872,7 +1873,7 @@ async fn follow_report_multiple_pruned_block() { let block_5 = block_builder.build().unwrap().block; let block_5_hash = block_5.header.hash(); client.import(BlockOrigin::Own, block_5.clone()).await.unwrap(); - let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -2048,7 +2049,7 @@ async fn pin_block_references() { } } - let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -2150,7 +2151,7 @@ async fn follow_finalized_before_new_block() { let block_1_hash = block_1.header.hash(); client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); - let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); // Trigger the `FinalizedNotification` for block 1 before the `BlockImportNotification`, and // expect for the `chainHead` to generate `NewBlock`, `BestBlock` and `Finalized` events. @@ -2246,7 +2247,7 @@ async fn ensure_operation_limits_works() { ) .into_rpc(); - let mut sub = api.subscribe("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -2344,7 +2345,7 @@ async fn check_continue_operation() { ) .into_rpc(); - let mut sub = api.subscribe("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -2523,7 +2524,7 @@ async fn stop_storage_operation() { ) .into_rpc(); - let mut sub = api.subscribe("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); diff --git a/substrate/client/rpc-spec-v2/src/chain_spec/tests.rs b/substrate/client/rpc-spec-v2/src/chain_spec/tests.rs index 9326fd5f3b73..3abd9a548a1e 100644 --- a/substrate/client/rpc-spec-v2/src/chain_spec/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_spec/tests.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::*; -use jsonrpsee::{types::EmptyServerParams as EmptyParams, RpcModule}; +use jsonrpsee::{core::EmptyServerParams as EmptyParams, RpcModule}; use sc_chain_spec::Properties; const CHAIN_NAME: &'static str = "TEST_CHAIN_NAME"; diff --git a/substrate/client/rpc-spec-v2/src/lib.rs b/substrate/client/rpc-spec-v2/src/lib.rs index d202bfef4a74..c2eb81f22b10 100644 --- a/substrate/client/rpc-spec-v2/src/lib.rs +++ b/substrate/client/rpc-spec-v2/src/lib.rs @@ -34,7 +34,7 @@ pub mod transaction; pub type SubscriptionTaskExecutor = std::sync::Arc; /// The result of an RPC method. -#[derive(Debug, Deserialize, Serialize, PartialEq)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] #[serde(untagged)] pub enum MethodResult { /// Method generated a result. diff --git a/substrate/client/rpc-spec-v2/src/transaction/transaction.rs b/substrate/client/rpc-spec-v2/src/transaction/transaction.rs index fe16310aeffa..7dc9d0f758de 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/transaction.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/transaction.rs @@ -29,27 +29,21 @@ use crate::{ }, SubscriptionTaskExecutor, }; -use jsonrpsee::{ - core::async_trait, - types::{ - error::{CallError, ErrorObject}, - SubscriptionResult, - }, - SubscriptionSink, -}; +use jsonrpsee::{core::async_trait, types::error::ErrorObject, PendingSubscriptionSink}; use sc_transaction_pool_api::{ error::IntoPoolError, BlockHash, TransactionFor, TransactionPool, TransactionSource, TransactionStatus, }; use std::sync::Arc; +use sc_rpc::utils::pipe_from_stream; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_core::Bytes; use sp_runtime::traits::Block as BlockT; use codec::Decode; -use futures::{FutureExt, StreamExt, TryFutureExt}; +use futures::{StreamExt, TryFutureExt}; /// An API for transaction RPC calls. pub struct Transaction { @@ -90,52 +84,54 @@ where ::Hash: Unpin, Client: HeaderBackend + ProvideRuntimeApi + Send + Sync + 'static, { - fn submit_and_watch(&self, mut sink: SubscriptionSink, xt: Bytes) -> SubscriptionResult { - // This is the only place where the RPC server can return an error for this - // subscription. Other defects must be signaled as events to the sink. - let decoded_extrinsic = match TransactionFor::::decode(&mut &xt[..]) { - Ok(decoded_extrinsic) => decoded_extrinsic, - Err(e) => { - let err = CallError::Custom(ErrorObject::owned( - BAD_FORMAT, - format!("Extrinsic has invalid format: {}", e), - None::<()>, - )); - let _ = sink.reject(err); - return Ok(()) - }, - }; + fn submit_and_watch(&self, pending: PendingSubscriptionSink, xt: Bytes) { + let client = self.client.clone(); + let pool = self.pool.clone(); - let best_block_hash = self.client.info().best_hash; + let fut = async move { + // This is the only place where the RPC server can return an error for this + // subscription. Other defects must be signaled as events to the sink. + let decoded_extrinsic = match TransactionFor::::decode(&mut &xt[..]) { + Ok(decoded_extrinsic) => decoded_extrinsic, + Err(e) => { + let err = ErrorObject::owned( + BAD_FORMAT, + format!("Extrinsic has invalid format: {}", e), + None::<()>, + ); + let _ = pending.reject(err).await; + return + }, + }; - let submit = self - .pool - .submit_and_watch(best_block_hash, TX_SOURCE, decoded_extrinsic) - .map_err(|e| { - e.into_pool_error() - .map(Error::from) - .unwrap_or_else(|e| Error::Verification(Box::new(e))) - }); + let best_block_hash = client.info().best_hash; + + let submit = pool + .submit_and_watch(best_block_hash, TX_SOURCE, decoded_extrinsic) + .map_err(|e| { + e.into_pool_error() + .map(Error::from) + .unwrap_or_else(|e| Error::Verification(Box::new(e))) + }); - let fut = async move { match submit.await { Ok(stream) => { let mut state = TransactionState::new(); let stream = - stream.filter_map(|event| async move { state.handle_event(event) }); - sink.pipe_from_stream(stream.boxed()).await; + stream.filter_map(move |event| async move { state.handle_event(event) }); + pipe_from_stream(pending, stream.boxed(), 16).await; }, Err(err) => { // We have not created an `Watcher` for the tx. Make sure the // error is still propagated as an event. let event: TransactionEvent<::Hash> = err.into(); - sink.pipe_from_stream(futures::stream::once(async { event }).boxed()).await; + pipe_from_stream(pending, futures::stream::once(async { event }).boxed(), 16) + .await; }, }; }; - self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); - Ok(()) + sc_rpc::utils::spawn_subscription_task(&self.executor, fut); } } diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index dd1120e5b0f8..67b1ac303c11 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } futures = "0.3.21" -jsonrpsee = { version = "0.16.2", features = ["server"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } log = "0.4.17" parking_lot = "0.12.1" serde_json = "1.0.107" @@ -37,7 +37,6 @@ sp-runtime = { path = "../../primitives/runtime" } sp-session = { path = "../../primitives/session" } sp-version = { path = "../../primitives/version" } sp-statement-store = { path = "../../primitives/statement-store" } - tokio = "1.22.0" [dev-dependencies] @@ -52,6 +51,7 @@ tokio = "1.22.0" sp-io = { path = "../../primitives/io" } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } pretty_assertions = "1.2.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } [features] test-helpers = [] diff --git a/substrate/client/rpc/src/author/mod.rs b/substrate/client/rpc/src/author/mod.rs index 55d0a504aa67..45456b332ed9 100644 --- a/substrate/client/rpc/src/author/mod.rs +++ b/substrate/client/rpc/src/author/mod.rs @@ -23,15 +23,14 @@ mod tests; use std::sync::Arc; -use crate::SubscriptionTaskExecutor; +use crate::{ + utils::{pipe_from_stream, spawn_subscription_task}, + SubscriptionTaskExecutor, +}; use codec::{Decode, Encode}; -use futures::{FutureExt, TryFutureExt}; -use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError, RpcResult}, - types::SubscriptionResult, - SubscriptionSink, -}; +use futures::TryFutureExt; +use jsonrpsee::{core::async_trait, types::ErrorObject, PendingSubscriptionSink}; use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::{ error::IntoPoolError, BlockHash, InPoolTransaction, TransactionFor, TransactionPool, @@ -91,7 +90,7 @@ where P::Hash: Unpin, ::Hash: Unpin, { - async fn submit_extrinsic(&self, ext: Bytes) -> RpcResult> { + async fn submit_extrinsic(&self, ext: Bytes) -> Result> { let xt = match Decode::decode(&mut &ext[..]) { Ok(xt) => xt, Err(err) => return Err(Error::Client(Box::new(err)).into()), @@ -105,7 +104,7 @@ where }) } - fn insert_key(&self, key_type: String, suri: String, public: Bytes) -> RpcResult<()> { + fn insert_key(&self, key_type: String, suri: String, public: Bytes) -> Result<()> { self.deny_unsafe.check_if_safe()?; let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?; @@ -115,7 +114,7 @@ where Ok(()) } - fn rotate_keys(&self) -> RpcResult { + fn rotate_keys(&self) -> Result { self.deny_unsafe.check_if_safe()?; let best_block_hash = self.client.info().best_hash; @@ -129,7 +128,7 @@ where .map_err(|api_err| Error::Client(Box::new(api_err)).into()) } - fn has_session_keys(&self, session_keys: Bytes) -> RpcResult { + fn has_session_keys(&self, session_keys: Bytes) -> Result { self.deny_unsafe.check_if_safe()?; let best_block_hash = self.client.info().best_hash; @@ -143,21 +142,21 @@ where Ok(self.keystore.has_keys(&keys)) } - fn has_key(&self, public_key: Bytes, key_type: String) -> RpcResult { + fn has_key(&self, public_key: Bytes, key_type: String) -> Result { self.deny_unsafe.check_if_safe()?; let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?; Ok(self.keystore.has_keys(&[(public_key.to_vec(), key_type)])) } - fn pending_extrinsics(&self) -> RpcResult> { + fn pending_extrinsics(&self) -> Result> { Ok(self.pool.ready().map(|tx| tx.data().encode().into()).collect()) } fn remove_extrinsic( &self, bytes_or_hash: Vec>>, - ) -> RpcResult>> { + ) -> Result>> { self.deny_unsafe.check_if_safe()?; let hashes = bytes_or_hash .into_iter() @@ -178,13 +177,13 @@ where .collect()) } - fn watch_extrinsic(&self, mut sink: SubscriptionSink, xt: Bytes) -> SubscriptionResult { + fn watch_extrinsic(&self, pending: PendingSubscriptionSink, xt: Bytes) { let best_block_hash = self.client.info().best_hash; let dxt = match TransactionFor::

::decode(&mut &xt[..]).map_err(|e| Error::from(e)) { Ok(dxt) => dxt, Err(e) => { - let _ = sink.reject(JsonRpseeError::from(e)); - return Ok(()) + spawn_subscription_task(&self.executor, pending.reject(e)); + return }, }; @@ -198,15 +197,14 @@ where let stream = match submit.await { Ok(stream) => stream, Err(err) => { - let _ = sink.reject(JsonRpseeError::from(err)); + let _ = pending.reject(ErrorObject::from(err)).await; return }, }; - sink.pipe_from_stream(stream).await; + pipe_from_stream(pending, stream, 16).await; }; - self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); - Ok(()) + spawn_subscription_task(&self.executor, fut); } } diff --git a/substrate/client/rpc/src/author/tests.rs b/substrate/client/rpc/src/author/tests.rs index f48b2f957142..b173120a34c3 100644 --- a/substrate/client/rpc/src/author/tests.rs +++ b/substrate/client/rpc/src/author/tests.rs @@ -22,8 +22,7 @@ use crate::testing::{test_executor, timeout_secs}; use assert_matches::assert_matches; use codec::Encode; use jsonrpsee::{ - core::Error as RpcError, - types::{error::CallError, EmptyServerParams as EmptyParams}, + core::{EmptyServerParams as EmptyParams, Error as RpcError}, RpcModule, }; use sc_transaction_pool::{BasicPool, FullChainApi}; @@ -104,7 +103,7 @@ async fn author_submit_transaction_should_not_cause_error() { assert_matches!( api.call::<_, H256>("author_submitExtrinsic", [xt]).await, - Err(RpcError::Call(CallError::Custom(err))) if err.message().contains("Already Imported") && err.code() == 1013 + Err(RpcError::Call(err)) if err.message().contains("Already Imported") && err.code() == 1013 ); } @@ -119,7 +118,7 @@ async fn author_should_watch_extrinsic() { true, ); - let mut sub = api.subscribe("author_submitAndWatchExtrinsic", [xt]).await.unwrap(); + let mut sub = api.subscribe_unbounded("author_submitAndWatchExtrinsic", [xt]).await.unwrap(); let (tx, sub_id) = timeout_secs(10, sub.next::>()) .await .unwrap() @@ -157,11 +156,11 @@ async fn author_should_return_watch_validation_error() { let invalid_xt = ExtrinsicBuilder::new_fill_block(Perbill::from_percent(100)).build(); let api = TestSetup::into_rpc(); - let failed_sub = api.subscribe(METHOD, [to_hex(&invalid_xt.encode(), true)]).await; + let failed_sub = api.subscribe_unbounded(METHOD, [to_hex(&invalid_xt.encode(), true)]).await; assert_matches!( failed_sub, - Err(RpcError::Call(CallError::Custom(err))) if err.message().contains("Invalid Transaction") && err.code() == 1010 + Err(RpcError::Call(err)) if err.message().contains("Invalid Transaction") && err.code() == 1010 ); } @@ -277,7 +276,7 @@ async fn author_has_session_keys() { assert_matches!( api.call::<_, bool>("author_hasSessionKeys", vec![Bytes::from(vec![1, 2, 3])]).await, - Err(RpcError::Call(CallError::Custom(err))) if err.message().contains("Session keys are not encoded correctly") + Err(RpcError::Call(err)) if err.message().contains("Session keys are not encoded correctly") ); } diff --git a/substrate/client/rpc/src/chain/chain_full.rs b/substrate/client/rpc/src/chain/chain_full.rs index a88291eb7bd3..2d3e5153c28b 100644 --- a/substrate/client/rpc/src/chain/chain_full.rs +++ b/substrate/client/rpc/src/chain/chain_full.rs @@ -19,14 +19,17 @@ //! Blockchain API backend for full nodes. use super::{client_err, ChainBackend, Error}; -use crate::SubscriptionTaskExecutor; +use crate::{ + utils::{pipe_from_stream, spawn_subscription_task}, + SubscriptionTaskExecutor, +}; use std::{marker::PhantomData, sync::Arc}; use futures::{ - future::{self, FutureExt}, + future::{self}, stream::{self, Stream, StreamExt}, }; -use jsonrpsee::SubscriptionSink; +use jsonrpsee::{core::async_trait, PendingSubscriptionSink}; use sc_client_api::{BlockBackend, BlockchainEvents}; use sp_blockchain::HeaderBackend; use sp_runtime::{generic::SignedBlock, traits::Block as BlockT}; @@ -48,6 +51,7 @@ impl FullChain { } } +#[async_trait] impl ChainBackend for FullChain where Block: BlockT + 'static, @@ -66,11 +70,11 @@ where self.client.block(self.unwrap_or_best(hash)).map_err(client_err) } - fn subscribe_all_heads(&self, sink: SubscriptionSink) { + fn subscribe_all_heads(&self, pending: PendingSubscriptionSink) { subscribe_headers( &self.client, &self.executor, - sink, + pending, || self.client().info().best_hash, || { self.client() @@ -80,11 +84,11 @@ where ) } - fn subscribe_new_heads(&self, sink: SubscriptionSink) { + fn subscribe_new_heads(&self, pending: PendingSubscriptionSink) { subscribe_headers( &self.client, &self.executor, - sink, + pending, || self.client().info().best_hash, || { self.client() @@ -95,11 +99,11 @@ where ) } - fn subscribe_finalized_heads(&self, sink: SubscriptionSink) { + fn subscribe_finalized_heads(&self, pending: PendingSubscriptionSink) { subscribe_headers( &self.client, &self.executor, - sink, + pending, || self.client().info().finalized_hash, || { self.client() @@ -114,7 +118,7 @@ where fn subscribe_headers( client: &Arc, executor: &SubscriptionTaskExecutor, - mut sink: SubscriptionSink, + pending: PendingSubscriptionSink, best_block_hash: G, stream: F, ) where @@ -139,9 +143,5 @@ fn subscribe_headers( // duplicates at the beginning of the stream though. let stream = stream::iter(maybe_header).chain(stream()); - let fut = async move { - sink.pipe_from_stream(stream).await; - }; - - executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + spawn_subscription_task(executor, pipe_from_stream(pending, stream, 16)); } diff --git a/substrate/client/rpc/src/chain/mod.rs b/substrate/client/rpc/src/chain/mod.rs index 2b5994f217df..1c74db8642e6 100644 --- a/substrate/client/rpc/src/chain/mod.rs +++ b/substrate/client/rpc/src/chain/mod.rs @@ -27,7 +27,7 @@ use std::sync::Arc; use crate::SubscriptionTaskExecutor; -use jsonrpsee::{core::RpcResult, types::SubscriptionResult, SubscriptionSink}; +use jsonrpsee::{core::async_trait, PendingSubscriptionSink}; use sc_client_api::BlockchainEvents; use sp_rpc::{list::ListOrValue, number::NumberOrHex}; use sp_runtime::{ @@ -42,6 +42,7 @@ pub use sc_rpc_api::chain::*; use sp_blockchain::HeaderBackend; /// Blockchain backend API +#[async_trait] trait ChainBackend: Send + Sync + 'static where Block: BlockT + 'static, @@ -91,13 +92,13 @@ where } /// All new head subscription - fn subscribe_all_heads(&self, sink: SubscriptionSink); + fn subscribe_all_heads(&self, pending: PendingSubscriptionSink); /// New best head subscription - fn subscribe_new_heads(&self, sink: SubscriptionSink); + fn subscribe_new_heads(&self, pending: PendingSubscriptionSink); /// Finalized head subscription - fn subscribe_finalized_heads(&self, sink: SubscriptionSink); + fn subscribe_finalized_heads(&self, pending: PendingSubscriptionSink); } /// Create new state API that works on full node. @@ -118,6 +119,7 @@ pub struct Chain { backend: Box>, } +#[async_trait] impl ChainApiServer, Block::Hash, Block::Header, SignedBlock> for Chain where @@ -125,20 +127,20 @@ where Block::Header: Unpin, Client: HeaderBackend + BlockchainEvents + 'static, { - fn header(&self, hash: Option) -> RpcResult> { - self.backend.header(hash).map_err(Into::into) + fn header(&self, hash: Option) -> Result, Error> { + self.backend.header(hash) } - fn block(&self, hash: Option) -> RpcResult>> { - self.backend.block(hash).map_err(Into::into) + fn block(&self, hash: Option) -> Result>, Error> { + self.backend.block(hash) } fn block_hash( &self, number: Option>, - ) -> RpcResult>> { + ) -> Result>, Error> { match number { - None => self.backend.block_hash(None).map(ListOrValue::Value).map_err(Into::into), + None => self.backend.block_hash(None).map(ListOrValue::Value), Some(ListOrValue::Value(number)) => self .backend .block_hash(Some(number)) @@ -152,23 +154,20 @@ where } } - fn finalized_head(&self) -> RpcResult { - self.backend.finalized_head().map_err(Into::into) + fn finalized_head(&self) -> Result { + self.backend.finalized_head() } - fn subscribe_all_heads(&self, sink: SubscriptionSink) -> SubscriptionResult { - self.backend.subscribe_all_heads(sink); - Ok(()) + fn subscribe_all_heads(&self, pending: PendingSubscriptionSink) { + self.backend.subscribe_all_heads(pending); } - fn subscribe_new_heads(&self, sink: SubscriptionSink) -> SubscriptionResult { - self.backend.subscribe_new_heads(sink); - Ok(()) + fn subscribe_new_heads(&self, pending: PendingSubscriptionSink) { + self.backend.subscribe_new_heads(pending) } - fn subscribe_finalized_heads(&self, sink: SubscriptionSink) -> SubscriptionResult { - self.backend.subscribe_finalized_heads(sink); - Ok(()) + fn subscribe_finalized_heads(&self, pending: PendingSubscriptionSink) { + self.backend.subscribe_finalized_heads(pending) } } diff --git a/substrate/client/rpc/src/chain/tests.rs b/substrate/client/rpc/src/chain/tests.rs index 75211a43bd9f..6e9e4ebad324 100644 --- a/substrate/client/rpc/src/chain/tests.rs +++ b/substrate/client/rpc/src/chain/tests.rs @@ -19,7 +19,7 @@ use super::*; use crate::testing::{test_executor, timeout_secs}; use assert_matches::assert_matches; -use jsonrpsee::types::EmptyServerParams as EmptyParams; +use jsonrpsee::core::EmptyServerParams as EmptyParams; use sc_block_builder::BlockBuilderProvider; use sp_consensus::BlockOrigin; use sp_rpc::list::ListOrValue; @@ -231,7 +231,7 @@ async fn test_head_subscription(method: &str) { let mut sub = { let api = new_full(client.clone(), test_executor()).into_rpc(); - let sub = api.subscribe(method, EmptyParams::new()).await.unwrap(); + let sub = api.subscribe_unbounded(method, EmptyParams::new()).await.unwrap(); let block = client.new_block(Default::default()).unwrap().build().unwrap().block; let block_hash = block.hash(); client.import(BlockOrigin::Own, block).await.unwrap(); diff --git a/substrate/client/rpc/src/dev/mod.rs b/substrate/client/rpc/src/dev/mod.rs index 4d2e8618d553..424ef72b694e 100644 --- a/substrate/client/rpc/src/dev/mod.rs +++ b/substrate/client/rpc/src/dev/mod.rs @@ -22,7 +22,6 @@ #[cfg(test)] mod tests; -use jsonrpsee::core::RpcResult; use sc_client_api::{BlockBackend, HeaderBackend}; use sc_rpc_api::{dev::error::Error, DenyUnsafe}; use sp_api::{ApiExt, Core, ProvideRuntimeApi}; @@ -65,7 +64,7 @@ where + 'static, Client::Api: Core, { - fn block_stats(&self, hash: Block::Hash) -> RpcResult> { + fn block_stats(&self, hash: Block::Hash) -> Result, Error> { self.deny_unsafe.check_if_safe()?; let block = { diff --git a/substrate/client/rpc/src/dev/tests.rs b/substrate/client/rpc/src/dev/tests.rs index db6a9a119da0..4082d6aaff08 100644 --- a/substrate/client/rpc/src/dev/tests.rs +++ b/substrate/client/rpc/src/dev/tests.rs @@ -83,7 +83,7 @@ async fn deny_unsafe_works() { "{{\"jsonrpc\":\"2.0\",\"method\":\"dev_getBlockStats\",\"params\":[{}],\"id\":1}}", best_hash_param ); - let (resp, _) = api.raw_json_request(&request).await.expect("Raw calls should succeed"); + let (resp, _) = api.raw_json_request(&request, 1).await.expect("Raw calls should succeed"); assert_eq!( resp.result, diff --git a/substrate/client/rpc/src/lib.rs b/substrate/client/rpc/src/lib.rs index 94fdb2d734ff..cc756bdb310f 100644 --- a/substrate/client/rpc/src/lib.rs +++ b/substrate/client/rpc/src/lib.rs @@ -45,3 +45,147 @@ pub mod testing; /// Task executor that is being used by RPC subscriptions. pub type SubscriptionTaskExecutor = std::sync::Arc; + +/// JSON-RPC helpers. +pub mod utils { + use crate::SubscriptionTaskExecutor; + use futures::{ + future::{self, Either, Fuse, FusedFuture}, + Future, FutureExt, Stream, StreamExt, + }; + use jsonrpsee::{PendingSubscriptionSink, SubscriptionMessage, SubscriptionSink}; + use sp_runtime::Serialize; + use std::collections::VecDeque; + + /// A simple bounded VecDeque. + struct BoundedVecDeque { + inner: VecDeque, + max_cap: usize, + } + + impl BoundedVecDeque { + /// Create a new bounded VecDeque. + fn new(max_cap: usize) -> Self { + Self { inner: VecDeque::with_capacity(max_cap), max_cap } + } + + fn push_back(&mut self, item: T) -> Result<(), ()> { + if self.inner.len() >= self.max_cap { + Err(()) + } else { + self.inner.push_back(item); + Ok(()) + } + } + + fn pop_front(&mut self) -> Option { + self.inner.pop_front() + } + } + + /// Feed items to the subscription from the underlying stream. + /// + /// It's possible configure how many items from the stream + /// are allowed to be kept in memory until the subscription is dropped. + /// + /// This is needed because the underlying streams in substrate are + /// unbounded. + pub async fn pipe_from_stream( + pending: PendingSubscriptionSink, + mut stream: S, + max_cap: usize, + ) where + S: Stream + Unpin + Send + 'static, + T: Serialize + Send + 'static, + { + let mut buf = BoundedVecDeque::new(max_cap); + let accept_fut = pending.accept(); + + futures::pin_mut!(accept_fut); + + // Poll the stream while waiting for the subscription to be accepted + // + // If the `max_cap` is exceeded then the subscription is dropped. + let sink = loop { + match future::select(accept_fut, stream.next()).await { + Either::Left((Ok(sink), _)) => break sink, + Either::Right((Some(msg), f)) => { + if buf.push_back(msg).is_err() { + log::warn!(target: "rpc", "Subscription::accept failed buffer limit={} exceed; dropping subscription", buf.max_cap); + return + } + accept_fut = f; + }, + // The connection was closed or the stream was closed. + _ => return, + } + }; + + inner_pipe_from_stream(sink, stream, buf).await + } + + async fn inner_pipe_from_stream( + sink: SubscriptionSink, + mut stream: S, + mut buf: BoundedVecDeque, + ) where + S: Stream + Unpin + Send + 'static, + T: Serialize + Send + 'static, + { + let mut next_fut = Box::pin(Fuse::terminated()); + + let mut next_item = stream.next(); + let closed = sink.closed(); + + futures::pin_mut!(closed); + + loop { + if next_fut.is_terminated() { + if let Some(v) = buf.pop_front() { + let val = to_sub_message(&sink, &v); + next_fut.set(async { sink.send(val).await }.fuse()); + } + } + + match future::select(closed, future::select(next_fut, next_item)).await { + // Send operation finished. + Either::Right((Either::Left((_, n)), c)) => { + next_item = n; + closed = c; + next_fut = Box::pin(Fuse::terminated()); + }, + // New item from the stream + Either::Right((Either::Right((Some(v), n)), c)) => { + if buf.push_back(v).is_err() { + log::warn!(target: "rpc", "Subscription buffer limit={} exceed; dropping subscription", buf.max_cap); + return + } + + next_fut = n; + closed = c; + next_item = stream.next(); + }, + // The stream or subscription was closed. + _ => break, + } + } + } + + /// Builds a subscription message. + /// + /// # Panics + /// + /// This function panics `Serialize` fails and is treated a bug. + pub fn to_sub_message(sink: &SubscriptionSink, result: &impl Serialize) -> SubscriptionMessage { + SubscriptionMessage::new(sink.method_name(), sink.subscription_id(), result) + .expect("Serialize infallible; qed") + } + + /// Helper for spawning non-blocking rpc subscription task. + pub fn spawn_subscription_task( + executor: &SubscriptionTaskExecutor, + fut: impl Future + Send + 'static, + ) { + executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + } +} diff --git a/substrate/client/rpc/src/mixnet/mod.rs b/substrate/client/rpc/src/mixnet/mod.rs index 3f3d9c5aa452..64875c6fe764 100644 --- a/substrate/client/rpc/src/mixnet/mod.rs +++ b/substrate/client/rpc/src/mixnet/mod.rs @@ -18,7 +18,7 @@ //! Substrate mixnet API. -use jsonrpsee::core::{async_trait, RpcResult}; +use jsonrpsee::core::async_trait; use sc_mixnet::Api; use sc_rpc_api::mixnet::error::Error; pub use sc_rpc_api::mixnet::MixnetApiServer; @@ -36,7 +36,7 @@ impl Mixnet { #[async_trait] impl MixnetApiServer for Mixnet { - async fn submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult<()> { + async fn submit_extrinsic(&self, extrinsic: Bytes) -> Result<(), Error> { // We only hold the lock while pushing the request into the requests channel let fut = { let mut api = self.0.lock().await; diff --git a/substrate/client/rpc/src/offchain/mod.rs b/substrate/client/rpc/src/offchain/mod.rs index de711accdcc1..661673866053 100644 --- a/substrate/client/rpc/src/offchain/mod.rs +++ b/substrate/client/rpc/src/offchain/mod.rs @@ -22,7 +22,7 @@ mod tests; use self::error::Error; -use jsonrpsee::core::{async_trait, Error as JsonRpseeError, RpcResult}; +use jsonrpsee::core::async_trait; use parking_lot::RwLock; /// Re-export the API for backward compatibility. pub use sc_rpc_api::offchain::*; @@ -50,23 +50,23 @@ impl Offchain { #[async_trait] impl OffchainApiServer for Offchain { - fn set_local_storage(&self, kind: StorageKind, key: Bytes, value: Bytes) -> RpcResult<()> { + fn set_local_storage(&self, kind: StorageKind, key: Bytes, value: Bytes) -> Result<(), Error> { self.deny_unsafe.check_if_safe()?; let prefix = match kind { StorageKind::PERSISTENT => sp_offchain::STORAGE_PREFIX, - StorageKind::LOCAL => return Err(JsonRpseeError::from(Error::UnavailableStorageKind)), + StorageKind::LOCAL => return Err(Error::UnavailableStorageKind), }; self.storage.write().set(prefix, &key, &value); Ok(()) } - fn get_local_storage(&self, kind: StorageKind, key: Bytes) -> RpcResult> { + fn get_local_storage(&self, kind: StorageKind, key: Bytes) -> Result, Error> { self.deny_unsafe.check_if_safe()?; let prefix = match kind { StorageKind::PERSISTENT => sp_offchain::STORAGE_PREFIX, - StorageKind::LOCAL => return Err(JsonRpseeError::from(Error::UnavailableStorageKind)), + StorageKind::LOCAL => return Err(Error::UnavailableStorageKind), }; Ok(self.storage.read().get(prefix, &key).map(Into::into)) diff --git a/substrate/client/rpc/src/offchain/tests.rs b/substrate/client/rpc/src/offchain/tests.rs index 62a846d0887c..7758fac7fabd 100644 --- a/substrate/client/rpc/src/offchain/tests.rs +++ b/substrate/client/rpc/src/offchain/tests.rs @@ -39,7 +39,6 @@ fn local_storage_should_work() { #[test] fn offchain_calls_considered_unsafe() { - use jsonrpsee::types::error::CallError; let storage = InMemOffchainStorage::default(); let offchain = Offchain::new(storage, DenyUnsafe::Yes); let key = Bytes(b"offchain_storage".to_vec()); @@ -47,14 +46,14 @@ fn offchain_calls_considered_unsafe() { assert_matches!( offchain.set_local_storage(StorageKind::PERSISTENT, key.clone(), value.clone()), - Err(JsonRpseeError::Call(CallError::Custom(err))) => { - assert_eq!(err.message(), "RPC call is unsafe to be called externally") + Err(Error::UnsafeRpcCalled(e)) => { + assert_eq!(e.to_string(), "RPC call is unsafe to be called externally") } ); assert_matches!( offchain.get_local_storage(StorageKind::PERSISTENT, key), - Err(JsonRpseeError::Call(CallError::Custom(err))) => { - assert_eq!(err.message(), "RPC call is unsafe to be called externally") + Err(Error::UnsafeRpcCalled(e)) => { + assert_eq!(e.to_string(), "RPC call is unsafe to be called externally") } ); } diff --git a/substrate/client/rpc/src/state/mod.rs b/substrate/client/rpc/src/state/mod.rs index 057661d6ec7f..c9a41e25eda8 100644 --- a/substrate/client/rpc/src/state/mod.rs +++ b/substrate/client/rpc/src/state/mod.rs @@ -24,32 +24,23 @@ mod utils; #[cfg(test)] mod tests; -use std::sync::Arc; - use crate::SubscriptionTaskExecutor; - -use jsonrpsee::{ - core::{async_trait, server::rpc_module::SubscriptionSink, Error as JsonRpseeError, RpcResult}, - types::SubscriptionResult, +use jsonrpsee::{core::async_trait, PendingSubscriptionSink}; +use sc_client_api::{ + Backend, BlockBackend, BlockchainEvents, ExecutorProvider, ProofProvider, StorageProvider, }; - use sc_rpc_api::DenyUnsafe; +use sp_api::{CallApiAt, Metadata, ProvideRuntimeApi}; +use sp_blockchain::{HeaderBackend, HeaderMetadata}; use sp_core::{ storage::{PrefixedStorageKey, StorageChangeSet, StorageData, StorageKey}, Bytes, }; use sp_runtime::traits::Block as BlockT; use sp_version::RuntimeVersion; +use std::sync::Arc; -use sp_api::{CallApiAt, Metadata, ProvideRuntimeApi}; - -use self::error::Error; - -use sc_client_api::{ - Backend, BlockBackend, BlockchainEvents, ExecutorProvider, ProofProvider, StorageProvider, -}; pub use sc_rpc_api::{child_state::*, state::*}; -use sp_blockchain::{HeaderBackend, HeaderMetadata}; const STORAGE_KEYS_PAGED_MAX_COUNT: u32 = 1000; @@ -158,10 +149,15 @@ where ) -> Result; /// New runtime version subscription - fn subscribe_runtime_version(&self, sink: SubscriptionSink); + fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink); /// New storage subscription - fn subscribe_storage(&self, sink: SubscriptionSink, keys: Option>); + fn subscribe_storage( + &self, + pending: PendingSubscriptionSink, + keys: Option>, + deny_unsafe: DenyUnsafe, + ); } /// Create new state API that works on full node. @@ -207,7 +203,12 @@ where Block: BlockT + 'static, Client: Send + Sync + 'static, { - fn call(&self, method: String, data: Bytes, block: Option) -> RpcResult { + fn call( + &self, + method: String, + data: Bytes, + block: Option, + ) -> Result { self.backend.call(block, method, data).map_err(Into::into) } @@ -215,7 +216,7 @@ where &self, key_prefix: StorageKey, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.backend.storage_keys(block, key_prefix).map_err(Into::into) } @@ -223,7 +224,7 @@ where &self, key_prefix: StorageKey, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.deny_unsafe.check_if_safe()?; self.backend.storage_pairs(block, key_prefix).map_err(Into::into) } @@ -234,12 +235,9 @@ where count: u32, start_key: Option, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { if count > STORAGE_KEYS_PAGED_MAX_COUNT { - return Err(JsonRpseeError::from(Error::InvalidCount { - value: count, - max: STORAGE_KEYS_PAGED_MAX_COUNT, - })) + return Err(Error::InvalidCount { value: count, max: STORAGE_KEYS_PAGED_MAX_COUNT }) } self.backend .storage_keys_paged(block, prefix, count, start_key) @@ -250,7 +248,7 @@ where &self, key: StorageKey, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.backend.storage(block, key).map_err(Into::into) } @@ -258,7 +256,7 @@ where &self, key: StorageKey, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.backend.storage_hash(block, key).map_err(Into::into) } @@ -266,18 +264,18 @@ where &self, key: StorageKey, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.backend .storage_size(block, key, self.deny_unsafe) .await .map_err(Into::into) } - fn metadata(&self, block: Option) -> RpcResult { + fn metadata(&self, block: Option) -> Result { self.backend.metadata(block).map_err(Into::into) } - fn runtime_version(&self, at: Option) -> RpcResult { + fn runtime_version(&self, at: Option) -> Result { self.backend.runtime_version(at).map_err(Into::into) } @@ -286,7 +284,7 @@ where keys: Vec, from: Block::Hash, to: Option, - ) -> RpcResult>> { + ) -> Result>, Error> { self.deny_unsafe.check_if_safe()?; self.backend.query_storage(from, to, keys).map_err(Into::into) } @@ -295,7 +293,7 @@ where &self, keys: Vec, at: Option, - ) -> RpcResult>> { + ) -> Result>, Error> { self.backend.query_storage_at(keys, at).map_err(Into::into) } @@ -303,7 +301,7 @@ where &self, keys: Vec, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.backend.read_proof(block, keys).map_err(Into::into) } @@ -318,32 +316,19 @@ where targets: Option, storage_keys: Option, methods: Option, - ) -> RpcResult { + ) -> Result { self.deny_unsafe.check_if_safe()?; self.backend .trace_block(block, targets, storage_keys, methods) .map_err(Into::into) } - fn subscribe_runtime_version(&self, sink: SubscriptionSink) -> SubscriptionResult { - self.backend.subscribe_runtime_version(sink); - Ok(()) + fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink) { + self.backend.subscribe_runtime_version(pending) } - fn subscribe_storage( - &self, - mut sink: SubscriptionSink, - keys: Option>, - ) -> SubscriptionResult { - if keys.is_none() { - if let Err(err) = self.deny_unsafe.check_if_safe() { - let _ = sink.reject(JsonRpseeError::from(err)); - return Ok(()) - } - } - - self.backend.subscribe_storage(sink, keys); - Ok(()) + fn subscribe_storage(&self, pending: PendingSubscriptionSink, keys: Option>) { + self.backend.subscribe_storage(pending, keys, self.deny_unsafe) } } @@ -430,7 +415,7 @@ where storage_key: PrefixedStorageKey, key_prefix: StorageKey, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.backend.storage_keys(block, storage_key, key_prefix).map_err(Into::into) } @@ -441,7 +426,7 @@ where count: u32, start_key: Option, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.backend .storage_keys_paged(block, storage_key, prefix, count, start_key) .map_err(Into::into) @@ -452,7 +437,7 @@ where storage_key: PrefixedStorageKey, key: StorageKey, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.backend.storage(block, storage_key, key).map_err(Into::into) } @@ -461,7 +446,7 @@ where storage_key: PrefixedStorageKey, keys: Vec, block: Option, - ) -> RpcResult>> { + ) -> Result>, Error> { self.backend.storage_entries(block, storage_key, keys).map_err(Into::into) } @@ -470,7 +455,7 @@ where storage_key: PrefixedStorageKey, key: StorageKey, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.backend.storage_hash(block, storage_key, key).map_err(Into::into) } @@ -479,7 +464,7 @@ where storage_key: PrefixedStorageKey, key: StorageKey, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.backend.storage_size(block, storage_key, key).map_err(Into::into) } @@ -488,7 +473,7 @@ where child_storage_key: PrefixedStorageKey, keys: Vec, block: Option, - ) -> RpcResult> { + ) -> Result, Error> { self.backend .read_child_proof(block, child_storage_key, keys) .map_err(Into::into) diff --git a/substrate/client/rpc/src/state/state_full.rs b/substrate/client/rpc/src/state/state_full.rs index 9604d9165f98..0f3f2d4c9666 100644 --- a/substrate/client/rpc/src/state/state_full.rs +++ b/substrate/client/rpc/src/state/state_full.rs @@ -25,13 +25,13 @@ use super::{ error::{Error, Result}, ChildStateBackend, StateBackend, }; -use crate::{DenyUnsafe, SubscriptionTaskExecutor}; - -use futures::{future, stream, FutureExt, StreamExt}; -use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError}, - SubscriptionSink, +use crate::{ + utils::{pipe_from_stream, spawn_subscription_task}, + DenyUnsafe, SubscriptionTaskExecutor, }; + +use futures::{future, stream, StreamExt}; +use jsonrpsee::{core::async_trait, types::ErrorObject, PendingSubscriptionSink}; use sc_client_api::{ Backend, BlockBackend, BlockchainEvents, CallExecutor, ExecutorProvider, ProofProvider, StorageProvider, @@ -371,9 +371,7 @@ where .map_err(client_err) } - fn subscribe_runtime_version(&self, mut sink: SubscriptionSink) { - let client = self.client.clone(); - + fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink) { let initial = match self .block_or_best(None) .and_then(|block| self.client.runtime_version_at(block).map_err(Into::into)) @@ -381,12 +379,13 @@ where { Ok(initial) => initial, Err(e) => { - let _ = sink.reject(JsonRpseeError::from(e)); + spawn_subscription_task(&self.executor, pending.reject(e)); return }, }; let mut previous_version = initial.clone(); + let client = self.client.clone(); // A stream of new versions let version_stream = client @@ -406,24 +405,33 @@ where }); let stream = futures::stream::once(future::ready(initial)).chain(version_stream); - - let fut = async move { - sink.pipe_from_stream(stream).await; - }; - - self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream, 16)); } - fn subscribe_storage(&self, mut sink: SubscriptionSink, keys: Option>) { + fn subscribe_storage( + &self, + pending: PendingSubscriptionSink, + keys: Option>, + deny_unsafe: DenyUnsafe, + ) { + if keys.is_none() { + if let Err(err) = deny_unsafe.check_if_safe() { + spawn_subscription_task(&self.executor, pending.reject(ErrorObject::from(err))); + return + } + } + let stream = match self.client.storage_changes_notification_stream(keys.as_deref(), None) { Ok(stream) => stream, Err(blockchain_err) => { - let _ = sink.reject(JsonRpseeError::from(Error::Client(Box::new(blockchain_err)))); + spawn_subscription_task( + &self.executor, + pending.reject(Error::Client(Box::new(blockchain_err))), + ); return }, }; - // initial values let initial = stream::iter(keys.map(|keys| { let block = self.client.info().best_hash; let changes = keys @@ -436,7 +444,6 @@ where StorageChangeSet { block, changes } })); - // let storage_stream = stream.map(|(block, changes)| StorageChangeSet { let storage_stream = stream.map(|storage_notif| StorageChangeSet { block: storage_notif.block, changes: storage_notif @@ -450,11 +457,7 @@ where .chain(storage_stream) .filter(|storage| future::ready(!storage.changes.is_empty())); - let fut = async move { - sink.pipe_from_stream(stream).await; - }; - - self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream, 16)); } fn trace_block( diff --git a/substrate/client/rpc/src/state/tests.rs b/substrate/client/rpc/src/state/tests.rs index 35352f6d890e..e4c14fc62ece 100644 --- a/substrate/client/rpc/src/state/tests.rs +++ b/substrate/client/rpc/src/state/tests.rs @@ -21,10 +21,7 @@ use super::*; use crate::testing::{test_executor, timeout_secs}; use assert_matches::assert_matches; use futures::executor; -use jsonrpsee::{ - core::Error as RpcError, - types::{error::CallError as RpcCallError, EmptyServerParams as EmptyParams, ErrorObject}, -}; +use jsonrpsee::core::{EmptyServerParams as EmptyParams, Error as RpcError}; use sc_block_builder::BlockBuilderProvider; use sc_rpc_api::DenyUnsafe; use sp_consensus::BlockOrigin; @@ -42,6 +39,14 @@ fn prefixed_storage_key() -> PrefixedStorageKey { child_info.prefixed_storage_key() } +fn init_logger() { + use tracing_subscriber::{EnvFilter, FmtSubscriber}; + + let _ = FmtSubscriber::builder() + .with_env_filter(EnvFilter::from_default_env()) + .try_init(); +} + #[tokio::test] async fn should_return_storage() { const KEY: &[u8] = b":mock"; @@ -200,22 +205,25 @@ async fn should_call_contract() { let genesis_hash = client.genesis_hash(); let (client, _child) = new_full(client, test_executor(), DenyUnsafe::No); - use jsonrpsee::{core::Error, types::error::CallError}; - assert_matches!( client.call("balanceOf".into(), Bytes(vec![1, 2, 3]), Some(genesis_hash).into()), - Err(Error::Call(CallError::Failed(_))) + Err(Error::Client(_)) ) } #[tokio::test] async fn should_notify_about_storage_changes() { + init_logger(); + let mut sub = { let mut client = Arc::new(substrate_test_runtime_client::new()); let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No); let api_rpc = api.into_rpc(); - let sub = api_rpc.subscribe("state_subscribeStorage", EmptyParams::new()).await.unwrap(); + let sub = api_rpc + .subscribe_unbounded("state_subscribeStorage", EmptyParams::new()) + .await + .unwrap(); // Cause a change: let mut builder = client.new_block(Default::default()).unwrap(); @@ -237,11 +245,12 @@ async fn should_notify_about_storage_changes() { // NOTE: previous versions of the subscription code used to return an empty value for the // "initial" storage change here assert_matches!(timeout_secs(1, sub.next::>()).await, Ok(Some(_))); - assert_matches!(timeout_secs(1, sub.next::>()).await, Ok(None)); } #[tokio::test] async fn should_send_initial_storage_changes_and_notifications() { + init_logger(); + let mut sub = { let mut client = Arc::new(substrate_test_runtime_client::new()); let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No); @@ -259,7 +268,10 @@ async fn should_send_initial_storage_changes_and_notifications() { let api_rpc = api.into_rpc(); let sub = api_rpc - .subscribe("state_subscribeStorage", [[StorageKey(alice_balance_key)]]) + .subscribe_unbounded( + "state_subscribeStorage", + [[StorageKey(alice_balance_key.to_vec())]], + ) .await .unwrap(); @@ -280,9 +292,6 @@ async fn should_send_initial_storage_changes_and_notifications() { assert_matches!(timeout_secs(1, sub.next::>()).await, Ok(Some(_))); assert_matches!(timeout_secs(1, sub.next::>()).await, Ok(Some(_))); - - // No more messages to follow - assert_matches!(timeout_secs(1, sub.next::>()).await, Ok(None)); } #[tokio::test] @@ -381,108 +390,48 @@ async fn should_query_storage() { assert_eq!(result.unwrap(), expected); // Inverted range. - let result = api.query_storage(keys.clone(), block1_hash, Some(genesis_hash)); - - assert_eq!( - result.map_err(|e| e.to_string()), - Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( - 4001, - Error::InvalidBlockRange { - from: format!("1 ({:?})", block1_hash), - to: format!("0 ({:?})", genesis_hash), - details: "from number > to number".to_owned(), - } - .to_string(), - None::<()>, - )))) - .map_err(|e| e.to_string()) + assert_matches!( + api.query_storage(keys.clone(), block1_hash, Some(genesis_hash)), + Err(Error::InvalidBlockRange { from, to, details }) if from == format!("1 ({:?})", block1_hash) && to == format!("0 ({:?})", genesis_hash) && details == "from number > to number".to_owned() ); let random_hash1 = H256::random(); let random_hash2 = H256::random(); // Invalid second hash. - let result = api.query_storage(keys.clone(), genesis_hash, Some(random_hash1)); - - assert_eq!( - result.map_err(|e| e.to_string()), - Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( - 4001, - Error::InvalidBlockRange { - from: format!("{:?}", genesis_hash), - to: format!("{:?}", Some(random_hash1)), - details: format!( - "UnknownBlock: Header was not found in the database: {:?}", - random_hash1 - ), - } - .to_string(), - None::<()>, - )))) - .map_err(|e| e.to_string()) + assert_matches!( + api.query_storage(keys.clone(), genesis_hash, Some(random_hash1)), + Err(Error::InvalidBlockRange { from, to, details }) if from == format!("{:?}", genesis_hash) && to == format!("{:?}", Some(random_hash1)) && details == format!( + "UnknownBlock: Header was not found in the database: {:?}", + random_hash1 + ) ); // Invalid first hash with Some other hash. - let result = api.query_storage(keys.clone(), random_hash1, Some(genesis_hash)); - - assert_eq!( - result.map_err(|e| e.to_string()), - Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( - 4001, - Error::InvalidBlockRange { - from: format!("{:?}", random_hash1), - to: format!("{:?}", Some(genesis_hash)), - details: format!( - "UnknownBlock: Header was not found in the database: {:?}", - random_hash1 - ), - } - .to_string(), - None::<()>, - )))) - .map_err(|e| e.to_string()), + assert_matches!( + api.query_storage(keys.clone(), random_hash1, Some(genesis_hash)), + Err(Error::InvalidBlockRange { from, to, details }) if from == format!("{:?}", random_hash1) && to == format!("{:?}", Some(genesis_hash)) && details == format!( + "UnknownBlock: Header was not found in the database: {:?}", + random_hash1 + ) ); // Invalid first hash with None. - let result = api.query_storage(keys.clone(), random_hash1, None); - - assert_eq!( - result.map_err(|e| e.to_string()), - Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( - 4001, - Error::InvalidBlockRange { - from: format!("{:?}", random_hash1), - to: format!("{:?}", Some(block2_hash)), // Best block hash. - details: format!( - "UnknownBlock: Header was not found in the database: {:?}", - random_hash1 - ), - } - .to_string(), - None::<()>, - )))) - .map_err(|e| e.to_string()), + assert_matches!( + api.query_storage(keys.clone(), random_hash1, None), + Err(Error::InvalidBlockRange { from, to, details }) if from == format!("{:?}", random_hash1) && to == format!("{:?}", Some(block2_hash)) && details == format!( + "UnknownBlock: Header was not found in the database: {:?}", + random_hash1 + ) ); // Both hashes invalid. - let result = api.query_storage(keys.clone(), random_hash1, Some(random_hash2)); - - assert_eq!( - result.map_err(|e| e.to_string()), - Err(RpcError::Call(RpcCallError::Custom(ErrorObject::owned( - 4001, - Error::InvalidBlockRange { - from: format!("{:?}", random_hash1), // First hash not found. - to: format!("{:?}", Some(random_hash2)), - details: format!( - "UnknownBlock: Header was not found in the database: {:?}", - random_hash1 - ), - } - .to_string(), - None::<()> - )))) - .map_err(|e| e.to_string()), + assert_matches!( + api.query_storage(keys.clone(), random_hash1, Some(random_hash2)), + Err(Error::InvalidBlockRange { from, to, details }) if from == format!("{:?}", random_hash1) && to == format!("{:?}", Some(random_hash2)) && details == format!( + "UnknownBlock: Header was not found in the database: {:?}", + random_hash1 + ) ); // single block range @@ -536,7 +485,7 @@ async fn should_notify_on_runtime_version_initially() { let api_rpc = api.into_rpc(); let sub = api_rpc - .subscribe("state_subscribeRuntimeVersion", EmptyParams::new()) + .subscribe_unbounded("state_subscribeRuntimeVersion", EmptyParams::new()) .await .unwrap(); @@ -545,9 +494,6 @@ async fn should_notify_on_runtime_version_initially() { // assert initial version sent. assert_matches!(timeout_secs(10, sub.next::()).await, Ok(Some(_))); - - sub.close(); - assert_matches!(timeout_secs(10, sub.next::()).await, Ok(None)); } #[test] @@ -560,12 +506,14 @@ fn should_deserialize_storage_key() { #[tokio::test] async fn wildcard_storage_subscriptions_are_rpc_unsafe() { + init_logger(); + let client = Arc::new(substrate_test_runtime_client::new()); let (api, _child) = new_full(client, test_executor(), DenyUnsafe::Yes); let api_rpc = api.into_rpc(); - let err = api_rpc.subscribe("state_subscribeStorage", EmptyParams::new()).await; - assert_matches!(err, Err(RpcError::Call(RpcCallError::Custom(e))) if e.message() == "RPC call is unsafe to be called externally"); + let err = api_rpc.subscribe_unbounded("state_subscribeStorage", EmptyParams::new()).await; + assert_matches!(err, Err(RpcError::Call(e)) if e.message() == "RPC call is unsafe to be called externally"); } #[tokio::test] @@ -575,7 +523,7 @@ async fn concrete_storage_subscriptions_are_rpc_safe() { let api_rpc = api.into_rpc(); let key = StorageKey(STORAGE_KEY.to_vec()); - let sub = api_rpc.subscribe("state_subscribeStorage", [[key]]).await; + let sub = api_rpc.subscribe_unbounded("state_subscribeStorage", [[key]]).await; assert!(sub.is_ok()); } diff --git a/substrate/client/rpc/src/system/mod.rs b/substrate/client/rpc/src/system/mod.rs index 0da4f8d0e211..8c7510c64cb5 100644 --- a/substrate/client/rpc/src/system/mod.rs +++ b/substrate/client/rpc/src/system/mod.rs @@ -22,17 +22,12 @@ mod tests; use futures::channel::oneshot; -use jsonrpsee::{ - core::{async_trait, error::Error as JsonRpseeError, JsonValue, RpcResult}, - types::error::{CallError, ErrorCode, ErrorObject}, -}; +use jsonrpsee::core::{async_trait, JsonValue}; use sc_rpc_api::DenyUnsafe; use sc_tracing::logging; use sc_utils::mpsc::TracingUnboundedSender; use sp_runtime::traits::{self, Header as HeaderT}; -use self::error::Result; - pub use self::helpers::{Health, NodeRole, PeerInfo, SyncState, SystemInfo}; pub use sc_rpc_api::system::*; @@ -57,9 +52,9 @@ pub enum Request { /// Must return the state of the network. NetworkState(oneshot::Sender), /// Must return any potential parse error. - NetworkAddReservedPeer(String, oneshot::Sender>), + NetworkAddReservedPeer(String, oneshot::Sender>), /// Must return any potential parse error. - NetworkRemoveReservedPeer(String, oneshot::Sender>), + NetworkRemoveReservedPeer(String, oneshot::Sender>), /// Must return the list of reserved peers NetworkReservedPeers(oneshot::Sender>), /// Must return the node role. @@ -84,121 +79,109 @@ impl System { #[async_trait] impl SystemApiServer::Number> for System { - fn system_name(&self) -> RpcResult { + fn system_name(&self) -> Result { Ok(self.info.impl_name.clone()) } - fn system_version(&self) -> RpcResult { + fn system_version(&self) -> Result { Ok(self.info.impl_version.clone()) } - fn system_chain(&self) -> RpcResult { + fn system_chain(&self) -> Result { Ok(self.info.chain_name.clone()) } - fn system_type(&self) -> RpcResult { + fn system_type(&self) -> Result { Ok(self.info.chain_type.clone()) } - fn system_properties(&self) -> RpcResult { + fn system_properties(&self) -> Result { Ok(self.info.properties.clone()) } - async fn system_health(&self) -> RpcResult { + async fn system_health(&self) -> Result { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::Health(tx)); - rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) + rx.await.map_err(|e| Error::Internal(e.to_string())) } - async fn system_local_peer_id(&self) -> RpcResult { + async fn system_local_peer_id(&self) -> Result { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::LocalPeerId(tx)); - rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) + rx.await.map_err(|e| Error::Internal(e.to_string())) } - async fn system_local_listen_addresses(&self) -> RpcResult> { + async fn system_local_listen_addresses(&self) -> Result, Error> { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::LocalListenAddresses(tx)); - rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) + rx.await.map_err(|e| Error::Internal(e.to_string())) } async fn system_peers( &self, - ) -> RpcResult::Number>>> { + ) -> Result::Number>>, Error> { self.deny_unsafe.check_if_safe()?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::Peers(tx)); - rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) + rx.await.map_err(|e| Error::Internal(e.to_string())) } - async fn system_network_state(&self) -> RpcResult { + async fn system_network_state(&self) -> Result { self.deny_unsafe.check_if_safe()?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NetworkState(tx)); - rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) + rx.await.map_err(|e| Error::Internal(e.to_string())) } - async fn system_add_reserved_peer(&self, peer: String) -> RpcResult<()> { + async fn system_add_reserved_peer(&self, peer: String) -> Result<(), Error> { self.deny_unsafe.check_if_safe()?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NetworkAddReservedPeer(peer, tx)); match rx.await { Ok(Ok(())) => Ok(()), - Ok(Err(e)) => Err(JsonRpseeError::from(e)), - Err(e) => Err(JsonRpseeError::to_call_error(e)), + Ok(Err(e)) => Err(e), + Err(e) => Err(Error::Internal(e.to_string())), } } - async fn system_remove_reserved_peer(&self, peer: String) -> RpcResult<()> { + async fn system_remove_reserved_peer(&self, peer: String) -> Result<(), Error> { self.deny_unsafe.check_if_safe()?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NetworkRemoveReservedPeer(peer, tx)); match rx.await { Ok(Ok(())) => Ok(()), - Ok(Err(e)) => Err(JsonRpseeError::from(e)), - Err(e) => Err(JsonRpseeError::to_call_error(e)), + Ok(Err(e)) => Err(e), + Err(e) => Err(Error::Internal(e.to_string())), } } - async fn system_reserved_peers(&self) -> RpcResult> { + async fn system_reserved_peers(&self) -> Result, Error> { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NetworkReservedPeers(tx)); - rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) + rx.await.map_err(|e| Error::Internal(e.to_string())) } - async fn system_node_roles(&self) -> RpcResult> { + async fn system_node_roles(&self) -> Result, Error> { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NodeRoles(tx)); - rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) + rx.await.map_err(|e| Error::Internal(e.to_string())) } - async fn system_sync_state(&self) -> RpcResult::Number>> { + async fn system_sync_state(&self) -> Result::Number>, Error> { let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::SyncState(tx)); - rx.await.map_err(|e| JsonRpseeError::to_call_error(e)) + rx.await.map_err(|e| Error::Internal(e.to_string())) } - fn system_add_log_filter(&self, directives: String) -> RpcResult<()> { + fn system_add_log_filter(&self, directives: String) -> Result<(), Error> { self.deny_unsafe.check_if_safe()?; logging::add_directives(&directives); - logging::reload_filter().map_err(|e| { - JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( - ErrorCode::InternalError.code(), - e, - None::<()>, - ))) - }) + logging::reload_filter().map_err(|e| Error::Internal(e)) } - fn system_reset_log_filter(&self) -> RpcResult<()> { + fn system_reset_log_filter(&self) -> Result<(), Error> { self.deny_unsafe.check_if_safe()?; - logging::reset_log_filter().map_err(|e| { - JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( - ErrorCode::InternalError.code(), - e, - None::<()>, - ))) - }) + logging::reset_log_filter().map_err(|e| Error::Internal(e)) } } diff --git a/substrate/client/rpc/src/system/tests.rs b/substrate/client/rpc/src/system/tests.rs index b6bfec7736b0..21d13ccfafaa 100644 --- a/substrate/client/rpc/src/system/tests.rs +++ b/substrate/client/rpc/src/system/tests.rs @@ -20,8 +20,7 @@ use super::{helpers::SyncState, *}; use assert_matches::assert_matches; use futures::prelude::*; use jsonrpsee::{ - core::Error as RpcError, - types::{error::CallError, EmptyServerParams as EmptyParams}, + core::{EmptyServerParams as EmptyParams, Error as RpcError}, RpcModule, }; use sc_network::{self, config::Role, PeerId}; @@ -312,7 +311,7 @@ async fn system_network_add_reserved() { let bad_peer_id = ["/ip4/198.51.100.19/tcp/30333"]; assert_matches!( api(None).call::<_, ()>("system_addReservedPeer", bad_peer_id).await, - Err(RpcError::Call(CallError::Custom(err))) if err.message().contains("Peer id is missing from the address") + Err(RpcError::Call(err)) if err.message().contains("Peer id is missing from the address") ); } @@ -328,7 +327,7 @@ async fn system_network_remove_reserved() { assert_matches!( api(None).call::<_, String>("system_removeReservedPeer", bad_peer_id).await, - Err(RpcError::Call(CallError::Custom(err))) if err.message().contains("base-58 decode error: provided string contained invalid character '/' at byte 0") + Err(RpcError::Call(err)) if err.message().contains("base-58 decode error: provided string contained invalid character '/' at byte 0") ); } #[tokio::test] diff --git a/substrate/client/rpc/src/testing.rs b/substrate/client/rpc/src/testing.rs index 6b6e1906d44d..e04f80a7b9e6 100644 --- a/substrate/client/rpc/src/testing.rs +++ b/substrate/client/rpc/src/testing.rs @@ -20,11 +20,50 @@ use std::{future::Future, sync::Arc}; -use sp_core::testing::TaskExecutor; +/// A task executor that can be used for running RPC tests. +/// +/// Warning: the tokio runtime must be initialized before calling this. +#[derive(Clone)] +pub struct TokioTestExecutor(tokio::runtime::Handle); + +impl TokioTestExecutor { + /// Create a new instance of `Self`. + pub fn new() -> Self { + Self(tokio::runtime::Handle::current()) + } +} + +impl Default for TokioTestExecutor { + fn default() -> Self { + Self::new() + } +} + +impl sp_core::traits::SpawnNamed for TokioTestExecutor { + fn spawn_blocking( + &self, + _name: &'static str, + _group: Option<&'static str>, + future: futures::future::BoxFuture<'static, ()>, + ) { + let handle = self.0.clone(); + self.0.spawn_blocking(move || { + handle.block_on(future); + }); + } + fn spawn( + &self, + _name: &'static str, + _group: Option<&'static str>, + future: futures::future::BoxFuture<'static, ()>, + ) { + self.0.spawn(future); + } +} /// Executor for testing. -pub fn test_executor() -> Arc { - Arc::new(TaskExecutor::default()) +pub fn test_executor() -> Arc { + Arc::new(TokioTestExecutor::default()) } /// Wrap a future in a timeout a little more concisely diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index 2386bebf24d2..2ff2664cb6dd 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -25,7 +25,7 @@ runtime-benchmarks = [ ] [dependencies] -jsonrpsee = { version = "0.16.2", features = ["server"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } thiserror = "1.0.48" futures = "0.3.21" rand = "0.8.5" diff --git a/substrate/client/service/src/config.rs b/substrate/client/service/src/config.rs index 39b7ee050790..0adb06622cf0 100644 --- a/substrate/client/service/src/config.rs +++ b/substrate/client/service/src/config.rs @@ -100,6 +100,8 @@ pub struct Configuration { pub rpc_max_subs_per_conn: u32, /// JSON-RPC server default port. pub rpc_port: u16, + /// The number of messages the JSON-RPC server is allowed to keep in memory. + pub rpc_message_buffer_capacity: u32, /// Prometheus endpoint configuration. `None` if disabled. pub prometheus_config: Option, /// Telemetry service URL. `None` if disabled. diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index ff9eb982b862..250511d1c0c2 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -37,7 +37,7 @@ mod task_manager; use std::{collections::HashMap, net::SocketAddr}; use codec::{Decode, Encode}; -use futures::{channel::mpsc, pin_mut, FutureExt, StreamExt}; +use futures::{pin_mut, FutureExt, StreamExt}; use jsonrpsee::{core::Error as JsonRpseeError, RpcModule}; use log::{debug, error, warn}; use sc_client_api::{blockchain::HeaderBackend, BlockBackend, BlockchainEvents, ProofProvider}; @@ -108,9 +108,9 @@ impl RpcHandlers { pub async fn rpc_query( &self, json_query: &str, - ) -> Result<(String, mpsc::UnboundedReceiver), JsonRpseeError> { + ) -> Result<(String, tokio::sync::mpsc::Receiver), JsonRpseeError> { self.0 - .raw_json_request(json_query) + .raw_json_request(json_query, usize::MAX) .await .map(|(method_res, recv)| (method_res.result, recv)) } @@ -393,6 +393,7 @@ where max_payload_in_mb: config.rpc_max_request_size, max_payload_out_mb: config.rpc_max_response_size, max_subs_per_conn: config.rpc_max_subs_per_conn, + message_buffer_capacity: config.rpc_message_buffer_capacity, rpc_api: gen_rpc_module(deny_unsafe(addr, &config.rpc_methods))?, metrics, id_provider: rpc_id_provider, diff --git a/substrate/client/service/test/src/lib.rs b/substrate/client/service/test/src/lib.rs index 9700c7643c48..cef433213d78 100644 --- a/substrate/client/service/test/src/lib.rs +++ b/substrate/client/service/test/src/lib.rs @@ -253,6 +253,7 @@ fn node_config< rpc_id_provider: Default::default(), rpc_max_subs_per_conn: Default::default(), rpc_port: 9944, + rpc_message_buffer_capacity: Default::default(), prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index e582d0b7e4ff..3372f3f03203 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.20.3", features = ["client-core", "server", "macros"] } serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" thiserror = "1.0.48" diff --git a/substrate/client/sync-state-rpc/src/lib.rs b/substrate/client/sync-state-rpc/src/lib.rs index dda8a7edfa9b..cb737cc6c52b 100644 --- a/substrate/client/sync-state-rpc/src/lib.rs +++ b/substrate/client/sync-state-rpc/src/lib.rs @@ -44,9 +44,9 @@ use std::sync::Arc; use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError, RpcResult}, + core::async_trait, proc_macros::rpc, - types::{error::CallError, ErrorObject}, + types::{ErrorObject, ErrorObjectOwned}, }; use sc_client_api::StorageData; @@ -80,13 +80,13 @@ pub enum Error { LightSyncStateExtensionNotFound, } -impl From> for JsonRpseeError { +impl From> for ErrorObjectOwned { fn from(error: Error) -> Self { let message = match error { Error::JsonRpc(s) => s, _ => error.to_string(), }; - CallError::Custom(ErrorObject::owned(1, message, None::<()>)).into() + ErrorObject::owned(1, message, None::<()>) } } @@ -126,10 +126,10 @@ pub struct LightSyncState { /// An api for sync state RPC calls. #[rpc(client, server)] -pub trait SyncStateApi { +pub trait SyncStateApi { /// Returns the JSON serialized chainspec running the node, with a sync state. #[method(name = "sync_state_genSyncSpec")] - async fn system_gen_sync_spec(&self, raw: bool) -> RpcResult; + async fn system_gen_sync_spec(&self, raw: bool) -> Result>; } /// An api for sync state RPC calls. @@ -188,12 +188,12 @@ where } #[async_trait] -impl SyncStateApiServer for SyncState +impl SyncStateApiServer for SyncState where Block: BlockT, Backend: HeaderBackend + sc_client_api::AuxStore + 'static, { - async fn system_gen_sync_spec(&self, raw: bool) -> RpcResult { + async fn system_gen_sync_spec(&self, raw: bool) -> Result> { let current_sync_state = self.build_sync_state().await?; let mut chain_spec = self.chain_spec.cloned_box(); @@ -202,10 +202,11 @@ where ) .ok_or(Error::::LightSyncStateExtensionNotFound)?; - let val = serde_json::to_value(¤t_sync_state)?; + let val = serde_json::to_value(¤t_sync_state) + .map_err(|e| Error::::JsonRpc(e.to_string()))?; *extension = Some(val); let json_str = chain_spec.as_json(raw).map_err(|e| Error::::JsonRpc(e))?; - serde_json::from_str(&json_str).map_err(Into::into) + serde_json::from_str(&json_str).map_err(|e| Error::::JsonRpc(e.to_string())) } } diff --git a/substrate/frame/support/procedural/src/pallet/expand/warnings.rs b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs index 6ce2097c2684..030e3ddaf323 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/warnings.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/warnings.rs @@ -33,9 +33,7 @@ pub(crate) fn weight_witness_warning( if dev_mode { return } - let CallWeightDef::Immediate(w) = &method.weight else { - return - }; + let CallWeightDef::Immediate(w) = &method.weight else { return }; let partial_warning = Warning::new_deprecated("UncheckedWeightWitness") .old("not check weight witness data") @@ -66,9 +64,7 @@ pub(crate) fn weight_constant_warning( if dev_mode { return } - let syn::Expr::Lit(lit) = weight else { - return - }; + let syn::Expr::Lit(lit) = weight else { return }; let warning = Warning::new_deprecated("ConstantWeight") .index(warnings.len()) diff --git a/substrate/frame/transaction-payment/rpc/Cargo.toml b/substrate/frame/transaction-payment/rpc/Cargo.toml index 8a0052e0337e..fe71c4681f38 100644 --- a/substrate/frame/transaction-payment/rpc/Cargo.toml +++ b/substrate/frame/transaction-payment/rpc/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.20.3", features = ["client-core", "server", "macros"] } pallet-transaction-payment-rpc-runtime-api = { path = "runtime-api" } sp-api = { path = "../../../primitives/api" } sp-blockchain = { path = "../../../primitives/blockchain" } diff --git a/substrate/frame/transaction-payment/rpc/src/lib.rs b/substrate/frame/transaction-payment/rpc/src/lib.rs index 7f8ed4b80267..f5323cf852e9 100644 --- a/substrate/frame/transaction-payment/rpc/src/lib.rs +++ b/substrate/frame/transaction-payment/rpc/src/lib.rs @@ -21,9 +21,12 @@ use std::{convert::TryInto, sync::Arc}; use codec::{Codec, Decode}; use jsonrpsee::{ - core::{Error as JsonRpseeError, RpcResult}, + core::RpcResult, proc_macros::rpc, - types::error::{CallError, ErrorCode, ErrorObject}, + types::{ + error::{ErrorCode, ErrorObject}, + ErrorObjectOwned, + }, }; use pallet_transaction_payment_rpc_runtime_api::{FeeDetails, InclusionFee, RuntimeDispatchInfo}; use sp_api::ProvideRuntimeApi; @@ -100,19 +103,15 @@ where let encoded_len = encoded_xt.len() as u32; let uxt: Block::Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( Error::DecodeError.into(), "Unable to query dispatch info.", Some(format!("{:?}", e)), - )) + ) })?; - fn map_err(error: impl ToString, desc: &'static str) -> CallError { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - desc, - Some(error.to_string()), - )) + fn map_err(error: impl ToString, desc: &'static str) -> ErrorObjectOwned { + ErrorObject::owned(Error::RuntimeError.into(), desc, Some(error.to_string())) } let res = api @@ -137,27 +136,27 @@ where let encoded_len = encoded_xt.len() as u32; let uxt: Block::Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( Error::DecodeError.into(), "Unable to query fee details.", Some(format!("{:?}", e)), - )) + ) })?; let fee_details = api.query_fee_details(at_hash, uxt, encoded_len).map_err(|e| { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( Error::RuntimeError.into(), "Unable to query fee details.", Some(e.to_string()), - )) + ) })?; let try_into_rpc_balance = |value: Balance| { value.try_into().map_err(|_| { - JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( + ErrorObject::owned( ErrorCode::InvalidParams.code(), format!("{} doesn't fit in NumberOrHex representation", value), None::<()>, - ))) + ) }) }; diff --git a/substrate/frame/transaction-payment/src/types.rs b/substrate/frame/transaction-payment/src/types.rs index cbe85309b856..25cecc58a63a 100644 --- a/substrate/frame/transaction-payment/src/types.rs +++ b/substrate/frame/transaction-payment/src/types.rs @@ -94,7 +94,7 @@ impl FeeDetails { /// Information related to a dispatchable's class, weight, and fee that can be queried from the /// runtime. #[derive(Eq, PartialEq, Encode, Decode, Default, TypeInfo)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize, Clone))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr( feature = "std", diff --git a/substrate/primitives/rpc/src/list.rs b/substrate/primitives/rpc/src/list.rs index 860e5161b97c..f1b06f3d2231 100644 --- a/substrate/primitives/rpc/src/list.rs +++ b/substrate/primitives/rpc/src/list.rs @@ -29,7 +29,7 @@ use serde::{Deserialize, Serialize}; /// /// Also it's nice to be able to maintain backward compatibility for methods that /// were initially taking a value and now we want to expand them to take a list. -#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] #[serde(untagged)] pub enum ListOrValue { /// A list of values of given type. diff --git a/substrate/primitives/storage/src/lib.rs b/substrate/primitives/storage/src/lib.rs index f8dc40f051c2..e9ed03dbe4fa 100644 --- a/substrate/primitives/storage/src/lib.rs +++ b/substrate/primitives/storage/src/lib.rs @@ -178,7 +178,7 @@ pub struct Storage { /// Storage change set #[derive(RuntimeDebug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, PartialEq, Eq))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, PartialEq, Eq, Clone))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct StorageChangeSet { /// Block hash diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 12863ac184c1..4e74909e5b15 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -36,3 +36,4 @@ sp-keyring = { path = "../../primitives/keyring" } sp-keystore = { path = "../../primitives/keystore" } sp-runtime = { path = "../../primitives/runtime" } sp-state-machine = { path = "../../primitives/state-machine" } +tokio = { version = "1.22.0", features = ["sync"] } \ No newline at end of file diff --git a/substrate/test-utils/client/src/lib.rs b/substrate/test-utils/client/src/lib.rs index 90e15e0f8d53..2f228dbfc281 100644 --- a/substrate/test-utils/client/src/lib.rs +++ b/substrate/test-utils/client/src/lib.rs @@ -283,7 +283,7 @@ pub struct RpcTransactionOutput { /// The output string of the transaction if any. pub result: String, /// An async receiver if data will be returned via a callback. - pub receiver: futures::channel::mpsc::UnboundedReceiver, + pub receiver: tokio::sync::mpsc::Receiver, } impl std::fmt::Debug for RpcTransactionOutput { @@ -343,7 +343,7 @@ impl RpcHandlersExt for RpcHandlers { pub(crate) fn parse_rpc_result( result: String, - receiver: futures::channel::mpsc::UnboundedReceiver, + receiver: tokio::sync::mpsc::Receiver, ) -> Result { let json: serde_json::Value = serde_json::from_str(&result).expect("the result can only be a JSONRPC string; qed"); @@ -397,7 +397,7 @@ where mod tests { #[test] fn parses_error_properly() { - let (_, rx) = futures::channel::mpsc::unbounded(); + let (_, rx) = tokio::sync::mpsc::channel(1); assert!(super::parse_rpc_result( r#"{ "jsonrpc": "2.0", @@ -409,7 +409,7 @@ mod tests { ) .is_ok()); - let (_, rx) = futures::channel::mpsc::unbounded(); + let (_, rx) = tokio::sync::mpsc::channel(1); let error = super::parse_rpc_result( r#"{ "jsonrpc": "2.0", @@ -427,7 +427,7 @@ mod tests { assert_eq!(error.message, "Method not found"); assert!(error.data.is_none()); - let (_, rx) = futures::channel::mpsc::unbounded(); + let (_, rx) = tokio::sync::mpsc::channel(1); let error = super::parse_rpc_result( r#"{ "jsonrpc": "2.0", diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index 7067aed238ac..1ed775c636d0 100644 --- a/substrate/utils/frame/remote-externalities/Cargo.toml +++ b/substrate/utils/frame/remote-externalities/Cargo.toml @@ -12,7 +12,7 @@ description = "An externalities provided environment that can load itself from r targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.16.2", features = ["http-client"] } +jsonrpsee = { version = "0.20.3", features = ["http-client"] } codec = { package = "parity-scale-codec", version = "3.6.1" } log = "0.4.17" serde = "1.0.188" diff --git a/substrate/utils/frame/remote-externalities/src/lib.rs b/substrate/utils/frame/remote-externalities/src/lib.rs index 71e9320ebeeb..26791ef14d19 100644 --- a/substrate/utils/frame/remote-externalities/src/lib.rs +++ b/substrate/utils/frame/remote-externalities/src/lib.rs @@ -189,7 +189,8 @@ impl Transport { uri.clone() }; let http_client = HttpClientBuilder::default() - .max_request_body_size(u32::MAX) + .max_request_size(u32::MAX) + .max_response_size(u32::MAX) .request_timeout(std::time::Duration::from_secs(60 * 5)) .build(uri) .map_err(|e| { diff --git a/substrate/utils/frame/rpc/client/Cargo.toml b/substrate/utils/frame/rpc/client/Cargo.toml index d0f323c096ff..bd749c664cf4 100644 --- a/substrate/utils/frame/rpc/client/Cargo.toml +++ b/substrate/utils/frame/rpc/client/Cargo.toml @@ -12,7 +12,7 @@ description = "Shared JSON-RPC client" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.16.2", features = ["ws-client"] } +jsonrpsee = { version = "0.20.3", features = ["ws-client"] } sc-rpc-api = { path = "../../../../client/rpc-api" } async-trait = "0.1.57" serde = "1" diff --git a/substrate/utils/frame/rpc/client/src/lib.rs b/substrate/utils/frame/rpc/client/src/lib.rs index a6a667bef568..9349ee2d357b 100644 --- a/substrate/utils/frame/rpc/client/src/lib.rs +++ b/substrate/utils/frame/rpc/client/src/lib.rs @@ -61,10 +61,11 @@ pub use sc_rpc_api::{ /// Create a new `WebSocket` connection with shared settings. pub async fn ws_client(uri: impl AsRef) -> Result { WsClientBuilder::default() - .max_request_body_size(u32::MAX) + .max_request_size(u32::MAX) + .max_response_size(u32::MAX) .request_timeout(std::time::Duration::from_secs(60 * 10)) .connection_timeout(std::time::Duration::from_secs(60)) - .max_notifs_per_subscription(1024) + .max_buffer_capacity_per_subscription(1024) .build(uri) .await .map_err(|e| format!("`WsClientBuilder` failed to build: {:?}", e)) diff --git a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 8ce9d06c2d11..9216051a7077 100644 --- a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -21,7 +21,7 @@ sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } trie-db = "0.28.0" -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.20.3", features = ["client-core", "server", "macros"] } # Substrate Dependencies sc-client-api = { path = "../../../../client/api" } diff --git a/substrate/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/substrate/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs index d1175fdea907..f45258ea593d 100644 --- a/substrate/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs +++ b/substrate/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -18,9 +18,9 @@ //! Rpc for state migration. use jsonrpsee::{ - core::{Error as JsonRpseeError, RpcResult}, + core::RpcResult, proc_macros::rpc, - types::error::{CallError, ErrorCode, ErrorObject}, + types::error::{ErrorCode, ErrorObject, ErrorObjectOwned}, }; use sc_rpc_api::DenyUnsafe; use serde::{Deserialize, Serialize}; @@ -112,7 +112,7 @@ where } /// Current state migration status. -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct MigrationStatusResult { @@ -168,10 +168,10 @@ where } } -fn error_into_rpc_err(err: impl std::fmt::Display) -> JsonRpseeError { - JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( +fn error_into_rpc_err(err: impl std::fmt::Display) -> ErrorObjectOwned { + ErrorObject::owned( ErrorCode::InternalError.code(), "Error while checking migration state", Some(err.to_string()), - ))) + ) } diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml index 22283fbf4506..08998e5686e3 100644 --- a/substrate/utils/frame/rpc/support/Cargo.toml +++ b/substrate/utils/frame/rpc/support/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.16.2", features = ["jsonrpsee-types"] } +jsonrpsee = { version = "0.20.3", features = ["jsonrpsee-types"] } serde = "1" frame-support = { path = "../../../../frame/support" } sc-rpc-api = { path = "../../../../client/rpc-api" } @@ -21,7 +21,7 @@ sp-storage = { path = "../../../../primitives/storage" } [dev-dependencies] scale-info = "2.10.0" -jsonrpsee = { version = "0.16.2", features = ["ws-client", "jsonrpsee-types"] } +jsonrpsee = { version = "0.20.3", features = ["ws-client", "jsonrpsee-types"] } tokio = "1.22.0" sp-core = { path = "../../../../primitives/core" } sp-runtime = { path = "../../../../primitives/runtime" } diff --git a/substrate/utils/frame/rpc/system/Cargo.toml b/substrate/utils/frame/rpc/system/Cargo.toml index 77c3b7eeee3c..4a0cba6773b4 100644 --- a/substrate/utils/frame/rpc/system/Cargo.toml +++ b/substrate/utils/frame/rpc/system/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.16.2", features = ["client-core", "server", "macros"] } +jsonrpsee = { version = "0.20.3", features = ["client-core", "server", "macros"] } futures = "0.3.21" log = "0.4.17" frame-system-rpc-runtime-api = { path = "../../../../frame/system/rpc/runtime-api" } diff --git a/substrate/utils/frame/rpc/system/src/lib.rs b/substrate/utils/frame/rpc/system/src/lib.rs index f467a8798904..bb0592599b2a 100644 --- a/substrate/utils/frame/rpc/system/src/lib.rs +++ b/substrate/utils/frame/rpc/system/src/lib.rs @@ -23,7 +23,7 @@ use codec::{self, Codec, Decode, Encode}; use jsonrpsee::{ core::{async_trait, RpcResult}, proc_macros::rpc, - types::error::{CallError, ErrorObject}, + types::error::ErrorObject, }; use sc_rpc_api::DenyUnsafe; @@ -103,11 +103,11 @@ where let best = self.client.info().best_hash; let nonce = api.account_nonce(best, account.clone()).map_err(|e| { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( Error::RuntimeError.into(), "Unable to query nonce.", Some(e.to_string()), - )) + ) })?; Ok(adjust_nonce(&*self.pool, account, nonce)) } @@ -125,28 +125,28 @@ where let uxt: ::Extrinsic = Decode::decode(&mut &*extrinsic).map_err(|e| { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( Error::DecodeError.into(), "Unable to dry run extrinsic", Some(e.to_string()), - )) + ) })?; let api_version = api .api_version::>(best_hash) .map_err(|e| { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( Error::RuntimeError.into(), "Unable to dry run extrinsic.", Some(e.to_string()), - )) + ) })? .ok_or_else(|| { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( Error::RuntimeError.into(), "Unable to dry run extrinsic.", Some(format!("Could not find `BlockBuilder` api for block `{:?}`.", best_hash)), - )) + ) })?; let result = if api_version < 6 { @@ -154,19 +154,19 @@ where api.apply_extrinsic_before_version_6(best_hash, uxt) .map(legacy::byte_sized_error::convert_to_latest) .map_err(|e| { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( Error::RuntimeError.into(), "Unable to dry run extrinsic.", Some(e.to_string()), - )) + ) })? } else { api.apply_extrinsic(best_hash, uxt).map_err(|e| { - CallError::Custom(ErrorObject::owned( + ErrorObject::owned( Error::RuntimeError.into(), "Unable to dry run extrinsic.", Some(e.to_string()), - )) + ) })? }; @@ -216,7 +216,6 @@ mod tests { use assert_matches::assert_matches; use futures::executor::block_on; - use jsonrpsee::{core::Error as JsonRpseeError, types::error::CallError}; use sc_transaction_pool::BasicPool; use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidityError}, @@ -274,7 +273,7 @@ mod tests { // when let res = accounts.dry_run(vec![].into(), None).await; - assert_matches!(res, Err(JsonRpseeError::Call(CallError::Custom(e))) => { + assert_matches!(res, Err(e) => { assert!(e.message().contains("RPC call is unsafe to be called externally")); }); } From 989ad97c41786fee98295586142f6a2ba7f6ca53 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 30 Oct 2023 12:42:19 +0100 Subject: [PATCH 02/17] RpcHandlers: fix panic in tokio::mpsc --- substrate/client/service/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index 250511d1c0c2..ba9ce0aa9711 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -110,7 +110,7 @@ impl RpcHandlers { json_query: &str, ) -> Result<(String, tokio::sync::mpsc::Receiver), JsonRpseeError> { self.0 - .raw_json_request(json_query, usize::MAX) + .raw_json_request(json_query, tokio::sync::Semaphore::MAX_PERMITS) .await .map(|(method_res, recv)| (method_res.result, recv)) } From 310227c74e7c324aa6c977d6b0ea47b730e8ca3b Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 30 Oct 2023 18:13:18 +0100 Subject: [PATCH 03/17] fix host filtering --- substrate/client/rpc-servers/src/lib.rs | 35 +++++++++++++------------ 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/substrate/client/rpc-servers/src/lib.rs b/substrate/client/rpc-servers/src/lib.rs index 9725f6d221d9..5d8da190f627 100644 --- a/substrate/client/rpc-servers/src/lib.rs +++ b/substrate/client/rpc-servers/src/lib.rs @@ -29,6 +29,7 @@ use jsonrpsee::{ server::middleware::{HostFilterLayer, ProxyGetRequestLayer}, RpcModule, }; +use tokio::net::TcpListener; use tower_http::cors::{AllowOrigin, CorsLayer}; pub use crate::middleware::RpcMetrics; @@ -87,7 +88,9 @@ pub async fn start_server( rpc_api, } = config; - let host_filter = hosts_filtering(cors.is_some(), &addrs); + let std_listener = TcpListener::bind(addrs.as_slice()).await?.into_std()?; + let local_addr = std_listener.local_addr().ok(); + let host_filter = hosts_filtering(cors.is_some(), local_addr); let middleware = tower::ServiceBuilder::new() .option_layer(host_filter) @@ -112,34 +115,32 @@ pub async fn start_server( }; let rpc_api = build_rpc_api(rpc_api); - let (handle, addr) = if let Some(metrics) = metrics { - let server = builder.set_logger(metrics).build(&addrs[..]).await?; - let addr = server.local_addr(); - (server.start(rpc_api), addr) + let handle = if let Some(metrics) = metrics { + let server = builder.set_logger(metrics).build_from_tcp(std_listener)?; + server.start(rpc_api) } else { - let server = builder.build(&addrs[..]).await?; - let addr = server.local_addr(); - (server.start(rpc_api), addr) + let server = builder.build_from_tcp(std_listener)?; + server.start(rpc_api) }; log::info!( "Running JSON-RPC server: addr={}, allowed origins={}", - addr.map_or_else(|_| "unknown".to_string(), |a| a.to_string()), + local_addr.map_or_else(|| "unknown".to_string(), |a| a.to_string()), format_cors(cors) ); Ok(handle) } -fn hosts_filtering(enabled: bool, addrs: &[SocketAddr]) -> Option { +fn hosts_filtering(enabled: bool, addr: Option) -> Option { + // If the local_addr failed, fallback to wildcard. + let port = addr.map_or("*".to_string(), |p| p.port().to_string()); + if enabled { - // NOTE The listening addresses are whitelisted by default. - let mut hosts = Vec::with_capacity(addrs.len() * 2); - for addr in addrs { - hosts.push(format!("localhost:{}", addr.port())); - hosts.push(format!("127.0.0.1:{}", addr.port())); - } - Some(HostFilterLayer::new(hosts).expect("SockAddr is valid host; qed")) + // NOTE: The listening addresses are whitelisted by default. + let hosts = + [format!("localhost:{port}"), format!("127.0.0.1:{port}"), format!("[::1]:{port}")]; + Some(HostFilterLayer::new(hosts).expect("Valid hosts; qed")) } else { None } From 635e6f97f9091b64af709038a38fcabee375a1e4 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 31 Oct 2023 09:51:20 +0100 Subject: [PATCH 04/17] Update substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs --- substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 23b18efa8a4f..3958d188668f 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -348,7 +348,7 @@ where }; self.executor - .spawn("rpcV2-chainHead-unstable-storage", Some("rpc"), fut.boxed()); + .spawn_blocking("substrate-rpc-subscription", Some("rpc"), fut.boxed()); Ok(MethodResponse::Started(MethodResponseStarted { operation_id, discarded_items: Some(discarded), From 97335eb006d410ccf83434cfa1f6b4e5acd838d1 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 31 Oct 2023 10:18:02 +0100 Subject: [PATCH 05/17] fix nits --- cumulus/pallets/xcmp-queue/src/bridging.rs | 4 +--- cumulus/pallets/xcmp-queue/src/tests.rs | 22 +++++++------------- substrate/client/cli/src/commands/run_cmd.rs | 3 ++- substrate/test-utils/client/Cargo.toml | 3 ++- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/cumulus/pallets/xcmp-queue/src/bridging.rs b/cumulus/pallets/xcmp-queue/src/bridging.rs index 53238fe2bf7a..0fc3f1f39ea3 100644 --- a/cumulus/pallets/xcmp-queue/src/bridging.rs +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -55,9 +55,7 @@ impl, Runtime: crate::Config> let sibling_bridge_hub_id: ParaId = SiblingBridgeHubParaId::get(); // let's find the channel's state with the sibling parachain, - let Some((outbound_state, queued_pages)) = - pallet::Pallet::::outbound_channel_state(sibling_bridge_hub_id) - else { + let Some((outbound_state, queued_pages)) = pallet::Pallet::::outbound_channel_state(sibling_bridge_hub_id) else { return false }; // suspended channel => it is congested diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index bab7e92ca2de..cf6d947609d2 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -410,11 +410,9 @@ fn verify_fee_factor_increase_and_decrease() { assert_eq!(DeliveryFeeFactor::::get(sibling_para_id), initial); // Sending the message right now is cheap - let (_, delivery_fees) = - validate_send::(destination, xcm.clone()).expect("message can be sent; qed"); - let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { - unreachable!("asset is fungible; qed"); - }; + let (_, delivery_fees) = validate_send::(destination, xcm.clone()) + .expect("message can be sent; qed"); + let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); }; assert_eq!(delivery_fee_amount, 402_000_000); let smaller_xcm = Xcm(vec![ClearOrigin; 30]); @@ -424,23 +422,19 @@ fn verify_fee_factor_increase_and_decrease() { assert_ok!(send_xcm::(destination, xcm.clone())); // Size 520 assert_eq!(DeliveryFeeFactor::::get(sibling_para_id), FixedU128::from_float(1.05)); - for _ in 0..12 { - // We finish at size 929 + for _ in 0..12 { // We finish at size 929 assert_ok!(send_xcm::(destination, smaller_xcm.clone())); } assert!(DeliveryFeeFactor::::get(sibling_para_id) > FixedU128::from_float(1.88)); // Sending the message right now is expensive - let (_, delivery_fees) = - validate_send::(destination, xcm.clone()).expect("message can be sent; qed"); - let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { - unreachable!("asset is fungible; qed"); - }; + let (_, delivery_fees) = validate_send::(destination, xcm.clone()) + .expect("message can be sent; qed"); + let Fungible(delivery_fee_amount) = delivery_fees.inner()[0].fun else { unreachable!("asset is fungible; qed"); }; assert_eq!(delivery_fee_amount, 758_030_955); // Fee factor only decreases in `take_outbound_messages` - for _ in 0..5 { - // We take 5 100 byte pages + for _ in 0..5 { // We take 5 100 byte pages XcmpQueue::take_outbound_messages(1); } assert!(DeliveryFeeFactor::::get(sibling_para_id) < FixedU128::from_float(1.72)); diff --git a/substrate/client/cli/src/commands/run_cmd.rs b/substrate/client/cli/src/commands/run_cmd.rs index 228262a5256f..f161bddcad54 100644 --- a/substrate/client/cli/src/commands/run_cmd.rs +++ b/substrate/client/cli/src/commands/run_cmd.rs @@ -113,7 +113,8 @@ pub struct RunCmd { #[arg(long, default_value_t = RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN)] pub rpc_message_buffer_capacity_per_connection: u32, - /// Specify browser Origins allowed to access the HTTP & WS RPC servers. + /// Specify browser *origins* allowed to access the HTTP & WS RPC servers. + /// /// A comma-separated list of origins (protocol://domain or special `null` /// value). Value of `all` will disable origin validation. Default is to /// allow localhost and origins. When running in diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 4e74909e5b15..8d1ab56dd840 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -36,4 +36,5 @@ sp-keyring = { path = "../../primitives/keyring" } sp-keystore = { path = "../../primitives/keystore" } sp-runtime = { path = "../../primitives/runtime" } sp-state-machine = { path = "../../primitives/state-machine" } -tokio = { version = "1.22.0", features = ["sync"] } \ No newline at end of file +tokio = { version = "1.22.0", features = ["sync"] } + From 875319cda4f9e74fce0ec2950372d485bdbc219d Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 1 Nov 2023 09:51:17 +0100 Subject: [PATCH 06/17] Update substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs --- substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 3958d188668f..3e893ad39f08 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -216,7 +216,7 @@ where }; self.executor - .spawn_blocking("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + .spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } fn chain_head_unstable_body( From 98da3fc91f821053f63d79a0162b52d9fc1a3711 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 1 Nov 2023 10:06:50 +0100 Subject: [PATCH 07/17] cargo fmt --- substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 3e893ad39f08..85cca9739d7d 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -215,8 +215,7 @@ where debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription removed", sub_id); }; - self.executor - .spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } fn chain_head_unstable_body( From 48e1e17df8384ef42e6f2be82f8759abb4172623 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 4 Jan 2024 13:27:43 +0100 Subject: [PATCH 08/17] cargo fmt --- .../runtime_vs_smart_contract.rs | 21 ++++++++++++------- .../node/core/candidate-validation/src/lib.rs | 6 +++--- .../core/candidate-validation/src/tests.rs | 2 +- .../client/consensus/beefy/src/import.rs | 2 +- substrate/client/consensus/beefy/src/lib.rs | 2 +- .../src/protocol/notifications/behaviour.rs | 2 +- .../client/rpc-spec-v2/src/chain_head/api.rs | 7 ++++--- .../rpc-spec-v2/src/chain_head/tests.rs | 6 +++--- substrate/frame/contracts/fixtures/build.rs | 6 +++--- .../src/construct_runtime/expand/task.rs | 2 +- substrate/frame/system/src/tests.rs | 2 +- substrate/primitives/core/src/address_uri.rs | 2 +- substrate/primitives/core/src/crypto.rs | 4 ++-- .../utils/wasm-builder/src/wasm_project.rs | 2 +- 14 files changed, 37 insertions(+), 29 deletions(-) diff --git a/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs b/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs index 16db44d8be49..099512cf4ee1 100644 --- a/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs +++ b/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs @@ -32,14 +32,21 @@ //! //! ## Comparative Table //! -//! | Aspect | Runtime | Smart Contracts | +//! | Aspect | Runtime +//! | Smart Contracts | //! |-----------------------|-------------------------------------------------------------------------|----------------------------------------------------------------------| -//! | **Design Philosophy** | Core logic of a blockchain, allowing broad and deep customization. | Designed for DApps deployed on the blockchain runtime.| -//! | **Development Complexity** | Requires in-depth knowledge of Rust and Substrate. Suitable for complex blockchain architectures. | Easier to develop with knowledge of Smart Contract languages like Solidity or [ink!](https://use.ink/). | -//! | **Upgradeability and Flexibility** | Offers comprehensive upgradeability with migration logic and on-chain governance, allowing modifications to the entire blockchain logic without hard forks. | Less flexible in upgrade migrations but offers more straightforward deployment and iteration. | -//! | **Performance and Efficiency** | More efficient, optimized for specific needs of the blockchain. | Can be less efficient due to its generic nature (e.g. the overhead of a virtual machine). | -//! | **Security Considerations** | Security flaws can affect the entire blockchain. | Security risks usually localized to the individual contract. | -//! | **Weighing and Metering** | Operations can be weighed, allowing for precise benchmarking. | Execution is metered, allowing for measurement of resource consumption. | +//! | **Design Philosophy** | Core logic of a blockchain, allowing broad and deep customization. +//! | Designed for DApps deployed on the blockchain runtime.| | **Development Complexity** | Requires in-depth knowledge of Rust and Substrate. Suitable for complex blockchain architectures. | Easier to develop with knowledge of Smart Contract languages like Solidity or [ink!](https://use.ink/). | +//! | **Upgradeability and Flexibility** | Offers comprehensive upgradeability with migration logic +//! and on-chain governance, allowing modifications to the entire blockchain logic without hard +//! forks. | Less flexible in upgrade migrations but offers more straightforward deployment and +//! iteration. | | **Performance and Efficiency** | More efficient, optimized for specific needs of +//! the blockchain. | Can be less efficient due to its generic nature (e.g. the overhead of a +//! virtual machine). | | **Security Considerations** | Security flaws can affect the entire +//! blockchain. | Security risks usually localized to the individual +//! contract. | | **Weighing and Metering** | Operations can be weighed, allowing for precise +//! benchmarking. | Execution is metered, allowing for measurement of resource +//! consumption. | //! //! We will now explore these differences in more detail. //! diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 5c4e449b2c90..18c279689158 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -773,21 +773,21 @@ trait ValidationBackend { if num_death_retries_left > 0 { num_death_retries_left -= 1; } else { - break; + break }, Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError(_))) => if num_job_error_retries_left > 0 { num_job_error_retries_left -= 1; } else { - break; + break }, Err(ValidationError::Internal(_)) => if num_internal_retries_left > 0 { num_internal_retries_left -= 1; } else { - break; + break }, Ok(_) | Err(ValidationError::Invalid(_) | ValidationError::Preparation(_)) => break, diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index 110785804652..f646f8535495 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -726,7 +726,7 @@ fn candidate_validation_retry_on_error_helper( ExecutorParams::default(), exec_kind, &Default::default(), - )); + )) } #[test] diff --git a/substrate/client/consensus/beefy/src/import.rs b/substrate/client/consensus/beefy/src/import.rs index 5bbf07fba70a..6eced17b58ff 100644 --- a/substrate/client/consensus/beefy/src/import.rs +++ b/substrate/client/consensus/beefy/src/import.rs @@ -148,7 +148,7 @@ where // The block is imported as part of some chain sync. // The voter doesn't need to process it now. // It will be detected and processed as part of the voter state init. - return Ok(inner_import_result); + return Ok(inner_import_result) }, } diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 51e82b6a8112..2e2e22288e3b 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -398,7 +398,7 @@ where header = wait_for_parent_header(backend.blockchain(), header, HEADER_SYNC_DELAY).await?; } - return Ok(state); + return Ok(state) } // No valid voter-state persisted, re-initialize from pallet genesis. diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index cdbf2a71b932..9ad41e376e82 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -1037,7 +1037,7 @@ impl Notifications { peerset_rejected, incoming_index, }; - return self.report_reject(index).map_or((), |_| ()); + return self.report_reject(index).map_or((), |_| ()) } trace!( diff --git a/substrate/client/rpc-spec-v2/src/chain_head/api.rs b/substrate/client/rpc-spec-v2/src/chain_head/api.rs index ed91e499e3dd..418dfe63dbb6 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/api.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/api.rs @@ -19,8 +19,10 @@ #![allow(non_snake_case)] //! API trait of the chain head. -use crate::chain_head::error::Error; -use crate::chain_head::event::{FollowEvent, MethodResponse, StorageQuery}; +use crate::chain_head::{ + error::Error, + event::{FollowEvent, MethodResponse, StorageQuery}, +}; use jsonrpsee::proc_macros::rpc; use sp_rpc::list::ListOrValue; @@ -75,7 +77,6 @@ pub trait ChainHeadApi { hash: Hash, ) -> Result, Error>; - /// Returns storage entries at a specific block's state. /// /// # Unstable diff --git a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs index 0a1d4800c90a..e8a62a2cdbbb 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -27,10 +27,10 @@ use codec::{Decode, Encode}; use futures::Future; use jsonrpsee::{ core::{ - error::Error, server::Subscription as RpcSubscription, EmptyServerParams as EmptyParams, + error::Error, + server::{rpc_module::Subscription as RpcSubscription, Subscription as RpcSubscription}, + EmptyServerParams as EmptyParams, }, - rpc_params, RpcModule, - core::{error::Error, server::rpc_module::Subscription as RpcSubscription}, rpc_params, types::error::CallError, RpcModule, diff --git a/substrate/frame/contracts/fixtures/build.rs b/substrate/frame/contracts/fixtures/build.rs index 49deb94a7faa..08cac69e1332 100644 --- a/substrate/frame/contracts/fixtures/build.rs +++ b/substrate/frame/contracts/fixtures/build.rs @@ -79,7 +79,7 @@ fn collect_entries(contracts_dir: &Path, out_dir: &Path) -> Vec { .filter_map(|file| { let path = file.expect("file exists; qed").path(); if path.extension().map_or(true, |ext| ext != "rs") { - return None; + return None } let entry = Entry::new(path); @@ -239,7 +239,7 @@ fn find_workspace_root(current_dir: &Path) -> Option { let cargo_toml_contents = std::fs::read_to_string(current_dir.join("Cargo.toml")).ok()?; if cargo_toml_contents.contains("[workspace]") { - return Some(current_dir); + return Some(current_dir) } } @@ -257,7 +257,7 @@ fn main() -> Result<()> { let entries = collect_entries(&contracts_dir, &out_dir); if entries.is_empty() { - return Ok(()); + return Ok(()) } let tmp_dir = tempfile::tempdir()?; diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/task.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/task.rs index bd952202bbbe..6531c0e9e070 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/task.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/task.rs @@ -31,7 +31,7 @@ pub fn expand_outer_task( let mut task_paths = Vec::new(); for decl in pallet_decls { if decl.find_part("Task").is_none() { - continue; + continue } let variant_name = &decl.name; diff --git a/substrate/frame/system/src/tests.rs b/substrate/frame/system/src/tests.rs index 053cec24f89c..e437e7f9f39b 100644 --- a/substrate/frame/system/src/tests.rs +++ b/substrate/frame/system/src/tests.rs @@ -828,7 +828,7 @@ fn last_runtime_upgrade_spec_version_usage() { // a runtime upgrade in the pipeline of being applied, you should use the spec version // of this upgrade. if System::last_runtime_upgrade_spec_version() > 1337 { - return Weight::zero(); + return Weight::zero() } // Do the migration. diff --git a/substrate/primitives/core/src/address_uri.rs b/substrate/primitives/core/src/address_uri.rs index 862747c9a4b6..211d47c0093d 100644 --- a/substrate/primitives/core/src/address_uri.rs +++ b/substrate/primitives/core/src/address_uri.rs @@ -184,7 +184,7 @@ impl<'a> AddressUri<'a> { Error::in_pass(initial_input, initial_input_len - input.len()) } else { Error::in_phrase(initial_input, initial_input_len - input.len()) - }); + }) } } diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index 1f3ae7445332..2da38d44be4b 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -434,7 +434,7 @@ impl + AsRef<[u8]> + Public + Derive> Ss58Codec for T { fn from_string(s: &str) -> Result { let cap = AddressUri::parse(s)?; if cap.pass.is_some() { - return Err(PublicError::PasswordNotAllowed); + return Err(PublicError::PasswordNotAllowed) } let s = cap.phrase.unwrap_or(DEV_ADDRESS); let addr = if let Some(stripped) = s.strip_prefix("0x") { @@ -454,7 +454,7 @@ impl + AsRef<[u8]> + Public + Derive> Ss58Codec for T { fn from_string_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> { let cap = AddressUri::parse(s)?; if cap.pass.is_some() { - return Err(PublicError::PasswordNotAllowed); + return Err(PublicError::PasswordNotAllowed) } let (addr, v) = Self::from_ss58check_with_version(cap.phrase.unwrap_or(DEV_ADDRESS))?; if cap.paths.is_empty() { diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index 5bf44c2c9b20..2126a49bd7ff 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -935,7 +935,7 @@ fn generate_rerun_if_changed_instructions( while let Some(dependency) = dependencies.pop() { // Ignore all dev dependencies if dependency.kind == DependencyKind::Development { - continue; + continue } let path_or_git_dep = From eac69bcd7bb0c8c6b44254661f86449e393e7959 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 4 Jan 2024 14:30:29 +0100 Subject: [PATCH 09/17] fix toml fmt --- substrate/client/rpc-api/Cargo.toml | 2 +- substrate/test-utils/client/Cargo.toml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index 0e23c2c50a5a..0567940b6383 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -28,4 +28,4 @@ sp-core = { path = "../../primitives/core" } sp-rpc = { path = "../../primitives/rpc" } sp-runtime = { path = "../../primitives/runtime" } sp-version = { path = "../../primitives/version" } -jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } \ No newline at end of file +jsonrpsee = { version = "0.20.3", features = ["client-core", "macros", "server"] } diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 63385c0833ba..cd1b9b8238b3 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -40,4 +40,3 @@ sp-keystore = { path = "../../primitives/keystore" } sp-runtime = { path = "../../primitives/runtime" } sp-state-machine = { path = "../../primitives/state-machine" } tokio = { version = "1.22.0", features = ["sync"] } - From b70d07ca05fe4ebd0cb6bf1501c6b81b0bce4a57 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 4 Jan 2024 15:01:02 +0100 Subject: [PATCH 10/17] fix merge nits --- .../rpc-spec-v2/src/chain_head/tests.rs | 68 ++++--------------- 1 file changed, 15 insertions(+), 53 deletions(-) diff --git a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs index e8a62a2cdbbb..7023e55a3a0d 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -26,14 +26,8 @@ use assert_matches::assert_matches; use codec::{Decode, Encode}; use futures::Future; use jsonrpsee::{ - core::{ - error::Error, - server::{rpc_module::Subscription as RpcSubscription, Subscription as RpcSubscription}, - EmptyServerParams as EmptyParams, - }, - rpc_params, - types::error::CallError, - RpcModule, + core::{error::Error, server::Subscription as RpcSubscription}, + rpc_params, RpcModule, }; use sc_block_builder::BlockBuilderBuilder; use sc_client_api::ChildInfo; @@ -364,11 +358,7 @@ async fn get_header() { .await .unwrap_err(); assert_matches!(err, -<<<<<<< HEAD - Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" -======= - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ->>>>>>> origin/master + Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Obtain the valid header. @@ -397,11 +387,7 @@ async fn get_body() { .await .unwrap_err(); assert_matches!(err, -<<<<<<< HEAD - Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" -======= - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ->>>>>>> origin/master + Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Valid call. @@ -486,11 +472,7 @@ async fn call_runtime() { .await .unwrap_err(); assert_matches!(err, -<<<<<<< HEAD - Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" -======= - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ->>>>>>> origin/master + Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Pass an invalid parameters that cannot be decode. @@ -503,11 +485,7 @@ async fn call_runtime() { .await .unwrap_err(); assert_matches!(err, -<<<<<<< HEAD - Error::Call(err) if err.code() == 2003 && err.message().contains("Invalid parameter") -======= - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::json_rpc_spec::INVALID_PARAM_ERROR && err.message().contains("Invalid parameter") ->>>>>>> origin/master + Error::Call(err) if err.code() == super::error::json_rpc_spec::INVALID_PARAM_ERROR && err.message().contains("Invalid parameter") ); // Valid call. @@ -610,11 +588,7 @@ async fn call_runtime_without_flag() { .unwrap_err(); assert_matches!(err, -<<<<<<< HEAD - Error::Call(err) if err.code() == 2003 && err.message().contains("The runtime updates flag must be set") -======= - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_RUNTIME_CALL && err.message().contains("subscription was started with `withRuntime` set to `false`") ->>>>>>> origin/master + Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_RUNTIME_CALL && err.message().contains("subscription was started with `withRuntime` set to `false`") ); } @@ -652,11 +626,7 @@ async fn get_storage_hash() { .await .unwrap_err(); assert_matches!(err, -<<<<<<< HEAD - Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" -======= - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ->>>>>>> origin/master + Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Valid call without storage at the key. @@ -924,11 +894,7 @@ async fn get_storage_value() { .await .unwrap_err(); assert_matches!(err, -<<<<<<< HEAD - Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" -======= - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ->>>>>>> origin/master + Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Valid call without storage at the key. @@ -1604,11 +1570,7 @@ async fn follow_with_unpin() { .await .unwrap_err(); assert_matches!(err, -<<<<<<< HEAD - Error::Call(err) if err.code() == 2001 && err.message() == "Invalid block hash" -======= - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ->>>>>>> origin/master + Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // To not exceed the number of pinned blocks, we need to unpin before the next import. @@ -1673,7 +1635,7 @@ async fn follow_with_multiple_unpin_hashes() { ) .into_rpc(); - let mut sub = api.subscribe("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -1757,7 +1719,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); let _res: () = api @@ -1774,7 +1736,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); // Unpin multiple blocks. @@ -1792,7 +1754,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); let err = api @@ -1803,7 +1765,7 @@ async fn follow_with_multiple_unpin_hashes() { .await .unwrap_err(); assert_matches!(err, - Error::Call(CallError::Custom(ref err)) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" + Error::Call(err) if err.code() == super::error::rpc_spec_v2::INVALID_BLOCK_ERROR && err.message() == "Invalid block hash" ); } From 34f8f94847d38ac62e49a6e8fffe4794a9decfe9 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 19 Jan 2024 20:08:41 +0100 Subject: [PATCH 11/17] address grumbles --- .../assets/asset-hub-rococo/src/xcm_config.rs | 14 +- .../asset-hub-westend/src/xcm_config.rs | 14 +- .../xcm/xcm-builder/src/matches_location.rs | 13 +- .../client/consensus/beefy/rpc/src/lib.rs | 5 +- .../client/consensus/grandpa/rpc/src/lib.rs | 5 +- .../src/transaction/transaction.rs | 5 +- substrate/client/rpc/src/author/mod.rs | 2 +- substrate/client/rpc/src/chain/chain_full.rs | 2 +- substrate/client/rpc/src/lib.rs | 145 +----------------- substrate/client/rpc/src/state/state_full.rs | 4 +- 10 files changed, 20 insertions(+), 189 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index fdc7836cb37d..bdd7a40b07c5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -208,20 +208,14 @@ impl MatchesLocalAndForeignAssetsLocation { fn is_local(location: &xcm::v3::Location) -> bool { use assets_common::fungible_conversion::MatchesLocation; - let latest_location: Location = if let Ok(location) = (*location).try_into() { - location - } else { - return false - }; + let latest_location: Location = + if let Ok(location) = (*location).try_into() { location } else { return false }; TrustBackedAssetsConvertedConcreteId::contains(&latest_location) } fn is_foreign(location: &xcm::v3::Location) -> bool { use assets_common::fungible_conversion::MatchesLocation; - let latest_location: Location = if let Ok(location) = (*location).try_into() { - location - } else { - return false - }; + let latest_location: Location = + if let Ok(location) = (*location).try_into() { location } else { return false }; ForeignAssetsConvertedConcreteId::contains(&latest_location) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index ee86d7f14283..0f6310dc15e1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -202,21 +202,15 @@ impl MatchesLocalAndForeignAssetsLocation { fn is_local(location: &xcm::v3::Location) -> bool { use assets_common::fungible_conversion::MatchesLocation; - let latest_location: Location = if let Ok(location) = (*location).try_into() { - location - } else { - return false - }; + let latest_location: Location = + if let Ok(location) = (*location).try_into() { location } else { return false }; TrustBackedAssetsConvertedConcreteId::contains(&latest_location) } fn is_foreign(location: &xcm::v3::Location) -> bool { use assets_common::fungible_conversion::MatchesLocation; - let latest_location: Location = if let Ok(location) = (*location).try_into() { - location - } else { - return false - }; + let latest_location: Location = + if let Ok(location) = (*location).try_into() { location } else { return false }; ForeignAssetsConvertedConcreteId::contains(&latest_location) } } diff --git a/polkadot/xcm/xcm-builder/src/matches_location.rs b/polkadot/xcm/xcm-builder/src/matches_location.rs index bcd7a13efbe2..1664c2477290 100644 --- a/polkadot/xcm/xcm-builder/src/matches_location.rs +++ b/polkadot/xcm/xcm-builder/src/matches_location.rs @@ -25,16 +25,9 @@ use xcm::latest::{InteriorLocation, Location, NetworkId}; pub struct StartsWith(sp_std::marker::PhantomData<(T, L)>); impl, L: TryInto + Clone> Contains for StartsWith { fn contains(location: &L) -> bool { - let latest_location: Location = if let Ok(location) = (*location).clone().try_into() { - location - } else { - return false - }; - let latest_t = if let Ok(location) = T::get().try_into() { - location - } else { - return false - }; + let latest_location: Location = + if let Ok(location) = (*location).clone().try_into() { location } else { return false }; + let latest_t = if let Ok(location) = T::get().try_into() { location } else { return false }; latest_location.starts_with(&latest_t) } } diff --git a/substrate/client/consensus/beefy/rpc/src/lib.rs b/substrate/client/consensus/beefy/rpc/src/lib.rs index a11c6a2fabc7..03c83e92716c 100644 --- a/substrate/client/consensus/beefy/rpc/src/lib.rs +++ b/substrate/client/consensus/beefy/rpc/src/lib.rs @@ -140,10 +140,7 @@ where .subscribe(100_000) .map(|vfp| notification::EncodedVersionedFinalityProof::new::(vfp)); - sc_rpc::utils::spawn_subscription_task( - &self.executor, - pipe_from_stream(pending, stream, 16), - ); + sc_rpc::utils::spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream)); } async fn latest_finalized(&self) -> Result { diff --git a/substrate/client/consensus/grandpa/rpc/src/lib.rs b/substrate/client/consensus/grandpa/rpc/src/lib.rs index 13925a190c68..878cefacc479 100644 --- a/substrate/client/consensus/grandpa/rpc/src/lib.rs +++ b/substrate/client/consensus/grandpa/rpc/src/lib.rs @@ -108,10 +108,7 @@ where }, ); - sc_rpc::utils::spawn_subscription_task( - &self.executor, - pipe_from_stream(pending, stream, 16), - ); + sc_rpc::utils::spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream)); } async fn prove_finality( diff --git a/substrate/client/rpc-spec-v2/src/transaction/transaction.rs b/substrate/client/rpc-spec-v2/src/transaction/transaction.rs index 7dc9d0f758de..b2cfa36c9c99 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/transaction.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/transaction.rs @@ -119,14 +119,13 @@ where let mut state = TransactionState::new(); let stream = stream.filter_map(move |event| async move { state.handle_event(event) }); - pipe_from_stream(pending, stream.boxed(), 16).await; + pipe_from_stream(pending, stream.boxed()).await; }, Err(err) => { // We have not created an `Watcher` for the tx. Make sure the // error is still propagated as an event. let event: TransactionEvent<::Hash> = err.into(); - pipe_from_stream(pending, futures::stream::once(async { event }).boxed(), 16) - .await; + pipe_from_stream(pending, futures::stream::once(async { event }).boxed()).await; }, }; }; diff --git a/substrate/client/rpc/src/author/mod.rs b/substrate/client/rpc/src/author/mod.rs index 45456b332ed9..975f66406a6a 100644 --- a/substrate/client/rpc/src/author/mod.rs +++ b/substrate/client/rpc/src/author/mod.rs @@ -202,7 +202,7 @@ where }, }; - pipe_from_stream(pending, stream, 16).await; + pipe_from_stream(pending, stream).await; }; spawn_subscription_task(&self.executor, fut); diff --git a/substrate/client/rpc/src/chain/chain_full.rs b/substrate/client/rpc/src/chain/chain_full.rs index 2d3e5153c28b..515c0f62c8ad 100644 --- a/substrate/client/rpc/src/chain/chain_full.rs +++ b/substrate/client/rpc/src/chain/chain_full.rs @@ -143,5 +143,5 @@ fn subscribe_headers( // duplicates at the beginning of the stream though. let stream = stream::iter(maybe_header).chain(stream()); - spawn_subscription_task(executor, pipe_from_stream(pending, stream, 16)); + spawn_subscription_task(executor, pipe_from_stream(pending, stream)); } diff --git a/substrate/client/rpc/src/lib.rs b/substrate/client/rpc/src/lib.rs index cc756bdb310f..b40d0341e321 100644 --- a/substrate/client/rpc/src/lib.rs +++ b/substrate/client/rpc/src/lib.rs @@ -39,153 +39,10 @@ pub mod offchain; pub mod state; pub mod statement; pub mod system; +pub mod utils; #[cfg(any(test, feature = "test-helpers"))] pub mod testing; /// Task executor that is being used by RPC subscriptions. pub type SubscriptionTaskExecutor = std::sync::Arc; - -/// JSON-RPC helpers. -pub mod utils { - use crate::SubscriptionTaskExecutor; - use futures::{ - future::{self, Either, Fuse, FusedFuture}, - Future, FutureExt, Stream, StreamExt, - }; - use jsonrpsee::{PendingSubscriptionSink, SubscriptionMessage, SubscriptionSink}; - use sp_runtime::Serialize; - use std::collections::VecDeque; - - /// A simple bounded VecDeque. - struct BoundedVecDeque { - inner: VecDeque, - max_cap: usize, - } - - impl BoundedVecDeque { - /// Create a new bounded VecDeque. - fn new(max_cap: usize) -> Self { - Self { inner: VecDeque::with_capacity(max_cap), max_cap } - } - - fn push_back(&mut self, item: T) -> Result<(), ()> { - if self.inner.len() >= self.max_cap { - Err(()) - } else { - self.inner.push_back(item); - Ok(()) - } - } - - fn pop_front(&mut self) -> Option { - self.inner.pop_front() - } - } - - /// Feed items to the subscription from the underlying stream. - /// - /// It's possible configure how many items from the stream - /// are allowed to be kept in memory until the subscription is dropped. - /// - /// This is needed because the underlying streams in substrate are - /// unbounded. - pub async fn pipe_from_stream( - pending: PendingSubscriptionSink, - mut stream: S, - max_cap: usize, - ) where - S: Stream + Unpin + Send + 'static, - T: Serialize + Send + 'static, - { - let mut buf = BoundedVecDeque::new(max_cap); - let accept_fut = pending.accept(); - - futures::pin_mut!(accept_fut); - - // Poll the stream while waiting for the subscription to be accepted - // - // If the `max_cap` is exceeded then the subscription is dropped. - let sink = loop { - match future::select(accept_fut, stream.next()).await { - Either::Left((Ok(sink), _)) => break sink, - Either::Right((Some(msg), f)) => { - if buf.push_back(msg).is_err() { - log::warn!(target: "rpc", "Subscription::accept failed buffer limit={} exceed; dropping subscription", buf.max_cap); - return - } - accept_fut = f; - }, - // The connection was closed or the stream was closed. - _ => return, - } - }; - - inner_pipe_from_stream(sink, stream, buf).await - } - - async fn inner_pipe_from_stream( - sink: SubscriptionSink, - mut stream: S, - mut buf: BoundedVecDeque, - ) where - S: Stream + Unpin + Send + 'static, - T: Serialize + Send + 'static, - { - let mut next_fut = Box::pin(Fuse::terminated()); - - let mut next_item = stream.next(); - let closed = sink.closed(); - - futures::pin_mut!(closed); - - loop { - if next_fut.is_terminated() { - if let Some(v) = buf.pop_front() { - let val = to_sub_message(&sink, &v); - next_fut.set(async { sink.send(val).await }.fuse()); - } - } - - match future::select(closed, future::select(next_fut, next_item)).await { - // Send operation finished. - Either::Right((Either::Left((_, n)), c)) => { - next_item = n; - closed = c; - next_fut = Box::pin(Fuse::terminated()); - }, - // New item from the stream - Either::Right((Either::Right((Some(v), n)), c)) => { - if buf.push_back(v).is_err() { - log::warn!(target: "rpc", "Subscription buffer limit={} exceed; dropping subscription", buf.max_cap); - return - } - - next_fut = n; - closed = c; - next_item = stream.next(); - }, - // The stream or subscription was closed. - _ => break, - } - } - } - - /// Builds a subscription message. - /// - /// # Panics - /// - /// This function panics `Serialize` fails and is treated a bug. - pub fn to_sub_message(sink: &SubscriptionSink, result: &impl Serialize) -> SubscriptionMessage { - SubscriptionMessage::new(sink.method_name(), sink.subscription_id(), result) - .expect("Serialize infallible; qed") - } - - /// Helper for spawning non-blocking rpc subscription task. - pub fn spawn_subscription_task( - executor: &SubscriptionTaskExecutor, - fut: impl Future + Send + 'static, - ) { - executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); - } -} diff --git a/substrate/client/rpc/src/state/state_full.rs b/substrate/client/rpc/src/state/state_full.rs index 0f3f2d4c9666..bda678c1b45e 100644 --- a/substrate/client/rpc/src/state/state_full.rs +++ b/substrate/client/rpc/src/state/state_full.rs @@ -405,7 +405,7 @@ where }); let stream = futures::stream::once(future::ready(initial)).chain(version_stream); - spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream, 16)); + spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream)); } fn subscribe_storage( @@ -457,7 +457,7 @@ where .chain(storage_stream) .filter(|storage| future::ready(!storage.changes.is_empty())); - spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream, 16)); + spawn_subscription_task(&self.executor, pipe_from_stream(pending, stream)); } fn trace_block( From 231761e0965def0878dcb3ace9a760b4230200da Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 19 Jan 2024 20:09:42 +0100 Subject: [PATCH 12/17] commit missing file --- substrate/client/rpc/src/utils.rs | 227 ++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 substrate/client/rpc/src/utils.rs diff --git a/substrate/client/rpc/src/utils.rs b/substrate/client/rpc/src/utils.rs new file mode 100644 index 000000000000..8edfcd7de2f4 --- /dev/null +++ b/substrate/client/rpc/src/utils.rs @@ -0,0 +1,227 @@ +//! JSON-RPC helpers. +use crate::SubscriptionTaskExecutor; +use futures::{ + future::{self, Either, Fuse, FusedFuture}, + Future, FutureExt, Stream, StreamExt, +}; +use jsonrpsee::{PendingSubscriptionSink, SubscriptionMessage, SubscriptionSink}; +use sp_runtime::Serialize; +use std::collections::VecDeque; + +const DEFAULT_BUF_SIZE: usize = 16; + +/// A simple bounded VecDeque. +struct BoundedVecDeque { + inner: VecDeque, + max_cap: usize, +} + +impl BoundedVecDeque { + /// Create a new bounded VecDeque. + fn new() -> Self { + Self { inner: VecDeque::with_capacity(DEFAULT_BUF_SIZE), max_cap: DEFAULT_BUF_SIZE } + } + + fn push_back(&mut self, item: T) -> Result<(), ()> { + if self.inner.len() >= self.max_cap { + Err(()) + } else { + self.inner.push_back(item); + Ok(()) + } + } + + fn pop_front(&mut self) -> Option { + self.inner.pop_front() + } +} + +/// Feed items to the subscription from the underlying stream. +/// +/// It's possible configure how many items from the stream +/// are allowed to be kept in memory until the subscription is dropped. +/// +/// This is needed because the underlying streams in substrate are +/// unbounded. +pub async fn pipe_from_stream(pending: PendingSubscriptionSink, mut stream: S) +where + S: Stream + Unpin + Send + 'static, + T: Serialize + Send + 'static + std::fmt::Debug, +{ + let mut buf = BoundedVecDeque::new(); + let accept_fut = pending.accept(); + + futures::pin_mut!(accept_fut); + + // Poll the stream while waiting for the subscription to be accepted + // + // If the `max_cap` is exceeded then the subscription is dropped. + let sink = loop { + match future::select(accept_fut, stream.next()).await { + Either::Left((Ok(sink), _)) => break sink, + Either::Right((Some(msg), f)) => { + if buf.push_back(msg).is_err() { + log::warn!(target: "rpc", "Subscription::accept failed buffer limit={} exceed; dropping subscription", buf.max_cap); + return + } + accept_fut = f; + }, + // The connection was closed or the stream was closed. + _ => return, + } + }; + + inner_pipe_from_stream(sink, stream, buf).await +} + +async fn inner_pipe_from_stream( + sink: SubscriptionSink, + mut stream: S, + mut buf: BoundedVecDeque, +) where + S: Stream + Unpin + Send + 'static, + T: Serialize + Send + 'static + std::fmt::Debug, +{ + let mut next_fut = Box::pin(Fuse::terminated()); + let mut next_item = stream.next(); + let closed = sink.closed(); + + futures::pin_mut!(closed); + + loop { + if next_fut.is_terminated() { + if let Some(v) = buf.pop_front() { + let val = to_sub_message(&sink, &v); + next_fut.set(async { sink.send(val).await }.fuse()); + } + } + + match future::select(closed, future::select(next_fut, next_item)).await { + // Send operation finished. + Either::Right((Either::Left((_, n)), c)) => { + next_item = n; + closed = c; + next_fut = Box::pin(Fuse::terminated()); + }, + // New item from the stream + Either::Right((Either::Right((Some(v), n)), c)) => { + if buf.push_back(v).is_err() { + log::warn!(target: "rpc", "Subscription buffer limit={} exceed; dropping subscription", buf.max_cap); + return + } + + next_fut = n; + closed = c; + next_item = stream.next(); + }, + // Stream "finished". + // + // Process remaining items and terminate. + Either::Right((Either::Right((None, pending_fut)), _)) => { + if pending_fut.await.is_err() { + return; + } + + while let Some(v) = buf.pop_front() { + let val = to_sub_message(&sink, &v); + if sink.send(val).await.is_err() { + return; + } + } + + return; + }, + // Subscription was closed. + Either::Left(_) => return, + } + } +} + +/// Builds a subscription message. +/// +/// # Panics +/// +/// This function panics `Serialize` fails and it is treated a bug. +pub fn to_sub_message(sink: &SubscriptionSink, result: &impl Serialize) -> SubscriptionMessage { + SubscriptionMessage::new(sink.method_name(), sink.subscription_id(), result) + .expect("Serialize infallible; qed") +} + +/// Helper for spawning non-blocking rpc subscription task. +pub fn spawn_subscription_task( + executor: &SubscriptionTaskExecutor, + fut: impl Future + Send + 'static, +) { + executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); +} + +#[cfg(test)] +mod tests { + use super::pipe_from_stream; + use futures::StreamExt; + use jsonrpsee::{core::EmptyServerParams, RpcModule, Subscription}; + + async fn subscribe() -> Subscription { + let mut module = RpcModule::new(()); + module + .register_subscription("sub", "my_sub", "unsub", |_, pending, _| async move { + let stream = futures::stream::iter([0; 16]); + pipe_from_stream(pending, stream).await; + Ok(()) + }) + .unwrap(); + + module.subscribe("sub", EmptyServerParams::new(), 1).await.unwrap() + } + + #[tokio::test] + async fn pipe_from_stream_works() { + let mut sub = subscribe().await; + let mut rx = 0; + + while let Some(Ok(_)) = sub.next::().await { + rx += 1; + } + + assert_eq!(rx, 16); + } + + #[tokio::test] + async fn pipe_from_stream_is_bounded() { + let (tx, mut rx) = futures::channel::mpsc::unbounded::<()>(); + + let mut module = RpcModule::new(tx); + module + .register_subscription("sub", "my_sub", "unsub", |_, pending, ctx| async move { + let stream = futures::stream::iter([0; 32]); + pipe_from_stream(pending, stream).await; + _ = ctx.unbounded_send(()); + Ok(()) + }) + .unwrap(); + + let mut sub = module.subscribe("sub", EmptyServerParams::new(), 1).await.unwrap(); + + // When the 17th item arrives the subscription is dropped + _ = rx.next().await.unwrap(); + assert!(sub.next::().await.is_none()); + } + + #[tokio::test] + async fn wait_for_buffered_items() { + let mut sub = subscribe().await; + + // HACK: we can't really know when all items have + // processed by pipe_from_stream and that's + // why we just sleep long enough here. + tokio::time::sleep(std::time::Duration::from_secs(6)).await; + + let mut rx = 0; + + while let Some(Ok(_)) = sub.next::().await { + rx += 1; + } + + assert_eq!(rx, 16); + } +} From ffb52b97c9b0d33ffd285dd53ddba68773a272a3 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 19 Jan 2024 21:12:06 +0100 Subject: [PATCH 13/17] remove needless bounds --- substrate/client/rpc/src/utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/client/rpc/src/utils.rs b/substrate/client/rpc/src/utils.rs index 8edfcd7de2f4..4c9d7ccc350d 100644 --- a/substrate/client/rpc/src/utils.rs +++ b/substrate/client/rpc/src/utils.rs @@ -46,7 +46,7 @@ impl BoundedVecDeque { pub async fn pipe_from_stream(pending: PendingSubscriptionSink, mut stream: S) where S: Stream + Unpin + Send + 'static, - T: Serialize + Send + 'static + std::fmt::Debug, + T: Serialize + Send + 'static, { let mut buf = BoundedVecDeque::new(); let accept_fut = pending.accept(); @@ -80,7 +80,7 @@ async fn inner_pipe_from_stream( mut buf: BoundedVecDeque, ) where S: Stream + Unpin + Send + 'static, - T: Serialize + Send + 'static + std::fmt::Debug, + T: Serialize + Send + 'static, { let mut next_fut = Box::pin(Fuse::terminated()); let mut next_item = stream.next(); From 6bb81d43ad731f5c0545dbd15c3649ffdc6d979d Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 22 Jan 2024 09:13:12 +0100 Subject: [PATCH 14/17] add missing license header --- substrate/client/rpc/src/utils.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/substrate/client/rpc/src/utils.rs b/substrate/client/rpc/src/utils.rs index 4c9d7ccc350d..b7b5527f4d9e 100644 --- a/substrate/client/rpc/src/utils.rs +++ b/substrate/client/rpc/src/utils.rs @@ -1,3 +1,21 @@ +// 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 . + //! JSON-RPC helpers. use crate::SubscriptionTaskExecutor; use futures::{ From 746075fe70a53cd9c2c1b5e550c3e7e4bea12837 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 22 Jan 2024 10:53:01 +0100 Subject: [PATCH 15/17] add prdoc --- prdoc/pr_1313.prdoc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 prdoc/pr_1313.prdoc diff --git a/prdoc/pr_1313.prdoc b/prdoc/pr_1313.prdoc new file mode 100644 index 000000000000..0ee91da41a9a --- /dev/null +++ b/prdoc/pr_1313.prdoc @@ -0,0 +1,18 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: backpressured JSON-RPC server (upgrade jsonrpsee) + +doc: + - audience: Node Operator + description: | + Modifies the jsonrpc server to be "backpressured" and it's possible to configure + how many messages can be "buffered" via the CLI `--rpc_message_buffer_capacity`. + + Major changes in this PR: + - The subscriptions are now bounded and if subscription can't keep up with the server it is dropped + - CLI: add parameter to configure the jsonrpc server bounded message buffer (default is 64) + - Add our own subscription helper to deal with the unbounded streams in substrate + +crates: +- name: sc-rpc-server From 2d9ee10b8170c6248126d611062e119932359363 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 23 Jan 2024 07:43:57 +0100 Subject: [PATCH 16/17] fix faulty comment + remove one test --- substrate/client/rpc/src/utils.rs | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/substrate/client/rpc/src/utils.rs b/substrate/client/rpc/src/utils.rs index b7b5527f4d9e..b5ae4a2b6bc7 100644 --- a/substrate/client/rpc/src/utils.rs +++ b/substrate/client/rpc/src/utils.rs @@ -17,6 +17,7 @@ // along with this program. If not, see . //! JSON-RPC helpers. + use crate::SubscriptionTaskExecutor; use futures::{ future::{self, Either, Fuse, FusedFuture}, @@ -56,11 +57,11 @@ impl BoundedVecDeque { /// Feed items to the subscription from the underlying stream. /// -/// It's possible configure how many items from the stream -/// are allowed to be kept in memory until the subscription is dropped. +/// This is bounded because the underlying streams in substrate are +/// unbounded and if the subscription can't keep with stream it can +/// cause the buffer to become very large and consume lots of memory. /// -/// This is needed because the underlying streams in substrate are -/// unbounded. +/// In such cases the subscription is dropped. pub async fn pipe_from_stream(pending: PendingSubscriptionSink, mut stream: S) where S: Stream + Unpin + Send + 'static, @@ -224,22 +225,4 @@ mod tests { _ = rx.next().await.unwrap(); assert!(sub.next::().await.is_none()); } - - #[tokio::test] - async fn wait_for_buffered_items() { - let mut sub = subscribe().await; - - // HACK: we can't really know when all items have - // processed by pipe_from_stream and that's - // why we just sleep long enough here. - tokio::time::sleep(std::time::Duration::from_secs(6)).await; - - let mut rx = 0; - - while let Some(Ok(_)) = sub.next::().await { - rx += 1; - } - - assert_eq!(rx, 16); - } } From b67e888c450817597c3c65fa6e4b42a4d956c5ed Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 23 Jan 2024 08:07:58 +0100 Subject: [PATCH 17/17] grumbles: add comment for tokio::MAX_PERMITS --- substrate/client/service/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index 176563d4004f..875cb9ca79e2 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -110,8 +110,14 @@ impl RpcHandlers { &self, json_query: &str, ) -> Result<(String, tokio::sync::mpsc::Receiver), JsonRpseeError> { + // Because `tokio::sync::mpsc::channel` is used under the hood + // it will panic if it's set to usize::MAX. + // + // This limit is used to prevent panics and is large enough. + const TOKIO_MPSC_MAX_SIZE: usize = tokio::sync::Semaphore::MAX_PERMITS; + self.0 - .raw_json_request(json_query, tokio::sync::Semaphore::MAX_PERMITS) + .raw_json_request(json_query, TOKIO_MPSC_MAX_SIZE) .await .map(|(method_res, recv)| (method_res.result, recv)) }