From 0d7becf23b95f66d38676a31d2493c569a98278d Mon Sep 17 00:00:00 2001 From: Parth Date: Tue, 27 Aug 2024 19:08:36 +0400 Subject: [PATCH 01/11] Make `PendingConfigs` storage item public (#5467) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR changes `PendingConfigs` storage item's visibility from crate to public. This enable us to read it in our runtime. --------- Co-authored-by: Bastian Köcher --- polkadot/runtime/parachains/src/configuration.rs | 2 +- prdoc/pr_5467.prdoc | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 prdoc/pr_5467.prdoc diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index d09962ef2b44..19df1f8c3607 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -557,7 +557,7 @@ pub mod pallet { /// The list is sorted ascending by session index. Also, this list can only contain at most /// 2 items: for the next session and for the `scheduled_session`. #[pallet::storage] - pub(crate) type PendingConfigs = + pub type PendingConfigs = StorageValue<_, Vec<(SessionIndex, HostConfiguration>)>, ValueQuery>; /// If this is set, then the configuration setters will bypass the consistency checks. This diff --git a/prdoc/pr_5467.prdoc b/prdoc/pr_5467.prdoc new file mode 100644 index 000000000000..2634c255e168 --- /dev/null +++ b/prdoc/pr_5467.prdoc @@ -0,0 +1,10 @@ +title: Make PendingConfigs storage item public + +doc: + - audience: Runtime Dev + description: | + Make PendingConfigs storage item in polkadot's configuration crate public. + +crates: + - name: polkadot-runtime-parachains + bump: minor \ No newline at end of file From 7a2c5375fa4b950f9518a47c87d92bd611b1bfdc Mon Sep 17 00:00:00 2001 From: Frazz <59382025+Sudo-Whodo@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:23:17 -0700 Subject: [PATCH 02/11] Adding stkd bootnodes (#5470) Opening this PR to add our bootnodes for the IBP. These nodes are located in Santiago Chile, we own and manage the underlying hardware. If you need any more information please let me know. Commands to test: ``` ./polkadot --tmp --name "testing-bootnode" --chain kusama --reserved-only --reserved-nodes "/dns/kusama.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWJHhnF64TXSmyxNkhPkXAHtYNRy86LuvGQu1LTi5vrJCL" --no-hardware-benchmarks ./polkadot --tmp --name "testing-bootnode" --chain paseo --reserved-only --reserved-nodes "/dns/paseo.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWMdND5nwfCs5M2rfp5kyRo41BGDgD8V67rVRaB3acgZ53" --no-hardware-benchmarks ./polkadot --tmp --name "testing-bootnode" --chain polkadot --reserved-only --reserved-nodes "/dns/polkadot.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWEymrFRHz6c17YP3FAyd8kXS5gMRLgkW4U77ZJD2ZNCLZ" --no-hardware-benchmarks ./polkadot --tmp --name "testing-bootnode" --chain westend --reserved-only --reserved-nodes "/dns/westend.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWHaQKkJiTPqeNgqDcW7dfYgJxYwT8YqJMtTkueSu6378V" --no-hardware-benchmarks ``` --- polkadot/node/service/chain-specs/kusama.json | 3 ++- polkadot/node/service/chain-specs/paseo.json | 3 ++- polkadot/node/service/chain-specs/polkadot.json | 3 ++- polkadot/node/service/chain-specs/westend.json | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/polkadot/node/service/chain-specs/kusama.json b/polkadot/node/service/chain-specs/kusama.json index 5d2413ac1e02..ff38192906da 100644 --- a/polkadot/node/service/chain-specs/kusama.json +++ b/polkadot/node/service/chain-specs/kusama.json @@ -37,7 +37,8 @@ "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30333/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT", "/dns/boot-kusama.luckyfriday.io/tcp/443/wss/p2p/12D3KooWS1Lu6DmK8YHSvkErpxpcXmk14vG6y4KVEFEkd9g62PP8", "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30334/wss/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT", - "/dns4/kusama-0.boot.onfinality.io/tcp/27682/ws/p2p/12D3KooWFrwFo7ry3dEuFwhehGSSN96a5Xdzxot7SWfXeSbhELAe" + "/dns4/kusama-0.boot.onfinality.io/tcp/27682/ws/p2p/12D3KooWFrwFo7ry3dEuFwhehGSSN96a5Xdzxot7SWfXeSbhELAe", + "/dns/kusama.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWJHhnF64TXSmyxNkhPkXAHtYNRy86LuvGQu1LTi5vrJCL" ], "telemetryEndpoints": [ [ diff --git a/polkadot/node/service/chain-specs/paseo.json b/polkadot/node/service/chain-specs/paseo.json index 35ac9aa6aa93..aacfdb025786 100644 --- a/polkadot/node/service/chain-specs/paseo.json +++ b/polkadot/node/service/chain-specs/paseo.json @@ -20,7 +20,8 @@ "/dns/pso16.rotko.net/tcp/33246/p2p/12D3KooWRH8eBMhw8c7bucy6pJfy94q4dKpLkF3pmeGohHmemdRu", "/dns/pso16.rotko.net/tcp/35246/wss/p2p/12D3KooWRH8eBMhw8c7bucy6pJfy94q4dKpLkF3pmeGohHmemdRu", "/dns/paseo-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWBLLFKDGBxCwq3QmU3YwWKXUx953WwprRshJQicYu4Cfr", - "/dns/paseo-boot-ng.dwellir.com/tcp/30354/p2p/12D3KooWBLLFKDGBxCwq3QmU3YwWKXUx953WwprRshJQicYu4Cfr" + "/dns/paseo-boot-ng.dwellir.com/tcp/30354/p2p/12D3KooWBLLFKDGBxCwq3QmU3YwWKXUx953WwprRshJQicYu4Cfr", + "/dns/paseo.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWMdND5nwfCs5M2rfp5kyRo41BGDgD8V67rVRaB3acgZ53" ], "telemetryEndpoints": null, "protocolId": "pas", diff --git a/polkadot/node/service/chain-specs/polkadot.json b/polkadot/node/service/chain-specs/polkadot.json index 553ff1bb3e41..7e1e90f6a8c1 100644 --- a/polkadot/node/service/chain-specs/polkadot.json +++ b/polkadot/node/service/chain-specs/polkadot.json @@ -38,7 +38,8 @@ "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30333/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ", "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ", "/dns/boot-polkadot.luckyfriday.io/tcp/443/wss/p2p/12D3KooWAdyiVAaeGdtBt6vn5zVetwA4z4qfm9Fi2QCSykN1wTBJ", - "/dns4/polkadot-0.boot.onfinality.io/tcp/24446/ws/p2p/12D3KooWT1PWaNdAwYrSr89dvStnoGdH3t4LNRbcVNN4JCtsotkR" + "/dns4/polkadot-0.boot.onfinality.io/tcp/24446/ws/p2p/12D3KooWT1PWaNdAwYrSr89dvStnoGdH3t4LNRbcVNN4JCtsotkR", + "/dns/polkadot.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWEymrFRHz6c17YP3FAyd8kXS5gMRLgkW4U77ZJD2ZNCLZ" ], "telemetryEndpoints": [ [ diff --git a/polkadot/node/service/chain-specs/westend.json b/polkadot/node/service/chain-specs/westend.json index 9059d525689d..08c5bd33b4bd 100644 --- a/polkadot/node/service/chain-specs/westend.json +++ b/polkadot/node/service/chain-specs/westend.json @@ -33,7 +33,8 @@ "/dns/wnd14.rotko.net/tcp/35234/wss/p2p/12D3KooWLK8Zj1uZ46phU3vQwiDVda8tB76S8J26rXZQLHpwWkDJ", "/dns/wnd14.rotko.net/tcp/33234/p2p/12D3KooWLK8Zj1uZ46phU3vQwiDVda8tB76S8J26rXZQLHpwWkDJ", "/dns/ibp-boot-westend.luckyfriday.io/tcp/30333/p2p/12D3KooWDg1YEytdwFFNWroFj6gio4YFsMB3miSbHKgdpJteUMB9", - "/dns/ibp-boot-westend.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWDg1YEytdwFFNWroFj6gio4YFsMB3miSbHKgdpJteUMB9" + "/dns/ibp-boot-westend.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWDg1YEytdwFFNWroFj6gio4YFsMB3miSbHKgdpJteUMB9", + "/dns/westend.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWHaQKkJiTPqeNgqDcW7dfYgJxYwT8YqJMtTkueSu6378V" ], "telemetryEndpoints": [ [ From f90bfa6ada211ef1bb55861ffbb7588b15ec21df Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Tue, 27 Aug 2024 20:22:51 +0200 Subject: [PATCH 03/11] Add feature to allow Aura collator to use full PoV size (#5393) This PR introduces a feature that allows to optionally enable using the full PoV size. Technically, we're ready to enable it by default, but as corresponding runtime changes have not been propagated to the system parachain runtimes yet, doing so could put them at risk. On the other hand, there are teams that could benefit from it right now, and it makes no sense for them to wait for the fellowship release and everything. --------- Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> --- cumulus/client/consensus/aura/Cargo.toml | 4 ++++ .../client/consensus/aura/src/collators/basic.rs | 16 +++++++++++----- .../consensus/aura/src/collators/lookahead.rs | 16 +++++++++++----- .../collators/slot_based/block_builder_task.rs | 16 +++++++++++----- prdoc/pr_5393.prdoc | 15 +++++++++++++++ 5 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 prdoc/pr_5393.prdoc diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index 01e07cb395a9..47e2d8572c3f 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -54,3 +54,7 @@ polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-overseer = { workspace = true, default-features = true } + +[features] +# Allows collator to use full PoV size for block building +full-pov-size = [] diff --git a/cumulus/client/consensus/aura/src/collators/basic.rs b/cumulus/client/consensus/aura/src/collators/basic.rs index 0f9583cd0eb0..d843483b79fa 100644 --- a/cumulus/client/consensus/aura/src/collators/basic.rs +++ b/cumulus/client/consensus/aura/src/collators/basic.rs @@ -237,6 +237,16 @@ where .await ); + let allowed_pov_size = if cfg!(feature = "full-pov-size") { + validation_data.max_pov_size + } else { + // Set the block limit to 50% of the maximum PoV size. + // + // TODO: If we got benchmarking that includes the proof size, + // we should be able to use the maximum pov size. + validation_data.max_pov_size / 2 + } as usize; + let maybe_collation = try_request!( collator .collate( @@ -245,11 +255,7 @@ where None, (parachain_inherent_data, other_inherent_data), params.authoring_duration, - // Set the block limit to 50% of the maximum PoV size. - // - // TODO: If we got benchmarking that includes the proof size, - // we should be able to use the maximum pov size. - (validation_data.max_pov_size / 2) as usize, + allowed_pov_size, ) .await ); diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index 02d60538a732..0be1e0a23ca5 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -412,6 +412,16 @@ where ) .await; + let allowed_pov_size = if cfg!(feature = "full-pov-size") { + validation_data.max_pov_size + } else { + // Set the block limit to 50% of the maximum PoV size. + // + // TODO: If we got benchmarking that includes the proof size, + // we should be able to use the maximum pov size. + validation_data.max_pov_size / 2 + } as usize; + match collator .collate( &parent_header, @@ -419,11 +429,7 @@ where None, (parachain_inherent_data, other_inherent_data), params.authoring_duration, - // Set the block limit to 50% of the maximum PoV size. - // - // TODO: If we got benchmarking that includes the proof size, - // we should be able to use the maximum pov size. - (validation_data.max_pov_size / 2) as usize, + allowed_pov_size, ) .await { diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs b/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs index 1fbc0689da86..b70cfe3841b7 100644 --- a/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs +++ b/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs @@ -350,6 +350,16 @@ where ) .await; + let allowed_pov_size = if cfg!(feature = "full-pov-size") { + validation_data.max_pov_size + } else { + // Set the block limit to 50% of the maximum PoV size. + // + // TODO: If we got benchmarking that includes the proof size, + // we should be able to use the maximum pov size. + validation_data.max_pov_size / 2 + } as usize; + let Ok(Some(candidate)) = collator .build_block_and_import( &parent_header, @@ -357,11 +367,7 @@ where None, (parachain_inherent_data, other_inherent_data), authoring_duration, - // Set the block limit to 50% of the maximum PoV size. - // - // TODO: If we got benchmarking that includes the proof size, - // we should be able to use the maximum pov size. - (validation_data.max_pov_size / 2) as usize, + allowed_pov_size, ) .await else { diff --git a/prdoc/pr_5393.prdoc b/prdoc/pr_5393.prdoc new file mode 100644 index 000000000000..7fcf3067fabc --- /dev/null +++ b/prdoc/pr_5393.prdoc @@ -0,0 +1,15 @@ +# 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: Allow to enable full PoV size + +doc: + - audience: Node Dev + description: | + A feature is introduced allowing a collator to enable full PoV size at compile time. + WARNING: To use this feature, security considerations must be understood and the latest + SDK version must be used. + +crates: + - name: cumulus-client-consensus-aura + bump: minor From 38fce08896ee595cb8572923bd0d9f40570e7cb6 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Wed, 28 Aug 2024 10:21:18 +0300 Subject: [PATCH 04/11] polkadot-parachain-bin: Remove contracts parachain (#5471) Related to: https://github.com/paritytech/polkadot-sdk/issues/5210 Follow-up for https://github.com/paritytech/polkadot-sdk/pull/5288, as per this comment: https://github.com/paritytech/polkadot-sdk/pull/5288#discussion_r1711157476 I hope I understood this correctly. --- .../chain-specs/contracts-rococo.json | 1 - .../src/chain_spec/contracts.rs | 239 ------------------ .../polkadot-parachain/src/chain_spec/mod.rs | 16 -- 3 files changed, 256 deletions(-) delete mode 120000 cumulus/polkadot-parachain/chain-specs/contracts-rococo.json delete mode 100644 cumulus/polkadot-parachain/src/chain_spec/contracts.rs diff --git a/cumulus/polkadot-parachain/chain-specs/contracts-rococo.json b/cumulus/polkadot-parachain/chain-specs/contracts-rococo.json deleted file mode 120000 index b9f8e8f31e84..000000000000 --- a/cumulus/polkadot-parachain/chain-specs/contracts-rococo.json +++ /dev/null @@ -1 +0,0 @@ -../../parachains/chain-specs/contracts-rococo.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs b/cumulus/polkadot-parachain/src/chain_spec/contracts.rs deleted file mode 100644 index eb10a43ffbea..000000000000 --- a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus 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. - -// Cumulus 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 Cumulus. If not, see . - -use crate::chain_spec::{get_account_id_from_seed, get_collator_keys_from_seed, SAFE_XCM_VERSION}; -use cumulus_primitives_core::ParaId; -use hex_literal::hex; -use parachains_common::{AccountId, AuraId}; -use polkadot_parachain_lib::chain_spec::{Extensions, GenericChainSpec}; -use sc_service::ChainType; -use sp_core::{crypto::UncheckedInto, sr25519}; - -/// No relay chain suffix because the id is the same over all relay chains. -const CONTRACTS_PARACHAIN_ID: u32 = 1002; - -/// The existential deposit is determined by the runtime "contracts-rococo". -const CONTRACTS_ROCOCO_ED: contracts_rococo_runtime::Balance = - testnet_parachains_constants::rococo::currency::EXISTENTIAL_DEPOSIT; - -pub fn contracts_rococo_development_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("tokenSymbol".into(), "ROC".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - GenericChainSpec::builder( - contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { - relay_chain: "rococo-local".into(), // You MUST set this to the correct network! - para_id: CONTRACTS_PARACHAIN_ID, - }, - ) - .with_name("Contracts on Rococo Development") - .with_id("contracts-rococo-dev") - .with_chain_type(ChainType::Development) - .with_genesis_config_patch(contracts_rococo_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - CONTRACTS_PARACHAIN_ID.into(), - )) - .with_boot_nodes(Vec::new()) - .build() -} - -pub fn contracts_rococo_local_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("tokenSymbol".into(), "ROC".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - GenericChainSpec::builder( - contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { - relay_chain: "rococo-local".into(), // You MUST set this to the correct network! - para_id: CONTRACTS_PARACHAIN_ID, - }, - ) - .with_name("Contracts on Rococo") - .with_id("contracts-rococo-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(contracts_rococo_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - CONTRACTS_PARACHAIN_ID.into(), - )) - .with_properties(properties) - .build() -} - -pub fn contracts_rococo_config() -> GenericChainSpec { - // Give your base currency a unit name and decimal places - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("tokenSymbol".into(), "ROC".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - GenericChainSpec::builder( - contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "rococo".into(), para_id: CONTRACTS_PARACHAIN_ID }, - ) - .with_name("Contracts on Rococo") - .with_id("contracts-rococo") - .with_chain_type(ChainType::Live) - .with_genesis_config_patch(contracts_rococo_genesis( - vec![ - // 5GKFbTTgrVS4Vz1UWWHPqMZQNFWZtqo7H2KpCDyYhEL3aS26 - ( - hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"] - .into(), - hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"] - .unchecked_into(), - ), - // 5EPRJHm2GpABVWcwnAujcrhnrjFZyDGd5TwKFzkBoGgdRyv2 - ( - hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"] - .into(), - hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"] - .unchecked_into(), - ), - // 5GH62vrJrVZxLREcHzm2PR5uTLAT5RQMJitoztCGyaP4o3uM - ( - hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"] - .into(), - hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"] - .unchecked_into(), - ), - // 5FHfoJDLdjRYX5KXLRqMDYBbWrwHLMtti21uK4QByUoUAbJF - ( - hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"] - .into(), - hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"] - .unchecked_into(), - ), - ], - // Warning: The configuration for a production chain should not contain - // any endowed accounts here, otherwise it'll be minting extra native tokens - // from the relay chain on the parachain. - vec![ - // NOTE: Remove endowed accounts if deployed on other relay chains. - // Endowed accounts - hex!["baa78c7154c7f82d6d377177e20bcab65d327eca0086513f9964f5a0f6bdad56"].into(), - // AccountId of an account which `ink-waterfall` uses for automated testing - hex!["0e47e2344d523c3cc5c34394b0d58b9a4200e813a038e6c5a6163cc07d70b069"].into(), - ], - CONTRACTS_PARACHAIN_ID.into(), - )) - .with_boot_nodes(vec![ - "/dns/contracts-collator-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWKg3Rpxcr9oJ8n6khoxpGKWztCZydtUZk2cojHqnfLrpj" - .parse() - .expect("MultiaddrWithPeerId"), - "/dns/contracts-collator-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWPEXYrz8tHU3nDtPoPw4V7ou5dzMEWSTuUj7vaWiYVAVh" - .parse() - .expect("MultiaddrWithPeerId"), - "/dns/contracts-collator-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWEVU8AFNary4nP4qEnEcwJaRuy59Wefekzdu9pKbnVEhk" - .parse() - .expect("MultiaddrWithPeerId"), - "/dns/contracts-collator-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWP6pV3ZmcXzGDjv8ZMgA6nZxfAKDxSz4VNiLx6vVCQgJX" - .parse() - .expect("MultiaddrWithPeerId"), - ]) - .with_properties(properties) - .build() -} - -fn contracts_rococo_genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - id: ParaId, -) -> serde_json::Value { - serde_json::json!( { - "balances": { - "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), - "candidacyBond": CONTRACTS_ROCOCO_ED * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - contracts_rococo_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - // no need to pass anything to aura, in fact it will panic if we do. Session will take care - // of this. - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - "sudo": { - "key": Some(sp_runtime::AccountId32::from(hex![ - "2681a28014e7d3a5bfb32a003b3571f53c408acbc28d351d6bf58f5028c4ef14" - ])), - }, - }) -} diff --git a/cumulus/polkadot-parachain/src/chain_spec/mod.rs b/cumulus/polkadot-parachain/src/chain_spec/mod.rs index de9c6a889ed0..cd704b5bd938 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/mod.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/mod.rs @@ -27,7 +27,6 @@ use sp_runtime::traits::{IdentifyAccount, Verify}; pub mod asset_hubs; pub mod bridge_hubs; pub mod collectives; -pub mod contracts; pub mod coretime; pub mod glutton; pub mod penpal; @@ -148,14 +147,6 @@ impl LoadSpec for ChainSpecLoader { &include_bytes!("../../chain-specs/collectives-westend.json")[..], )?), - // -- Contracts on Rococo - "contracts-rococo-dev" => Box::new(contracts::contracts_rococo_development_config()), - "contracts-rococo-local" => Box::new(contracts::contracts_rococo_local_config()), - "contracts-rococo-genesis" => Box::new(contracts::contracts_rococo_config()), - "contracts-rococo" => Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../../chain-specs/contracts-rococo.json")[..], - )?), - // -- BridgeHub bridge_like_id if bridge_like_id.starts_with(bridge_hubs::BridgeHubRuntimeType::ID_PREFIX) => @@ -238,7 +229,6 @@ enum LegacyRuntime { AssetHubPolkadot, AssetHub, Penpal, - ContractsRococo, Collectives, Glutton, BridgeHub(bridge_hubs::BridgeHubRuntimeType), @@ -266,8 +256,6 @@ impl LegacyRuntime { LegacyRuntime::AssetHub } else if id.starts_with("penpal") { LegacyRuntime::Penpal - } else if id.starts_with("contracts-rococo") { - LegacyRuntime::ContractsRococo } else if id.starts_with("collectives-polkadot") || id.starts_with("collectives-westend") { LegacyRuntime::Collectives } else if id.starts_with(bridge_hubs::BridgeHubRuntimeType::ID_PREFIX) { @@ -307,7 +295,6 @@ impl RuntimeResolverT for RuntimeResolver { LegacyRuntime::Collectives | LegacyRuntime::Coretime(_) | LegacyRuntime::People(_) | - LegacyRuntime::ContractsRococo | LegacyRuntime::Glutton | LegacyRuntime::Penpal | LegacyRuntime::Omni => Runtime::Omni(Consensus::Aura(AuraConsensusId::Sr25519)), @@ -383,9 +370,6 @@ mod tests { create_default_with_extensions("penpal-rococo-1000", Extensions2::default()); assert_eq!(LegacyRuntime::Penpal, LegacyRuntime::from_id(chain_spec.id())); - let chain_spec = crate::chain_spec::contracts::contracts_rococo_local_config(); - assert_eq!(LegacyRuntime::ContractsRococo, LegacyRuntime::from_id(chain_spec.id())); - let chain_spec = crate::chain_spec::rococo_parachain::rococo_parachain_local_config(); assert_eq!(LegacyRuntime::Omni, LegacyRuntime::from_id(chain_spec.id())); } From f4be48cf678e1aadabaf11e1642d757cf6c8260b Mon Sep 17 00:00:00 2001 From: Arsham Teymouri <75425316+ArshamTeymouri@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:27:32 +0200 Subject: [PATCH 05/11] change try-runtime rpc domains (#5443) as part of paritytech/devops/3502, try-runtime nodes were migrated to a new provider with a new domain address. The PR fixes all the references to try-runtime nodes on rococo, westend, kusama and polkadot networks. --------- Co-authored-by: ArshamTeymouri Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Niklas Adolfsson --- .config/lychee.toml | 2 +- .github/workflows/check-runtime-migration.yml | 4 ++-- .gitlab/pipeline/check.yml | 4 ++-- prdoc/pr_5443.prdoc | 10 ++++++++++ substrate/utils/frame/remote-externalities/src/lib.rs | 2 +- 5 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 prdoc/pr_5443.prdoc diff --git a/.config/lychee.toml b/.config/lychee.toml index 1de9fcd559dd..b7bb6f0ce495 100644 --- a/.config/lychee.toml +++ b/.config/lychee.toml @@ -32,7 +32,6 @@ exclude = [ "https://github.com/paritytech/polkadot-sdk/substrate/frame/timestamp", "https://github.com/paritytech/substrate/frame/fast-unstake", "https://github.com/zkcrypto/bls12_381/blob/e224ad4ea1babfc582ccd751c2bf128611d10936/src/test-data/mod.rs", - "https://polkadot-try-runtime-node.parity-chains.parity.io/", "https://polkadot.network/the-path-of-a-parachain-block/", "https://research.web3.foundation/en/latest/polkadot/NPoS/3.%20Balancing.html", "https://research.web3.foundation/en/latest/polkadot/Token%20Economics.html#inflation-model", @@ -41,6 +40,7 @@ exclude = [ "https://research.web3.foundation/en/latest/polkadot/overview/2-token-economics.html#inflation-model", "https://research.web3.foundation/en/latest/polkadot/slashing/npos.html", "https://rpc.polkadot.io/", + "https://try-runtime.polkadot.io/", "https://w3f.github.io/parachain-implementers-guide/node/approval/approval-distribution.html", "https://w3f.github.io/parachain-implementers-guide/node/index.html", "https://w3f.github.io/parachain-implementers-guide/protocol-chain-selection.html", diff --git a/.github/workflows/check-runtime-migration.yml b/.github/workflows/check-runtime-migration.yml index 9b7a6fafcd15..b8962f0e07ad 100644 --- a/.github/workflows/check-runtime-migration.yml +++ b/.github/workflows/check-runtime-migration.yml @@ -56,13 +56,13 @@ jobs: # - network: westend # package: westend-runtime # wasm: westend_runtime.compact.compressed.wasm - # uri: "wss://westend-try-runtime-node.parity-chains.parity.io:443" + # uri: "wss://try-runtime-westend.polkadot.io:443" # subcommand_extra_args: "--no-weight-warnings" # command_extra_args: "" # - network: rococo # package: rococo-runtime # wasm: rococo_runtime.compact.compressed.wasm - # uri: "wss://rococo-try-runtime-node.parity-chains.parity.io:443" + # uri: "wss://try-runtime-rococo.polkadot.io:443" # subcommand_extra_args: "--no-weight-warnings" # command_extra_args: "" - network: asset-hub-westend diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index bc12dd474b07..3e94eb77c7b4 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -106,7 +106,7 @@ check-runtime-migration-westend: NETWORK: "westend" PACKAGE: "westend-runtime" WASM: "westend_runtime.compact.compressed.wasm" - URI: "wss://westend-try-runtime-node.parity-chains.parity.io:443" + URI: "wss://try-runtime-westend.polkadot.io:443" SUBCOMMAND_EXTRA_ARGS: "--no-weight-warnings" check-runtime-migration-rococo: @@ -119,7 +119,7 @@ check-runtime-migration-rococo: NETWORK: "rococo" PACKAGE: "rococo-runtime" WASM: "rococo_runtime.compact.compressed.wasm" - URI: "wss://rococo-try-runtime-node.parity-chains.parity.io:443" + URI: "wss://try-runtime-rococo.polkadot.io:443" SUBCOMMAND_EXTRA_ARGS: "--no-weight-warnings" check-core-crypto-features: diff --git a/prdoc/pr_5443.prdoc b/prdoc/pr_5443.prdoc new file mode 100644 index 000000000000..0fd396be06a2 --- /dev/null +++ b/prdoc/pr_5443.prdoc @@ -0,0 +1,10 @@ +crates: +- name: frame-remote-externalities + bump: patch +doc: +- audience: Runtime Dev + description: as part of https://github.com/paritytech/devops/issues/3502, try-runtime + nodes were migrated to a new provider with a new domain address. The PR fixes + all the references to try-runtime nodes on rococo, westend, kusama and polkadot + networks +title: change try-runtime rpc domains diff --git a/substrate/utils/frame/remote-externalities/src/lib.rs b/substrate/utils/frame/remote-externalities/src/lib.rs index 40864085349b..955e79008c8c 100644 --- a/substrate/utils/frame/remote-externalities/src/lib.rs +++ b/substrate/utils/frame/remote-externalities/src/lib.rs @@ -55,7 +55,7 @@ type ChildKeyValues = Vec<(ChildInfo, Vec)>; type SnapshotVersion = Compact; const LOG_TARGET: &str = "remote-ext"; -const DEFAULT_HTTP_ENDPOINT: &str = "https://polkadot-try-runtime-node.parity-chains.parity.io:443"; +const DEFAULT_HTTP_ENDPOINT: &str = "https://try-runtime.polkadot.io:443"; const SNAPSHOT_VERSION: SnapshotVersion = Compact(4); /// The snapshot that we store on disk. From f0fd083e4a686ac9bd86a77fb631d612d1a78c5f Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Wed, 28 Aug 2024 12:01:23 +0300 Subject: [PATCH 06/11] Update approval-voting-regression-bench (#5504) The accepted divergence rate of 1/1000 is excessive and leads to false positives especially after https://github.com/paritytech/polkadot-sdk/pull/4772 and https://github.com/paritytech/polkadot-sdk/pull/5042, so let's increase it to 1/100 since we do have some randomness in the system and there is no point in being that strict. Fixes: https://github.com/paritytech/polkadot-sdk/issues/5463 --------- Signed-off-by: Alexandru Gheorghe --- .../benches/approval-voting-regression-bench.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs b/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs index a18e667253d0..41418bcc511f 100644 --- a/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs +++ b/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs @@ -74,11 +74,12 @@ fn main() -> Result<(), String> { .map_err(|e| e.to_string())?; println!("{}", average_usage); - // We expect no variance for received and sent - // but use 0.001 because we operate with floats + // We expect some small variance for received and sent because the + // test messages are generated at every benchmark run and they contain + // random data so use 0.01 as the accepted variance. messages.extend(average_usage.check_network_usage(&[ - ("Received from peers", 52941.6071, 0.001), - ("Sent to peers", 63810.1859, 0.001), + ("Received from peers", 52941.6071, 0.01), + ("Sent to peers", 63995.2200, 0.01), ])); messages.extend(average_usage.check_cpu_usage(&[ ("approval-distribution", 6.3912, 0.1), From 09254eb9f8670f942c68914ff6fc0ffb503aaf23 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 28 Aug 2024 12:12:50 +0200 Subject: [PATCH 07/11] rpc server: listen to `ipv6 socket` if available and `--experimental-rpc-endpoint` CLI option (#4792) Close https://github.com/paritytech/polkadot-sdk/issues/3488, https://github.com/paritytech/polkadot-sdk/issues/4331 This changes/adds the following: 1. The default setting is that substrate starts a rpc server that listens to localhost both Ipv4 and Ipv6 on the same port. Ipv6 is allowed to fail because some platforms may not support it 2. A new RPC CLI option `--experimental-rpc-endpoint` which allow to configure arbitrary listen addresses including the port, if this is enabled no other interfaces are enabled. 3. If the local addr is not found for any of the sockets the server is not started throws an error. 4. Remove the deny_unsafe from the RPC implementations instead this is an extension to allow different polices for different interfaces/sockets such one may enable unsafe on local interface and safe on only the external interface. So for instance in this PR it's now possible to start up three RPC endpoints as follows: ``` $ polkadot --experimental-rpc-endpoint "listen-addr=127.0.0.1:9944,rpc-methods=unsafe" --experimental-rpc-endpoint "listen-addr=0.0.0.0:9945,rpc-methods=safe,rate-limit=100" --experimental-rpc-endpoint "listen-addr=[::1]:9944,optional=true" ``` #### Needs to be addressed ~1. Support binding to a random port if it's fails with the default stuff for backward compatible reasons~ ~2. How to sync that the rpc CLI params and that the rpc-listen-addr align, hard to maintain...~ ~3. Add similar warning prints for exposing unsafe methods on external interfaces..~ ~4. Inline todos + the hacky String conversion from rpc params.~ #### Cons with this PR Manual strings parsing impl more error-prone than relying on clap.... //cc @jsdw @BulatSaif @PierreBesson @bkchr --------- Co-authored-by: Sebastian Kunert --- Cargo.lock | 76 ++-- Cargo.toml | 4 +- cumulus/client/cli/src/lib.rs | 4 +- .../polkadot-parachain-lib/src/cli.rs | 6 +- .../polkadot-parachain-lib/src/rpc.rs | 14 +- .../polkadot-parachain-lib/src/service.rs | 15 +- cumulus/test/service/src/cli.rs | 6 +- cumulus/test/service/src/lib.rs | 23 +- polkadot/node/service/src/lib.rs | 5 +- polkadot/rpc/src/lib.rs | 19 +- prdoc/pr_4792.prdoc | 62 +++ substrate/bin/node/cli/src/service.rs | 4 +- substrate/bin/node/rpc/Cargo.toml | 1 - substrate/bin/node/rpc/src/lib.rs | 16 +- substrate/client/cli/src/arg_enums.rs | 13 + substrate/client/cli/src/commands/run_cmd.rs | 112 ++++- substrate/client/cli/src/config.rs | 13 +- substrate/client/cli/src/params/mod.rs | 4 +- substrate/client/cli/src/params/rpc_params.rs | 395 ++++++++++++++++++ .../client/consensus/babe/rpc/src/lib.rs | 41 +- .../client/consensus/beefy/rpc/src/lib.rs | 14 +- .../client/consensus/grandpa/rpc/src/lib.rs | 8 +- substrate/client/rpc-api/src/author/mod.rs | 10 +- substrate/client/rpc-api/src/dev/mod.rs | 2 +- substrate/client/rpc-api/src/lib.rs | 2 +- substrate/client/rpc-api/src/offchain/mod.rs | 4 +- substrate/client/rpc-api/src/policy.rs | 9 + substrate/client/rpc-api/src/state/mod.rs | 9 +- substrate/client/rpc-api/src/statement/mod.rs | 2 +- substrate/client/rpc-api/src/system/mod.rs | 12 +- substrate/client/rpc-servers/Cargo.toml | 7 +- substrate/client/rpc-servers/src/lib.rs | 377 +++++++++-------- substrate/client/rpc-servers/src/utils.rs | 213 +++++++++- substrate/client/rpc-spec-v2/Cargo.toml | 4 +- substrate/client/rpc/Cargo.toml | 2 - substrate/client/rpc/src/author/mod.rs | 34 +- substrate/client/rpc/src/author/tests.rs | 27 +- substrate/client/rpc/src/dev/mod.rs | 16 +- substrate/client/rpc/src/dev/tests.rs | 9 +- substrate/client/rpc/src/lib.rs | 9 +- substrate/client/rpc/src/offchain/mod.rs | 28 +- substrate/client/rpc/src/offchain/tests.rs | 17 +- substrate/client/rpc/src/state/mod.rs | 41 +- substrate/client/rpc/src/state/tests.rs | 84 ++-- substrate/client/rpc/src/statement/mod.rs | 18 +- substrate/client/rpc/src/system/mod.rs | 43 +- substrate/client/rpc/src/system/tests.rs | 9 +- substrate/client/rpc/src/testing.rs | 17 + substrate/client/service/src/builder.rs | 33 +- substrate/client/service/src/config.rs | 28 +- substrate/client/service/src/lib.rs | 84 ++-- .../rpc/state-trie-migration-rpc/src/lib.rs | 18 +- substrate/utils/frame/rpc/system/src/lib.rs | 46 +- templates/minimal/node/Cargo.toml | 1 - templates/minimal/node/src/rpc.rs | 8 +- templates/minimal/node/src/service.rs | 5 +- templates/parachain/node/src/command.rs | 6 +- templates/parachain/node/src/rpc.rs | 7 +- templates/parachain/node/src/service.rs | 9 +- templates/solochain/node/Cargo.toml | 1 - templates/solochain/node/src/rpc.rs | 8 +- templates/solochain/node/src/service.rs | 5 +- 62 files changed, 1472 insertions(+), 647 deletions(-) create mode 100644 prdoc/pr_4792.prdoc create mode 100644 substrate/client/cli/src/params/rpc_params.rs diff --git a/Cargo.lock b/Cargo.lock index 35e46da1b473..8bf4c356397d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1465,15 +1465,6 @@ dependencies = [ "serde", ] -[[package]] -name = "beef" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" -dependencies = [ - "serde", -] - [[package]] name = "binary-merkle-tree" version = "13.0.0" @@ -1511,7 +1502,7 @@ dependencies = [ "proc-macro2 1.0.82", "quote 1.0.36", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn 2.0.61", ] @@ -7416,9 +7407,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.23.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b089779ad7f80768693755a031cc14a7766aba707cbe886674e3f79e9b7e47" +checksum = "5ec465b607a36dc5dd45d48b7689bc83f679f66a3ac6b6b21cc787a11e0f8685" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -7432,9 +7423,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.23.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08163edd8bcc466c33d79e10f695cdc98c00d1e6ddfb95cec41b6b0279dd5432" +checksum = "90f0977f9c15694371b8024c35ab58ca043dbbf4b51ccb03db8858a021241df1" dependencies = [ "base64 0.22.1", "futures-util", @@ -7455,13 +7446,11 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.23.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79712302e737d23ca0daa178e752c9334846b08321d439fd89af9a384f8c830b" +checksum = "e942c55635fbf5dc421938b8558a8141c7e773720640f4f1dbe1f4164ca4e221" dependencies = [ - "anyhow", "async-trait", - "beef", "bytes", "futures-timer", "futures-util", @@ -7472,7 +7461,7 @@ dependencies = [ "parking_lot 0.12.3", "pin-project", "rand", - "rustc-hash", + "rustc-hash 2.0.0", "serde", "serde_json", "thiserror", @@ -7483,9 +7472,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.23.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d90064e04fb9d7282b1c71044ea94d0bbc6eff5621c66f1a0bce9e9de7cf3ac" +checksum = "e33774602df12b68a2310b38a535733c477ca4a498751739f89fe8dbbb62ec4c" dependencies = [ "async-trait", "base64 0.22.1", @@ -7508,9 +7497,9 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.23.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7895f186d5921065d96e16bd795e5ca89ac8356ec423fafc6e3d7cf8ec11aee4" +checksum = "6b07a2daf52077ab1b197aea69a5c990c060143835bf04c77070e98903791715" dependencies = [ "heck 0.5.0", "proc-macro-crate 3.1.0", @@ -7521,11 +7510,10 @@ dependencies = [ [[package]] name = "jsonrpsee-server" -version = "0.23.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "654afab2e92e5d88ebd8a39d6074483f3f2bfdf91c5ac57fe285e7127cdd4f51" +checksum = "038fb697a709bec7134e9ccbdbecfea0e2d15183f7140254afef7c5610a3f488" dependencies = [ - "anyhow", "futures-util", "http 1.1.0", "http-body 1.0.0", @@ -7549,11 +7537,10 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.23.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c465fbe385238e861fdc4d1c85e04ada6c1fd246161d26385c1b311724d2af" +checksum = "23b67d6e008164f027afbc2e7bb79662650158d26df200040282d2aa1cbb093b" dependencies = [ - "beef", "http 1.1.0", "serde", "serde_json", @@ -7562,9 +7549,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.23.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c28759775f5cb2f1ea9667672d3fe2b0e701d1f4b7b67954e60afe7fd058b5e" +checksum = "992bf67d1132f88edf4a4f8cff474cf01abb2be203004a2b8e11c2b20795b99e" dependencies = [ "http 1.1.0", "jsonrpsee-client-transport", @@ -8748,7 +8735,6 @@ dependencies = [ "sc-executor", "sc-network", "sc-offchain", - "sc-rpc-api", "sc-service", "sc-telemetry", "sc-transaction-pool", @@ -9283,7 +9269,6 @@ dependencies = [ "sc-consensus-grandpa-rpc", "sc-mixnet", "sc-rpc", - "sc-rpc-api", "sc-sync-state-rpc", "sc-transaction-pool-api", "sp-api", @@ -15984,7 +15969,7 @@ dependencies = [ "pin-project-lite", "quinn-proto 0.9.6", "quinn-udp 0.3.2", - "rustc-hash", + "rustc-hash 1.1.0", "rustls 0.20.9", "thiserror", "tokio", @@ -16003,7 +15988,7 @@ dependencies = [ "pin-project-lite", "quinn-proto 0.10.6", "quinn-udp 0.4.1", - "rustc-hash", + "rustc-hash 1.1.0", "rustls 0.21.7", "thiserror", "tokio", @@ -16019,7 +16004,7 @@ dependencies = [ "bytes", "rand", "ring 0.16.20", - "rustc-hash", + "rustc-hash 1.1.0", "rustls 0.20.9", "slab", "thiserror", @@ -16037,7 +16022,7 @@ dependencies = [ "bytes", "rand", "ring 0.16.20", - "rustc-hash", + "rustc-hash 1.1.0", "rustls 0.21.7", "slab", "thiserror", @@ -16310,7 +16295,7 @@ checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" dependencies = [ "hashbrown 0.13.2", "log", - "rustc-hash", + "rustc-hash 1.1.0", "slice-group-by", "smallvec", ] @@ -16911,6 +16896,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -18281,11 +18272,9 @@ dependencies = [ "sp-runtime", "sp-session", "sp-statement-store", - "sp-tracing 16.0.0", "sp-version", "substrate-test-runtime-client", "tokio", - "tracing-subscriber 0.3.18", ] [[package]] @@ -18311,6 +18300,7 @@ dependencies = [ name = "sc-rpc-server" version = "11.0.0" dependencies = [ + "dyn-clone", "forwarded-header-value", "futures", "governor", @@ -18320,6 +18310,7 @@ dependencies = [ "ip_network", "jsonrpsee", "log", + "sc-rpc-api", "serde", "serde_json", "substrate-prometheus-endpoint", @@ -18597,7 +18588,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "sc-client-api", "sc-tracing-proc-macro", "serde", @@ -19957,7 +19948,6 @@ dependencies = [ "sc-executor", "sc-network", "sc-offchain", - "sc-rpc-api", "sc-service", "sc-telemetry", "sc-transaction-pool", @@ -20646,7 +20636,7 @@ dependencies = [ name = "sp-rpc" version = "26.0.0" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", "serde", "serde_json", "sp-core", diff --git a/Cargo.toml b/Cargo.toml index 275efe1df638..a181a935ea06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -812,8 +812,8 @@ isahc = { version = "1.2" } itertools = { version = "0.11" } jobserver = { version = "0.1.26" } jsonpath_lib = { version = "0.3" } -jsonrpsee = { version = "0.23.2" } -jsonrpsee-core = { version = "0.23.2" } +jsonrpsee = { version = "0.24.3" } +jsonrpsee-core = { version = "0.24.3" } k256 = { version = "0.13.3", default-features = false } kitchensink-runtime = { path = "substrate/bin/node/runtime" } kvdb = { version = "0.13.0" } diff --git a/cumulus/client/cli/src/lib.rs b/cumulus/client/cli/src/lib.rs index a7b2eb19de88..564d7b58c94d 100644 --- a/cumulus/client/cli/src/lib.rs +++ b/cumulus/client/cli/src/lib.rs @@ -21,13 +21,13 @@ use std::{ fs, io::{self, Write}, - net::SocketAddr, path::PathBuf, sync::Arc, }; use codec::Encode; use sc_chain_spec::ChainSpec; +use sc_cli::RpcEndpoint; use sc_client_api::HeaderBackend; use sc_service::{ config::{PrometheusConfig, RpcBatchRequestConfig, TelemetryEndpoints}, @@ -423,7 +423,7 @@ impl sc_cli::CliConfiguration for NormalizedRunCmd { self.base.rpc_cors(is_dev) } - fn rpc_addr(&self, default_listen_port: u16) -> sc_cli::Result> { + fn rpc_addr(&self, default_listen_port: u16) -> sc_cli::Result>> { self.base.rpc_addr(default_listen_port) } diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/cli.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/cli.rs index 2aa2b10fbb67..31eb2cf88060 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/cli.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/cli.rs @@ -25,10 +25,10 @@ use clap::{Command, CommandFactory, FromArgMatches}; use sc_chain_spec::ChainSpec; use sc_cli::{ CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, - SharedParams, SubstrateCli, + RpcEndpoint, SharedParams, SubstrateCli, }; use sc_service::{config::PrometheusConfig, BasePath}; -use std::{fmt::Debug, marker::PhantomData, net::SocketAddr, path::PathBuf}; +use std::{fmt::Debug, marker::PhantomData, path::PathBuf}; /// Trait that can be used to customize some of the customer-facing info related to the node binary /// that is being built using this library. @@ -300,7 +300,7 @@ impl CliConfiguration for RelayChainCli { .or_else(|| self.base_path.clone().map(Into::into))) } - fn rpc_addr(&self, default_listen_port: u16) -> sc_cli::Result> { + fn rpc_addr(&self, default_listen_port: u16) -> sc_cli::Result>> { self.base.base.rpc_addr(default_listen_port) } diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/rpc.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/rpc.rs index 283a73d931d7..d156ebe2bd6d 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/rpc.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/rpc.rs @@ -24,10 +24,7 @@ use crate::{ }; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; use parachains_common::{AccountId, Balance, Block, Nonce}; -use sc_rpc::{ - dev::{Dev, DevApiServer}, - DenyUnsafe, -}; +use sc_rpc::dev::{Dev, DevApiServer}; use std::{marker::PhantomData, sync::Arc}; use substrate_frame_rpc_system::{System, SystemApiServer}; use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer}; @@ -37,7 +34,6 @@ pub type RpcExtension = jsonrpsee::RpcModule<()>; pub(crate) trait BuildRpcExtensions { fn build_rpc_extensions( - deny_unsafe: DenyUnsafe, client: Arc, backend: Arc, pool: Arc, @@ -56,7 +52,6 @@ where RuntimeApi: ConstructNodeRuntimeApi> + Send + Sync + 'static, { fn build_rpc_extensions( - _deny_unsafe: DenyUnsafe, _client: Arc>, _backend: Arc, _pool: Arc>>, @@ -79,7 +74,6 @@ where + substrate_frame_rpc_system::AccountNonceApi, { fn build_rpc_extensions( - deny_unsafe: DenyUnsafe, client: Arc>, backend: Arc, pool: Arc>>, @@ -87,10 +81,10 @@ where let build = || -> Result> { let mut module = RpcExtension::new(()); - module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; + module.merge(System::new(client.clone(), pool).into_rpc())?; module.merge(TransactionPayment::new(client.clone()).into_rpc())?; - module.merge(StateMigration::new(client.clone(), backend, deny_unsafe).into_rpc())?; - module.merge(Dev::new(client, deny_unsafe).into_rpc())?; + module.merge(StateMigration::new(client.clone(), backend).into_rpc())?; + module.merge(Dev::new(client).into_rpc())?; Ok(module) }; diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/service.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/service.rs index 3b9ae6bd4457..057b8af9af52 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/service.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/service.rs @@ -281,9 +281,8 @@ pub(crate) trait NodeSpec { let transaction_pool = transaction_pool.clone(); let backend_for_rpc = backend.clone(); - Box::new(move |deny_unsafe, _| { + Box::new(move |_| { Self::BuildRpcExtensions::build_rpc_extensions( - deny_unsafe, client.clone(), backend_for_rpc.clone(), transaction_pool.clone(), @@ -837,11 +836,13 @@ where }, }; - let fut = - async move { - wait_for_aura(client).await; - aura::run_with_export::::Pair, _, _, _, _, _, _, _, _>(params).await; - }; + let fut = async move { + wait_for_aura(client).await; + aura::run_with_export::::Pair, _, _, _, _, _, _, _, _>( + params, + ) + .await; + }; task_manager.spawn_essential_handle().spawn("aura", None, fut); Ok(()) diff --git a/cumulus/test/service/src/cli.rs b/cumulus/test/service/src/cli.rs index 37ca27542cbf..739c2d4bda16 100644 --- a/cumulus/test/service/src/cli.rs +++ b/cumulus/test/service/src/cli.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use std::{net::SocketAddr, path::PathBuf}; +use std::path::PathBuf; use cumulus_client_cli::{ExportGenesisHeadCommand, ExportGenesisWasmCommand}; use polkadot_service::{ChainSpec, ParaId, PrometheusConfig}; use sc_cli::{ CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, - Result as CliResult, SharedParams, SubstrateCli, + Result as CliResult, RpcEndpoint, SharedParams, SubstrateCli, }; use sc_service::BasePath; @@ -122,7 +122,7 @@ impl CliConfiguration for RelayChainCli { .or_else(|| self.base_path.clone().map(Into::into))) } - fn rpc_addr(&self, default_listen_port: u16) -> CliResult> { + fn rpc_addr(&self, default_listen_port: u16) -> CliResult>> { self.base.base.rpc_addr(default_listen_port) } diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 503c2f24fd54..bc0fe9090d38 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -38,7 +38,7 @@ use sp_consensus_aura::sr25519::AuthorityPair; use std::{ collections::HashSet, future::Future, - net::{IpAddr, Ipv4Addr, SocketAddr}, + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, time::Duration, }; use url::Url; @@ -79,7 +79,7 @@ use sc_network::{ use sc_service::{ config::{ BlocksPruning, DatabaseSource, KeystoreConfig, MultiaddrWithPeerId, NetworkConfiguration, - OffchainWorkerConfig, PruningMode, RpcBatchRequestConfig, WasmExecutionMethod, + OffchainWorkerConfig, PruningMode, RpcBatchRequestConfig, RpcEndpoint, WasmExecutionMethod, }, BasePath, ChainSpec as ChainSpecService, Configuration, Error as ServiceError, PartialComponents, Role, RpcHandlers, TFullBackend, TFullClient, TaskManager, @@ -379,7 +379,7 @@ where let keystore = params.keystore_container.keystore(); let rpc_builder = { let client = client.clone(); - Box::new(move |_, _| rpc_ext_builder(client.clone())) + Box::new(move |_| rpc_ext_builder(client.clone())) }; let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { @@ -1006,7 +1006,22 @@ pub fn run_relay_chain_validator_node( ); if let Some(port) = port { - config.rpc_addr = Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port)); + config.rpc_addr = Some(vec![RpcEndpoint { + batch_config: config.rpc_batch_config, + cors: config.rpc_cors.clone(), + listen_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, port)), + max_connections: config.rpc_max_connections, + max_payload_in_mb: config.rpc_max_request_size, + max_payload_out_mb: config.rpc_max_response_size, + max_subscriptions_per_connection: config.rpc_max_subs_per_conn, + max_buffer_capacity_per_connection: config.rpc_message_buffer_capacity, + rpc_methods: config.rpc_methods, + rate_limit: config.rpc_rate_limit, + rate_limit_trust_proxy_headers: config.rpc_rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips: config.rpc_rate_limit_whitelisted_ips.clone(), + retry_random_port: true, + is_optional: false, + }]); } let mut workers_path = std::env::current_exe().unwrap(); diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index e1f42e1ca86a..a907d310c105 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -486,7 +486,6 @@ fn new_partial( sc_transaction_pool::FullPool, ( impl Fn( - polkadot_rpc::DenyUnsafe, polkadot_rpc::SubscriptionTaskExecutor, ) -> Result, ( @@ -593,15 +592,13 @@ where let chain_spec = config.chain_spec.cloned_box(); let backend = backend.clone(); - move |deny_unsafe, - subscription_executor: polkadot_rpc::SubscriptionTaskExecutor| + move |subscription_executor: polkadot_rpc::SubscriptionTaskExecutor| -> Result { let deps = polkadot_rpc::FullDeps { client: client.clone(), pool: transaction_pool.clone(), select_chain: select_chain.clone(), chain_spec: chain_spec.cloned_box(), - deny_unsafe, babe: polkadot_rpc::BabeDeps { babe_worker_handle: babe_worker_handle.clone(), keystore: keystore.clone(), diff --git a/polkadot/rpc/src/lib.rs b/polkadot/rpc/src/lib.rs index eb0133b6e8fd..0007df908e2b 100644 --- a/polkadot/rpc/src/lib.rs +++ b/polkadot/rpc/src/lib.rs @@ -27,7 +27,7 @@ use sc_consensus_beefy::communication::notification::{ BeefyBestBlockStream, BeefyVersionedFinalityProofStream, }; use sc_consensus_grandpa::FinalityProofProvider; -pub use sc_rpc::{DenyUnsafe, SubscriptionTaskExecutor}; +pub use sc_rpc::SubscriptionTaskExecutor; use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; use sp_application_crypto::RuntimeAppPublic; @@ -83,8 +83,6 @@ pub struct FullDeps { pub select_chain: SC, /// A copy of the chain spec. pub chain_spec: Box, - /// Whether to deny unsafe calls - pub deny_unsafe: DenyUnsafe, /// BABE specific dependencies. pub babe: BabeDeps, /// GRANDPA specific dependencies. @@ -97,7 +95,13 @@ pub struct FullDeps { /// Instantiate all RPC extensions. pub fn create_full( - FullDeps { client, pool, select_chain, chain_spec, deny_unsafe, babe, grandpa, beefy, backend } : FullDeps, + FullDeps { client, pool, select_chain, chain_spec, babe, grandpa, beefy, backend }: FullDeps< + C, + P, + SC, + B, + AuthorityId, + >, ) -> Result> where C: ProvideRuntimeApi @@ -138,8 +142,8 @@ where finality_provider, } = grandpa; - io.merge(StateMigration::new(client.clone(), backend.clone(), deny_unsafe).into_rpc())?; - io.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; + io.merge(StateMigration::new(client.clone(), backend.clone()).into_rpc())?; + io.merge(System::new(client.clone(), pool.clone()).into_rpc())?; io.merge(TransactionPayment::new(client.clone()).into_rpc())?; io.merge( Mmr::new( @@ -151,8 +155,7 @@ where .into_rpc(), )?; io.merge( - Babe::new(client.clone(), babe_worker_handle.clone(), keystore, select_chain, deny_unsafe) - .into_rpc(), + Babe::new(client.clone(), babe_worker_handle.clone(), keystore, select_chain).into_rpc(), )?; io.merge( Grandpa::new( diff --git a/prdoc/pr_4792.prdoc b/prdoc/pr_4792.prdoc new file mode 100644 index 000000000000..5ce4303bcf75 --- /dev/null +++ b/prdoc/pr_4792.prdoc @@ -0,0 +1,62 @@ +# 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: "rpc: bind to `ipv6` if available and add `CLI --experimental-rpc-endpoint` to specify listen addr" + +doc: + - audience: Node Operator + description: | + This PR changes/adds the following: + + 1. The default setting is that substrate starts a rpc server that listens to localhost both ipv4 and ipv6 on the same port. + ipv6 is allowed to fail because some platforms may not support it + 2. A new RPC CLI option `--experimental-rpc-endpoint` is introduced which allows to configure arbitrary listen addresses including the port, + if this is enabled no other interfaces are enabled. + 3. If the local addr is not found for any of the sockets the server is not started and throws an error. + 4. Remove the deny_unsafe from the RPC implementations instead this is an extension to allow different polices for different interfaces/sockets + such one may enable unsafe on local interface and safe on only the external interface. + 5. This new `--experimental-rpc-endpoint` has several options and in the help menu all possible parameters are documented. + 6. The log emitted by jsonrpc server when it has been started has been modified to indicate all started rpc endpoints. + + So for instance it's now possible to start up three RPC endpoints as follows: + ``` + $ polkadot --experimental-rpc-endpoint "listen-addr=127.0.0.1:9944,methods=unsafe" --experimental-rpc-endpoint "listen-addr=0.0.0.0:9945,methods=safe,rate-limit=100" --experimental-rpc-endpoint "listen-addr=[::1]:9944,optional=true" + ``` + +crates: + - name: sc-rpc-server + bump: major + - name: sc-rpc + bump: major + - name: sc-cli + bump: major + - name: sc-service + bump: major + - name: sc-rpc-api + bump: patch + - name: polkadot-dispute-distribution + bump: patch + - name: polkadot-parachain-lib + bump: patch + - name: substrate-frame-rpc-system + bump: major + - name: substrate-state-trie-migration-rpc + bump: major + - name: cumulus-client-cli + bump: major + validate: false + - name: sc-consensus-beefy-rpc + bump: major + validate: false + - name: sc-consensus-grandpa-rpc + bump: major + validate: false + - name: sc-consensus-babe-rpc + bump: major + validate: false + - name: polkadot-rpc + bump: major + validate: false + - name: polkadot-service + bump: major + validate: false diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index d45713db5222..8fdcc7261b55 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -177,7 +177,6 @@ pub fn new_partial( sc_transaction_pool::FullPool, ( impl Fn( - node_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor, ) -> Result, sc_service::Error>, ( @@ -318,13 +317,12 @@ pub fn new_partial( let rpc_backend = backend.clone(); let rpc_statement_store = statement_store.clone(); let rpc_extensions_builder = - move |deny_unsafe, subscription_executor: node_rpc::SubscriptionTaskExecutor| { + move |subscription_executor: node_rpc::SubscriptionTaskExecutor| { let deps = node_rpc::FullDeps { client: client.clone(), pool: pool.clone(), select_chain: select_chain.clone(), chain_spec: chain_spec.cloned_box(), - deny_unsafe, babe: node_rpc::BabeDeps { keystore: keystore.clone(), babe_worker_handle: babe_worker_handle.clone(), diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index d85998e3c87b..02f5d9a4a702 100644 --- a/substrate/bin/node/rpc/Cargo.toml +++ b/substrate/bin/node/rpc/Cargo.toml @@ -31,7 +31,6 @@ sc-consensus-grandpa = { workspace = true, default-features = true } sc-consensus-grandpa-rpc = { workspace = true, default-features = true } sc-mixnet = { workspace = true, default-features = true } sc-rpc = { workspace = true, default-features = true } -sc-rpc-api = { workspace = true, default-features = true } sc-sync-state-rpc = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } diff --git a/substrate/bin/node/rpc/src/lib.rs b/substrate/bin/node/rpc/src/lib.rs index c55e03ee9d6f..988502bb2bfd 100644 --- a/substrate/bin/node/rpc/src/lib.rs +++ b/substrate/bin/node/rpc/src/lib.rs @@ -44,7 +44,6 @@ use sc_consensus_grandpa::{ FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState, }; pub use sc_rpc::SubscriptionTaskExecutor; -pub use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; use sp_application_crypto::RuntimeAppPublic; @@ -97,8 +96,6 @@ pub struct FullDeps { pub select_chain: SC, /// A copy of the chain spec. pub chain_spec: Box, - /// Whether to deny unsafe calls - pub deny_unsafe: DenyUnsafe, /// BABE specific dependencies. pub babe: BabeDeps, /// GRANDPA specific dependencies. @@ -120,7 +117,6 @@ pub fn create_full( pool, select_chain, chain_spec, - deny_unsafe, babe, grandpa, beefy, @@ -175,7 +171,7 @@ where finality_provider, } = grandpa; - io.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; + io.merge(System::new(client.clone(), pool).into_rpc())?; // Making synchronous calls in light client freezes the browser currently, // more context: https://github.com/paritytech/substrate/pull/3480 // These RPCs should use an asynchronous caller instead. @@ -190,8 +186,7 @@ where )?; io.merge(TransactionPayment::new(client.clone()).into_rpc())?; io.merge( - Babe::new(client.clone(), babe_worker_handle.clone(), keystore, select_chain, deny_unsafe) - .into_rpc(), + Babe::new(client.clone(), babe_worker_handle.clone(), keystore, select_chain).into_rpc(), )?; io.merge( Grandpa::new( @@ -209,10 +204,9 @@ where .into_rpc(), )?; - io.merge(StateMigration::new(client.clone(), backend, deny_unsafe).into_rpc())?; - io.merge(Dev::new(client, deny_unsafe).into_rpc())?; - let statement_store = - sc_rpc::statement::StatementStore::new(statement_store, deny_unsafe).into_rpc(); + io.merge(StateMigration::new(client.clone(), backend).into_rpc())?; + io.merge(Dev::new(client).into_rpc())?; + let statement_store = sc_rpc::statement::StatementStore::new(statement_store).into_rpc(); io.merge(statement_store)?; if let Some(mixnet_api) = mixnet_api { diff --git a/substrate/client/cli/src/arg_enums.rs b/substrate/client/cli/src/arg_enums.rs index b5819d03447a..cd245dc01554 100644 --- a/substrate/client/cli/src/arg_enums.rs +++ b/substrate/client/cli/src/arg_enums.rs @@ -168,6 +168,19 @@ pub enum RpcMethods { Unsafe, } +impl FromStr for RpcMethods { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "safe" => Ok(RpcMethods::Safe), + "unsafe" => Ok(RpcMethods::Unsafe), + "auto" => Ok(RpcMethods::Auto), + invalid => Err(format!("Invalid rpc methods {invalid}")), + } + } +} + impl Into for RpcMethods { fn into(self) -> sc_service::config::RpcMethods { match self { diff --git a/substrate/client/cli/src/commands/run_cmd.rs b/substrate/client/cli/src/commands/run_cmd.rs index c1288b502c95..7245b46e2f7d 100644 --- a/substrate/client/cli/src/commands/run_cmd.rs +++ b/substrate/client/cli/src/commands/run_cmd.rs @@ -20,8 +20,8 @@ use crate::{ arg_enums::{Cors, RpcMethods}, error::{Error, Result}, params::{ - ImportParams, KeystoreParams, NetworkParams, OffchainWorkerParams, SharedParams, - TransactionPoolParams, + ImportParams, KeystoreParams, NetworkParams, OffchainWorkerParams, RpcEndpoint, + SharedParams, TransactionPoolParams, }, CliConfiguration, PrometheusParams, RuntimeParams, TelemetryParams, RPC_DEFAULT_MAX_CONNECTIONS, RPC_DEFAULT_MAX_REQUEST_SIZE_MB, RPC_DEFAULT_MAX_RESPONSE_SIZE_MB, @@ -37,7 +37,7 @@ use sc_service::{ }; use sc_telemetry::TelemetryEndpoints; use std::{ - net::{IpAddr, Ipv4Addr, SocketAddr}, + net::{Ipv4Addr, Ipv6Addr, SocketAddr}, num::NonZeroU32, }; @@ -128,6 +128,47 @@ pub struct RunCmd { #[arg(long, value_name = "PORT")] pub rpc_port: Option, + /// EXPERIMENTAL: Specify the JSON-RPC server interface and this option which can be enabled + /// several times if you want expose several RPC interfaces with different configurations. + /// + /// The format for this option is: + /// `--experimental-rpc-endpoint" listen-addr=,,..."` where each option is + /// separated by a comma and `listen-addr` is the only required param. + /// + /// The following options are available: + /// • listen-addr: The socket address (ip:port) to listen on. Be careful to not expose the + /// server to the public internet unless you know what you're doing. (required) + /// • disable-batch-requests: Disable batch requests (optional) + /// • max-connections: The maximum number of concurrent connections that the server will + /// accept (optional) + /// • max-request-size: The maximum size of a request body in megabytes (optional) + /// • max-response-size: The maximum size of a response body in megabytes (optional) + /// • max-subscriptions-per-connection: The maximum number of subscriptions per connection + /// (optional) + /// • max-buffer-capacity-per-connection: The maximum buffer capacity per connection + /// (optional) + /// • max-batch-request-len: The maximum number of requests in a batch (optional) + /// • cors: The CORS allowed origins, this can enabled more than once (optional) + /// • methods: Which RPC methods to allow, valid values are "safe", "unsafe" and "auto" + /// (optional) + /// • optional: If the listen address is optional i.e the interface is not required to be + /// available For example this may be useful if some platforms doesn't support ipv6 + /// (optional) + /// • rate-limit: The rate limit in calls per minute for each connection (optional) + /// • rate-limit-trust-proxy-headers: Trust proxy headers for disable rate limiting (optional) + /// • rate-limit-whitelisted-ips: Disable rate limiting for certain ip addresses, this can be + /// enabled more than once (optional) • retry-random-port: If the port is already in use, + /// retry with a random port (optional) + /// + /// Use with care, this flag is unstable and subject to change. + #[arg( + long, + num_args = 1.., + verbatim_doc_comment, + conflicts_with_all = &["rpc_external", "unsafe_rpc_external", "rpc_port", "rpc_cors", "rpc_rate_limit_trust_proxy_headers", "rpc_rate_limit", "rpc_rate_limit_whitelisted_ips", "rpc_message_buffer_capacity_per_connection", "rpc_disable_batch_requests", "rpc_max_subscriptions_per_connection", "rpc_max_request_size", "rpc_max_response_size"] + )] + pub experimental_rpc_endpoint: Vec, + /// Maximum number of RPC server connections. #[arg(long, value_name = "COUNT", default_value_t = RPC_DEFAULT_MAX_CONNECTIONS)] pub rpc_max_connections: u32, @@ -410,15 +451,68 @@ impl CliConfiguration for RunCmd { .into()) } - fn rpc_addr(&self, default_listen_port: u16) -> Result> { - let interface = rpc_interface( + fn rpc_addr(&self, default_listen_port: u16) -> Result>> { + if !self.experimental_rpc_endpoint.is_empty() { + for endpoint in &self.experimental_rpc_endpoint { + // Technically, `0.0.0.0` isn't a public IP address, but it's a way to listen on + // all interfaces. Thus, we consider it as a public endpoint and warn about it. + if endpoint.rpc_methods == RpcMethods::Unsafe && endpoint.is_global() || + endpoint.listen_addr.ip().is_unspecified() + { + log::warn!( + "It isn't safe to expose RPC publicly without a proxy server that filters \ + available set of RPC methods." + ); + } + } + + return Ok(Some(self.experimental_rpc_endpoint.clone())); + } + + let (ipv4, ipv6) = rpc_interface( self.rpc_external, self.unsafe_rpc_external, self.rpc_methods, self.validator, )?; - Ok(Some(SocketAddr::new(interface, self.rpc_port.unwrap_or(default_listen_port)))) + let cors = self.rpc_cors(self.is_dev()?)?; + let port = self.rpc_port.unwrap_or(default_listen_port); + + Ok(Some(vec![ + RpcEndpoint { + batch_config: self.rpc_batch_config()?, + max_connections: self.rpc_max_connections, + listen_addr: SocketAddr::new(std::net::IpAddr::V4(ipv4), port), + rpc_methods: self.rpc_methods, + rate_limit: self.rpc_rate_limit, + rate_limit_trust_proxy_headers: self.rpc_rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips: self.rpc_rate_limit_whitelisted_ips.clone(), + max_payload_in_mb: self.rpc_max_request_size, + max_payload_out_mb: self.rpc_max_response_size, + max_subscriptions_per_connection: self.rpc_max_subscriptions_per_connection, + max_buffer_capacity_per_connection: self.rpc_message_buffer_capacity_per_connection, + cors: cors.clone(), + retry_random_port: true, + is_optional: false, + }, + RpcEndpoint { + batch_config: self.rpc_batch_config()?, + max_connections: self.rpc_max_connections, + listen_addr: SocketAddr::new(std::net::IpAddr::V6(ipv6), port), + rpc_methods: self.rpc_methods, + rate_limit: self.rpc_rate_limit, + rate_limit_trust_proxy_headers: self.rpc_rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips: self.rpc_rate_limit_whitelisted_ips.clone(), + max_payload_in_mb: self.rpc_max_request_size, + max_payload_out_mb: self.rpc_max_response_size, + max_subscriptions_per_connection: self.rpc_max_subscriptions_per_connection, + max_buffer_capacity_per_connection: self.rpc_message_buffer_capacity_per_connection, + cors: cors.clone(), + retry_random_port: true, + is_optional: true, + }, + ])) } fn rpc_methods(&self) -> Result { @@ -523,7 +617,7 @@ fn rpc_interface( is_unsafe_external: bool, rpc_methods: RpcMethods, is_validator: bool, -) -> Result { +) -> Result<(Ipv4Addr, Ipv6Addr)> { if is_external && is_validator && rpc_methods != RpcMethods::Unsafe { return Err(Error::Input( "--rpc-external option shouldn't be used if the node is running as \ @@ -541,9 +635,9 @@ fn rpc_interface( ); } - Ok(Ipv4Addr::UNSPECIFIED.into()) + Ok((Ipv4Addr::UNSPECIFIED, Ipv6Addr::UNSPECIFIED)) } else { - Ok(Ipv4Addr::LOCALHOST.into()) + Ok((Ipv4Addr::LOCALHOST, Ipv6Addr::LOCALHOST)) } } diff --git a/substrate/client/cli/src/config.rs b/substrate/client/cli/src/config.rs index 406d1fb264dd..7c2358477611 100644 --- a/substrate/client/cli/src/config.rs +++ b/substrate/client/cli/src/config.rs @@ -20,7 +20,8 @@ use crate::{ arg_enums::Database, error::Result, DatabaseParams, ImportParams, KeystoreParams, - NetworkParams, NodeKeyParams, OffchainWorkerParams, PruningParams, SharedParams, SubstrateCli, + NetworkParams, NodeKeyParams, OffchainWorkerParams, PruningParams, RpcEndpoint, SharedParams, + SubstrateCli, }; use log::warn; use names::{Generator, Name}; @@ -34,7 +35,7 @@ use sc_service::{ BlocksPruning, ChainSpec, TracingReceiver, }; use sc_tracing::logging::LoggerBuilder; -use std::{net::SocketAddr, num::NonZeroU32, path::PathBuf}; +use std::{num::NonZeroU32, path::PathBuf}; /// The maximum number of characters for a node name. pub(crate) const NODE_NAME_MAX_LENGTH: usize = 64; @@ -301,7 +302,7 @@ pub trait CliConfiguration: Sized { } /// Get the RPC address. - fn rpc_addr(&self, _default_listen_port: u16) -> Result> { + fn rpc_addr(&self, _default_listen_port: u16) -> Result>> { Ok(None) } @@ -504,6 +505,10 @@ pub trait CliConfiguration: Sized { let telemetry_endpoints = self.telemetry_endpoints(&chain_spec)?; let runtime_cache_size = self.runtime_cache_size()?; + let rpc_addrs: Option> = self + .rpc_addr(DCV::rpc_listen_port())? + .map(|addrs| addrs.into_iter().map(Into::into).collect()); + Ok(Configuration { impl_name: C::impl_name(), impl_version: C::impl_version(), @@ -527,7 +532,7 @@ pub trait CliConfiguration: Sized { blocks_pruning: self.blocks_pruning()?, wasm_method: self.wasm_method()?, wasm_runtime_overrides: self.wasm_runtime_overrides(), - rpc_addr: self.rpc_addr(DCV::rpc_listen_port())?, + rpc_addr: rpc_addrs, rpc_methods: self.rpc_methods()?, rpc_max_connections: self.rpc_max_connections()?, rpc_cors: self.rpc_cors(is_dev)?, diff --git a/substrate/client/cli/src/params/mod.rs b/substrate/client/cli/src/params/mod.rs index f07223ec6a73..977b57ba0658 100644 --- a/substrate/client/cli/src/params/mod.rs +++ b/substrate/client/cli/src/params/mod.rs @@ -25,6 +25,7 @@ mod node_key_params; mod offchain_worker_params; mod prometheus_params; mod pruning_params; +mod rpc_params; mod runtime_params; mod shared_params; mod telemetry_params; @@ -32,6 +33,7 @@ mod transaction_pool_params; use crate::arg_enums::{CryptoScheme, OutputType}; use clap::Args; +use sc_service::config::{IpNetwork, RpcBatchRequestConfig}; use sp_core::crypto::{Ss58AddressFormat, Ss58AddressFormatRegistry}; use sp_runtime::{ generic::BlockId, @@ -42,7 +44,7 @@ use std::{fmt::Debug, str::FromStr}; pub use crate::params::{ database_params::*, import_params::*, keystore_params::*, message_params::*, mixnet_params::*, network_params::*, node_key_params::*, offchain_worker_params::*, prometheus_params::*, - pruning_params::*, runtime_params::*, shared_params::*, telemetry_params::*, + pruning_params::*, rpc_params::*, runtime_params::*, shared_params::*, telemetry_params::*, transaction_pool_params::*, }; diff --git a/substrate/client/cli/src/params/rpc_params.rs b/substrate/client/cli/src/params/rpc_params.rs new file mode 100644 index 000000000000..d0ec1fd00443 --- /dev/null +++ b/substrate/client/cli/src/params/rpc_params.rs @@ -0,0 +1,395 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{ + arg_enums::RpcMethods, + params::{IpNetwork, RpcBatchRequestConfig}, + RPC_DEFAULT_MAX_CONNECTIONS, RPC_DEFAULT_MAX_REQUEST_SIZE_MB, RPC_DEFAULT_MAX_RESPONSE_SIZE_MB, + RPC_DEFAULT_MAX_SUBS_PER_CONN, RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN, +}; +use std::{net::SocketAddr, num::NonZeroU32}; + +const RPC_LISTEN_ADDR: &str = "listen-addr"; +const RPC_CORS: &str = "cors"; +const RPC_MAX_CONNS: &str = "max-connections"; +const RPC_MAX_REQUEST_SIZE: &str = "max-request-size"; +const RPC_MAX_RESPONSE_SIZE: &str = "max-response-size"; +const RPC_MAX_SUBS_PER_CONN: &str = "max-subscriptions-per-connection"; +const RPC_MAX_BUF_CAP_PER_CONN: &str = "max-buffer-capacity-per-connection"; +const RPC_RATE_LIMIT: &str = "rate-limit"; +const RPC_RATE_LIMIT_TRUST_PROXY_HEADERS: &str = "rate-limit-trust-proxy-headers"; +const RPC_RATE_LIMIT_WHITELISTED_IPS: &str = "rate-limit-whitelisted-ips"; +const RPC_RETRY_RANDOM_PORT: &str = "retry-random-port"; +const RPC_METHODS: &str = "methods"; +const RPC_OPTIONAL: &str = "optional"; +const RPC_DISABLE_BATCH: &str = "disable-batch-requests"; +const RPC_BATCH_LIMIT: &str = "max-batch-request-len"; + +/// Represent a single RPC endpoint with its configuration. +#[derive(Debug, Clone)] +pub struct RpcEndpoint { + /// Listen address. + pub listen_addr: SocketAddr, + /// Batch request configuration. + pub batch_config: RpcBatchRequestConfig, + /// Maximum number of connections. + pub max_connections: u32, + /// Maximum inbound payload size in MB. + pub max_payload_in_mb: u32, + /// Maximum outbound payload size in MB. + pub max_payload_out_mb: u32, + /// Maximum number of subscriptions per connection. + pub max_subscriptions_per_connection: u32, + /// Maximum buffer capacity per connection. + pub max_buffer_capacity_per_connection: u32, + /// Rate limit per minute. + pub rate_limit: Option, + /// Whether to trust proxy headers for rate limiting. + pub rate_limit_trust_proxy_headers: bool, + /// Whitelisted IPs for rate limiting. + pub rate_limit_whitelisted_ips: Vec, + /// CORS. + pub cors: Option>, + /// RPC methods to expose. + pub rpc_methods: RpcMethods, + /// Whether it's an optional listening address i.e, it's ignored if it fails to bind. + /// For example substrate tries to bind both ipv4 and ipv6 addresses but some platforms + /// may not support ipv6. + pub is_optional: bool, + /// Whether to retry with a random port if the provided port is already in use. + pub retry_random_port: bool, +} + +impl std::str::FromStr for RpcEndpoint { + type Err = String; + + fn from_str(s: &str) -> Result { + let mut listen_addr = None; + let mut max_connections = None; + let mut max_payload_in_mb = None; + let mut max_payload_out_mb = None; + let mut max_subscriptions_per_connection = None; + let mut max_buffer_capacity_per_connection = None; + let mut cors: Option> = None; + let mut rpc_methods = None; + let mut is_optional = None; + let mut disable_batch_requests = None; + let mut max_batch_request_len = None; + let mut rate_limit = None; + let mut rate_limit_trust_proxy_headers = None; + let mut rate_limit_whitelisted_ips = Vec::new(); + let mut retry_random_port = None; + + for input in s.split(',') { + let (key, val) = input.trim().split_once('=').ok_or_else(|| invalid_input(input))?; + let key = key.trim(); + let val = val.trim(); + + match key { + RPC_LISTEN_ADDR => { + if listen_addr.is_some() { + return Err(only_once_err(RPC_LISTEN_ADDR)); + } + let val: SocketAddr = + val.parse().map_err(|_| invalid_value(RPC_LISTEN_ADDR, &val))?; + listen_addr = Some(val); + }, + RPC_CORS => { + if val.is_empty() { + return Err(invalid_value(RPC_CORS, &val)); + } + + if let Some(cors) = cors.as_mut() { + cors.push(val.to_string()); + } else { + cors = Some(vec![val.to_string()]); + } + }, + RPC_MAX_CONNS => { + if max_connections.is_some() { + return Err(only_once_err(RPC_MAX_CONNS)); + } + + let val = val.parse().map_err(|_| invalid_value(RPC_MAX_CONNS, &val))?; + max_connections = Some(val); + }, + RPC_MAX_REQUEST_SIZE => { + if max_payload_in_mb.is_some() { + return Err(only_once_err(RPC_MAX_REQUEST_SIZE)); + } + + let val = + val.parse().map_err(|_| invalid_value(RPC_MAX_RESPONSE_SIZE, &val))?; + max_payload_in_mb = Some(val); + }, + RPC_MAX_RESPONSE_SIZE => { + if max_payload_out_mb.is_some() { + return Err(only_once_err(RPC_MAX_RESPONSE_SIZE)); + } + + let val = + val.parse().map_err(|_| invalid_value(RPC_MAX_RESPONSE_SIZE, &val))?; + max_payload_out_mb = Some(val); + }, + RPC_MAX_SUBS_PER_CONN => { + if max_subscriptions_per_connection.is_some() { + return Err(only_once_err(RPC_MAX_SUBS_PER_CONN)); + } + + let val = + val.parse().map_err(|_| invalid_value(RPC_MAX_SUBS_PER_CONN, &val))?; + max_subscriptions_per_connection = Some(val); + }, + RPC_MAX_BUF_CAP_PER_CONN => { + if max_buffer_capacity_per_connection.is_some() { + return Err(only_once_err(RPC_MAX_BUF_CAP_PER_CONN)); + } + + let val = + val.parse().map_err(|_| invalid_value(RPC_MAX_BUF_CAP_PER_CONN, &val))?; + max_buffer_capacity_per_connection = Some(val); + }, + RPC_RATE_LIMIT => { + if rate_limit.is_some() { + return Err(only_once_err("rate-limit")); + } + + let val = val.parse().map_err(|_| invalid_value(RPC_RATE_LIMIT, &val))?; + rate_limit = Some(val); + }, + RPC_RATE_LIMIT_TRUST_PROXY_HEADERS => { + if rate_limit_trust_proxy_headers.is_some() { + return Err(only_once_err(RPC_RATE_LIMIT_TRUST_PROXY_HEADERS)); + } + + let val = val + .parse() + .map_err(|_| invalid_value(RPC_RATE_LIMIT_TRUST_PROXY_HEADERS, &val))?; + rate_limit_trust_proxy_headers = Some(val); + }, + RPC_RATE_LIMIT_WHITELISTED_IPS => { + let ip: IpNetwork = val + .parse() + .map_err(|_| invalid_value(RPC_RATE_LIMIT_WHITELISTED_IPS, &val))?; + rate_limit_whitelisted_ips.push(ip); + }, + RPC_RETRY_RANDOM_PORT => { + if retry_random_port.is_some() { + return Err(only_once_err(RPC_RETRY_RANDOM_PORT)); + } + let val = + val.parse().map_err(|_| invalid_value(RPC_RETRY_RANDOM_PORT, &val))?; + retry_random_port = Some(val); + }, + RPC_METHODS => { + if rpc_methods.is_some() { + return Err(only_once_err("methods")); + } + let val = val.parse().map_err(|_| invalid_value(RPC_METHODS, &val))?; + rpc_methods = Some(val); + }, + RPC_OPTIONAL => { + if is_optional.is_some() { + return Err(only_once_err(RPC_OPTIONAL)); + } + + let val = val.parse().map_err(|_| invalid_value(RPC_OPTIONAL, &val))?; + is_optional = Some(val); + }, + RPC_DISABLE_BATCH => { + if disable_batch_requests.is_some() { + return Err(only_once_err(RPC_DISABLE_BATCH)); + } + + let val = val.parse().map_err(|_| invalid_value(RPC_DISABLE_BATCH, &val))?; + disable_batch_requests = Some(val); + }, + RPC_BATCH_LIMIT => { + if max_batch_request_len.is_some() { + return Err(only_once_err(RPC_BATCH_LIMIT)); + } + + let val = val.parse().map_err(|_| invalid_value(RPC_BATCH_LIMIT, &val))?; + max_batch_request_len = Some(val); + }, + _ => return Err(invalid_key(key)), + } + } + + let listen_addr = listen_addr.ok_or("`listen-addr` must be specified exactly once")?; + + let batch_config = match (disable_batch_requests, max_batch_request_len) { + (Some(true), Some(_)) => { + return Err(format!("`{RPC_BATCH_LIMIT}` and `{RPC_DISABLE_BATCH}` are mutually exclusive and can't be used together")); + }, + (Some(false), None) => RpcBatchRequestConfig::Disabled, + (None, Some(len)) => RpcBatchRequestConfig::Limit(len), + _ => RpcBatchRequestConfig::Unlimited, + }; + + Ok(Self { + listen_addr, + batch_config, + max_connections: max_connections.unwrap_or(RPC_DEFAULT_MAX_CONNECTIONS), + max_payload_in_mb: max_payload_in_mb.unwrap_or(RPC_DEFAULT_MAX_REQUEST_SIZE_MB), + max_payload_out_mb: max_payload_out_mb.unwrap_or(RPC_DEFAULT_MAX_RESPONSE_SIZE_MB), + cors, + max_buffer_capacity_per_connection: max_buffer_capacity_per_connection + .unwrap_or(RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN), + max_subscriptions_per_connection: max_subscriptions_per_connection + .unwrap_or(RPC_DEFAULT_MAX_SUBS_PER_CONN), + rpc_methods: rpc_methods.unwrap_or(RpcMethods::Auto), + rate_limit, + rate_limit_trust_proxy_headers: rate_limit_trust_proxy_headers.unwrap_or(false), + rate_limit_whitelisted_ips, + is_optional: is_optional.unwrap_or(false), + retry_random_port: retry_random_port.unwrap_or(false), + }) + } +} + +impl Into for RpcEndpoint { + fn into(self) -> sc_service::config::RpcEndpoint { + sc_service::config::RpcEndpoint { + batch_config: self.batch_config, + listen_addr: self.listen_addr, + max_buffer_capacity_per_connection: self.max_buffer_capacity_per_connection, + max_connections: self.max_connections, + max_payload_in_mb: self.max_payload_in_mb, + max_payload_out_mb: self.max_payload_out_mb, + max_subscriptions_per_connection: self.max_subscriptions_per_connection, + rpc_methods: self.rpc_methods.into(), + rate_limit: self.rate_limit, + rate_limit_trust_proxy_headers: self.rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips: self.rate_limit_whitelisted_ips, + cors: self.cors, + retry_random_port: self.retry_random_port, + is_optional: self.is_optional, + } + } +} + +impl RpcEndpoint { + /// Returns whether the endpoint is globally exposed. + pub fn is_global(&self) -> bool { + let ip = IpNetwork::from(self.listen_addr.ip()); + ip.is_global() + } +} + +fn only_once_err(reason: &str) -> String { + format!("`{reason}` is only allowed be specified once") +} + +fn invalid_input(input: &str) -> String { + format!("`{input}`, expects: `key=value`") +} + +fn invalid_value(key: &str, value: &str) -> String { + format!("value=`{value}` key=`{key}`") +} + +fn invalid_key(key: &str) -> String { + format!("unknown key=`{key}`, see `--help` for available options") +} + +#[cfg(test)] +mod tests { + use super::*; + use std::{num::NonZeroU32, str::FromStr}; + + #[test] + fn parse_rpc_endpoint_works() { + assert!(RpcEndpoint::from_str("listen-addr=127.0.0.1:9944").is_ok()); + assert!(RpcEndpoint::from_str("listen-addr=[::1]:9944").is_ok()); + assert!(RpcEndpoint::from_str("listen-addr=127.0.0.1:9944,methods=auto").is_ok()); + assert!(RpcEndpoint::from_str("listen-addr=[::1]:9944,methods=auto").is_ok()); + assert!(RpcEndpoint::from_str( + "listen-addr=127.0.0.1:9944,methods=auto,cors=*,optional=true" + ) + .is_ok()); + + assert!(RpcEndpoint::from_str("listen-addrs=127.0.0.1:9944,foo=*").is_err()); + assert!(RpcEndpoint::from_str("listen-addrs=127.0.0.1:9944,cors=").is_err()); + } + + #[test] + fn parse_rpc_endpoint_all() { + let endpoint = RpcEndpoint::from_str( + "listen-addr=127.0.0.1:9944,methods=unsafe,cors=*,optional=true,retry-random-port=true,rate-limit=99,\ + max-batch-request-len=100,rate-limit-trust-proxy-headers=true,max-connections=33,max-request-size=4,\ + max-response-size=3,max-subscriptions-per-connection=7,max-buffer-capacity-per-connection=8,\ + rate-limit-whitelisted-ips=192.168.1.0/24,rate-limit-whitelisted-ips=ff01::0/32" + ).unwrap(); + assert_eq!(endpoint.listen_addr, ([127, 0, 0, 1], 9944).into()); + assert_eq!(endpoint.rpc_methods, RpcMethods::Unsafe); + assert_eq!(endpoint.cors, Some(vec!["*".to_string()])); + assert_eq!(endpoint.is_optional, true); + assert_eq!(endpoint.retry_random_port, true); + assert_eq!(endpoint.rate_limit, Some(NonZeroU32::new(99).unwrap())); + assert!(matches!(endpoint.batch_config, RpcBatchRequestConfig::Limit(l) if l == 100)); + assert_eq!(endpoint.rate_limit_trust_proxy_headers, true); + assert_eq!( + endpoint.rate_limit_whitelisted_ips, + vec![ + IpNetwork::V4("192.168.1.0/24".parse().unwrap()), + IpNetwork::V6("ff01::0/32".parse().unwrap()) + ] + ); + assert_eq!(endpoint.max_connections, 33); + assert_eq!(endpoint.max_payload_in_mb, 4); + assert_eq!(endpoint.max_payload_out_mb, 3); + assert_eq!(endpoint.max_subscriptions_per_connection, 7); + assert_eq!(endpoint.max_buffer_capacity_per_connection, 8); + } + + #[test] + fn parse_rpc_endpoint_multiple_cors() { + let addr = RpcEndpoint::from_str( + "listen-addr=127.0.0.1:9944,methods=auto,cors=https://polkadot.js.org,cors=*,cors=localhost:*", + ) + .unwrap(); + + assert_eq!( + addr.cors, + Some(vec![ + "https://polkadot.js.org".to_string(), + "*".to_string(), + "localhost:*".to_string() + ]) + ); + } + + #[test] + fn parse_rpc_endpoint_whitespaces() { + let addr = RpcEndpoint::from_str( + " listen-addr = 127.0.0.1:9944, methods = auto, optional = true ", + ) + .unwrap(); + assert_eq!(addr.rpc_methods, RpcMethods::Auto); + assert_eq!(addr.is_optional, true); + } + + #[test] + fn parse_rpc_endpoint_batch_options_mutually_exclusive() { + assert!(RpcEndpoint::from_str( + "listen-addr = 127.0.0.1:9944,disable-batch-requests=true,max-batch-request-len=100", + ) + .is_err()); + } +} diff --git a/substrate/client/consensus/babe/rpc/src/lib.rs b/substrate/client/consensus/babe/rpc/src/lib.rs index a3e811baecff..338d71a43256 100644 --- a/substrate/client/consensus/babe/rpc/src/lib.rs +++ b/substrate/client/consensus/babe/rpc/src/lib.rs @@ -25,12 +25,13 @@ use jsonrpsee::{ core::async_trait, proc_macros::rpc, types::{ErrorObject, ErrorObjectOwned}, + Extensions, }; use serde::{Deserialize, Serialize}; use sc_consensus_babe::{authorship, BabeWorkerHandle}; use sc_consensus_epochs::Epoch as EpochT; -use sc_rpc_api::{DenyUnsafe, UnsafeRpcError}; +use sc_rpc_api::{check_if_safe, UnsafeRpcError}; use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppCrypto; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; @@ -47,7 +48,7 @@ const BABE_ERROR: i32 = 9000; 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")] + #[method(name = "babe_epochAuthorship", with_extensions)] async fn epoch_authorship(&self) -> Result, Error>; } @@ -61,8 +62,6 @@ pub struct Babe { keystore: KeystorePtr, /// The SelectChain strategy select_chain: SC, - /// Whether to deny unsafe calls - deny_unsafe: DenyUnsafe, } impl Babe { @@ -72,9 +71,8 @@ impl Babe { babe_worker_handle: BabeWorkerHandle, keystore: KeystorePtr, select_chain: SC, - deny_unsafe: DenyUnsafe, ) -> Self { - Self { client, babe_worker_handle, keystore, select_chain, deny_unsafe } + Self { client, babe_worker_handle, keystore, select_chain } } } @@ -89,8 +87,11 @@ where C::Api: BabeRuntimeApi, SC: SelectChain + Clone + 'static, { - async fn epoch_authorship(&self) -> Result, Error> { - self.deny_unsafe.check_if_safe()?; + async fn epoch_authorship( + &self, + ext: &Extensions, + ) -> Result, Error> { + check_if_safe(ext)?; let best_header = self.select_chain.best_chain().map_err(Error::SelectChain).await?; @@ -193,6 +194,7 @@ impl From for ErrorObjectOwned { mod tests { use super::*; use sc_consensus_babe::ImportQueueParams; + use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::{OffchainTransactionPoolFactory, RejectAllTxPool}; use sp_consensus_babe::inherents::InherentDataProvider; use sp_core::{crypto::key_types::BABE, testing::TaskExecutor}; @@ -211,9 +213,8 @@ mod tests { keystore.into() } - fn test_babe_rpc_module( - deny_unsafe: DenyUnsafe, - ) -> Babe> { + fn test_babe_rpc_module() -> Babe> + { let builder = TestClientBuilder::new(); let (client, longest_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); @@ -248,29 +249,31 @@ mod tests { }) .unwrap(); - Babe::new(client.clone(), babe_worker_handle, keystore, longest_chain, deny_unsafe) + Babe::new(client.clone(), babe_worker_handle, keystore, longest_chain) } #[tokio::test] async fn epoch_authorship_works() { - let babe_rpc = test_babe_rpc_module(DenyUnsafe::No); - let api = babe_rpc.into_rpc(); + let babe_rpc = test_babe_rpc_module(); + let mut api = babe_rpc.into_rpc(); + api.extensions_mut().insert(DenyUnsafe::No); - let request = r#"{"jsonrpc":"2.0","method":"babe_epochAuthorship","params": [],"id":1}"#; + let request = r#"{"jsonrpc":"2.0","id":1,"method":"babe_epochAuthorship","params":[]}"#; let (response, _) = api.raw_json_request(request, 1).await.unwrap(); - let expected = r#"{"jsonrpc":"2.0","result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[],"secondary_vrf":[1,2,4]}},"id":1}"#; + let expected = r#"{"jsonrpc":"2.0","id":1,"result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[],"secondary_vrf":[1,2,4]}}}"#; assert_eq!(response, expected); } #[tokio::test] async fn epoch_authorship_is_unsafe() { - let babe_rpc = test_babe_rpc_module(DenyUnsafe::Yes); - let api = babe_rpc.into_rpc(); + let babe_rpc = test_babe_rpc_module(); + let mut api = babe_rpc.into_rpc(); + api.extensions_mut().insert(DenyUnsafe::Yes); let request = r#"{"jsonrpc":"2.0","method":"babe_epochAuthorship","params":[],"id":1}"#; 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}"#; + let expected = r#"{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"RPC call is unsafe to be called externally"}}"#; assert_eq!(response, expected); } diff --git a/substrate/client/consensus/beefy/rpc/src/lib.rs b/substrate/client/consensus/beefy/rpc/src/lib.rs index 83477d223dd2..ab58f6866275 100644 --- a/substrate/client/consensus/beefy/rpc/src/lib.rs +++ b/substrate/client/consensus/beefy/rpc/src/lib.rs @@ -201,7 +201,7 @@ mod tests { async fn uninitialized_rpc_handler() { 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}"#; + let expected_response = r#"{"jsonrpc":"2.0","id":1,"error":{"code":1,"message":"BEEFY RPC endpoint not ready"}}"#; let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); assert_eq!(expected_response, response); @@ -220,13 +220,13 @@ mod tests { let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#; let expected = "{\ \"jsonrpc\":\"2.0\",\ - \"result\":\"0x2f0039e93a27221fcf657fb877a1d4f60307106113e885096cb44a461cd0afbf\",\ - \"id\":1\ + \"id\":1,\ + \"result\":\"0x2f0039e93a27221fcf657fb877a1d4f60307106113e885096cb44a461cd0afbf\"\ }"; - let not_ready = "{\ + let not_ready: &str = "{\ \"jsonrpc\":\"2.0\",\ - \"error\":{\"code\":1,\"message\":\"BEEFY RPC endpoint not ready\"},\ - \"id\":1\ + \"id\":1,\ + \"error\":{\"code\":1,\"message\":\"BEEFY RPC endpoint not ready\"}\ }"; let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2); @@ -262,7 +262,7 @@ mod tests { ) .await .unwrap(); - let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; + let expected = r#"{"jsonrpc":"2.0","id":1,"result":false}"#; assert_eq!(response, expected); } diff --git a/substrate/client/consensus/grandpa/rpc/src/lib.rs b/substrate/client/consensus/grandpa/rpc/src/lib.rs index a41b14299089..99f98b81261a 100644 --- a/substrate/client/consensus/grandpa/rpc/src/lib.rs +++ b/substrate/client/consensus/grandpa/rpc/src/lib.rs @@ -275,7 +275,7 @@ mod tests { #[tokio::test] async fn uninitialized_rpc_handler() { 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 expected_response = r#"{"jsonrpc":"2.0","id":0,"error":{"code":1,"message":"GRANDPA RPC endpoint not ready"}}"#.to_string(); let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); @@ -285,7 +285,7 @@ mod tests { #[tokio::test] async fn working_rpc_handler() { let (rpc, _) = setup_io_handler(TestVoterState); - let expected_response = "{\"jsonrpc\":\"2.0\",\"result\":{\ + let expected_response = "{\"jsonrpc\":\"2.0\",\"id\":0,\"result\":{\ \"setId\":1,\ \"best\":{\ \"round\":2,\"totalWeight\":100,\"thresholdWeight\":67,\ @@ -297,7 +297,7 @@ mod tests { \"prevotes\":{\"currentWeight\":100,\"missing\":[]},\ \"precommits\":{\"currentWeight\":100,\"missing\":[]}\ }]\ - },\"id\":0}".to_string(); + }}".to_string(); let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); @@ -321,7 +321,7 @@ mod tests { ) .await .unwrap(); - let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; + let expected = r#"{"jsonrpc":"2.0","id":1,"result":false}"#; assert_eq!(response, expected); } diff --git a/substrate/client/rpc-api/src/author/mod.rs b/substrate/client/rpc-api/src/author/mod.rs index cfc56f4130ab..c39d6c68355a 100644 --- a/substrate/client/rpc-api/src/author/mod.rs +++ b/substrate/client/rpc-api/src/author/mod.rs @@ -34,11 +34,11 @@ pub trait AuthorApi { async fn submit_extrinsic(&self, extrinsic: Bytes) -> Result; /// Insert a key into the keystore. - #[method(name = "author_insertKey")] + #[method(name = "author_insertKey", with_extensions)] 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")] + #[method(name = "author_rotateKeys", with_extensions)] fn rotate_keys(&self) -> Result; /// Checks if the keystore has private keys for the given session public keys. @@ -46,13 +46,13 @@ pub trait AuthorApi { /// `session_keys` is the SCALE encoded session keys object from the runtime. /// /// Returns `true` iff all private keys could be found. - #[method(name = "author_hasSessionKeys")] + #[method(name = "author_hasSessionKeys", with_extensions)] 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")] + #[method(name = "author_hasKey", with_extensions)] fn has_key(&self, public_key: Bytes, key_type: String) -> Result; /// Returns all pending extrinsics, potentially grouped by sender. @@ -60,7 +60,7 @@ pub trait AuthorApi { fn pending_extrinsics(&self) -> Result, Error>; /// Remove given extrinsic from the pool and temporarily ban it to prevent reimporting. - #[method(name = "author_removeExtrinsic")] + #[method(name = "author_removeExtrinsic", with_extensions)] fn remove_extrinsic( &self, bytes_or_hash: Vec>, diff --git a/substrate/client/rpc-api/src/dev/mod.rs b/substrate/client/rpc-api/src/dev/mod.rs index 5bee6df73ba9..5c6208ff5d50 100644 --- a/substrate/client/rpc-api/src/dev/mod.rs +++ b/substrate/client/rpc-api/src/dev/mod.rs @@ -59,6 +59,6 @@ pub trait DevApi { /// This function requires the specified block and its parent to be available /// at the queried node. If either the specified block or the parent is pruned, /// this function will return `None`. - #[method(name = "dev_getBlockStats")] + #[method(name = "dev_getBlockStats", with_extensions)] 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 451ebdf7fc00..cc580fc0e7ca 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, UnsafeRpcError}; +pub use policy::{check_if_safe, DenyUnsafe, UnsafeRpcError}; pub mod author; pub mod chain; diff --git a/substrate/client/rpc-api/src/offchain/mod.rs b/substrate/client/rpc-api/src/offchain/mod.rs index 469e22d2b3fa..4dd5b066d49f 100644 --- a/substrate/client/rpc-api/src/offchain/mod.rs +++ b/substrate/client/rpc-api/src/offchain/mod.rs @@ -28,10 +28,10 @@ use sp_core::{offchain::StorageKind, Bytes}; #[rpc(client, server)] pub trait OffchainApi { /// Set offchain local storage under given key and prefix. - #[method(name = "offchain_localStorageSet")] + #[method(name = "offchain_localStorageSet", with_extensions)] 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")] + #[method(name = "offchain_localStorageGet", with_extensions)] 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 c0847de89d2c..7e0657db8d17 100644 --- a/substrate/client/rpc-api/src/policy.rs +++ b/substrate/client/rpc-api/src/policy.rs @@ -23,6 +23,15 @@ use jsonrpsee::types::{error::ErrorCode, ErrorObject, ErrorObjectOwned}; +/// Checks if the RPC call is safe to be called externally. +pub fn check_if_safe(ext: &jsonrpsee::Extensions) -> Result<(), UnsafeRpcError> { + match ext.get::().map(|deny_unsafe| deny_unsafe.check_if_safe()) { + Some(Ok(())) => Ok(()), + Some(Err(e)) => Err(e), + None => unreachable!("DenyUnsafe extension is always set by the substrate rpc server; qed"), + } +} + /// Signifies whether a potentially unsafe RPC should be denied. #[derive(Clone, Copy, Debug)] pub enum DenyUnsafe { diff --git a/substrate/client/rpc-api/src/state/mod.rs b/substrate/client/rpc-api/src/state/mod.rs index e38e383c4c15..ee62387b6bd4 100644 --- a/substrate/client/rpc-api/src/state/mod.rs +++ b/substrate/client/rpc-api/src/state/mod.rs @@ -48,7 +48,7 @@ pub trait StateApi { ) -> Result, Error>; /// Returns the keys with prefix, leave empty to get all the keys - #[method(name = "state_getPairs", blocking)] + #[method(name = "state_getPairs", blocking, with_extensions)] fn storage_pairs( &self, prefix: StorageKey, @@ -76,7 +76,7 @@ pub trait StateApi { 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"])] + #[method(name = "state_getStorageSize", aliases = ["state_getStorageSizeAt"], with_extensions)] async fn storage_size(&self, key: StorageKey, hash: Option) -> Result, Error>; @@ -95,7 +95,7 @@ pub trait StateApi { /// Subsequent values in the vector represent changes to the previous state (diffs). /// WARNING: The time complexity of this query is O(|keys|*dist(block, hash)), and the /// memory complexity is O(dist(block, hash)) -- use with caution. - #[method(name = "state_queryStorage", blocking)] + #[method(name = "state_queryStorage", blocking, with_extensions)] fn query_storage( &self, keys: Vec, @@ -136,6 +136,7 @@ pub trait StateApi { name = "state_subscribeStorage" => "state_storage", unsubscribe = "state_unsubscribeStorage", item = StorageChangeSet, + with_extensions, )] fn subscribe_storage(&self, keys: Option>); @@ -291,7 +292,7 @@ pub trait StateApi { /// /// If you are having issues with maximum payload size you can use the flag /// `-ltracing=trace` to get some logging during tracing. - #[method(name = "state_traceBlock", blocking)] + #[method(name = "state_traceBlock", blocking, with_extensions)] fn trace_block( &self, block: Hash, diff --git a/substrate/client/rpc-api/src/statement/mod.rs b/substrate/client/rpc-api/src/statement/mod.rs index 39ec52cbea01..eee58f506e16 100644 --- a/substrate/client/rpc-api/src/statement/mod.rs +++ b/substrate/client/rpc-api/src/statement/mod.rs @@ -27,7 +27,7 @@ pub mod error; #[rpc(client, server)] pub trait StatementApi { /// Return all statements, SCALE-encoded. - #[method(name = "statement_dump")] + #[method(name = "statement_dump", with_extensions)] fn dump(&self) -> RpcResult>; /// Return the data of all known statements which include all topics and have no `DecryptionKey` diff --git a/substrate/client/rpc-api/src/system/mod.rs b/substrate/client/rpc-api/src/system/mod.rs index c38fa8f3d817..2d6d48e1ddb4 100644 --- a/substrate/client/rpc-api/src/system/mod.rs +++ b/substrate/client/rpc-api/src/system/mod.rs @@ -69,7 +69,7 @@ pub trait SystemApi { async fn system_local_listen_addresses(&self) -> Result, Error>; /// Returns currently connected peers - #[method(name = "system_peers")] + #[method(name = "system_peers", with_extensions)] async fn system_peers(&self) -> Result>, Error>; /// Returns current state of the network. @@ -78,7 +78,7 @@ pub trait SystemApi { /// as its format might change at any time. // 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")] + #[method(name = "system_unstable_networkState", with_extensions)] async fn system_network_state(&self) -> Result; /// Adds a reserved peer. Returns the empty string or an error. The string @@ -86,12 +86,12 @@ 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")] + #[method(name = "system_addReservedPeer", with_extensions)] 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")] + #[method(name = "system_removeReservedPeer", with_extensions)] async fn system_remove_reserved_peer(&self, peer_id: String) -> Result<(), Error>; /// Returns the list of reserved peers @@ -112,10 +112,10 @@ pub trait SystemApi { /// The syntax is identical to the CLI `=`: /// /// `sync=debug,state=trace` - #[method(name = "system_addLogFilter")] + #[method(name = "system_addLogFilter", with_extensions)] fn system_add_log_filter(&self, directives: String) -> Result<(), Error>; /// Resets the log filter to Substrate defaults - #[method(name = "system_resetLogFilter")] + #[method(name = "system_resetLogFilter", with_extensions)] 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 7e3d3bf55b74..b39c3fdda67c 100644 --- a/substrate/client/rpc-servers/Cargo.toml +++ b/substrate/client/rpc-servers/Cargo.toml @@ -16,21 +16,20 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +dyn-clone = { workspace = true } forwarded-header-value = { workspace = true } futures = { workspace = true } governor = { workspace = true } http = { workspace = true } http-body-util = { workspace = true } +hyper = { workspace = true } ip_network = { workspace = true } jsonrpsee = { features = ["server"], workspace = true } log = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } +sc-rpc-api = { workspace = true } serde = { workspace = true } serde_json = { workspace = true, default-features = true } tokio = { features = ["parking_lot"], workspace = true, default-features = true } tower = { workspace = true, features = ["util"] } tower-http = { workspace = true, features = ["cors"] } - -# Dependencies outside the polkadot-sdk workspace -# which requires hyper v1 -hyper = "1.3" diff --git a/substrate/client/rpc-servers/src/lib.rs b/substrate/client/rpc-servers/src/lib.rs index 0bae16b113df..ca74c2371c25 100644 --- a/substrate/client/rpc-servers/src/lib.rs +++ b/substrate/client/rpc-servers/src/lib.rs @@ -23,246 +23,255 @@ pub mod middleware; pub mod utils; -use std::{error::Error as StdError, net::SocketAddr, num::NonZeroU32, sync::Arc, time::Duration}; +use std::{error::Error as StdError, time::Duration}; use jsonrpsee::{ core::BoxError, - server::{ - serve_with_graceful_shutdown, stop_channel, ws, PingConfig, StopHandle, TowerServiceBuilder, - }, + server::{serve_with_graceful_shutdown, stop_channel, ws, PingConfig, StopHandle}, Methods, RpcModule, }; use middleware::NodeHealthProxyLayer; -use tokio::net::TcpListener; use tower::Service; -use utils::{build_rpc_api, format_cors, get_proxy_ip, host_filtering, try_into_cors}; +use utils::{ + build_rpc_api, deny_unsafe, format_listen_addrs, get_proxy_ip, ListenAddrError, RpcSettings, +}; pub use ip_network::IpNetwork; pub use jsonrpsee::{ - core::{ - id_providers::{RandomIntegerIdProvider, RandomStringIdProvider}, - traits::IdProvider, - }, + core::id_providers::{RandomIntegerIdProvider, RandomStringIdProvider}, server::{middleware::rpc::RpcServiceBuilder, BatchRequestConfig}, }; pub use middleware::{Metrics, MiddlewareLayer, RpcMetrics}; +pub use utils::{RpcEndpoint, RpcMethods}; const MEGABYTE: u32 = 1024 * 1024; /// Type alias for the JSON-RPC server. pub type Server = jsonrpsee::server::ServerHandle; +/// Trait for providing subscription IDs that can be cloned. +pub trait SubscriptionIdProvider: + jsonrpsee::core::traits::IdProvider + dyn_clone::DynClone +{ +} + +dyn_clone::clone_trait_object!(SubscriptionIdProvider); + /// RPC server configuration. #[derive(Debug)] -pub struct Config<'a, M: Send + Sync + 'static> { - /// Socket addresses. - pub addrs: [SocketAddr; 2], - /// CORS. - pub cors: Option<&'a Vec>, - /// Maximum connections. - pub max_connections: u32, - /// Maximum subscriptions per connection. - pub max_subs_per_conn: u32, - /// Maximum rpc request payload size. - pub max_payload_in_mb: u32, - /// Maximum rpc response payload size. - pub max_payload_out_mb: u32, +pub struct Config { + /// RPC interfaces to start. + pub endpoints: Vec, /// Metrics. pub metrics: Option, - /// Message buffer size - pub message_buffer_capacity: u32, /// RPC API. pub rpc_api: RpcModule, /// Subscription ID provider. - pub id_provider: Option>, + pub id_provider: Option>, /// Tokio runtime handle. pub tokio_handle: tokio::runtime::Handle, - /// Batch request config. - pub batch_config: BatchRequestConfig, - /// Rate limit calls per minute. - pub rate_limit: Option, - /// Disable rate limit for certain ips. - pub rate_limit_whitelisted_ips: Vec, - /// Trust proxy headers for rate limiting. - pub rate_limit_trust_proxy_headers: bool, } #[derive(Debug, Clone)] -struct PerConnection { +struct PerConnection { methods: Methods, stop_handle: StopHandle, metrics: Option, tokio_handle: tokio::runtime::Handle, - service_builder: TowerServiceBuilder, - rate_limit_whitelisted_ips: Arc>, } /// Start RPC server listening on given address. -pub async fn start_server( - config: Config<'_, M>, -) -> Result> +pub async fn start_server(config: Config) -> Result> where M: Send + Sync, { - let Config { - addrs, - batch_config, - cors, - max_payload_in_mb, - max_payload_out_mb, - max_connections, - max_subs_per_conn, - metrics, - message_buffer_capacity, - id_provider, - tokio_handle, - rpc_api, - rate_limit, - rate_limit_whitelisted_ips, - rate_limit_trust_proxy_headers, - } = config; - - let listener = TcpListener::bind(addrs.as_slice()).await?; - let local_addr = listener.local_addr().ok(); - let host_filter = host_filtering(cors.is_some(), local_addr); - - let http_middleware = tower::ServiceBuilder::new() - .option_layer(host_filter) - // Proxy `GET /health, /health/readiness` requests to the internal `system_health` method. - .layer(NodeHealthProxyLayer::default()) - .layer(try_into_cors(cors)?); - - 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) - .enable_ws_ping( - PingConfig::new() - .ping_interval(Duration::from_secs(30)) - .inactive_limit(Duration::from_secs(60)) - .max_failures(3), - ) - .set_http_middleware(http_middleware) - .set_message_buffer_capacity(message_buffer_capacity) - .set_batch_request_config(batch_config) - .custom_tokio_runtime(tokio_handle.clone()); - - if let Some(provider) = id_provider { - builder = builder.set_id_provider(provider); - } else { - builder = builder.set_id_provider(RandomStringIdProvider::new(16)); - }; + let Config { endpoints, metrics, tokio_handle, rpc_api, id_provider } = config; let (stop_handle, server_handle) = stop_channel(); let cfg = PerConnection { methods: build_rpc_api(rpc_api).into(), - service_builder: builder.to_service_builder(), metrics, tokio_handle: tokio_handle.clone(), stop_handle, - rate_limit_whitelisted_ips: Arc::new(rate_limit_whitelisted_ips), }; - tokio_handle.spawn(async move { - loop { - let (sock, remote_addr) = tokio::select! { - res = listener.accept() => { - match res { - Ok(s) => s, - Err(e) => { - log::debug!(target: "rpc", "Failed to accept ipv4 connection: {:?}", e); - continue; + let mut local_addrs = Vec::new(); + + for endpoint in endpoints { + let allowed_to_fail = endpoint.is_optional; + let local_addr = endpoint.listen_addr; + + let mut listener = match endpoint.bind().await { + Ok(l) => l, + Err(e) if allowed_to_fail => { + log::debug!(target: "rpc", "JSON-RPC server failed to bind optional address: {:?}, error: {:?}", local_addr, e); + continue; + }, + Err(e) => return Err(e), + }; + let local_addr = listener.local_addr(); + local_addrs.push(local_addr); + let cfg = cfg.clone(); + + let mut id_provider2 = id_provider.clone(); + + tokio_handle.spawn(async move { + loop { + let (sock, remote_addr, rpc_cfg) = tokio::select! { + res = listener.accept() => { + match res { + Ok(s) => s, + Err(e) => { + log::debug!(target: "rpc", "Failed to accept connection: {:?}", e); + continue; + } } } - } - _ = cfg.stop_handle.clone().shutdown() => break, - }; - - let ip = remote_addr.ip(); - let cfg2 = cfg.clone(); - let svc = tower::service_fn(move |req: http::Request| { - let PerConnection { - methods, - service_builder, - metrics, - tokio_handle, - stop_handle, - rate_limit_whitelisted_ips, - } = cfg2.clone(); - - let proxy_ip = - if rate_limit_trust_proxy_headers { get_proxy_ip(&req) } else { None }; - - let rate_limit_cfg = if rate_limit_whitelisted_ips - .iter() - .any(|ips| ips.contains(proxy_ip.unwrap_or(ip))) - { - log::debug!(target: "rpc", "ip={ip}, proxy_ip={:?} is trusted, disabling rate-limit", proxy_ip); - None - } else { - if !rate_limit_whitelisted_ips.is_empty() { - log::debug!(target: "rpc", "ip={ip}, proxy_ip={:?} is not trusted, rate-limit enabled", proxy_ip); - } - rate_limit + _ = cfg.stop_handle.clone().shutdown() => break, }; - let is_websocket = ws::is_upgrade_request(&req); - let transport_label = if is_websocket { "ws" } else { "http" }; - - let middleware_layer = match (metrics, rate_limit_cfg) { - (None, None) => None, - (Some(metrics), None) => Some( - MiddlewareLayer::new().with_metrics(Metrics::new(metrics, transport_label)), - ), - (None, Some(rate_limit)) => - Some(MiddlewareLayer::new().with_rate_limit_per_minute(rate_limit)), - (Some(metrics), Some(rate_limit)) => Some( - MiddlewareLayer::new() - .with_metrics(Metrics::new(metrics, transport_label)) - .with_rate_limit_per_minute(rate_limit), - ), + let RpcSettings { + batch_config, + max_connections, + max_payload_in_mb, + max_payload_out_mb, + max_buffer_capacity_per_connection, + max_subscriptions_per_connection, + rpc_methods, + rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips, + host_filter, + cors, + rate_limit, + } = rpc_cfg; + + let http_middleware = tower::ServiceBuilder::new() + .option_layer(host_filter) + // Proxy `GET /health, /health/readiness` requests to the internal + // `system_health` method. + .layer(NodeHealthProxyLayer::default()) + .layer(cors); + + 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_subscriptions_per_connection) + .enable_ws_ping( + PingConfig::new() + .ping_interval(Duration::from_secs(30)) + .inactive_limit(Duration::from_secs(60)) + .max_failures(3), + ) + .set_http_middleware(http_middleware) + .set_message_buffer_capacity(max_buffer_capacity_per_connection) + .set_batch_request_config(batch_config) + .custom_tokio_runtime(cfg.tokio_handle.clone()) + .set_id_provider(RandomStringIdProvider::new(16)); + + if let Some(provider) = id_provider2.take() { + builder = builder.set_id_provider(provider); + } else { + builder = builder.set_id_provider(RandomStringIdProvider::new(16)); }; - let rpc_middleware = RpcServiceBuilder::new() - .rpc_logger(1024) - .option_layer(middleware_layer.clone()); - let mut svc = - service_builder.set_rpc_middleware(rpc_middleware).build(methods, stop_handle); - - async move { - if is_websocket { - let on_disconnect = svc.on_session_closed(); - - // Spawn a task to handle when the connection is closed. - tokio_handle.spawn(async move { - let now = std::time::Instant::now(); - middleware_layer.as_ref().map(|m| m.ws_connect()); - on_disconnect.await; - middleware_layer.as_ref().map(|m| m.ws_disconnect(now)); - }); - } - - // https://github.com/rust-lang/rust/issues/102211 the error type can't be inferred - // to be `Box` so we need to convert it to - // a concrete type as workaround. - svc.call(req).await.map_err(|e| BoxError::from(e)) - } - }); - - cfg.tokio_handle.spawn(serve_with_graceful_shutdown( - sock, - svc, - cfg.stop_handle.clone().shutdown(), - )); - } - }); - - log::info!( - "Running JSON-RPC server: addr={}, allowed origins={}", - local_addr.map_or_else(|| "unknown".to_string(), |a| a.to_string()), - format_cors(cors) - ); + let service_builder = builder.to_service_builder(); + let deny_unsafe = deny_unsafe(&local_addr, &rpc_methods); + + let ip = remote_addr.ip(); + let cfg2 = cfg.clone(); + let service_builder2 = service_builder.clone(); + + let svc = + tower::service_fn(move |mut req: http::Request| { + req.extensions_mut().insert(deny_unsafe); + + let PerConnection { methods, metrics, tokio_handle, stop_handle } = + cfg2.clone(); + let service_builder = service_builder2.clone(); + + let proxy_ip = + if rate_limit_trust_proxy_headers { get_proxy_ip(&req) } else { None }; + + let rate_limit_cfg = if rate_limit_whitelisted_ips + .iter() + .any(|ips| ips.contains(proxy_ip.unwrap_or(ip))) + { + log::debug!(target: "rpc", "ip={ip}, proxy_ip={:?} is trusted, disabling rate-limit", proxy_ip); + None + } else { + if !rate_limit_whitelisted_ips.is_empty() { + log::debug!(target: "rpc", "ip={ip}, proxy_ip={:?} is not trusted, rate-limit enabled", proxy_ip); + } + rate_limit + }; + + let is_websocket = ws::is_upgrade_request(&req); + let transport_label = if is_websocket { "ws" } else { "http" }; + + let middleware_layer = match (metrics, rate_limit_cfg) { + (None, None) => None, + (Some(metrics), None) => Some( + MiddlewareLayer::new() + .with_metrics(Metrics::new(metrics, transport_label)), + ), + (None, Some(rate_limit)) => + Some(MiddlewareLayer::new().with_rate_limit_per_minute(rate_limit)), + (Some(metrics), Some(rate_limit)) => Some( + MiddlewareLayer::new() + .with_metrics(Metrics::new(metrics, transport_label)) + .with_rate_limit_per_minute(rate_limit), + ), + }; + + let rpc_middleware = + RpcServiceBuilder::new().option_layer(middleware_layer.clone()); + let mut svc = service_builder + .set_rpc_middleware(rpc_middleware) + .build(methods, stop_handle); + + async move { + if is_websocket { + let on_disconnect = svc.on_session_closed(); + + // Spawn a task to handle when the connection is closed. + tokio_handle.spawn(async move { + let now = std::time::Instant::now(); + middleware_layer.as_ref().map(|m| m.ws_connect()); + on_disconnect.await; + middleware_layer.as_ref().map(|m| m.ws_disconnect(now)); + }); + } + + // https://github.com/rust-lang/rust/issues/102211 the error type can't be inferred + // to be `Box` so we need to + // convert it to a concrete type as workaround. + svc.call(req).await.map_err(|e| BoxError::from(e)) + } + }); + + cfg.tokio_handle.spawn(serve_with_graceful_shutdown( + sock, + svc, + cfg.stop_handle.clone().shutdown(), + )); + } + }); + } + + if local_addrs.is_empty() { + return Err(Box::new(ListenAddrError)); + } + + // The previous logging format was before + // `Running JSON-RPC server: addr=127.0.0.1:9944, allowed origins=["*"]` + // + // The new format is `Running JSON-RPC server: addr=` + // with the exception that for a single address it will be `Running JSON-RPC server: addr=addr,` + // with a trailing comma. + // + // This is to make it work with old scripts/utils that parse the logs. + log::info!("Running JSON-RPC server: addr={}", format_listen_addrs(&local_addrs)); Ok(server_handle) } diff --git a/substrate/client/rpc-servers/src/utils.rs b/substrate/client/rpc-servers/src/utils.rs index d9d943c7c1fb..5b4a4bf22b95 100644 --- a/substrate/client/rpc-servers/src/utils.rs +++ b/substrate/client/rpc-servers/src/utils.rs @@ -18,29 +18,190 @@ //! Substrate RPC server utils. +use crate::BatchRequestConfig; use std::{ error::Error as StdError, net::{IpAddr, SocketAddr}, + num::NonZeroU32, str::FromStr, }; use forwarded_header_value::ForwardedHeaderValue; use http::header::{HeaderName, HeaderValue}; +use ip_network::IpNetwork; use jsonrpsee::{server::middleware::http::HostFilterLayer, RpcModule}; +use sc_rpc_api::DenyUnsafe; use tower_http::cors::{AllowOrigin, CorsLayer}; const X_FORWARDED_FOR: HeaderName = HeaderName::from_static("x-forwarded-for"); const X_REAL_IP: HeaderName = HeaderName::from_static("x-real-ip"); const FORWARDED: HeaderName = HeaderName::from_static("forwarded"); -pub(crate) fn host_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()); +#[derive(Debug)] +pub(crate) struct ListenAddrError; +impl std::error::Error for ListenAddrError {} + +impl std::fmt::Display for ListenAddrError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "No listen address was successfully bound") + } +} + +/// Available RPC methods. +#[derive(Debug, Copy, Clone)] +pub enum RpcMethods { + /// Allow only a safe subset of RPC methods. + Safe, + /// Expose every RPC method (even potentially unsafe ones). + Unsafe, + /// Automatically determine the RPC methods based on the connection. + Auto, +} + +impl Default for RpcMethods { + fn default() -> Self { + RpcMethods::Auto + } +} + +impl FromStr for RpcMethods { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "safe" => Ok(RpcMethods::Safe), + "unsafe" => Ok(RpcMethods::Unsafe), + "auto" => Ok(RpcMethods::Auto), + invalid => Err(format!("Invalid rpc methods {invalid}")), + } + } +} + +#[derive(Debug, Clone)] +pub(crate) struct RpcSettings { + pub(crate) batch_config: BatchRequestConfig, + pub(crate) max_connections: u32, + pub(crate) max_payload_in_mb: u32, + pub(crate) max_payload_out_mb: u32, + pub(crate) max_subscriptions_per_connection: u32, + pub(crate) max_buffer_capacity_per_connection: u32, + pub(crate) rpc_methods: RpcMethods, + pub(crate) rate_limit: Option, + pub(crate) rate_limit_trust_proxy_headers: bool, + pub(crate) rate_limit_whitelisted_ips: Vec, + pub(crate) cors: CorsLayer, + pub(crate) host_filter: Option, +} + +/// Represent a single RPC endpoint with its configuration. +#[derive(Debug, Clone)] +pub struct RpcEndpoint { + /// Listen address. + pub listen_addr: SocketAddr, + /// Batch request configuration. + pub batch_config: BatchRequestConfig, + /// Maximum number of connections. + pub max_connections: u32, + /// Maximum inbound payload size in MB. + pub max_payload_in_mb: u32, + /// Maximum outbound payload size in MB. + pub max_payload_out_mb: u32, + /// Maximum number of subscriptions per connection. + pub max_subscriptions_per_connection: u32, + /// Maximum buffer capacity per connection. + pub max_buffer_capacity_per_connection: u32, + /// Rate limit per minute. + pub rate_limit: Option, + /// Whether to trust proxy headers for rate limiting. + pub rate_limit_trust_proxy_headers: bool, + /// Whitelisted IPs for rate limiting. + pub rate_limit_whitelisted_ips: Vec, + /// CORS. + pub cors: Option>, + /// RPC methods to expose. + pub rpc_methods: RpcMethods, + /// Whether it's an optional listening address i.e, it's ignored if it fails to bind. + /// For example substrate tries to bind both ipv4 and ipv6 addresses but some platforms + /// may not support ipv6. + pub is_optional: bool, + /// Whether to retry with a random port if the provided port is already in use. + pub retry_random_port: bool, +} + +impl RpcEndpoint { + /// Binds to the listen address. + pub(crate) async fn bind(self) -> Result> { + let listener = match tokio::net::TcpListener::bind(self.listen_addr).await { + Ok(listener) => listener, + Err(_) if self.retry_random_port => { + let mut addr = self.listen_addr; + addr.set_port(0); + + tokio::net::TcpListener::bind(addr).await? + }, + Err(e) => return Err(e.into()), + }; + let local_addr = listener.local_addr()?; + let host_filter = host_filtering(self.cors.is_some(), local_addr); + let cors = try_into_cors(self.cors)?; + + Ok(Listener { + listener, + local_addr, + cfg: RpcSettings { + batch_config: self.batch_config, + max_connections: self.max_connections, + max_payload_in_mb: self.max_payload_in_mb, + max_payload_out_mb: self.max_payload_out_mb, + max_subscriptions_per_connection: self.max_subscriptions_per_connection, + max_buffer_capacity_per_connection: self.max_buffer_capacity_per_connection, + rpc_methods: self.rpc_methods, + rate_limit: self.rate_limit, + rate_limit_trust_proxy_headers: self.rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips: self.rate_limit_whitelisted_ips, + host_filter, + cors, + }, + }) + } +} + +/// TCP socket server with RPC settings. +pub(crate) struct Listener { + listener: tokio::net::TcpListener, + local_addr: SocketAddr, + cfg: RpcSettings, +} + +impl Listener { + /// Accepts a new connection. + pub(crate) async fn accept( + &mut self, + ) -> std::io::Result<(tokio::net::TcpStream, SocketAddr, RpcSettings)> { + let (sock, remote_addr) = self.listener.accept().await?; + Ok((sock, remote_addr, self.cfg.clone())) + } + + /// Returns the local address the listener is bound to. + pub fn local_addr(&self) -> SocketAddr { + self.local_addr + } +} + +pub(crate) fn host_filtering(enabled: bool, addr: SocketAddr) -> Option { if enabled { // NOTE: The listening addresses are whitelisted by default. - let hosts = - [format!("localhost:{port}"), format!("127.0.0.1:{port}"), format!("[::1]:{port}")]; + + let mut hosts = Vec::new(); + + if addr.is_ipv4() { + hosts.push(format!("localhost:{}", addr.port())); + hosts.push(format!("127.0.0.1:{}", addr.port())); + } else { + hosts.push(format!("[::1]:{}", addr.port())); + } + Some(HostFilterLayer::new(hosts).expect("Valid hosts; qed")) } else { None @@ -65,13 +226,15 @@ pub(crate) fn build_rpc_api(mut rpc_api: RpcModule) } pub(crate) fn try_into_cors( - maybe_cors: Option<&Vec>, + maybe_cors: Option>, ) -> Result> { if let Some(cors) = maybe_cors { let mut list = Vec::new(); + for origin in cors { - list.push(HeaderValue::from_str(origin)?); + list.push(HeaderValue::from_str(&origin)?) } + Ok(CorsLayer::new().allow_origin(AllowOrigin::list(list))) } else { // allow all cors @@ -79,14 +242,6 @@ pub(crate) fn try_into_cors( } } -pub(crate) fn format_cors(maybe_cors: Option<&Vec>) -> String { - if let Some(cors) = maybe_cors { - format!("{:?}", cors) - } else { - format!("{:?}", ["*"]) - } -} - /// Extracts the IP addr from the HTTP request. /// /// It is extracted in the following order: @@ -126,6 +281,34 @@ pub(crate) fn get_proxy_ip(req: &http::Request) -> Option { None } +/// Get the `deny_unsafe` setting based on the address and the RPC methods exposed by the interface. +pub fn deny_unsafe(addr: &SocketAddr, methods: &RpcMethods) -> DenyUnsafe { + match (addr.ip().is_loopback(), methods) { + | (_, RpcMethods::Unsafe) | (false, RpcMethods::Auto) => DenyUnsafe::No, + _ => DenyUnsafe::Yes, + } +} + +pub(crate) fn format_listen_addrs(addr: &[SocketAddr]) -> String { + let mut s = String::new(); + + let mut it = addr.iter().peekable(); + + while let Some(addr) = it.next() { + s.push_str(&addr.to_string()); + + if it.peek().is_some() { + s.push(','); + } + } + + if addr.len() == 1 { + s.push(','); + } + + s +} + #[cfg(test)] mod tests { use super::*; diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index 1ec7895e3088..ae21895de38d 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { features = ["client-core", "macros", "server-core"], workspace = true } +jsonrpsee = { workspace = true, features = ["client-core", "macros", "server-core"] } # Internal chain structures for "chain_spec". sc-chain-spec = { workspace = true, default-features = true } # Pool for submitting extrinsics required by "transaction" @@ -45,7 +45,7 @@ rand = { workspace = true, default-features = true } schnellru = { workspace = true } [dev-dependencies] -jsonrpsee = { features = ["server", "ws-client"], workspace = true } +jsonrpsee = { workspace = true, features = ["server", "ws-client"] } serde_json = { workspace = true, default-features = true } tokio = { features = ["macros"], workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index 4a8f4b3ec630..6fe28a3873e9 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -43,7 +43,6 @@ sp-statement-store = { workspace = true, default-features = true } tokio = { workspace = true, default-features = true } [dev-dependencies] -sp-tracing = { workspace = true } assert_matches = { workspace = true } sc-block-builder = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } @@ -55,7 +54,6 @@ tokio = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } substrate-test-runtime-client = { workspace = true } pretty_assertions = { workspace = true } -tracing-subscriber = { features = ["env-filter"], workspace = true } [features] test-helpers = [] diff --git a/substrate/client/rpc/src/author/mod.rs b/substrate/client/rpc/src/author/mod.rs index 2fc21a238bc9..731f4df2f6f3 100644 --- a/substrate/client/rpc/src/author/mod.rs +++ b/substrate/client/rpc/src/author/mod.rs @@ -30,8 +30,8 @@ use crate::{ use codec::{Decode, Encode}; use futures::TryFutureExt; -use jsonrpsee::{core::async_trait, types::ErrorObject, PendingSubscriptionSink}; -use sc_rpc_api::DenyUnsafe; +use jsonrpsee::{core::async_trait, types::ErrorObject, Extensions, PendingSubscriptionSink}; +use sc_rpc_api::check_if_safe; use sc_transaction_pool_api::{ error::IntoPoolError, BlockHash, InPoolTransaction, TransactionFor, TransactionPool, TransactionSource, TxHash, @@ -55,8 +55,6 @@ pub struct Author { pool: Arc

, /// The key store. keystore: KeystorePtr, - /// Whether to deny unsafe calls - deny_unsafe: DenyUnsafe, /// Executor to spawn subscriptions. executor: SubscriptionTaskExecutor, } @@ -67,10 +65,9 @@ impl Author { client: Arc, pool: Arc

, keystore: KeystorePtr, - deny_unsafe: DenyUnsafe, executor: SubscriptionTaskExecutor, ) -> Self { - Author { client, pool, keystore, deny_unsafe, executor } + Author { client, pool, keystore, executor } } } @@ -104,8 +101,14 @@ where }) } - fn insert_key(&self, key_type: String, suri: String, public: Bytes) -> Result<()> { - self.deny_unsafe.check_if_safe()?; + fn insert_key( + &self, + ext: &Extensions, + key_type: String, + suri: String, + public: Bytes, + ) -> Result<()> { + check_if_safe(ext)?; let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?; self.keystore @@ -114,8 +117,8 @@ where Ok(()) } - fn rotate_keys(&self) -> Result { - self.deny_unsafe.check_if_safe()?; + fn rotate_keys(&self, ext: &Extensions) -> Result { + check_if_safe(ext)?; let best_block_hash = self.client.info().best_hash; let mut runtime_api = self.client.runtime_api(); @@ -128,8 +131,8 @@ where .map_err(|api_err| Error::Client(Box::new(api_err)).into()) } - fn has_session_keys(&self, session_keys: Bytes) -> Result { - self.deny_unsafe.check_if_safe()?; + fn has_session_keys(&self, ext: &Extensions, session_keys: Bytes) -> Result { + check_if_safe(ext)?; let best_block_hash = self.client.info().best_hash; let keys = self @@ -142,8 +145,8 @@ where Ok(self.keystore.has_keys(&keys)) } - fn has_key(&self, public_key: Bytes, key_type: String) -> Result { - self.deny_unsafe.check_if_safe()?; + fn has_key(&self, ext: &Extensions, public_key: Bytes, key_type: String) -> Result { + check_if_safe(ext)?; let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?; Ok(self.keystore.has_keys(&[(public_key.to_vec(), key_type)])) @@ -155,9 +158,10 @@ where fn remove_extrinsic( &self, + ext: &Extensions, bytes_or_hash: Vec>>, ) -> Result>> { - self.deny_unsafe.check_if_safe()?; + check_if_safe(ext)?; let hashes = bytes_or_hash .into_iter() .map(|x| match x { diff --git a/substrate/client/rpc/src/author/tests.rs b/substrate/client/rpc/src/author/tests.rs index 6bcb3e7863c0..bde60960eaf4 100644 --- a/substrate/client/rpc/src/author/tests.rs +++ b/substrate/client/rpc/src/author/tests.rs @@ -22,6 +22,7 @@ use crate::testing::{test_executor, timeout_secs}; use assert_matches::assert_matches; use codec::Encode; use jsonrpsee::{core::EmptyServerParams as EmptyParams, MethodsError as RpcError, RpcModule}; +use sc_rpc_api::DenyUnsafe; use sc_transaction_pool::{BasicPool, FullChainApi}; use sc_transaction_pool_api::TransactionStatus; use sp_core::{ @@ -72,26 +73,27 @@ impl Default for TestSetup { } impl TestSetup { - fn author(&self) -> Author> { - Author { + fn to_rpc(&self) -> RpcModule>> { + let mut module = Author { client: self.client.clone(), pool: self.pool.clone(), keystore: self.keystore.clone(), - deny_unsafe: DenyUnsafe::No, executor: test_executor(), } + .into_rpc(); + module.extensions_mut().insert(DenyUnsafe::No); + module } fn into_rpc() -> RpcModule>> { - Self::default().author().into_rpc() + Self::default().to_rpc() } } #[tokio::test] async fn author_submit_transaction_should_not_cause_error() { - sp_tracing::init_for_tests(); - let author = TestSetup::default().author(); - let api = author.into_rpc(); + let api = TestSetup::into_rpc(); + let xt: Bytes = uxt(AccountKeyring::Alice, 1).encode().into(); let extrinsic_hash: H256 = blake2_256(&xt).into(); let response: H256 = api.call("author_submitExtrinsic", [xt.clone()]).await.unwrap(); @@ -179,7 +181,7 @@ async fn author_should_return_pending_extrinsics() { async fn author_should_remove_extrinsics() { const METHOD: &'static str = "author_removeExtrinsic"; let setup = TestSetup::default(); - let api = setup.author().into_rpc(); + let api = setup.to_rpc(); // Submit three extrinsics, then remove two of them (will cause the third to be removed as well, // having a higher nonce) @@ -214,7 +216,7 @@ async fn author_should_remove_extrinsics() { #[tokio::test] async fn author_should_insert_key() { let setup = TestSetup::default(); - let api = setup.author().into_rpc(); + let api = setup.to_rpc(); let suri = "//Alice"; let keypair = ed25519::Pair::from_string(suri, None).expect("generates keypair"); let params: (String, String, Bytes) = ( @@ -231,7 +233,7 @@ async fn author_should_insert_key() { #[tokio::test] async fn author_should_rotate_keys() { let setup = TestSetup::default(); - let api = setup.author().into_rpc(); + let api = setup.to_rpc(); let new_pubkeys: Bytes = api.call("author_rotateKeys", EmptyParams::new()).await.unwrap(); let session_keys = @@ -244,7 +246,6 @@ async fn author_should_rotate_keys() { #[tokio::test] async fn author_has_session_keys() { - // Setup let api = TestSetup::into_rpc(); // Add a valid session key @@ -255,7 +256,7 @@ async fn author_has_session_keys() { // Add a session key in a different keystore let non_existent_pubkeys: Bytes = { - let api2 = TestSetup::default().author().into_rpc(); + let api2 = TestSetup::into_rpc(); api2.call("author_rotateKeys", EmptyParams::new()) .await .expect("Rotates the keys") @@ -279,8 +280,6 @@ async fn author_has_session_keys() { #[tokio::test] async fn author_has_key() { - sp_tracing::init_for_tests(); - let api = TestSetup::into_rpc(); let suri = "//Alice"; let alice_keypair = ed25519::Pair::from_string(suri, None).expect("Generates keypair"); diff --git a/substrate/client/rpc/src/dev/mod.rs b/substrate/client/rpc/src/dev/mod.rs index 424ef72b694e..3ccda760c3f5 100644 --- a/substrate/client/rpc/src/dev/mod.rs +++ b/substrate/client/rpc/src/dev/mod.rs @@ -22,8 +22,9 @@ #[cfg(test)] mod tests; +use jsonrpsee::Extensions; use sc_client_api::{BlockBackend, HeaderBackend}; -use sc_rpc_api::{dev::error::Error, DenyUnsafe}; +use sc_rpc_api::{check_if_safe, dev::error::Error}; use sp_api::{ApiExt, Core, ProvideRuntimeApi}; use sp_core::Encode; use sp_runtime::{ @@ -42,14 +43,13 @@ type HasherOf = <::Header as Header>::Hashing; /// The Dev API. All methods are unsafe. pub struct Dev { client: Arc, - deny_unsafe: DenyUnsafe, _phantom: PhantomData, } impl Dev { /// Create a new Dev API. - pub fn new(client: Arc, deny_unsafe: DenyUnsafe) -> Self { - Self { client, deny_unsafe, _phantom: PhantomData::default() } + pub fn new(client: Arc) -> Self { + Self { client, _phantom: PhantomData::default() } } } @@ -64,8 +64,12 @@ where + 'static, Client::Api: Core, { - fn block_stats(&self, hash: Block::Hash) -> Result, Error> { - self.deny_unsafe.check_if_safe()?; + fn block_stats( + &self, + ext: &Extensions, + hash: Block::Hash, + ) -> Result, Error> { + check_if_safe(ext)?; let block = { let block = self.client.block(hash).map_err(|e| Error::BlockQueryError(Box::new(e)))?; diff --git a/substrate/client/rpc/src/dev/tests.rs b/substrate/client/rpc/src/dev/tests.rs index 8f09d48e8a5d..ff691af7de41 100644 --- a/substrate/client/rpc/src/dev/tests.rs +++ b/substrate/client/rpc/src/dev/tests.rs @@ -17,6 +17,7 @@ // along with this program. If not, see . use super::*; +use crate::DenyUnsafe; use sc_block_builder::BlockBuilderBuilder; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; @@ -25,7 +26,8 @@ use substrate_test_runtime_client::{prelude::*, runtime::Block}; #[tokio::test] async fn block_stats_work() { let client = Arc::new(substrate_test_runtime_client::new()); - let api = >::new(client.clone(), DenyUnsafe::No).into_rpc(); + let mut api = >::new(client.clone()).into_rpc(); + api.extensions_mut().insert(DenyUnsafe::No); let block = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().genesis_hash) @@ -77,7 +79,8 @@ async fn block_stats_work() { #[tokio::test] async fn deny_unsafe_works() { let client = Arc::new(substrate_test_runtime_client::new()); - let api = >::new(client.clone(), DenyUnsafe::Yes).into_rpc(); + let mut api = >::new(client.clone()).into_rpc(); + api.extensions_mut().insert(DenyUnsafe::Yes); let block = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().genesis_hash) @@ -101,6 +104,6 @@ async fn deny_unsafe_works() { assert_eq!( resp, - r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"RPC call is unsafe to be called externally"},"id":1}"# + r#"{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"RPC call is unsafe to be called externally"}}"# ); } diff --git a/substrate/client/rpc/src/lib.rs b/substrate/client/rpc/src/lib.rs index b40d0341e321..33e4ac2f4c89 100644 --- a/substrate/client/rpc/src/lib.rs +++ b/substrate/client/rpc/src/lib.rs @@ -22,12 +22,9 @@ #![warn(missing_docs)] -pub use jsonrpsee::core::{ - id_providers::{ - RandomIntegerIdProvider as RandomIntegerSubscriptionId, - RandomStringIdProvider as RandomStringSubscriptionId, - }, - traits::IdProvider as RpcSubscriptionIdProvider, +pub use jsonrpsee::core::id_providers::{ + RandomIntegerIdProvider as RandomIntegerSubscriptionId, + RandomStringIdProvider as RandomStringSubscriptionId, }; pub use sc_rpc_api::DenyUnsafe; diff --git a/substrate/client/rpc/src/offchain/mod.rs b/substrate/client/rpc/src/offchain/mod.rs index 661673866053..af6bc1ba58c8 100644 --- a/substrate/client/rpc/src/offchain/mod.rs +++ b/substrate/client/rpc/src/offchain/mod.rs @@ -22,11 +22,11 @@ mod tests; use self::error::Error; -use jsonrpsee::core::async_trait; +use jsonrpsee::{core::async_trait, Extensions}; use parking_lot::RwLock; +use sc_rpc_api::check_if_safe; /// Re-export the API for backward compatibility. pub use sc_rpc_api::offchain::*; -use sc_rpc_api::DenyUnsafe; use sp_core::{ offchain::{OffchainStorage, StorageKind}, Bytes, @@ -38,20 +38,25 @@ use std::sync::Arc; pub struct Offchain { /// Offchain storage storage: Arc>, - deny_unsafe: DenyUnsafe, } impl Offchain { /// Create new instance of Offchain API. - pub fn new(storage: T, deny_unsafe: DenyUnsafe) -> Self { - Offchain { storage: Arc::new(RwLock::new(storage)), deny_unsafe } + pub fn new(storage: T) -> Self { + Offchain { storage: Arc::new(RwLock::new(storage)) } } } #[async_trait] impl OffchainApiServer for Offchain { - fn set_local_storage(&self, kind: StorageKind, key: Bytes, value: Bytes) -> Result<(), Error> { - self.deny_unsafe.check_if_safe()?; + fn set_local_storage( + &self, + ext: &Extensions, + kind: StorageKind, + key: Bytes, + value: Bytes, + ) -> Result<(), Error> { + check_if_safe(ext)?; let prefix = match kind { StorageKind::PERSISTENT => sp_offchain::STORAGE_PREFIX, @@ -61,8 +66,13 @@ impl OffchainApiServer for Offchain { Ok(()) } - fn get_local_storage(&self, kind: StorageKind, key: Bytes) -> Result, Error> { - self.deny_unsafe.check_if_safe()?; + fn get_local_storage( + &self, + ext: &Extensions, + kind: StorageKind, + key: Bytes, + ) -> Result, Error> { + check_if_safe(ext)?; let prefix = match kind { StorageKind::PERSISTENT => sp_offchain::STORAGE_PREFIX, diff --git a/substrate/client/rpc/src/offchain/tests.rs b/substrate/client/rpc/src/offchain/tests.rs index 7758fac7fabd..41f22c2dc964 100644 --- a/substrate/client/rpc/src/offchain/tests.rs +++ b/substrate/client/rpc/src/offchain/tests.rs @@ -17,22 +17,25 @@ // along with this program. If not, see . use super::*; +use crate::testing::{allow_unsafe, deny_unsafe}; use assert_matches::assert_matches; use sp_core::{offchain::storage::InMemOffchainStorage, Bytes}; #[test] fn local_storage_should_work() { let storage = InMemOffchainStorage::default(); - let offchain = Offchain::new(storage, DenyUnsafe::No); + let offchain = Offchain::new(storage); let key = Bytes(b"offchain_storage".to_vec()); let value = Bytes(b"offchain_value".to_vec()); + let ext = allow_unsafe(); + assert_matches!( - offchain.set_local_storage(StorageKind::PERSISTENT, key.clone(), value.clone()), + offchain.set_local_storage(&ext, StorageKind::PERSISTENT, key.clone(), value.clone()), Ok(()) ); assert_matches!( - offchain.get_local_storage(StorageKind::PERSISTENT, key), + offchain.get_local_storage(&ext, StorageKind::PERSISTENT, key), Ok(Some(ref v)) if *v == value ); } @@ -40,18 +43,20 @@ fn local_storage_should_work() { #[test] fn offchain_calls_considered_unsafe() { let storage = InMemOffchainStorage::default(); - let offchain = Offchain::new(storage, DenyUnsafe::Yes); + let offchain = Offchain::new(storage); let key = Bytes(b"offchain_storage".to_vec()); let value = Bytes(b"offchain_value".to_vec()); + let ext = deny_unsafe(); + assert_matches!( - offchain.set_local_storage(StorageKind::PERSISTENT, key.clone(), value.clone()), + offchain.set_local_storage(&ext, StorageKind::PERSISTENT, key.clone(), value.clone()), 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), + offchain.get_local_storage(&ext, StorageKind::PERSISTENT, key), 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 c9a41e25eda8..d8989b3e1bee 100644 --- a/substrate/client/rpc/src/state/mod.rs +++ b/substrate/client/rpc/src/state/mod.rs @@ -25,11 +25,11 @@ mod utils; mod tests; use crate::SubscriptionTaskExecutor; -use jsonrpsee::{core::async_trait, PendingSubscriptionSink}; +use jsonrpsee::{core::async_trait, Extensions, PendingSubscriptionSink}; use sc_client_api::{ Backend, BlockBackend, BlockchainEvents, ExecutorProvider, ProofProvider, StorageProvider, }; -use sc_rpc_api::DenyUnsafe; +use sc_rpc_api::{check_if_safe, DenyUnsafe}; use sp_api::{CallApiAt, Metadata, ProvideRuntimeApi}; use sp_blockchain::{HeaderBackend, HeaderMetadata}; use sp_core::{ @@ -164,7 +164,6 @@ where pub fn new_full( client: Arc, executor: SubscriptionTaskExecutor, - deny_unsafe: DenyUnsafe, ) -> (State, ChildState) where Block: BlockT + 'static, @@ -187,14 +186,12 @@ where let child_backend = Box::new(self::state_full::FullState::new(client.clone(), executor.clone())); let backend = Box::new(self::state_full::FullState::new(client, executor)); - (State { backend, deny_unsafe }, ChildState { backend: child_backend }) + (State { backend }, ChildState { backend: child_backend }) } /// State API with subscriptions support. pub struct State { backend: Box>, - /// Whether to deny unsafe calls - deny_unsafe: DenyUnsafe, } #[async_trait] @@ -222,10 +219,11 @@ where fn storage_pairs( &self, + ext: &Extensions, key_prefix: StorageKey, block: Option, ) -> Result, Error> { - self.deny_unsafe.check_if_safe()?; + check_if_safe(ext)?; self.backend.storage_pairs(block, key_prefix).map_err(Into::into) } @@ -262,13 +260,15 @@ where async fn storage_size( &self, + ext: &Extensions, key: StorageKey, block: Option, ) -> Result, Error> { - self.backend - .storage_size(block, key, self.deny_unsafe) - .await - .map_err(Into::into) + let deny_unsafe = ext + .get::() + .cloned() + .expect("DenyUnsafe extension is always set by the substrate rpc server; qed"); + self.backend.storage_size(block, key, deny_unsafe).await.map_err(Into::into) } fn metadata(&self, block: Option) -> Result { @@ -281,11 +281,12 @@ where fn query_storage( &self, + ext: &Extensions, keys: Vec, from: Block::Hash, to: Option, ) -> Result>, Error> { - self.deny_unsafe.check_if_safe()?; + check_if_safe(ext)?; self.backend.query_storage(from, to, keys).map_err(Into::into) } @@ -312,12 +313,13 @@ where /// Note: requires runtimes compiled with wasm tracing support, `--features with-tracing`. fn trace_block( &self, + ext: &Extensions, block: Block::Hash, targets: Option, storage_keys: Option, methods: Option, ) -> Result { - self.deny_unsafe.check_if_safe()?; + check_if_safe(ext)?; self.backend .trace_block(block, targets, storage_keys, methods) .map_err(Into::into) @@ -327,8 +329,17 @@ where self.backend.subscribe_runtime_version(pending) } - fn subscribe_storage(&self, pending: PendingSubscriptionSink, keys: Option>) { - self.backend.subscribe_storage(pending, keys, self.deny_unsafe) + fn subscribe_storage( + &self, + pending: PendingSubscriptionSink, + ext: &Extensions, + keys: Option>, + ) { + let deny_unsafe = ext + .get::() + .cloned() + .expect("DenyUnsafe extension is always set by the substrate rpc server; qed"); + self.backend.subscribe_storage(pending, keys, deny_unsafe) } } diff --git a/substrate/client/rpc/src/state/tests.rs b/substrate/client/rpc/src/state/tests.rs index 86df46f63a0f..eef795070343 100644 --- a/substrate/client/rpc/src/state/tests.rs +++ b/substrate/client/rpc/src/state/tests.rs @@ -18,12 +18,11 @@ use self::error::Error; use super::*; -use crate::testing::{test_executor, timeout_secs}; +use crate::testing::{allow_unsafe, test_executor, timeout_secs}; use assert_matches::assert_matches; use futures::executor; use jsonrpsee::{core::EmptyServerParams as EmptyParams, MethodsError as RpcError}; use sc_block_builder::BlockBuilderBuilder; -use sc_rpc_api::DenyUnsafe; use sp_consensus::BlockOrigin; use sp_core::{hash::H256, storage::ChildInfo}; use std::sync::Arc; @@ -39,14 +38,6 @@ 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"; @@ -62,8 +53,9 @@ async fn should_return_storage() { .add_extra_storage(b":map:acc2".to_vec(), vec![1, 2, 3]) .build(); let genesis_hash = client.genesis_hash(); - let (client, child) = new_full(Arc::new(client), test_executor(), DenyUnsafe::No); + let (client, child) = new_full(Arc::new(client), test_executor()); let key = StorageKey(KEY.to_vec()); + let ext = allow_unsafe(); assert_eq!( client @@ -78,11 +70,15 @@ async fn should_return_storage() { Ok(true) ); assert_eq!( - client.storage_size(key.clone(), None).await.unwrap().unwrap() as usize, + client.storage_size(&ext, key.clone(), None).await.unwrap().unwrap() as usize, VALUE.len(), ); assert_eq!( - client.storage_size(StorageKey(b":map".to_vec()), None).await.unwrap().unwrap() as usize, + client + .storage_size(&ext, StorageKey(b":map".to_vec()), None) + .await + .unwrap() + .unwrap() as usize, 2 + 3, ); assert_eq!( @@ -110,7 +106,7 @@ async fn should_return_storage_entries() { .add_extra_child_storage(&child_info, KEY2.to_vec(), CHILD_VALUE2.to_vec()) .build(); let genesis_hash = client.genesis_hash(); - let (_client, child) = new_full(Arc::new(client), test_executor(), DenyUnsafe::No); + let (_client, child) = new_full(Arc::new(client), test_executor()); let keys = &[StorageKey(KEY1.to_vec()), StorageKey(KEY2.to_vec())]; assert_eq!( @@ -141,7 +137,7 @@ async fn should_return_child_storage() { .build(), ); let genesis_hash = client.genesis_hash(); - let (_client, child) = new_full(client, test_executor(), DenyUnsafe::No); + let (_client, child) = new_full(client, test_executor()); let child_key = prefixed_storage_key(); let key = StorageKey(b"key".to_vec()); @@ -172,7 +168,7 @@ async fn should_return_child_storage_entries() { .build(), ); let genesis_hash = client.genesis_hash(); - let (_client, child) = new_full(client, test_executor(), DenyUnsafe::No); + let (_client, child) = new_full(client, test_executor()); let child_key = prefixed_storage_key(); let keys = vec![StorageKey(b"key1".to_vec()), StorageKey(b"key2".to_vec())]; @@ -203,7 +199,7 @@ async fn should_return_child_storage_entries() { async fn should_call_contract() { let client = Arc::new(substrate_test_runtime_client::new()); let genesis_hash = client.genesis_hash(); - let (client, _child) = new_full(client, test_executor(), DenyUnsafe::No); + let (client, _child) = new_full(client, test_executor()); assert_matches!( client.call("balanceOf".into(), Bytes(vec![1, 2, 3]), Some(genesis_hash).into()), @@ -213,13 +209,12 @@ async fn should_call_contract() { #[tokio::test] async fn should_notify_about_storage_changes() { - init_logger(); - let mut sub = { let client = Arc::new(substrate_test_runtime_client::new()); - let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No); + let (api, _child) = new_full(client.clone(), test_executor()); + let mut api_rpc = api.into_rpc(); + api_rpc.extensions_mut().insert(DenyUnsafe::No); - let api_rpc = api.into_rpc(); let sub = api_rpc .subscribe_unbounded("state_subscribeStorage", EmptyParams::new()) .await @@ -253,11 +248,9 @@ async fn should_notify_about_storage_changes() { #[tokio::test] async fn should_send_initial_storage_changes_and_notifications() { - init_logger(); - let mut sub = { let client = Arc::new(substrate_test_runtime_client::new()); - let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No); + let (api, _child) = new_full(client.clone(), test_executor()); let alice_balance_key = [ sp_crypto_hashing::twox_128(b"System"), @@ -270,7 +263,9 @@ async fn should_send_initial_storage_changes_and_notifications() { .cloned() .collect::>(); - let api_rpc = api.into_rpc(); + let mut api_rpc = api.into_rpc(); + api_rpc.extensions_mut().insert(DenyUnsafe::No); + let sub = api_rpc .subscribe_unbounded( "state_subscribeStorage", @@ -305,7 +300,7 @@ async fn should_send_initial_storage_changes_and_notifications() { #[tokio::test] async fn should_query_storage() { async fn run_tests(client: Arc) { - let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No); + let (api, _child) = new_full(client.clone(), test_executor()); let add_block = |index| { let mut builder = BlockBuilderBuilder::new(&*client) @@ -377,14 +372,16 @@ async fn should_query_storage() { }, ]; + let ext = allow_unsafe(); + // Query changes only up to block1 let keys = (1..6).map(|k| StorageKey(vec![k])).collect::>(); - let result = api.query_storage(keys.clone(), genesis_hash, Some(block1_hash).into()); + let result = api.query_storage(&ext, keys.clone(), genesis_hash, Some(block1_hash).into()); assert_eq!(result.unwrap(), expected); // Query all changes - let result = api.query_storage(keys.clone(), genesis_hash, None.into()); + let result = api.query_storage(&ext, keys.clone(), genesis_hash, None.into()); expected.push(StorageChangeSet { block: block2_hash, @@ -397,13 +394,13 @@ async fn should_query_storage() { assert_eq!(result.unwrap(), expected); // Query changes up to block2. - let result = api.query_storage(keys.clone(), genesis_hash, Some(block2_hash)); + let result = api.query_storage(&ext, keys.clone(), genesis_hash, Some(block2_hash)); assert_eq!(result.unwrap(), expected); // Inverted range. assert_matches!( - api.query_storage(keys.clone(), block1_hash, Some(genesis_hash)), + api.query_storage(&ext, 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() ); @@ -412,7 +409,7 @@ async fn should_query_storage() { // Invalid second hash. assert_matches!( - api.query_storage(keys.clone(), genesis_hash, Some(random_hash1)), + api.query_storage(&ext, 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 @@ -421,7 +418,7 @@ async fn should_query_storage() { // Invalid first hash with Some other hash. assert_matches!( - api.query_storage(keys.clone(), random_hash1, Some(genesis_hash)), + api.query_storage(&ext, 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 @@ -430,7 +427,7 @@ async fn should_query_storage() { // Invalid first hash with None. assert_matches!( - api.query_storage(keys.clone(), random_hash1, None), + api.query_storage(&ext, 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 @@ -439,7 +436,7 @@ async fn should_query_storage() { // Both hashes invalid. assert_matches!( - api.query_storage(keys.clone(), random_hash1, Some(random_hash2)), + api.query_storage(&ext, 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 @@ -471,7 +468,7 @@ async fn should_query_storage() { #[tokio::test] async fn should_return_runtime_version() { let client = Arc::new(substrate_test_runtime_client::new()); - let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No); + let (api, _child) = new_full(client.clone(), test_executor()); // it is basically json-encoded substrate_test_runtime_client::runtime::VERSION let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\ @@ -493,9 +490,10 @@ async fn should_return_runtime_version() { async fn should_notify_on_runtime_version_initially() { let mut sub = { let client = Arc::new(substrate_test_runtime_client::new()); - let (api, _child) = new_full(client, test_executor(), DenyUnsafe::No); + let (api, _child) = new_full(client, test_executor()); + let mut api_rpc = api.into_rpc(); + api_rpc.extensions_mut().insert(DenyUnsafe::No); - let api_rpc = api.into_rpc(); let sub = api_rpc .subscribe_unbounded("state_subscribeRuntimeVersion", EmptyParams::new()) .await @@ -518,12 +516,11 @@ 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, _child) = new_full(client, test_executor()); + let mut api_rpc = api.into_rpc(); + api_rpc.extensions_mut().insert(DenyUnsafe::Yes); - let api_rpc = api.into_rpc(); let err = api_rpc.subscribe_unbounded("state_subscribeStorage", EmptyParams::new()).await; assert_matches!(err, Err(RpcError::JsonRpc(e)) if e.message() == "RPC call is unsafe to be called externally"); } @@ -531,8 +528,9 @@ async fn wildcard_storage_subscriptions_are_rpc_unsafe() { #[tokio::test] async fn concrete_storage_subscriptions_are_rpc_safe() { 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 (api, _child) = new_full(client, test_executor()); + let mut api_rpc = api.into_rpc(); + api_rpc.extensions_mut().insert(DenyUnsafe::Yes); let key = StorageKey(STORAGE_KEY.to_vec()); let sub = api_rpc.subscribe_unbounded("state_subscribeStorage", [[key]]).await; diff --git a/substrate/client/rpc/src/statement/mod.rs b/substrate/client/rpc/src/statement/mod.rs index e99135aec38c..81aa50f73430 100644 --- a/substrate/client/rpc/src/statement/mod.rs +++ b/substrate/client/rpc/src/statement/mod.rs @@ -19,10 +19,12 @@ //! Substrate statement store API. use codec::{Decode, Encode}; -use jsonrpsee::core::{async_trait, RpcResult}; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + Extensions, +}; /// Re-export the API for backward compatibility. pub use sc_rpc_api::statement::{error::Error, StatementApiServer}; -use sc_rpc_api::DenyUnsafe; use sp_core::Bytes; use sp_statement_store::{StatementSource, SubmitResult}; use std::sync::Arc; @@ -30,23 +32,19 @@ use std::sync::Arc; /// Statement store API pub struct StatementStore { store: Arc, - deny_unsafe: DenyUnsafe, } impl StatementStore { /// Create new instance of Offchain API. - pub fn new( - store: Arc, - deny_unsafe: DenyUnsafe, - ) -> Self { - StatementStore { store, deny_unsafe } + pub fn new(store: Arc) -> Self { + StatementStore { store } } } #[async_trait] impl StatementApiServer for StatementStore { - fn dump(&self) -> RpcResult> { - self.deny_unsafe.check_if_safe()?; + fn dump(&self, ext: &Extensions) -> RpcResult> { + sc_rpc_api::check_if_safe(ext)?; let statements = self.store.statements().map_err(|e| Error::StatementStore(e.to_string()))?; diff --git a/substrate/client/rpc/src/system/mod.rs b/substrate/client/rpc/src/system/mod.rs index 8c7510c64cb5..e0752749bcbd 100644 --- a/substrate/client/rpc/src/system/mod.rs +++ b/substrate/client/rpc/src/system/mod.rs @@ -22,8 +22,11 @@ mod tests; use futures::channel::oneshot; -use jsonrpsee::core::{async_trait, JsonValue}; -use sc_rpc_api::DenyUnsafe; +use jsonrpsee::{ + core::{async_trait, JsonValue}, + Extensions, +}; +use sc_rpc_api::check_if_safe; use sc_tracing::logging; use sc_utils::mpsc::TracingUnboundedSender; use sp_runtime::traits::{self, Header as HeaderT}; @@ -35,7 +38,6 @@ pub use sc_rpc_api::system::*; pub struct System { info: SystemInfo, send_back: TracingUnboundedSender>, - deny_unsafe: DenyUnsafe, } /// Request to be processed. @@ -68,12 +70,8 @@ impl System { /// /// The `send_back` will be used to transmit some of the requests. The user is responsible for /// reading from that channel and answering the requests. - pub fn new( - info: SystemInfo, - send_back: TracingUnboundedSender>, - deny_unsafe: DenyUnsafe, - ) -> Self { - System { info, send_back, deny_unsafe } + pub fn new(info: SystemInfo, send_back: TracingUnboundedSender>) -> Self { + System { info, send_back } } } @@ -119,22 +117,23 @@ impl SystemApiServer::Number> async fn system_peers( &self, + ext: &Extensions, ) -> Result::Number>>, Error> { - self.deny_unsafe.check_if_safe()?; + check_if_safe(ext)?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::Peers(tx)); rx.await.map_err(|e| Error::Internal(e.to_string())) } - async fn system_network_state(&self) -> Result { - self.deny_unsafe.check_if_safe()?; + async fn system_network_state(&self, ext: &Extensions) -> Result { + check_if_safe(ext)?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NetworkState(tx)); rx.await.map_err(|e| Error::Internal(e.to_string())) } - async fn system_add_reserved_peer(&self, peer: String) -> Result<(), Error> { - self.deny_unsafe.check_if_safe()?; + async fn system_add_reserved_peer(&self, ext: &Extensions, peer: String) -> Result<(), Error> { + check_if_safe(ext)?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NetworkAddReservedPeer(peer, tx)); match rx.await { @@ -144,8 +143,12 @@ impl SystemApiServer::Number> } } - async fn system_remove_reserved_peer(&self, peer: String) -> Result<(), Error> { - self.deny_unsafe.check_if_safe()?; + async fn system_remove_reserved_peer( + &self, + ext: &Extensions, + peer: String, + ) -> Result<(), Error> { + check_if_safe(ext)?; let (tx, rx) = oneshot::channel(); let _ = self.send_back.unbounded_send(Request::NetworkRemoveReservedPeer(peer, tx)); match rx.await { @@ -173,15 +176,15 @@ impl SystemApiServer::Number> rx.await.map_err(|e| Error::Internal(e.to_string())) } - fn system_add_log_filter(&self, directives: String) -> Result<(), Error> { - self.deny_unsafe.check_if_safe()?; + fn system_add_log_filter(&self, ext: &Extensions, directives: String) -> Result<(), Error> { + check_if_safe(ext)?; logging::add_directives(&directives); logging::reload_filter().map_err(|e| Error::Internal(e)) } - fn system_reset_log_filter(&self) -> Result<(), Error> { - self.deny_unsafe.check_if_safe()?; + fn system_reset_log_filter(&self, ext: &Extensions) -> Result<(), Error> { + check_if_safe(ext)?; 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 03967c63523c..bfef0e429ceb 100644 --- a/substrate/client/rpc/src/system/tests.rs +++ b/substrate/client/rpc/src/system/tests.rs @@ -17,6 +17,7 @@ // along with this program. If not, see . use super::{helpers::SyncState, *}; +use crate::DenyUnsafe; use assert_matches::assert_matches; use futures::prelude::*; use jsonrpsee::{core::EmptyServerParams as EmptyParams, MethodsError as RpcError, RpcModule}; @@ -127,7 +128,7 @@ fn api>>(sync: T) -> RpcModule> { future::ready(()) })) }); - System::new( + let mut module = System::new( SystemInfo { impl_name: "testclient".into(), impl_version: "0.2.0".into(), @@ -136,9 +137,11 @@ fn api>>(sync: T) -> RpcModule> { chain_type: Default::default(), }, tx, - sc_rpc_api::DenyUnsafe::No, ) - .into_rpc() + .into_rpc(); + + module.extensions_mut().insert(DenyUnsafe::No); + module } #[tokio::test] diff --git a/substrate/client/rpc/src/testing.rs b/substrate/client/rpc/src/testing.rs index e04f80a7b9e6..990f81ba551e 100644 --- a/substrate/client/rpc/src/testing.rs +++ b/substrate/client/rpc/src/testing.rs @@ -20,6 +20,9 @@ use std::{future::Future, sync::Arc}; +use jsonrpsee::Extensions; +use sc_rpc_api::DenyUnsafe; + /// A task executor that can be used for running RPC tests. /// /// Warning: the tokio runtime must be initialized before calling this. @@ -70,3 +73,17 @@ pub fn test_executor() -> Arc { pub fn timeout_secs>(s: u64, f: F) -> tokio::time::Timeout { tokio::time::timeout(std::time::Duration::from_secs(s), f) } + +/// Helper to create an extension that denies unsafe calls. +pub fn deny_unsafe() -> Extensions { + let mut ext = Extensions::new(); + ext.insert(DenyUnsafe::Yes); + ext +} + +/// Helper to create an extension that allows unsafe calls. +pub fn allow_unsafe() -> Extensions { + let mut ext = Extensions::new(); + ext.insert(DenyUnsafe::No); + ext +} diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index d9a91e715fd5..9a6c3fde37d9 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -361,8 +361,7 @@ pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> { /// A shared transaction pool. pub transaction_pool: Arc, /// Builds additional [`RpcModule`]s that should be added to the server - pub rpc_builder: - Box Result, Error>>, + pub rpc_builder: Box Result, Error>>, /// A shared network instance. pub network: Arc, /// A Sender for RPC requests. @@ -491,9 +490,8 @@ where let rpc_id_provider = config.rpc_id_provider.take(); // jsonrpsee RPC - let gen_rpc_module = |deny_unsafe: DenyUnsafe| { + let gen_rpc_module = || { gen_rpc_module( - deny_unsafe, task_manager.spawn_handle(), client.clone(), transaction_pool.clone(), @@ -505,8 +503,14 @@ where ) }; - let rpc = start_rpc_servers(&config, gen_rpc_module, rpc_id_provider)?; - let rpc_handlers = RpcHandlers::new(Arc::new(gen_rpc_module(sc_rpc::DenyUnsafe::No)?.into())); + let rpc_server_handle = start_rpc_servers(&config, gen_rpc_module, rpc_id_provider)?; + let in_memory_rpc = { + let mut module = gen_rpc_module()?; + module.extensions_mut().insert(DenyUnsafe::No); + module + }; + + let in_memory_rpc_handle = RpcHandlers::new(Arc::new(in_memory_rpc)); // Spawn informant task spawn_handle.spawn( @@ -515,9 +519,9 @@ where sc_informant::build(client.clone(), network, sync_service.clone()), ); - task_manager.keep_alive((config.base_path, rpc)); + task_manager.keep_alive((config.base_path, rpc_server_handle)); - Ok(rpc_handlers) + Ok(in_memory_rpc_handle) } /// Returns a future that forwards imported transactions to the transaction networking protocol. @@ -590,7 +594,6 @@ where /// Generate RPC module using provided configuration pub fn gen_rpc_module( - deny_unsafe: DenyUnsafe, spawn_handle: SpawnTaskHandle, client: Arc, transaction_pool: Arc, @@ -598,7 +601,7 @@ pub fn gen_rpc_module( system_rpc_tx: TracingUnboundedSender>, config: &Configuration, backend: Arc, - rpc_builder: &(dyn Fn(DenyUnsafe, SubscriptionTaskExecutor) -> Result, Error>), + rpc_builder: &(dyn Fn(SubscriptionTaskExecutor) -> Result, Error>), ) -> Result, Error> where TBl: BlockT, @@ -633,8 +636,7 @@ where let (chain, state, child_state) = { let chain = sc_rpc::chain::new_full(client.clone(), task_executor.clone()).into_rpc(); - let (state, child_state) = - sc_rpc::state::new_full(client.clone(), task_executor.clone(), deny_unsafe); + let (state, child_state) = sc_rpc::state::new_full(client.clone(), task_executor.clone()); let state = state.into_rpc(); let child_state = child_state.into_rpc(); @@ -698,15 +700,14 @@ where client.clone(), transaction_pool, keystore, - deny_unsafe, task_executor.clone(), ) .into_rpc(); - let system = sc_rpc::system::System::new(system_info, system_rpc_tx, deny_unsafe).into_rpc(); + let system = sc_rpc::system::System::new(system_info, system_rpc_tx).into_rpc(); if let Some(storage) = backend.offchain_storage() { - let offchain = sc_rpc::offchain::Offchain::new(storage, deny_unsafe).into_rpc(); + let offchain = sc_rpc::offchain::Offchain::new(storage).into_rpc(); rpc_api.merge(offchain).map_err(|e| Error::Application(e.into()))?; } @@ -726,7 +727,7 @@ where rpc_api.merge(state).map_err(|e| Error::Application(e.into()))?; rpc_api.merge(child_state).map_err(|e| Error::Application(e.into()))?; // Additional [`RpcModule`]s defined in the node to fit the specific blockchain - let extra_rpcs = rpc_builder(deny_unsafe, task_executor.clone())?; + let extra_rpcs = rpc_builder(task_executor.clone())?; rpc_api.merge(extra_rpcs).map_err(|e| Error::Application(e.into()))?; Ok(rpc_api) diff --git a/substrate/client/service/src/config.rs b/substrate/client/service/src/config.rs index f8d8511f2718..8387f818e68b 100644 --- a/substrate/client/service/src/config.rs +++ b/substrate/client/service/src/config.rs @@ -33,7 +33,9 @@ pub use sc_network::{ }, Multiaddr, }; -pub use sc_rpc_server::IpNetwork; +pub use sc_rpc_server::{ + IpNetwork, RpcEndpoint, RpcMethods, SubscriptionIdProvider as RpcSubscriptionIdProvider, +}; pub use sc_telemetry::TelemetryEndpoints; pub use sc_transaction_pool::Options as TransactionPoolOptions; use sp_core::crypto::SecretString; @@ -82,8 +84,8 @@ pub struct Configuration { /// over on-chain runtimes when the spec version matches. Set to `None` to /// disable overrides (default). pub wasm_runtime_overrides: Option, - /// JSON-RPC server binding address. - pub rpc_addr: Option, + /// JSON-RPC server endpoints. + pub rpc_addr: Option>, /// Maximum number of connections for JSON-RPC server. pub rpc_max_connections: u32, /// CORS settings for HTTP & WS servers. `None` if all origins are allowed. @@ -97,7 +99,7 @@ pub struct Configuration { /// Custom JSON-RPC subscription ID provider. /// /// Default: [`crate::RandomStringSubscriptionId`]. - pub rpc_id_provider: Option>, + pub rpc_id_provider: Option>, /// Maximum allowed subscriptions per rpc connection pub rpc_max_subs_per_conn: u32, /// JSON-RPC server default port. @@ -255,24 +257,6 @@ impl Configuration { } } -/// Available RPC methods. -#[derive(Debug, Copy, Clone)] -pub enum RpcMethods { - /// Expose every RPC method only when RPC is listening on `localhost`, - /// otherwise serve only safe RPC methods. - Auto, - /// Allow only a safe subset of RPC methods. - Safe, - /// Expose every RPC method (even potentially unsafe ones). - Unsafe, -} - -impl Default for RpcMethods { - fn default() -> RpcMethods { - RpcMethods::Auto - } -} - #[static_init::dynamic(drop, lazy)] static mut BASE_PATH_TEMP: Option = None; diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index 5fb304edd7e1..9e8aed39c897 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -34,7 +34,10 @@ mod client; mod metrics; mod task_manager; -use std::{collections::HashMap, net::SocketAddr}; +use std::{ + collections::HashMap, + net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, +}; use codec::{Decode, Encode}; use futures::{pin_mut, FutureExt, StreamExt}; @@ -85,9 +88,7 @@ pub use sc_executor::NativeExecutionDispatch; pub use sc_network_sync::WarpSyncConfig; #[doc(hidden)] pub use sc_network_transactions::config::{TransactionImport, TransactionImportFuture}; -pub use sc_rpc::{ - RandomIntegerSubscriptionId, RandomStringSubscriptionId, RpcSubscriptionIdProvider, -}; +pub use sc_rpc::{RandomIntegerSubscriptionId, RandomStringSubscriptionId}; pub use sc_tracing::TracingReceiver; pub use sc_transaction_pool::Options as TransactionPoolOptions; pub use sc_transaction_pool_api::{error::IntoPoolError, InPoolTransaction, TransactionPool}; @@ -377,45 +378,64 @@ mod waiting { pub fn start_rpc_servers( config: &Configuration, gen_rpc_module: R, - rpc_id_provider: Option>, + rpc_id_provider: Option>, ) -> Result, error::Error> where - R: Fn(sc_rpc::DenyUnsafe) -> Result, Error>, + R: Fn() -> Result, Error>, { - fn deny_unsafe(addr: SocketAddr, methods: &RpcMethods) -> sc_rpc::DenyUnsafe { - let is_exposed_addr = !addr.ip().is_loopback(); - match (is_exposed_addr, methods) { - | (_, RpcMethods::Unsafe) | (false, RpcMethods::Auto) => sc_rpc::DenyUnsafe::No, - _ => sc_rpc::DenyUnsafe::Yes, - } - } - - // if binding the specified port failed then a random port is assigned by the OS. - let backup_port = |mut addr: SocketAddr| { - addr.set_port(0); - addr + let endpoints: Vec = if let Some(endpoints) = + config.rpc_addr.as_ref() + { + endpoints.clone() + } else { + let ipv6 = SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::LOCALHOST, config.rpc_port, 0, 0)); + let ipv4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, config.rpc_port)); + + vec![ + sc_rpc_server::RpcEndpoint { + batch_config: config.rpc_batch_config, + cors: config.rpc_cors.clone(), + listen_addr: ipv4, + max_buffer_capacity_per_connection: config.rpc_message_buffer_capacity, + max_connections: config.rpc_max_connections, + max_payload_in_mb: config.rpc_max_request_size, + max_payload_out_mb: config.rpc_max_response_size, + max_subscriptions_per_connection: config.rpc_max_subs_per_conn, + rpc_methods: config.rpc_methods.into(), + rate_limit: config.rpc_rate_limit, + rate_limit_trust_proxy_headers: config.rpc_rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips: config.rpc_rate_limit_whitelisted_ips.clone(), + retry_random_port: true, + is_optional: false, + }, + sc_rpc_server::RpcEndpoint { + batch_config: config.rpc_batch_config, + cors: config.rpc_cors.clone(), + listen_addr: ipv6, + max_buffer_capacity_per_connection: config.rpc_message_buffer_capacity, + max_connections: config.rpc_max_connections, + max_payload_in_mb: config.rpc_max_request_size, + max_payload_out_mb: config.rpc_max_response_size, + max_subscriptions_per_connection: config.rpc_max_subs_per_conn, + rpc_methods: config.rpc_methods.into(), + rate_limit: config.rpc_rate_limit, + rate_limit_trust_proxy_headers: config.rpc_rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips: config.rpc_rate_limit_whitelisted_ips.clone(), + retry_random_port: true, + is_optional: true, + }, + ] }; - let addr = config.rpc_addr.unwrap_or_else(|| ([127, 0, 0, 1], config.rpc_port).into()); - let backup_addr = backup_port(addr); let metrics = sc_rpc_server::RpcMetrics::new(config.prometheus_registry())?; + let rpc_api = gen_rpc_module()?; let server_config = sc_rpc_server::Config { - addrs: [addr, backup_addr], - batch_config: config.rpc_batch_config, - max_connections: config.rpc_max_connections, - 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))?, + endpoints, + rpc_api, metrics, id_provider: rpc_id_provider, - cors: config.rpc_cors.as_ref(), tokio_handle: config.tokio_handle.clone(), - rate_limit: config.rpc_rate_limit, - rate_limit_whitelisted_ips: config.rpc_rate_limit_whitelisted_ips.clone(), - rate_limit_trust_proxy_headers: config.rpc_rate_limit_trust_proxy_headers, }; // TODO: https://github.com/paritytech/substrate/issues/13773 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 c0333bb7dac0..c455d8d39b7d 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 @@ -21,8 +21,9 @@ use jsonrpsee::{ core::RpcResult, proc_macros::rpc, types::error::{ErrorCode, ErrorObject, ErrorObjectOwned}, + Extensions, }; -use sc_rpc_api::DenyUnsafe; +use sc_rpc_api::check_if_safe; use serde::{Deserialize, Serialize}; use sp_runtime::traits::Block as BlockT; use std::sync::Arc; @@ -134,7 +135,7 @@ pub trait StateMigrationApi { /// This call is performed locally without submitting any transactions. Thus executing this /// won't change any state. Nonetheless it is a VERY costly call that should be /// only exposed to trusted peers. - #[method(name = "state_trieMigrationStatus")] + #[method(name = "state_trieMigrationStatus", with_extensions)] fn call(&self, at: Option) -> RpcResult; } @@ -142,14 +143,13 @@ pub trait StateMigrationApi { pub struct StateMigration { client: Arc, backend: Arc, - deny_unsafe: DenyUnsafe, _marker: std::marker::PhantomData<(B, BA)>, } impl StateMigration { /// Create new state migration rpc for the given reference to the client. - pub fn new(client: Arc, backend: Arc, deny_unsafe: DenyUnsafe) -> Self { - StateMigration { client, backend, deny_unsafe, _marker: Default::default() } + pub fn new(client: Arc, backend: Arc) -> Self { + StateMigration { client, backend, _marker: Default::default() } } } @@ -159,8 +159,12 @@ where C: Send + Sync + 'static + sc_client_api::HeaderBackend, BA: 'static + sc_client_api::backend::Backend, { - fn call(&self, at: Option<::Hash>) -> RpcResult { - self.deny_unsafe.check_if_safe()?; + fn call( + &self, + ext: &Extensions, + at: Option<::Hash>, + ) -> RpcResult { + check_if_safe(ext)?; let hash = at.unwrap_or_else(|| self.client.info().best_hash); let state = self.backend.state_at(hash).map_err(error_into_rpc_err)?; diff --git a/substrate/utils/frame/rpc/system/src/lib.rs b/substrate/utils/frame/rpc/system/src/lib.rs index 8cb7b785bc7c..9fcaa53a35d8 100644 --- a/substrate/utils/frame/rpc/system/src/lib.rs +++ b/substrate/utils/frame/rpc/system/src/lib.rs @@ -24,9 +24,9 @@ use jsonrpsee::{ core::{async_trait, RpcResult}, proc_macros::rpc, types::error::ErrorObject, + Extensions, }; -use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool}; use sp_api::ApiExt; use sp_block_builder::BlockBuilder; @@ -49,7 +49,7 @@ pub trait SystemApi { async fn nonce(&self, account: AccountId) -> RpcResult; /// Dry run an extrinsic at a given block. Return SCALE encoded ApplyExtrinsicResult. - #[method(name = "system_dryRun", aliases = ["system_dryRunAt"])] + #[method(name = "system_dryRun", aliases = ["system_dryRunAt"], with_extensions)] async fn dry_run(&self, extrinsic: Bytes, at: Option) -> RpcResult; } @@ -74,14 +74,13 @@ impl From for i32 { pub struct System { client: Arc, pool: Arc

, - deny_unsafe: DenyUnsafe, _marker: std::marker::PhantomData, } impl System { /// Create new `FullSystem` given client and transaction pool. - pub fn new(client: Arc, pool: Arc

, deny_unsafe: DenyUnsafe) -> Self { - Self { client, pool, deny_unsafe, _marker: Default::default() } + pub fn new(client: Arc, pool: Arc

) -> Self { + Self { client, pool, _marker: Default::default() } } } @@ -115,10 +114,12 @@ where async fn dry_run( &self, + ext: &Extensions, extrinsic: Bytes, at: Option<::Hash>, ) -> RpcResult { - self.deny_unsafe.check_if_safe()?; + sc_rpc_api::check_if_safe(ext)?; + let api = self.client.runtime_api(); let best_hash = at.unwrap_or_else(|| // If the block hash is not supplied assume the best block. @@ -217,6 +218,7 @@ mod tests { use assert_matches::assert_matches; use futures::executor::block_on; + use sc_rpc_api::DenyUnsafe; use sc_transaction_pool::BasicPool; use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidityError}, @@ -224,6 +226,18 @@ mod tests { }; use substrate_test_runtime_client::{runtime::Transfer, AccountKeyring}; + fn deny_unsafe() -> Extensions { + let mut ext = Extensions::new(); + ext.insert(DenyUnsafe::Yes); + ext + } + + fn allow_unsafe() -> Extensions { + let mut ext = Extensions::new(); + ext.insert(DenyUnsafe::No); + ext + } + #[tokio::test] async fn should_return_next_nonce_for_some_account() { sp_tracing::try_init_simple(); @@ -251,7 +265,7 @@ mod tests { let ext1 = new_transaction(1); block_on(pool.submit_one(hash_of_block0, source, ext1)).unwrap(); - let accounts = System::new(client, pool, DenyUnsafe::Yes); + let accounts = System::new(client, pool); // when let nonce = accounts.nonce(AccountKeyring::Alice.into()).await; @@ -270,10 +284,10 @@ mod tests { let pool = BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); - let accounts = System::new(client, pool, DenyUnsafe::Yes); + let accounts = System::new(client, pool); // when - let res = accounts.dry_run(vec![].into(), None).await; + let res = accounts.dry_run(&deny_unsafe(), vec![].into(), None).await; assert_matches!(res, Err(e) => { assert!(e.message().contains("RPC call is unsafe to be called externally")); }); @@ -289,7 +303,7 @@ mod tests { let pool = BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); - let accounts = System::new(client, pool, DenyUnsafe::No); + let accounts = System::new(client, pool); let tx = Transfer { from: AccountKeyring::Alice.into(), @@ -300,7 +314,10 @@ mod tests { .into_unchecked_extrinsic(); // when - let bytes = accounts.dry_run(tx.encode().into(), None).await.expect("Call is successful"); + let bytes = accounts + .dry_run(&allow_unsafe(), tx.encode().into(), None) + .await + .expect("Call is successful"); // then let apply_res: ApplyExtrinsicResult = Decode::decode(&mut bytes.as_ref()).unwrap(); @@ -317,7 +334,7 @@ mod tests { let pool = BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); - let accounts = System::new(client, pool, DenyUnsafe::No); + let accounts = System::new(client, pool); let tx = Transfer { from: AccountKeyring::Alice.into(), @@ -328,7 +345,10 @@ mod tests { .into_unchecked_extrinsic(); // when - let bytes = accounts.dry_run(tx.encode().into(), None).await.expect("Call is successful"); + let bytes = accounts + .dry_run(&allow_unsafe(), tx.encode().into(), None) + .await + .expect("Call is successful"); // then let apply_res: ApplyExtrinsicResult = Decode::decode(&mut bytes.as_ref()).unwrap(); diff --git a/templates/minimal/node/Cargo.toml b/templates/minimal/node/Cargo.toml index da5073ea687c..c6bd89d23370 100644 --- a/templates/minimal/node/Cargo.toml +++ b/templates/minimal/node/Cargo.toml @@ -30,7 +30,6 @@ sc-transaction-pool = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-consensus-manual-seal = { workspace = true, default-features = true } -sc-rpc-api = { workspace = true, default-features = true } sc-basic-authorship = { workspace = true, default-features = true } sc-offchain = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } diff --git a/templates/minimal/node/src/rpc.rs b/templates/minimal/node/src/rpc.rs index 451e7b21dd0c..f51dfe1a1ace 100644 --- a/templates/minimal/node/src/rpc.rs +++ b/templates/minimal/node/src/rpc.rs @@ -28,16 +28,12 @@ use sc_transaction_pool_api::TransactionPool; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use std::sync::Arc; -pub use sc_rpc_api::DenyUnsafe; - /// Full client dependencies. pub struct FullDeps { /// The client instance to use. pub client: Arc, /// Transaction pool instance. pub pool: Arc

, - /// Whether to deny unsafe calls - pub deny_unsafe: DenyUnsafe, } #[docify::export] @@ -59,9 +55,9 @@ where { use substrate_frame_rpc_system::{System, SystemApiServer}; let mut module = RpcModule::new(()); - let FullDeps { client, pool, deny_unsafe } = deps; + let FullDeps { client, pool } = deps; - module.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; + module.merge(System::new(client.clone(), pool.clone()).into_rpc())?; Ok(module) } diff --git a/templates/minimal/node/src/service.rs b/templates/minimal/node/src/service.rs index decb9d6c636e..d362ae36d23a 100644 --- a/templates/minimal/node/src/service.rs +++ b/templates/minimal/node/src/service.rs @@ -168,9 +168,8 @@ pub fn new_full::Ha let client = client.clone(); let pool = transaction_pool.clone(); - Box::new(move |deny_unsafe, _| { - let deps = - crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe }; + Box::new(move |_| { + let deps = crate::rpc::FullDeps { client: client.clone(), pool: pool.clone() }; crate::rpc::create_full(deps).map_err(Into::into) }) }; diff --git a/templates/parachain/node/src/command.rs b/templates/parachain/node/src/command.rs index eba7fdcdae71..f346ae4386a6 100644 --- a/templates/parachain/node/src/command.rs +++ b/templates/parachain/node/src/command.rs @@ -1,5 +1,3 @@ -use std::net::SocketAddr; - use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; use cumulus_primitives_core::ParaId; use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; @@ -7,7 +5,7 @@ use log::info; use parachain_template_runtime::Block; use sc_cli::{ ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, - NetworkParams, Result, SharedParams, SubstrateCli, + NetworkParams, Result, RpcEndpoint, SharedParams, SubstrateCli, }; use sc_service::config::{BasePath, PrometheusConfig}; @@ -297,7 +295,7 @@ impl CliConfiguration for RelayChainCli { .or_else(|| self.base_path.clone().map(Into::into))) } - fn rpc_addr(&self, default_listen_port: u16) -> Result> { + fn rpc_addr(&self, default_listen_port: u16) -> Result>> { self.base.base.rpc_addr(default_listen_port) } diff --git a/templates/parachain/node/src/rpc.rs b/templates/parachain/node/src/rpc.rs index bb52b974f0ce..4937469e11e2 100644 --- a/templates/parachain/node/src/rpc.rs +++ b/templates/parachain/node/src/rpc.rs @@ -9,7 +9,6 @@ use std::sync::Arc; use parachain_template_runtime::{opaque::Block, AccountId, Balance, Nonce}; -pub use sc_rpc::DenyUnsafe; use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; @@ -24,8 +23,6 @@ pub struct FullDeps { pub client: Arc, /// Transaction pool instance. pub pool: Arc

, - /// Whether to deny unsafe calls - pub deny_unsafe: DenyUnsafe, } /// Instantiate all RPC extensions. @@ -48,9 +45,9 @@ where use substrate_frame_rpc_system::{System, SystemApiServer}; let mut module = RpcExtension::new(()); - let FullDeps { client, pool, deny_unsafe } = deps; + let FullDeps { client, pool } = deps; - module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; + module.merge(System::new(client.clone(), pool).into_rpc())?; module.merge(TransactionPayment::new(client).into_rpc())?; Ok(module) } diff --git a/templates/parachain/node/src/service.rs b/templates/parachain/node/src/service.rs index 88f2710a5cb8..b46b6ecfde18 100644 --- a/templates/parachain/node/src/service.rs +++ b/templates/parachain/node/src/service.rs @@ -305,12 +305,9 @@ pub async fn start_parachain_node( let client = client.clone(); let transaction_pool = transaction_pool.clone(); - Box::new(move |deny_unsafe, _| { - let deps = crate::rpc::FullDeps { - client: client.clone(), - pool: transaction_pool.clone(), - deny_unsafe, - }; + Box::new(move |_| { + let deps = + crate::rpc::FullDeps { client: client.clone(), pool: transaction_pool.clone() }; crate::rpc::create_full(deps).map_err(Into::into) }) diff --git a/templates/solochain/node/Cargo.toml b/templates/solochain/node/Cargo.toml index 9dd1b144d229..8f74c6b3cb55 100644 --- a/templates/solochain/node/Cargo.toml +++ b/templates/solochain/node/Cargo.toml @@ -36,7 +36,6 @@ sc-consensus = { workspace = true, default-features = true } sc-consensus-grandpa = { workspace = true, default-features = true } sp-consensus-grandpa = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } -sc-rpc-api = { workspace = true, default-features = true } sc-basic-authorship = { workspace = true, default-features = true } # substrate primitives diff --git a/templates/solochain/node/src/rpc.rs b/templates/solochain/node/src/rpc.rs index fe2b6ca72ede..1fc6eb0127e9 100644 --- a/templates/solochain/node/src/rpc.rs +++ b/templates/solochain/node/src/rpc.rs @@ -14,16 +14,12 @@ use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; -pub use sc_rpc_api::DenyUnsafe; - /// Full client dependencies. pub struct FullDeps { /// The client instance to use. pub client: Arc, /// Transaction pool instance. pub pool: Arc

, - /// Whether to deny unsafe calls - pub deny_unsafe: DenyUnsafe, } /// Instantiate all full RPC extensions. @@ -43,9 +39,9 @@ where use substrate_frame_rpc_system::{System, SystemApiServer}; let mut module = RpcModule::new(()); - let FullDeps { client, pool, deny_unsafe } = deps; + let FullDeps { client, pool } = deps; - module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; + module.merge(System::new(client.clone(), pool).into_rpc())?; module.merge(TransactionPayment::new(client).into_rpc())?; // Extend this RPC with a custom API by using the following syntax. diff --git a/templates/solochain/node/src/service.rs b/templates/solochain/node/src/service.rs index 7eef9766b107..2b43ecfa1ce2 100644 --- a/templates/solochain/node/src/service.rs +++ b/templates/solochain/node/src/service.rs @@ -212,9 +212,8 @@ pub fn new_full< let client = client.clone(); let pool = transaction_pool.clone(); - Box::new(move |deny_unsafe, _| { - let deps = - crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe }; + Box::new(move |_| { + let deps = crate::rpc::FullDeps { client: client.clone(), pool: pool.clone() }; crate::rpc::create_full(deps).map_err(Into::into) }) }; From ef3a0d8f118d381fba1f828209eababe9c24f051 Mon Sep 17 00:00:00 2001 From: A Ahmad <57046949+abbaahmad@users.noreply.github.com> Date: Wed, 28 Aug 2024 14:01:12 +0100 Subject: [PATCH 08/11] IBP Coretime Polkadot bootnodes (#5499) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✄ ----------------------------------------------------------------------------- Thank you for your Pull Request! 🙏 Please make sure it follows the contribution guidelines outlined in [this document](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CONTRIBUTING.md) and fill out the sections below. Once you're ready to submit your PR for review, please delete this section and leave only the text under the "Description" heading. # Description *A concise description of what your PR is doing, and what potential issue it is solving. Use [Github semantic linking](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) to link the PR to an issue that must be closed once this is merged.* ## Integration *In depth notes about how this PR should be integrated by downstream projects. This part is mandatory, and should be reviewed by reviewers, if the PR does NOT have the `R0-Silent` label. In case of a `R0-Silent`, it can be ignored.* ## Review Notes *In depth notes about the **implementation** details of your PR. This should be the main guide for reviewers to understand your approach and effectively review it. If too long, use [`

`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details)*. *Imagine that someone who is depending on the old code wants to integrate your new code and the only information that they get is this section. It helps to include example usage and default value here, with a `diff` code-block to show possibly integration.* *Include your leftover TODOs, if any, here.* # Checklist * [ ] My PR includes a detailed description as outlined in the "Description" and its two subsections above. * [ ] My PR follows the [labeling requirements]( https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CONTRIBUTING.md#Process ) of this project (at minimum one label for `T` required) * External contributors: ask maintainers to put the right label on your PR. * [ ] I have made corresponding changes to the documentation (if applicable) * [ ] I have added tests that prove my fix is effective or that my feature works (if applicable) You can remove the "Checklist" section once all have been checked. Thank you for your contribution! ✄ ----------------------------------------------------------------------------- Co-authored-by: Dónal Murray --- cumulus/parachains/chain-specs/coretime-polkadot.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cumulus/parachains/chain-specs/coretime-polkadot.json b/cumulus/parachains/chain-specs/coretime-polkadot.json index 73e104b38290..806231db7646 100644 --- a/cumulus/parachains/chain-specs/coretime-polkadot.json +++ b/cumulus/parachains/chain-specs/coretime-polkadot.json @@ -8,7 +8,9 @@ "/dns/polkadot-coretime-connect-a-0.polkadot.io/tcp/443/wss/p2p/12D3KooWKjnixAHbKMsPTJwGx8SrBeGEJLHA8KmKcEDYMp3YmWgR", "/dns/polkadot-coretime-connect-a-1.polkadot.io/tcp/443/wss/p2p/12D3KooWQ7B7p4DFv1jWqaKfhrZBcMmi5g8bWFnmskguLaGEmT6n", "/dns4/coretime-polkadot.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWFJ2yBTKFKYwgKUjfY3F7XfaxHV8hY6fbJu5oMkpP7wZ9", - "/dns4/coretime-polkadot.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWCy5pToLafcQzPHn5kadxAftmF6Eh8ZJGPXhSeXSUDfjv" + "/dns4/coretime-polkadot.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWCy5pToLafcQzPHn5kadxAftmF6Eh8ZJGPXhSeXSUDfjv", + "/dns/coretime-polkadot-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWGpmytHjdthrkKgkXDZyKm9ABtJ2PtGk9NStJDG4pChy9", + "/dns/coretime-polkadot-boot-ng.dwellir.com/tcp/30361/p2p/12D3KooWGpmytHjdthrkKgkXDZyKm9ABtJ2PtGk9NStJDG4pChy9" ], "telemetryEndpoints": null, "protocolId": null, From 9cf5e8105f0142abf5302bf9be9cffb0106731bf Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Wed, 28 Aug 2024 15:08:08 +0200 Subject: [PATCH 09/11] Use umbrella crate for minimal template (#5155) Co-authored-by: kianenigma Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 35 +--- Cargo.toml | 2 +- bridges/relays/utils/Cargo.toml | 2 +- cumulus/client/consensus/proposer/Cargo.toml | 2 +- docs/sdk/Cargo.toml | 2 +- .../chain_spec_runtime/src/runtime.rs | 5 +- prdoc/pr_5155.prdoc | 27 +++ scripts/generate-umbrella.py | 8 +- substrate/bin/node/runtime/Cargo.toml | 2 +- substrate/frame/contracts/fixtures/Cargo.toml | 4 +- substrate/frame/revive/fixtures/Cargo.toml | 6 +- substrate/frame/src/lib.rs | 27 ++- .../test/tests/pallet_outer_enums_explicit.rs | 6 +- .../test/tests/pallet_outer_enums_implicit.rs | 6 +- .../primitives/wasm-interface/Cargo.toml | 6 +- templates/minimal/node/Cargo.toml | 33 +--- templates/minimal/node/build.rs | 2 +- templates/minimal/node/src/chain_spec.rs | 9 +- templates/minimal/node/src/cli.rs | 2 +- templates/minimal/node/src/command.rs | 3 +- templates/minimal/node/src/main.rs | 2 +- templates/minimal/node/src/rpc.rs | 9 +- templates/minimal/node/src/service.rs | 15 +- templates/minimal/pallets/template/Cargo.toml | 14 +- templates/minimal/pallets/template/src/lib.rs | 4 +- templates/minimal/runtime/Cargo.toml | 42 ++--- templates/minimal/runtime/build.rs | 2 +- templates/minimal/runtime/src/lib.rs | 24 +-- umbrella/Cargo.toml | 172 +----------------- 29 files changed, 136 insertions(+), 337 deletions(-) create mode 100644 prdoc/pr_5155.prdoc diff --git a/Cargo.lock b/Cargo.lock index 8bf4c356397d..885e2b4b4cf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8726,47 +8726,18 @@ dependencies = [ "futures-timer", "jsonrpsee", "minimal-template-runtime", - "polkadot-sdk-frame", - "sc-basic-authorship", - "sc-cli", - "sc-client-api", - "sc-consensus", - "sc-consensus-manual-seal", - "sc-executor", - "sc-network", - "sc-offchain", - "sc-service", - "sc-telemetry", - "sc-transaction-pool", - "sc-transaction-pool-api", + "polkadot-sdk", "serde_json", - "sp-api", - "sp-block-builder", - "sp-blockchain", - "sp-io", - "sp-keyring", - "sp-runtime", - "sp-timestamp", - "substrate-build-script-utils", - "substrate-frame-rpc-system", ] [[package]] name = "minimal-template-runtime" version = "0.0.0" dependencies = [ - "pallet-balances", "pallet-minimal-template", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", - "polkadot-sdk-frame", + "polkadot-sdk", "scale-info", - "sp-genesis-builder", - "sp-runtime", - "substrate-wasm-builder", ] [[package]] @@ -10957,7 +10928,7 @@ name = "pallet-minimal-template" version = "0.0.0" dependencies = [ "parity-scale-codec", - "polkadot-sdk-frame", + "polkadot-sdk", "scale-info", ] diff --git a/Cargo.toml b/Cargo.toml index a181a935ea06..9d39962f8974 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -584,7 +584,7 @@ ahash = { version = "0.8.2" } alloy-primitives = { version = "0.4.2", default-features = false } alloy-sol-types = { version = "0.4.2", default-features = false } always-assert = { version = "0.1" } -anyhow = { version = "1.0.81" } +anyhow = { version = "1.0.81", default-features = false } aquamarine = { version = "0.5.0" } arbitrary = { version = "1.3.2" } ark-bls12-377 = { version = "0.4.0", default-features = false } diff --git a/bridges/relays/utils/Cargo.toml b/bridges/relays/utils/Cargo.toml index beb03b9381d4..4c25566607dc 100644 --- a/bridges/relays/utils/Cargo.toml +++ b/bridges/relays/utils/Cargo.toml @@ -11,7 +11,7 @@ publish = false workspace = true [dependencies] -anyhow = { workspace = true } +anyhow = { workspace = true, default-features = true } async-std = { workspace = true } async-trait = { workspace = true } backoff = { workspace = true } diff --git a/cumulus/client/consensus/proposer/Cargo.toml b/cumulus/client/consensus/proposer/Cargo.toml index ce91d48bf589..bb760ae03f4d 100644 --- a/cumulus/client/consensus/proposer/Cargo.toml +++ b/cumulus/client/consensus/proposer/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -anyhow = { workspace = true } +anyhow = { workspace = true, default-features = true } async-trait = { workspace = true } thiserror = { workspace = true } diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 424758c32b34..adc1c1a8efbc 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -31,7 +31,7 @@ simple-mermaid = "0.1.1" docify = { workspace = true } # Polkadot SDK deps, typically all should only be in scope such that we can link to their doc item. -polkadot-sdk = { features = ["runtime"], workspace = true, default-features = true } +polkadot-sdk = { features = ["runtime-full"], workspace = true, default-features = true } node-cli = { workspace = true } kitchensink-runtime = { workspace = true } chain-spec-builder = { workspace = true, default-features = true } diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs b/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs index c45f0126337e..195d1b124474 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs @@ -32,10 +32,7 @@ use frame::{ runtime, }, prelude::*, - runtime::{ - apis::{self, impl_runtime_apis, ExtrinsicInclusionMode}, - prelude::*, - }, + runtime::{apis, prelude::*}, }; use sp_genesis_builder::PresetId; diff --git a/prdoc/pr_5155.prdoc b/prdoc/pr_5155.prdoc new file mode 100644 index 000000000000..373522eea1c3 --- /dev/null +++ b/prdoc/pr_5155.prdoc @@ -0,0 +1,27 @@ +# 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: Use umbrella crate for minimal template + +doc: + - audience: Runtime Dev + description: | + Minor additions to the `polkadot-sdk-frame` crate and making it ready for usage in more templates. This PR already integrates it in the minimal template. + + +crates: + - name: polkadot-sdk + bump: major + - name: polkadot-sdk-frame + bump: patch + - name: sp-wasm-interface + bump: patch + - name: pallet-revive + bump: patch + - name: pallet-revive-fixtures + bump: patch + - name: frame-support + bump: patch + - name: pallet-balances + bump: patch + diff --git a/scripts/generate-umbrella.py b/scripts/generate-umbrella.py index 5b9cc89c5308..e1ef6de86f9c 100644 --- a/scripts/generate-umbrella.py +++ b/scripts/generate-umbrella.py @@ -86,6 +86,8 @@ def main(path, version): # Sort by name std_crates.sort(key=lambda x: x[0].name) nostd_crates.sort(key=lambda x: x[0].name) + + runtime_crates = [crate for crate in nostd_crates if 'frame' in crate[0].name or crate[0].name.startswith('sp-')] all_crates = std_crates + nostd_crates all_crates.sort(key=lambda x: x[0].name) dependencies = {} @@ -105,7 +107,8 @@ def main(path, version): "serde": [], "experimental": [], "with-tracing": [], - "runtime": list([f"{d.name}" for d, _ in nostd_crates]), + "runtime-full": list([f"{d.name}" for d, _ in nostd_crates]), + "runtime": list([f"{d.name}" for d, _ in runtime_crates]), "node": ["std"] + list([f"{d.name}" for d, _ in std_crates]), "tuples-96": [], "riscv": [], @@ -120,7 +123,7 @@ def main(path, version): "description": "Polkadot SDK umbrella crate.", "license": "Apache-2.0", "metadata": { "docs": { "rs": { - "features": ["runtime", "node"], + "features": ["runtime-full", "node"], "targets": ["x86_64-unknown-linux-gnu"] }}} }, @@ -204,3 +207,4 @@ def parse_args(): if __name__ == "__main__": args = parse_args() main(args.sdk, args.version) + diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index c262d74fa8a8..6310e16d5a14 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -31,7 +31,7 @@ serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } # pallet-asset-conversion: turn on "num-traits" feature primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } -polkadot-sdk = { features = ["runtime", "tuples-96"], workspace = true } +polkadot-sdk = { features = ["runtime-full", "tuples-96"], workspace = true } # shared code between runtime and node node-primitives = { workspace = true } diff --git a/substrate/frame/contracts/fixtures/Cargo.toml b/substrate/frame/contracts/fixtures/Cargo.toml index 6b0751571cc9..6cb6447d8fd7 100644 --- a/substrate/frame/contracts/fixtures/Cargo.toml +++ b/substrate/frame/contracts/fixtures/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] frame-system = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -anyhow = { workspace = true } +anyhow = { workspace = true, default-features = true } [build-dependencies] parity-wasm = { workspace = true } @@ -21,7 +21,7 @@ tempfile = { workspace = true } toml = { workspace = true } twox-hash = { workspace = true, default-features = true } polkavm-linker = { workspace = true, optional = true } -anyhow = { workspace = true } +anyhow = { workspace = true, default-features = true } [features] riscv = ["polkavm-linker"] diff --git a/substrate/frame/revive/fixtures/Cargo.toml b/substrate/frame/revive/fixtures/Cargo.toml index 1b668c061f85..9e54acdace70 100644 --- a/substrate/frame/revive/fixtures/Cargo.toml +++ b/substrate/frame/revive/fixtures/Cargo.toml @@ -29,4 +29,8 @@ default = ["std"] # we will remove this once there is an upstream toolchain riscv = [] # only when std is enabled all fixtures are available -std = ["frame-system", "sp-runtime"] +std = [ + "anyhow/std", + "frame-system", + "sp-runtime", +] diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index 235d75a4b752..e5fb15cdd07c 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -177,8 +177,15 @@ pub mod runtime { pub use frame_executive::*; /// Macro to amalgamate the runtime into `struct Runtime`. + /// + /// Consider using the new version of this [`frame_construct_runtime`]. pub use frame_support::construct_runtime; + /// Macro to amalgamate the runtime into `struct Runtime`. + /// + /// This is the newer version of [`construct_runtime`]. + pub use frame_support::runtime as frame_construct_runtime; + /// Macro to easily derive the `Config` trait of various pallet for `Runtime`. pub use frame_support::derive_impl; @@ -186,12 +193,18 @@ pub mod runtime { // TODO: using linking in the Get in the line above triggers an ICE :/ pub use frame_support::{ord_parameter_types, parameter_types}; + /// For building genesis config. + pub use frame_support::genesis_builder_helper::{build_state, get_preset}; + /// Const types that can easily be used in conjuncture with `Get`. pub use frame_support::traits::{ ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, }; + /// Used for simple fee calculation. + pub use frame_support::weights::{self, FixedFee, NoFee}; + /// Primary types used to parameterize `EnsureOrigin` and `EnsureRootWithArg`. pub use frame_system::{ EnsureNever, EnsureNone, EnsureRoot, EnsureRootWithSuccess, EnsureSigned, @@ -201,11 +214,16 @@ pub mod runtime { /// Types to define your runtime version. pub use sp_version::{create_runtime_str, runtime_version, RuntimeVersion}; + #[cfg(feature = "std")] + pub use sp_version::NativeVersion; + /// Macro to implement runtime APIs. pub use sp_api::impl_runtime_apis; - #[cfg(feature = "std")] - pub use sp_version::NativeVersion; + // Types often used in the runtime APIs. + pub use sp_core::OpaqueMetadata; + pub use sp_inherents::{CheckInherentsResult, InherentData}; + pub use sp_runtime::{ApplyExtrinsicResult, ExtrinsicInclusionMode}; } /// Types and traits for runtimes that implement runtime APIs. @@ -223,11 +241,6 @@ pub mod runtime { // moved to file similarly. #[allow(ambiguous_glob_reexports)] pub mod apis { - // Types often used in the runtime APIs. - pub use sp_core::OpaqueMetadata; - pub use sp_inherents::{CheckInherentsResult, InherentData}; - pub use sp_runtime::{ApplyExtrinsicResult, ExtrinsicInclusionMode}; - pub use frame_system_rpc_runtime_api::*; pub use sp_api::{self, *}; pub use sp_block_builder::*; diff --git a/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs b/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs index 326f3530e26e..81cdd40d1bcf 100644 --- a/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs +++ b/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs @@ -19,8 +19,6 @@ use frame_support::derive_impl; mod common; -use common::outer_enums::{pallet, pallet2}; - pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; @@ -75,8 +73,10 @@ frame_support::construct_runtime!( } ); +#[cfg(feature = "experimental")] #[test] fn module_error_outer_enum_expand_explicit() { + use common::outer_enums::{pallet, pallet2}; // The Runtime has *all* parts explicitly defined. // Check that all error types are propagated @@ -90,9 +90,7 @@ fn module_error_outer_enum_expand_explicit() { frame_system::Error::NonZeroRefCount => (), frame_system::Error::CallFiltered => (), frame_system::Error::MultiBlockMigrationsOngoing => (), - #[cfg(feature = "experimental")] frame_system::Error::InvalidTask => (), - #[cfg(feature = "experimental")] frame_system::Error::FailedTask => (), frame_system::Error::NothingAuthorized => (), frame_system::Error::Unauthorized => (), diff --git a/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs b/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs index 4149c4880cca..d2e759640c73 100644 --- a/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs +++ b/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs @@ -19,8 +19,6 @@ use frame_support::derive_impl; mod common; -use common::outer_enums::{pallet, pallet2}; - pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; @@ -75,8 +73,10 @@ frame_support::construct_runtime!( } ); +#[cfg(feature = "experimental")] #[test] fn module_error_outer_enum_expand_implicit() { + use common::outer_enums::{pallet, pallet2}; // The Runtime has *all* parts implicitly defined. // Check that all error types are propagated @@ -90,9 +90,7 @@ fn module_error_outer_enum_expand_implicit() { frame_system::Error::NonZeroRefCount => (), frame_system::Error::CallFiltered => (), frame_system::Error::MultiBlockMigrationsOngoing => (), - #[cfg(feature = "experimental")] frame_system::Error::InvalidTask => (), - #[cfg(feature = "experimental")] frame_system::Error::FailedTask => (), frame_system::Error::NothingAuthorized => (), frame_system::Error::Unauthorized => (), diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index 96ea8f4235d5..9d0310fd22e8 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -25,5 +25,9 @@ anyhow = { optional = true, workspace = true } [features] default = ["std"] -std = ["codec/std", "log/std"] +std = [ + "anyhow?/std", + "codec/std", + "log/std", +] wasmtime = ["anyhow", "dep:wasmtime"] diff --git a/templates/minimal/node/Cargo.toml b/templates/minimal/node/Cargo.toml index c6bd89d23370..956efca34532 100644 --- a/templates/minimal/node/Cargo.toml +++ b/templates/minimal/node/Cargo.toml @@ -21,42 +21,15 @@ futures-timer = { workspace = true } jsonrpsee = { features = ["server"], workspace = true } serde_json = { workspace = true, default-features = true } -sc-cli = { workspace = true, default-features = true } -sc-executor = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } -sc-service = { workspace = true, default-features = true } -sc-telemetry = { workspace = true, default-features = true } -sc-transaction-pool = { workspace = true, default-features = true } -sc-transaction-pool-api = { workspace = true, default-features = true } -sc-consensus = { workspace = true, default-features = true } -sc-consensus-manual-seal = { workspace = true, default-features = true } -sc-basic-authorship = { workspace = true, default-features = true } -sc-offchain = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } - -sp-timestamp = { workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } -sp-api = { workspace = true, default-features = true } -sp-blockchain = { workspace = true, default-features = true } -sp-block-builder = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } - -substrate-frame-rpc-system = { workspace = true, default-features = true } - -# Once the native runtime is gone, there should be little to no dependency on FRAME here, and -# certainly no dependency on the runtime. -frame = { features = [ - "experimental", - "runtime", -], workspace = true, default-features = true } +polkadot-sdk = { workspace = true, features = ["experimental", "node"] } minimal-template-runtime = { workspace = true } [build-dependencies] -substrate-build-script-utils = { workspace = true, default-features = true } +polkadot-sdk = { workspace = true, features = ["substrate-build-script-utils"] } [features] default = ["std"] std = [ "minimal-template-runtime/std", + "polkadot-sdk/std", ] diff --git a/templates/minimal/node/build.rs b/templates/minimal/node/build.rs index fa7686e01099..47ab77ae2969 100644 --- a/templates/minimal/node/build.rs +++ b/templates/minimal/node/build.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; +use polkadot_sdk::substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; fn main() { generate_cargo_keys(); diff --git a/templates/minimal/node/src/chain_spec.rs b/templates/minimal/node/src/chain_spec.rs index 5b53b0f80ac0..0646460acef6 100644 --- a/templates/minimal/node/src/chain_spec.rs +++ b/templates/minimal/node/src/chain_spec.rs @@ -16,9 +16,12 @@ // limitations under the License. use minimal_template_runtime::{BalancesConfig, SudoConfig, WASM_BINARY}; -use sc_service::{ChainType, Properties}; +use polkadot_sdk::{ + sc_service::{ChainType, Properties}, + sp_keyring::AccountKeyring, + *, +}; use serde_json::{json, Value}; -use sp_keyring::AccountKeyring; /// This is a specialization of the general Substrate ChainSpec type. pub type ChainSpec = sc_service::GenericChainSpec; @@ -42,8 +45,8 @@ pub fn development_config() -> Result { /// Configure initial storage state for FRAME pallets. fn testnet_genesis() -> Value { - use frame::traits::Get; use minimal_template_runtime::interface::{Balance, MinimumBalance}; + use polkadot_sdk::polkadot_sdk_frame::traits::Get; let endowment = >::get().max(1) * 1000; let balances = AccountKeyring::iter() .map(|a| (a.to_account_id(), endowment)) diff --git a/templates/minimal/node/src/cli.rs b/templates/minimal/node/src/cli.rs index 22726b7eb9a3..54107df75a36 100644 --- a/templates/minimal/node/src/cli.rs +++ b/templates/minimal/node/src/cli.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use sc_cli::RunCmd; +use polkadot_sdk::{sc_cli::RunCmd, *}; #[derive(Debug, Clone)] pub enum Consensus { diff --git a/templates/minimal/node/src/command.rs b/templates/minimal/node/src/command.rs index 504be1ccc36e..b09ea1fab237 100644 --- a/templates/minimal/node/src/command.rs +++ b/templates/minimal/node/src/command.rs @@ -20,8 +20,7 @@ use crate::{ cli::{Cli, Subcommand}, service, }; -use sc_cli::SubstrateCli; -use sc_service::PartialComponents; +use polkadot_sdk::{sc_cli::SubstrateCli, sc_service::PartialComponents, *}; impl SubstrateCli for Cli { fn impl_name() -> String { diff --git a/templates/minimal/node/src/main.rs b/templates/minimal/node/src/main.rs index 3cf7d98311ea..8f36da5bf83a 100644 --- a/templates/minimal/node/src/main.rs +++ b/templates/minimal/node/src/main.rs @@ -24,6 +24,6 @@ mod command; mod rpc; mod service; -fn main() -> sc_cli::Result<()> { +fn main() -> polkadot_sdk::sc_cli::Result<()> { command::run() } diff --git a/templates/minimal/node/src/rpc.rs b/templates/minimal/node/src/rpc.rs index f51dfe1a1ace..64497c4bcaca 100644 --- a/templates/minimal/node/src/rpc.rs +++ b/templates/minimal/node/src/rpc.rs @@ -24,8 +24,11 @@ use jsonrpsee::RpcModule; use minimal_template_runtime::interface::{AccountId, Nonce, OpaqueBlock}; -use sc_transaction_pool_api::TransactionPool; -use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use polkadot_sdk::{ + sc_transaction_pool_api::TransactionPool, + sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}, + *, +}; use std::sync::Arc; /// Full client dependencies. @@ -53,7 +56,7 @@ where C::Api: substrate_frame_rpc_system::AccountNonceApi, P: TransactionPool + 'static, { - use substrate_frame_rpc_system::{System, SystemApiServer}; + use polkadot_sdk::substrate_frame_rpc_system::{System, SystemApiServer}; let mut module = RpcModule::new(()); let FullDeps { client, pool } = deps; diff --git a/templates/minimal/node/src/service.rs b/templates/minimal/node/src/service.rs index d362ae36d23a..ce3afe1e6b76 100644 --- a/templates/minimal/node/src/service.rs +++ b/templates/minimal/node/src/service.rs @@ -17,12 +17,15 @@ use futures::FutureExt; use minimal_template_runtime::{interface::OpaqueBlock as Block, RuntimeApi}; -use sc_client_api::backend::Backend; -use sc_executor::WasmExecutor; -use sc_service::{error::Error as ServiceError, Configuration, TaskManager}; -use sc_telemetry::{Telemetry, TelemetryWorker}; -use sc_transaction_pool_api::OffchainTransactionPoolFactory; -use sp_runtime::traits::Block as BlockT; +use polkadot_sdk::{ + sc_client_api::backend::Backend, + sc_executor::WasmExecutor, + sc_service::{error::Error as ServiceError, Configuration, TaskManager}, + sc_telemetry::{Telemetry, TelemetryWorker}, + sc_transaction_pool_api::OffchainTransactionPoolFactory, + sp_runtime::traits::Block as BlockT, + *, +}; use std::sync::Arc; use crate::cli::Consensus; diff --git a/templates/minimal/pallets/template/Cargo.toml b/templates/minimal/pallets/template/Cargo.toml index 9d231fe7d7d4..9a02d4daeaac 100644 --- a/templates/minimal/pallets/template/Cargo.toml +++ b/templates/minimal/pallets/template/Cargo.toml @@ -13,18 +13,14 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { features = [ - "derive", -], workspace = true } -scale-info = { features = [ - "derive", -], workspace = true } -frame = { features = [ +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } +polkadot-sdk = { workspace = true, default-features = false, features = [ "experimental", "runtime", -], workspace = true } +] } [features] default = ["std"] -std = ["codec/std", "frame/std", "scale-info/std"] +std = ["codec/std", "polkadot-sdk/std", "scale-info/std"] diff --git a/templates/minimal/pallets/template/src/lib.rs b/templates/minimal/pallets/template/src/lib.rs index 92b90ad4412b..b8a8614932a6 100644 --- a/templates/minimal/pallets/template/src/lib.rs +++ b/templates/minimal/pallets/template/src/lib.rs @@ -5,7 +5,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame::prelude::*; +use polkadot_sdk::polkadot_sdk_frame as frame; // Re-export all pallet parts, this is needed to properly import the pallet into the runtime. pub use pallet::*; @@ -15,7 +15,7 @@ pub mod pallet { use super::*; #[pallet::config] - pub trait Config: frame_system::Config {} + pub trait Config: polkadot_sdk::frame_system::Config {} #[pallet::pallet] pub struct Pallet(_); diff --git a/templates/minimal/runtime/Cargo.toml b/templates/minimal/runtime/Cargo.toml index 5d3cf8492e52..49ddf3987e96 100644 --- a/templates/minimal/runtime/Cargo.toml +++ b/templates/minimal/runtime/Cargo.toml @@ -12,47 +12,29 @@ publish = false [dependencies] codec = { workspace = true } scale-info = { workspace = true } - -# this is a frame-based runtime, thus importing `frame` with runtime feature enabled. -frame = { features = [ +polkadot-sdk = { workspace = true, features = [ "experimental", + "pallet-balances", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", "runtime", -], workspace = true } - -# pallets that we want to use -pallet-balances = { workspace = true } -pallet-sudo = { workspace = true } -pallet-timestamp = { workspace = true } -pallet-transaction-payment = { workspace = true } -pallet-transaction-payment-rpc-runtime-api = { workspace = true } - -# genesis builder that allows us to interact with runtime genesis config -sp-genesis-builder = { workspace = true } -sp-runtime = { features = ["serde"], workspace = true } +] } # local pallet templates pallet-minimal-template = { workspace = true } [build-dependencies] -substrate-wasm-builder = { optional = true, workspace = true, default-features = true } +polkadot-sdk = { optional = true, workspace = true, features = [ + "substrate-wasm-builder", +] } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - - "frame/std", - - "pallet-balances/std", - "pallet-sudo/std", - "pallet-timestamp/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", - "pallet-minimal-template/std", - - "sp-genesis-builder/std", - "sp-runtime/std", - "substrate-wasm-builder", + "polkadot-sdk/std", + "scale-info/std", ] diff --git a/templates/minimal/runtime/build.rs b/templates/minimal/runtime/build.rs index e6f92757e225..2cb2966b5d82 100644 --- a/templates/minimal/runtime/build.rs +++ b/templates/minimal/runtime/build.rs @@ -18,6 +18,6 @@ fn main() { #[cfg(feature = "std")] { - substrate_wasm_builder::WasmBuilder::build_using_defaults(); + polkadot_sdk::substrate_wasm_builder::WasmBuilder::build_using_defaults(); } } diff --git a/templates/minimal/runtime/src/lib.rs b/templates/minimal/runtime/src/lib.rs index 08ad537ecdd1..474d9ddfb9e8 100644 --- a/templates/minimal/runtime/src/lib.rs +++ b/templates/minimal/runtime/src/lib.rs @@ -26,20 +26,14 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); extern crate alloc; use alloc::{vec, vec::Vec}; -use frame::{ - deps::frame_support::{ - genesis_builder_helper::{build_state, get_preset}, - runtime, - weights::{FixedFee, NoFee}, - }, - prelude::*, - runtime::{ - apis::{ - self, impl_runtime_apis, ApplyExtrinsicResult, CheckInherentsResult, - ExtrinsicInclusionMode, OpaqueMetadata, - }, +use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; +use polkadot_sdk::{ + polkadot_sdk_frame::{ + self as frame, prelude::*, + runtime::{apis, prelude::*}, }, + *, }; /// The runtime version. @@ -83,7 +77,7 @@ type SignedExtra = ( ); // Composes the runtime by adding all the used pallets and deriving necessary types. -#[runtime] +#[frame_construct_runtime] mod runtime { /// The main runtime type. #[runtime::runtime] @@ -171,8 +165,6 @@ type Header = HeaderFor; type RuntimeExecutive = Executive, Runtime, AllPalletsWithSystem>; -use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; - impl_runtime_apis! { impl apis::Core for Runtime { fn version() -> RuntimeVersion { @@ -296,7 +288,7 @@ impl_runtime_apis! { // https://github.com/paritytech/substrate/issues/10579#issuecomment-1600537558 pub mod interface { use super::Runtime; - use frame::deps::frame_system; + use polkadot_sdk::{polkadot_sdk_frame as frame, *}; pub type Block = super::Block; pub use frame::runtime::types_common::OpaqueBlock; diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index 9c2ed30c527a..6d380a4bcbb7 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -536,37 +536,8 @@ with-tracing = [ "sp-tracing?/with-tracing", "sp-tracing?/with-tracing", ] +runtime-full = ["assets-common", "binary-merkle-tree", "bp-header-chain", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-core", "bp-relayers", "bp-runtime", "bp-test-utils", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-assets-freezer", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-revive", "pallet-revive-fixtures", "pallet-revive-proc-macro", "pallet-revive-uapi", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "xcm-procedural", "xcm-runtime-apis"] runtime = [ - "assets-common", - "binary-merkle-tree", - "bp-header-chain", - "bp-messages", - "bp-parachains", - "bp-polkadot", - "bp-polkadot-core", - "bp-relayers", - "bp-runtime", - "bp-test-utils", - "bp-xcm-bridge-hub", - "bp-xcm-bridge-hub-router", - "bridge-hub-common", - "bridge-runtime-common", - "cumulus-pallet-aura-ext", - "cumulus-pallet-dmp-queue", - "cumulus-pallet-parachain-system", - "cumulus-pallet-parachain-system-proc-macro", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-solo-to-para", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-ping", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", - "cumulus-primitives-proof-size-hostfunction", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-timestamp", - "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", @@ -580,138 +551,8 @@ runtime = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "pallet-alliance", - "pallet-asset-conversion", - "pallet-asset-conversion-ops", - "pallet-asset-conversion-tx-payment", - "pallet-asset-rate", - "pallet-asset-tx-payment", - "pallet-assets", - "pallet-assets-freezer", - "pallet-atomic-swap", - "pallet-aura", - "pallet-authority-discovery", - "pallet-authorship", - "pallet-babe", - "pallet-bags-list", - "pallet-balances", - "pallet-beefy", - "pallet-beefy-mmr", - "pallet-bounties", - "pallet-bridge-grandpa", - "pallet-bridge-messages", - "pallet-bridge-parachains", - "pallet-bridge-relayers", - "pallet-broker", - "pallet-child-bounties", - "pallet-collator-selection", - "pallet-collective", - "pallet-collective-content", - "pallet-contracts", - "pallet-contracts-proc-macro", - "pallet-contracts-uapi", - "pallet-conviction-voting", - "pallet-core-fellowship", - "pallet-delegated-staking", - "pallet-democracy", - "pallet-dev-mode", - "pallet-election-provider-multi-phase", - "pallet-election-provider-support-benchmarking", - "pallet-elections-phragmen", - "pallet-fast-unstake", - "pallet-glutton", - "pallet-grandpa", - "pallet-identity", - "pallet-im-online", - "pallet-indices", - "pallet-insecure-randomness-collective-flip", - "pallet-lottery", - "pallet-membership", - "pallet-message-queue", - "pallet-migrations", - "pallet-mixnet", - "pallet-mmr", - "pallet-multisig", - "pallet-nft-fractionalization", - "pallet-nfts", - "pallet-nfts-runtime-api", - "pallet-nis", - "pallet-node-authorization", - "pallet-nomination-pools", - "pallet-nomination-pools-benchmarking", - "pallet-nomination-pools-runtime-api", - "pallet-offences", - "pallet-offences-benchmarking", - "pallet-paged-list", - "pallet-parameters", - "pallet-preimage", - "pallet-proxy", - "pallet-ranked-collective", - "pallet-recovery", - "pallet-referenda", - "pallet-remark", - "pallet-revive", - "pallet-revive-fixtures", - "pallet-revive-proc-macro", - "pallet-revive-uapi", - "pallet-root-offences", - "pallet-root-testing", - "pallet-safe-mode", - "pallet-salary", - "pallet-scheduler", - "pallet-scored-pool", - "pallet-session", - "pallet-session-benchmarking", - "pallet-skip-feeless-payment", - "pallet-society", - "pallet-staking", - "pallet-staking-reward-curve", - "pallet-staking-reward-fn", - "pallet-staking-runtime-api", - "pallet-state-trie-migration", - "pallet-statement", - "pallet-sudo", - "pallet-timestamp", - "pallet-tips", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-transaction-storage", - "pallet-treasury", - "pallet-tx-pause", - "pallet-uniques", - "pallet-utility", - "pallet-vesting", - "pallet-whitelist", - "pallet-xcm", - "pallet-xcm-benchmarks", - "pallet-xcm-bridge-hub", - "pallet-xcm-bridge-hub-router", - "parachains-common", - "polkadot-core-primitives", - "polkadot-parachain-primitives", - "polkadot-primitives", - "polkadot-runtime-common", - "polkadot-runtime-metrics", - "polkadot-runtime-parachains", "polkadot-sdk-frame", "polkadot-sdk-frame?/runtime", - "sc-chain-spec-derive", - "sc-tracing-proc-macro", - "slot-range-helper", - "snowbridge-beacon-primitives", - "snowbridge-core", - "snowbridge-ethereum", - "snowbridge-outbound-queue-merkle-tree", - "snowbridge-outbound-queue-runtime-api", - "snowbridge-pallet-ethereum-client", - "snowbridge-pallet-ethereum-client-fixtures", - "snowbridge-pallet-inbound-queue", - "snowbridge-pallet-inbound-queue-fixtures", - "snowbridge-pallet-outbound-queue", - "snowbridge-pallet-system", - "snowbridge-router-primitives", - "snowbridge-runtime-common", - "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", @@ -758,15 +599,6 @@ runtime = [ "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-bip39", - "testnet-parachains-constants", - "tracing-gum-proc-macro", - "xcm-procedural", - "xcm-runtime-apis", ] node = ["asset-test-utils", "bridge-hub-test-utils", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", "cumulus-test-relay-sproof-builder", "emulated-integration-tests-common", "fork-tree", "frame-benchmarking-cli", "frame-remote-externalities", "frame-support-procedural-tools", "generate-bags", "mmr-gadget", "mmr-rpc", "pallet-contracts-mock-network", "pallet-revive-mock-network", "pallet-transaction-payment-rpc", "parachains-runtimes-test-utils", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-cli", "polkadot-collator-protocol", "polkadot-dispute-distribution", "polkadot-erasure-coding", "polkadot-gossip-support", "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", "polkadot-node-core-candidate-validation", "polkadot-node-core-chain-api", "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", "polkadot-node-core-parachains-inherent", "polkadot-node-core-prospective-parachains", "polkadot-node-core-provisioner", "polkadot-node-core-pvf", "polkadot-node-core-pvf-checker", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", "polkadot-node-core-runtime-api", "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-parachain-lib", "polkadot-rpc", "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", "sc-allocator", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", "sc-chain-spec", "sc-cli", "sc-client-api", "sc-client-db", "sc-consensus", "sc-consensus-aura", "sc-consensus-babe", "sc-consensus-babe-rpc", "sc-consensus-beefy", "sc-consensus-beefy-rpc", "sc-consensus-epochs", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", "sc-consensus-manual-seal", "sc-consensus-pow", "sc-consensus-slots", "sc-executor", "sc-executor-common", "sc-executor-polkavm", "sc-executor-wasmtime", "sc-informant", "sc-keystore", "sc-mixnet", "sc-network", "sc-network-common", "sc-network-gossip", "sc-network-light", "sc-network-statement", "sc-network-sync", "sc-network-transactions", "sc-network-types", "sc-offchain", "sc-proposer-metrics", "sc-rpc", "sc-rpc-api", "sc-rpc-server", "sc-rpc-spec-v2", "sc-service", "sc-state-db", "sc-statement-store", "sc-storage-monitor", "sc-sync-state-rpc", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", "snowbridge-runtime-test-common", "sp-blockchain", "sp-consensus", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-database", "sp-maybe-compressed-blob", "sp-panic-handler", "sp-rpc", "staging-chain-spec-builder", "staging-node-inspect", "staging-tracking-allocator", "std", "subkey", "substrate-build-script-utils", "substrate-frame-rpc-support", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-rpc-client", "substrate-state-trie-migration-rpc", "substrate-wasm-builder", "tracing-gum", "xcm-emulator", "xcm-simulator"] tuples-96 = [ @@ -2655,5 +2487,5 @@ default-features = false optional = true [package.metadata.docs.rs] -features = ["node", "runtime"] +features = ["node", "runtime-full"] targets = ["x86_64-unknown-linux-gnu"] From 97fa922c85976523f755acdd104fdc77ed63dae9 Mon Sep 17 00:00:00 2001 From: Guillaume Thiolliere Date: Wed, 28 Aug 2024 23:42:37 +0900 Subject: [PATCH 10/11] Refactor verbose test (#5506) A test is triggering a log error. But is correct and successful. This is a refactor without triggering the log error. --- .../multi-block-migrations/src/migrations/v1/tests.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs index 838ba29a6212..3d2360d63a73 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs @@ -27,6 +27,7 @@ use crate::{ System, }, }; +use codec::Decode; use frame_support::traits::OnRuntimeUpgrade; use pallet_migrations::WeightInfo as _; @@ -51,10 +52,18 @@ fn lazy_migration_works() { let mut last_decodable = 0; for block in 2..=65 { run_to_block(block); + let mut decodable = 0; for i in 0..1024 { - if crate::MyMap::::get(i).is_some() { + let key = crate::MyMap::::hashed_key_for(i); + let value = + frame_support::storage::unhashed::get_raw(&key[..]).expect("value exists"); + + if let Ok(value) = u64::decode(&mut &value[..]) { + assert_eq!(value, i as u64); decodable += 1; + } else { + assert_eq!(u32::decode(&mut &value[..]).expect("not migrated yet"), i); } } From c4ced11fcc728f51011ddef2602d825df8a9becb Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Wed, 28 Aug 2024 20:40:21 +0300 Subject: [PATCH 11/11] polkadot-parachain: Add omni-node variant with u64 block number (#5269) Related to https://github.com/paritytech/polkadot-sdk/issues/4787 The main changes in this PR are the following: - making the NodeSpec logic generic on the Block type - adding an omni-node variant with u64 block number Apart from this, the PR also moves some of the logic in `service.rs` to the `common` subfolder The omni-node variant with u64 block number is not used yet. We have to either expose the option in the CLI or to read the block number from the chain spec somehow. Will do it in a future PR. --- Cargo.lock | 1 + .../polkadot-parachain-lib/Cargo.toml | 2 + .../polkadot-parachain-lib/src/cli.rs | 5 + .../polkadot-parachain-lib/src/command.rs | 52 +- .../src/common/command.rs | 161 ++++ .../polkadot-parachain-lib/src/common/mod.rs | 32 +- .../src/{ => common}/rpc.rs | 50 +- .../src/common/runtime.rs | 15 +- .../polkadot-parachain-lib/src/common/spec.rs | 392 +++++++++ .../src/common/types.rs | 56 ++ .../asset_hub_polkadot_aura.rs | 197 ----- .../src/fake_runtime_api/aura.rs | 197 ----- .../src/fake_runtime_api/mod.rs | 18 +- .../src/fake_runtime_api/utils.rs | 220 ++++++ .../polkadot-parachain-lib/src/lib.rs | 3 +- .../polkadot-parachain-lib/src/service.rs | 745 +++--------------- .../polkadot-parachain/src/chain_spec/mod.rs | 9 +- prdoc/pr_5269.prdoc | 15 + 18 files changed, 1109 insertions(+), 1061 deletions(-) create mode 100644 cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs rename cumulus/polkadot-parachain/polkadot-parachain-lib/src/{ => common}/rpc.rs (65%) create mode 100644 cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/spec.rs create mode 100644 cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/types.rs delete mode 100644 cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/asset_hub_polkadot_aura.rs delete mode 100644 cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/aura.rs create mode 100644 cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/utils.rs create mode 100644 prdoc/pr_5269.prdoc diff --git a/Cargo.lock b/Cargo.lock index 885e2b4b4cf3..07295630b129 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13992,6 +13992,7 @@ dependencies = [ "sc-chain-spec", "sc-cli", "sc-client-api", + "sc-client-db", "sc-consensus", "sc-executor", "sc-network", diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml b/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml index 09bde034cf26..066cbfae53ae 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml @@ -38,6 +38,7 @@ sc-consensus = { workspace = true, default-features = true } frame-support = { optional = true, workspace = true, default-features = true } sc-cli = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } +sc-client-db = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } sc-telemetry = { workspace = true, default-features = true } @@ -105,6 +106,7 @@ runtime-benchmarks = [ "parachains-common/runtime-benchmarks", "polkadot-cli/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", + "sc-client-db/runtime-benchmarks", "sc-service/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/cli.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/cli.rs index 31eb2cf88060..15d21235d1a1 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/cli.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/cli.rs @@ -36,8 +36,10 @@ use std::{fmt::Debug, marker::PhantomData, path::PathBuf}; /// The related info is shown to the customer as part of logs or help messages. /// It does not impact functionality. pub trait CliConfig { + /// The version of the resulting node binary. fn impl_version() -> String; + /// The description of the resulting node binary. fn description(executable_name: String) -> String { format!( "The command-line arguments provided first will be passed to the parachain node, \n\ @@ -50,10 +52,13 @@ pub trait CliConfig { ) } + /// The author of the resulting node binary. fn author() -> String; + /// The support URL for the resulting node binary. fn support_url() -> String; + /// The starting copyright year of the resulting node binary. fn copyright_start_year() -> u16; } diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs index 7f915b729e0a..320511ece5e5 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -#[cfg(feature = "runtime-benchmarks")] -use crate::service::Block; use crate::{ cli::{Cli, RelayChainCli, Subcommand}, common::{ @@ -24,32 +22,56 @@ use crate::{ AuraConsensusId, Consensus, Runtime, RuntimeResolver as RuntimeResolverT, RuntimeResolver, }, - NodeExtraArgs, - }, - fake_runtime_api::{ - asset_hub_polkadot_aura::RuntimeApi as AssetHubPolkadotRuntimeApi, - aura::RuntimeApi as AuraRuntimeApi, + spec::DynNodeSpec, + types::Block, + NodeBlock, NodeExtraArgs, }, - service::{new_aura_node_spec, DynNodeSpec, ShellNode}, + fake_runtime_api, + runtime::BlockNumber, + service::ShellNode, }; #[cfg(feature = "runtime-benchmarks")] use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; use cumulus_primitives_core::ParaId; use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; use log::info; -use parachains_common::{AssetHubPolkadotAuraId, AuraId}; use sc_cli::{Result, SubstrateCli}; use sp_runtime::traits::AccountIdConversion; #[cfg(feature = "runtime-benchmarks")] use sp_runtime::traits::HashingFor; +use std::panic::{RefUnwindSafe, UnwindSafe}; /// Structure that can be used in order to provide customizers for different functionalities of the /// node binary that is being built using this library. pub struct RunConfig { + /// A custom chain spec loader. pub chain_spec_loader: Box, + /// A custom runtime resolver. pub runtime_resolver: Box, } +pub fn new_aura_node_spec( + aura_id: AuraConsensusId, + extra_args: &NodeExtraArgs, +) -> Box +where + Block: NodeBlock + UnwindSafe + RefUnwindSafe, + Block::BoundedHeader: UnwindSafe + RefUnwindSafe, +{ + match aura_id { + AuraConsensusId::Sr25519 => crate::service::new_aura_node_spec::< + Block, + fake_runtime_api::aura_sr25519::RuntimeApi, + sp_consensus_aura::sr25519::AuthorityId, + >(extra_args), + AuraConsensusId::Ed25519 => crate::service::new_aura_node_spec::< + Block, + fake_runtime_api::aura_ed25519::RuntimeApi, + sp_consensus_aura::ed25519::AuthorityId, + >(extra_args), + } +} + fn new_node_spec( config: &sc_service::Configuration, runtime_resolver: &Box, @@ -59,11 +81,11 @@ fn new_node_spec( Ok(match runtime { Runtime::Shell => Box::new(ShellNode), - Runtime::Omni(consensus) => match consensus { - Consensus::Aura(AuraConsensusId::Sr25519) => - new_aura_node_spec::(extra_args), - Consensus::Aura(AuraConsensusId::Ed25519) => - new_aura_node_spec::(extra_args), + Runtime::Omni(block_number, consensus) => match (block_number, consensus) { + (BlockNumber::U32, Consensus::Aura(aura_id)) => + new_aura_node_spec::>(aura_id, extra_args), + (BlockNumber::U64, Consensus::Aura(aura_id)) => + new_aura_node_spec::>(aura_id, extra_args), }, }) } @@ -156,7 +178,7 @@ pub fn run(cmd_config: RunConfig) -> Result<() match cmd { #[cfg(feature = "runtime-benchmarks")] BenchmarkCmd::Pallet(cmd) => runner.sync_run(|config| { - cmd.run_with_spec::, ReclaimHostFunctions>(Some( + cmd.run_with_spec::>, ReclaimHostFunctions>(Some( config.chain_spec, )) }), diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs new file mode 100644 index 000000000000..e2826826d40e --- /dev/null +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs @@ -0,0 +1,161 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +use crate::common::spec::NodeSpec; +use cumulus_client_cli::ExportGenesisHeadCommand; +use frame_benchmarking_cli::BlockCmd; +#[cfg(any(feature = "runtime-benchmarks"))] +use frame_benchmarking_cli::StorageCmd; +use sc_cli::{CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; +use sc_service::{Configuration, TaskManager}; +use std::{future::Future, pin::Pin}; + +type SyncCmdResult = sc_cli::Result<()>; + +type AsyncCmdResult<'a> = + sc_cli::Result<(Pin + 'a>>, TaskManager)>; + +pub trait NodeCommandRunner { + fn prepare_check_block_cmd( + self: Box, + config: Configuration, + cmd: &CheckBlockCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_export_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ExportBlocksCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_export_state_cmd( + self: Box, + config: Configuration, + cmd: &ExportStateCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_import_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ImportBlocksCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_revert_cmd( + self: Box, + config: Configuration, + cmd: &RevertCmd, + ) -> AsyncCmdResult<'_>; + + fn run_export_genesis_head_cmd( + self: Box, + config: Configuration, + cmd: &ExportGenesisHeadCommand, + ) -> SyncCmdResult; + + fn run_benchmark_block_cmd( + self: Box, + config: Configuration, + cmd: &BlockCmd, + ) -> SyncCmdResult; + + #[cfg(any(feature = "runtime-benchmarks"))] + fn run_benchmark_storage_cmd( + self: Box, + config: Configuration, + cmd: &StorageCmd, + ) -> SyncCmdResult; +} + +impl NodeCommandRunner for T +where + T: NodeSpec, +{ + fn prepare_check_block_cmd( + self: Box, + config: Configuration, + cmd: &CheckBlockCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) + } + + fn prepare_export_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ExportBlocksCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, config.database)), partial.task_manager)) + } + + fn prepare_export_state_cmd( + self: Box, + config: Configuration, + cmd: &ExportStateCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, config.chain_spec)), partial.task_manager)) + } + + fn prepare_import_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ImportBlocksCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) + } + + fn prepare_revert_cmd( + self: Box, + config: Configuration, + cmd: &RevertCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.backend, None)), partial.task_manager)) + } + + fn run_export_genesis_head_cmd( + self: Box, + config: Configuration, + cmd: &ExportGenesisHeadCommand, + ) -> SyncCmdResult { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + cmd.run(partial.client) + } + + fn run_benchmark_block_cmd( + self: Box, + config: Configuration, + cmd: &BlockCmd, + ) -> SyncCmdResult { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + cmd.run(partial.client) + } + + #[cfg(any(feature = "runtime-benchmarks"))] + fn run_benchmark_storage_cmd( + self: Box, + config: Configuration, + cmd: &StorageCmd, + ) -> SyncCmdResult { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + let db = partial.backend.expose_db(); + let storage = partial.backend.expose_storage(); + + cmd.run(config, partial.client, db, storage) + } +} diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/mod.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/mod.rs index 89bc7511dac3..907f09263fc1 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/mod.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/mod.rs @@ -20,15 +20,43 @@ pub(crate) mod aura; pub mod chain_spec; +pub mod command; +pub mod rpc; pub mod runtime; +pub mod spec; +pub mod types; use cumulus_primitives_core::CollectCollationInfo; +use sc_client_db::DbHash; use sp_api::{ApiExt, CallApiAt, ConstructRuntimeApi, Metadata}; use sp_block_builder::BlockBuilder; -use sp_runtime::traits::Block as BlockT; +use sp_runtime::{ + traits::{Block as BlockT, BlockNumber, Header as HeaderT, NumberFor}, + OpaqueExtrinsic, +}; use sp_session::SessionKeys; use sp_transaction_pool::runtime_api::TaggedTransactionQueue; -use std::path::PathBuf; +use std::{fmt::Debug, path::PathBuf, str::FromStr}; + +pub trait NodeBlock: + BlockT + + for<'de> serde::Deserialize<'de> +{ + type BoundedFromStrErr: Debug; + type BoundedNumber: FromStr + BlockNumber; + type BoundedHeader: HeaderT + Unpin; +} + +impl NodeBlock for T +where + T: BlockT + for<'de> serde::Deserialize<'de>, + ::Header: Unpin, + as FromStr>::Err: Debug, +{ + type BoundedFromStrErr = as FromStr>::Err; + type BoundedNumber = NumberFor; + type BoundedHeader = ::Header; +} /// Convenience trait that defines the basic bounds for the `RuntimeApi` of a parachain node. pub trait NodeRuntimeApi: diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/rpc.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/rpc.rs similarity index 65% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/rpc.rs rename to cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/rpc.rs index d156ebe2bd6d..a4e157e87216 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/rpc.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/rpc.rs @@ -18,13 +18,13 @@ #![warn(missing_docs)] -use crate::{ - common::ConstructNodeRuntimeApi, - service::{ParachainBackend, ParachainClient}, +use crate::common::{ + types::{AccountId, Balance, Nonce, ParachainBackend, ParachainClient}, + ConstructNodeRuntimeApi, }; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; -use parachains_common::{AccountId, Balance, Block, Nonce}; use sc_rpc::dev::{Dev, DevApiServer}; +use sp_runtime::traits::Block as BlockT; use std::{marker::PhantomData, sync::Arc}; use substrate_frame_rpc_system::{System, SystemApiServer}; use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer}; @@ -40,43 +40,45 @@ pub(crate) trait BuildRpcExtensions { ) -> sc_service::error::Result; } -pub(crate) struct BuildEmptyRpcExtensions(PhantomData); +pub(crate) struct BuildEmptyRpcExtensions(PhantomData<(Block, RuntimeApi)>); -impl +impl BuildRpcExtensions< - ParachainClient, - ParachainBackend, - sc_transaction_pool::FullPool>, - > for BuildEmptyRpcExtensions + ParachainClient, + ParachainBackend, + sc_transaction_pool::FullPool>, + > for BuildEmptyRpcExtensions where - RuntimeApi: ConstructNodeRuntimeApi> + Send + Sync + 'static, + RuntimeApi: + ConstructNodeRuntimeApi> + Send + Sync + 'static, { fn build_rpc_extensions( - _client: Arc>, - _backend: Arc, - _pool: Arc>>, + _client: Arc>, + _backend: Arc>, + _pool: Arc>>, ) -> sc_service::error::Result { Ok(RpcExtension::new(())) } } -pub(crate) struct BuildParachainRpcExtensions(PhantomData); +pub(crate) struct BuildParachainRpcExtensions(PhantomData<(Block, RuntimeApi)>); -impl +impl BuildRpcExtensions< - ParachainClient, - ParachainBackend, - sc_transaction_pool::FullPool>, - > for BuildParachainRpcExtensions + ParachainClient, + ParachainBackend, + sc_transaction_pool::FullPool>, + > for BuildParachainRpcExtensions where - RuntimeApi: ConstructNodeRuntimeApi> + Send + Sync + 'static, + RuntimeApi: + ConstructNodeRuntimeApi> + Send + Sync + 'static, RuntimeApi::RuntimeApi: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + substrate_frame_rpc_system::AccountNonceApi, { fn build_rpc_extensions( - client: Arc>, - backend: Arc, - pool: Arc>>, + client: Arc>, + backend: Arc>, + pool: Arc>>, ) -> sc_service::error::Result { let build = || -> Result> { let mut module = RpcExtension::new(()); diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/runtime.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/runtime.rs index c64eda12d5ef..bddbb0a85d03 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/runtime.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/runtime.rs @@ -34,12 +34,21 @@ pub enum Consensus { Aura(AuraConsensusId), } +/// The choice of block number for the parachain omni-node. +#[derive(PartialEq)] +pub enum BlockNumber { + /// u32 + U32, + /// u64 + U64, +} + /// Helper enum listing the supported Runtime types #[derive(PartialEq)] pub enum Runtime { /// None of the system-chain runtimes, rather the node will act agnostic to the runtime ie. be /// an omni-node, and simply run a node with the given consensus algorithm. - Omni(Consensus), + Omni(BlockNumber, Consensus), /// Shell Shell, } @@ -51,11 +60,11 @@ pub trait RuntimeResolver { } /// Default implementation for `RuntimeResolver` that just returns -/// `Runtime::Omni(Consensus::Aura(AuraConsensusId::Sr25519))`. +/// `Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Sr25519))`. pub struct DefaultRuntimeResolver; impl RuntimeResolver for DefaultRuntimeResolver { fn runtime(&self, _chain_spec: &dyn ChainSpec) -> sc_cli::Result { - Ok(Runtime::Omni(Consensus::Aura(AuraConsensusId::Sr25519))) + Ok(Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Sr25519))) } } diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/spec.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/spec.rs new file mode 100644 index 000000000000..55e042aed87e --- /dev/null +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/spec.rs @@ -0,0 +1,392 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +use crate::common::{ + command::NodeCommandRunner, + rpc::BuildRpcExtensions, + types::{ + ParachainBackend, ParachainBlockImport, ParachainClient, ParachainHostFunctions, + ParachainService, + }, + ConstructNodeRuntimeApi, NodeBlock, NodeExtraArgs, +}; +use cumulus_client_cli::CollatorOptions; +use cumulus_client_service::{ + build_network, build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks, + BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams, +}; +use cumulus_primitives_core::{BlockT, ParaId}; +use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; +use parachains_common::Hash; +use polkadot_primitives::CollatorPair; +use prometheus_endpoint::Registry; +use sc_consensus::DefaultImportQueue; +use sc_executor::{HeapAllocStrategy, DEFAULT_HEAP_ALLOC_STRATEGY}; +use sc_network::{config::FullNetworkConfiguration, NetworkBackend, NetworkBlock}; +use sc_service::{Configuration, ImportQueue, PartialComponents, TaskManager}; +use sc_sysinfo::HwBench; +use sc_telemetry::{TelemetryHandle, TelemetryWorker}; +use sc_transaction_pool::FullPool; +use sp_keystore::KeystorePtr; +use std::{future::Future, pin::Pin, sync::Arc, time::Duration}; + +pub(crate) trait BuildImportQueue { + fn build_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry_handle: Option, + task_manager: &TaskManager, + ) -> sc_service::error::Result>; +} + +pub(crate) trait StartConsensus +where + RuntimeApi: ConstructNodeRuntimeApi>, +{ + fn start_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + keystore: KeystorePtr, + relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + backend: Arc>, + node_extra_args: NodeExtraArgs, + ) -> Result<(), sc_service::Error>; +} + +/// Checks that the hardware meets the requirements and print a warning otherwise. +fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { + // Polkadot para-chains should generally use these requirements to ensure that the relay-chain + // will not take longer than expected to import its blocks. + if let Err(err) = frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench) { + log::warn!( + "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", + err + ); + } +} + +pub(crate) trait NodeSpec { + type Block: NodeBlock; + + type RuntimeApi: ConstructNodeRuntimeApi< + Self::Block, + ParachainClient, + >; + + type BuildImportQueue: BuildImportQueue; + + type BuildRpcExtensions: BuildRpcExtensions< + ParachainClient, + ParachainBackend, + FullPool>, + >; + + type StartConsensus: StartConsensus; + + const SYBIL_RESISTANCE: CollatorSybilResistance; + + /// Starts a `ServiceBuilder` for a full service. + /// + /// Use this macro if you don't actually need the full service, but just the builder in order to + /// be able to perform chain operations. + fn new_partial( + config: &Configuration, + ) -> sc_service::error::Result> { + let telemetry = config + .telemetry_endpoints + .clone() + .filter(|x| !x.is_empty()) + .map(|endpoints| -> Result<_, sc_telemetry::Error> { + let worker = TelemetryWorker::new(16)?; + let telemetry = worker.handle().new_telemetry(endpoints); + Ok((worker, telemetry)) + }) + .transpose()?; + + let heap_pages = config.default_heap_pages.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| { + HeapAllocStrategy::Static { extra_pages: h as _ } + }); + + let executor = sc_executor::WasmExecutor::::builder() + .with_execution_method(config.wasm_method) + .with_max_runtime_instances(config.max_runtime_instances) + .with_runtime_cache_size(config.runtime_cache_size) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .build(); + + let (client, backend, keystore_container, task_manager) = + sc_service::new_full_parts_record_import::( + config, + telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), + executor, + true, + )?; + let client = Arc::new(client); + + let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); + + let telemetry = telemetry.map(|(worker, telemetry)| { + task_manager.spawn_handle().spawn("telemetry", None, worker.run()); + telemetry + }); + + let transaction_pool = sc_transaction_pool::BasicPool::new_full( + config.transaction_pool.clone(), + config.role.is_authority().into(), + config.prometheus_registry(), + task_manager.spawn_essential_handle(), + client.clone(), + ); + + let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); + + let import_queue = Self::BuildImportQueue::build_import_queue( + client.clone(), + block_import.clone(), + config, + telemetry.as_ref().map(|telemetry| telemetry.handle()), + &task_manager, + )?; + + Ok(PartialComponents { + backend, + client, + import_queue, + keystore_container, + task_manager, + transaction_pool, + select_chain: (), + other: (block_import, telemetry, telemetry_worker_handle), + }) + } + + /// Start a node with the given parachain spec. + /// + /// This is the actual implementation that is abstract over the executor and the runtime api. + fn start_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + node_extra_args: NodeExtraArgs, + ) -> Pin>>> + where + Net: NetworkBackend, + { + Box::pin(async move { + let parachain_config = prepare_node_config(parachain_config); + + let params = Self::new_partial(¶chain_config)?; + let (block_import, mut telemetry, telemetry_worker_handle) = params.other; + + let client = params.client.clone(); + let backend = params.backend.clone(); + + let mut task_manager = params.task_manager; + let (relay_chain_interface, collator_key) = build_relay_chain_interface( + polkadot_config, + ¶chain_config, + telemetry_worker_handle, + &mut task_manager, + collator_options.clone(), + hwbench.clone(), + ) + .await + .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; + + let validator = parachain_config.role.is_authority(); + let prometheus_registry = parachain_config.prometheus_registry().cloned(); + let transaction_pool = params.transaction_pool.clone(); + let import_queue_service = params.import_queue.service(); + let net_config = FullNetworkConfiguration::<_, _, Net>::new( + ¶chain_config.network, + prometheus_registry.clone(), + ); + + let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + build_network(BuildNetworkParams { + parachain_config: ¶chain_config, + net_config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + para_id, + spawn_handle: task_manager.spawn_handle(), + relay_chain_interface: relay_chain_interface.clone(), + import_queue: params.import_queue, + sybil_resistance_level: Self::SYBIL_RESISTANCE, + }) + .await?; + + let rpc_builder = { + let client = client.clone(); + let transaction_pool = transaction_pool.clone(); + let backend_for_rpc = backend.clone(); + + Box::new(move |_| { + Self::BuildRpcExtensions::build_rpc_extensions( + client.clone(), + backend_for_rpc.clone(), + transaction_pool.clone(), + ) + }) + }; + + sc_service::spawn_tasks(sc_service::SpawnTasksParams { + rpc_builder, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + task_manager: &mut task_manager, + config: parachain_config, + keystore: params.keystore_container.keystore(), + backend: backend.clone(), + network: network.clone(), + sync_service: sync_service.clone(), + system_rpc_tx, + tx_handler_controller, + telemetry: telemetry.as_mut(), + })?; + + if let Some(hwbench) = hwbench { + sc_sysinfo::print_hwbench(&hwbench); + if validator { + warn_if_slow_hardware(&hwbench); + } + + if let Some(ref mut telemetry) = telemetry { + let telemetry_handle = telemetry.handle(); + task_manager.spawn_handle().spawn( + "telemetry_hwbench", + None, + sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), + ); + } + } + + let announce_block = { + let sync_service = sync_service.clone(); + Arc::new(move |hash, data| sync_service.announce_block(hash, data)) + }; + + let relay_chain_slot_duration = Duration::from_secs(6); + + let overseer_handle = relay_chain_interface + .overseer_handle() + .map_err(|e| sc_service::Error::Application(Box::new(e)))?; + + start_relay_chain_tasks(StartRelayChainTasksParams { + client: client.clone(), + announce_block: announce_block.clone(), + para_id, + relay_chain_interface: relay_chain_interface.clone(), + task_manager: &mut task_manager, + da_recovery_profile: if validator { + DARecoveryProfile::Collator + } else { + DARecoveryProfile::FullNode + }, + import_queue: import_queue_service, + relay_chain_slot_duration, + recovery_handle: Box::new(overseer_handle.clone()), + sync_service, + })?; + + if validator { + Self::StartConsensus::start_consensus( + client.clone(), + block_import, + prometheus_registry.as_ref(), + telemetry.as_ref().map(|t| t.handle()), + &task_manager, + relay_chain_interface.clone(), + transaction_pool, + params.keystore_container.keystore(), + relay_chain_slot_duration, + para_id, + collator_key.expect("Command line arguments do not allow this. qed"), + overseer_handle, + announce_block, + backend.clone(), + node_extra_args, + )?; + } + + start_network.start_network(); + + Ok(task_manager) + }) + } +} + +pub(crate) trait DynNodeSpec: NodeCommandRunner { + fn start_node( + self: Box, + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + node_extra_args: NodeExtraArgs, + ) -> Pin>>>; +} + +impl DynNodeSpec for T +where + T: NodeSpec + NodeCommandRunner, +{ + fn start_node( + self: Box, + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + node_extra_args: NodeExtraArgs, + ) -> Pin>>> { + match parachain_config.network.network_backend { + sc_network::config::NetworkBackendType::Libp2p => + ::start_node::>( + parachain_config, + polkadot_config, + collator_options, + para_id, + hwbench, + node_extra_args, + ), + sc_network::config::NetworkBackendType::Litep2p => + ::start_node::( + parachain_config, + polkadot_config, + collator_options, + para_id, + hwbench, + node_extra_args, + ), + } + } +} diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/types.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/types.rs new file mode 100644 index 000000000000..9cfdcb22451c --- /dev/null +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/types.rs @@ -0,0 +1,56 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport; +use cumulus_primitives_core::relay_chain::UncheckedExtrinsic; +use sc_consensus::DefaultImportQueue; +use sc_executor::WasmExecutor; +use sc_service::{PartialComponents, TFullBackend, TFullClient}; +use sc_telemetry::{Telemetry, TelemetryWorkerHandle}; +use sc_transaction_pool::FullPool; +use sp_runtime::{generic, traits::BlakeTwo256}; +use std::sync::Arc; + +pub use parachains_common::{AccountId, Balance, Hash, Nonce}; + +type Header = generic::Header; +pub type Block = generic::Block, UncheckedExtrinsic>; + +#[cfg(not(feature = "runtime-benchmarks"))] +pub type ParachainHostFunctions = cumulus_client_service::ParachainHostFunctions; +#[cfg(feature = "runtime-benchmarks")] +pub type ParachainHostFunctions = ( + cumulus_client_service::ParachainHostFunctions, + frame_benchmarking::benchmarking::HostFunctions, +); + +pub type ParachainClient = + TFullClient>; + +pub type ParachainBackend = TFullBackend; + +pub type ParachainBlockImport = + TParachainBlockImport>, ParachainBackend>; + +/// Assembly of PartialComponents (enough to run chain ops subcommands) +pub type ParachainService = PartialComponents< + ParachainClient, + ParachainBackend, + (), + DefaultImportQueue, + FullPool>, + (ParachainBlockImport, Option, Option), +>; diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/asset_hub_polkadot_aura.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/asset_hub_polkadot_aura.rs deleted file mode 100644 index f2b8b4d562b9..000000000000 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/asset_hub_polkadot_aura.rs +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus 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. - -// Cumulus 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 Cumulus. If not, see . - -//! These are used to provide a type that implements these runtime APIs without requiring to import -//! the native runtimes. - -use parachains_common::{AccountId, AssetHubPolkadotAuraId, Balance, Block, Nonce}; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::{ - traits::Block as BlockT, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, -}; -use sp_weights::Weight; - -pub struct Runtime; - -sp_api::impl_runtime_apis! { - impl sp_api::Core for Runtime { - fn version() -> sp_version::RuntimeVersion { - unimplemented!() - } - - fn execute_block(_: Block) { - unimplemented!() - } - - fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { - unimplemented!() - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - unimplemented!() - } - - fn metadata_at_version(_: u32) -> Option { - unimplemented!() - } - - fn metadata_versions() -> Vec { - unimplemented!() - } - } - - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - unimplemented!() - } - - fn authorities() -> Vec { - unimplemented!() - } - } - - impl cumulus_primitives_aura::AuraUnincludedSegmentApi for Runtime { - fn can_build_upon( - _: ::Hash, - _: cumulus_primitives_aura::Slot, - ) -> bool { - unimplemented!() - } - } - - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic(_: ::Extrinsic) -> ApplyExtrinsicResult { - unimplemented!() - } - - fn finalize_block() -> ::Header { - unimplemented!() - } - - fn inherent_extrinsics(_: sp_inherents::InherentData) -> Vec<::Extrinsic> { - unimplemented!() - } - - fn check_inherents(_: Block, _: sp_inherents::InherentData) -> sp_inherents::CheckInherentsResult { - unimplemented!() - } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - _: TransactionSource, - _: ::Extrinsic, - _: ::Hash, - ) -> TransactionValidity { - unimplemented!() - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(_: Option>) -> Vec { - unimplemented!() - } - - fn decode_session_keys( - _: Vec, - ) -> Option, KeyTypeId)>> { - unimplemented!() - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { - fn query_info( - _: ::Extrinsic, - _: u32, - ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { - unimplemented!() - } - fn query_fee_details( - _: ::Extrinsic, - _: u32, - ) -> pallet_transaction_payment::FeeDetails { - unimplemented!() - } - fn query_weight_to_fee(_: Weight) -> Balance { - unimplemented!() - } - fn query_length_to_fee(_: u32) -> Balance { - unimplemented!() - } - } - - impl cumulus_primitives_core::CollectCollationInfo for Runtime { - fn collect_collation_info(_: &::Header) -> cumulus_primitives_core::CollationInfo { - unimplemented!() - } - } - - #[cfg(feature = "try-runtime")] - impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(_: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - unimplemented!() - } - - fn execute_block( - _: Block, - _: bool, - _: bool, - _: frame_try_runtime::TryStateSelect, - ) -> Weight { - unimplemented!() - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(_: AccountId) -> Nonce { - unimplemented!() - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(_: bool) -> ( - Vec, - Vec, - ) { - unimplemented!() - } - - fn dispatch_benchmark( - _: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { - unimplemented!() - } - } - - impl sp_genesis_builder::GenesisBuilder for Runtime { - fn build_state(_: Vec) -> sp_genesis_builder::Result { - unimplemented!() - } - - fn get_preset(_id: &Option) -> Option> { - unimplemented!() - } - - fn preset_names() -> Vec { - unimplemented!() - } - } -} diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/aura.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/aura.rs deleted file mode 100644 index eb6d3fafa3d6..000000000000 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/aura.rs +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus 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. - -// Cumulus 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 Cumulus. If not, see . - -//! These are used to provide a type that implements these runtime APIs without requiring to import -//! the native runtimes. - -use parachains_common::{AccountId, AuraId, Balance, Block, Nonce}; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::{ - traits::Block as BlockT, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, -}; -use sp_weights::Weight; - -pub struct Runtime; - -sp_api::impl_runtime_apis! { - impl sp_api::Core for Runtime { - fn version() -> sp_version::RuntimeVersion { - unimplemented!() - } - - fn execute_block(_: Block) { - unimplemented!() - } - - fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { - unimplemented!() - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - unimplemented!() - } - - fn metadata_at_version(_: u32) -> Option { - unimplemented!() - } - - fn metadata_versions() -> Vec { - unimplemented!() - } - } - - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - unimplemented!() - } - - fn authorities() -> Vec { - unimplemented!() - } - } - - impl cumulus_primitives_aura::AuraUnincludedSegmentApi for Runtime { - fn can_build_upon( - _: ::Hash, - _: cumulus_primitives_aura::Slot, - ) -> bool { - unimplemented!() - } - } - - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic(_: ::Extrinsic) -> ApplyExtrinsicResult { - unimplemented!() - } - - fn finalize_block() -> ::Header { - unimplemented!() - } - - fn inherent_extrinsics(_: sp_inherents::InherentData) -> Vec<::Extrinsic> { - unimplemented!() - } - - fn check_inherents(_: Block, _: sp_inherents::InherentData) -> sp_inherents::CheckInherentsResult { - unimplemented!() - } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - _: TransactionSource, - _: ::Extrinsic, - _: ::Hash, - ) -> TransactionValidity { - unimplemented!() - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(_: Option>) -> Vec { - unimplemented!() - } - - fn decode_session_keys( - _: Vec, - ) -> Option, KeyTypeId)>> { - unimplemented!() - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { - fn query_info( - _: ::Extrinsic, - _: u32, - ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { - unimplemented!() - } - fn query_fee_details( - _: ::Extrinsic, - _: u32, - ) -> pallet_transaction_payment::FeeDetails { - unimplemented!() - } - fn query_weight_to_fee(_: Weight) -> Balance { - unimplemented!() - } - fn query_length_to_fee(_: u32) -> Balance { - unimplemented!() - } - } - - impl cumulus_primitives_core::CollectCollationInfo for Runtime { - fn collect_collation_info(_: &::Header) -> cumulus_primitives_core::CollationInfo { - unimplemented!() - } - } - - #[cfg(feature = "try-runtime")] - impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(_: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - unimplemented!() - } - - fn execute_block( - _: Block, - _: bool, - _: bool, - _: frame_try_runtime::TryStateSelect, - ) -> Weight { - unimplemented!() - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(_: AccountId) -> Nonce { - unimplemented!() - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(_: bool) -> ( - Vec, - Vec, - ) { - unimplemented!() - } - - fn dispatch_benchmark( - _: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { - unimplemented!() - } - } - - impl sp_genesis_builder::GenesisBuilder for Runtime { - fn build_state(_: Vec) -> sp_genesis_builder::Result { - unimplemented!() - } - - fn get_preset(_id: &Option) -> Option> { - unimplemented!() - } - - fn preset_names() -> Vec { - unimplemented!() - } - } -} diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/mod.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/mod.rs index 29e2736b06ff..02aa867d70fe 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/mod.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/mod.rs @@ -17,5 +17,19 @@ //! In an ideal world this would be one runtime which would simplify the code massively. //! This is not an ideal world - Polkadot Asset Hub has a different key type. -pub mod asset_hub_polkadot_aura; -pub mod aura; +mod utils; + +use utils::{impl_node_runtime_apis, imports::*}; + +type CustomBlock = crate::common::types::Block; +pub mod aura_sr25519 { + use super::*; + struct FakeRuntime; + impl_node_runtime_apis!(FakeRuntime, CustomBlock, sp_consensus_aura::sr25519::AuthorityId); +} + +pub mod aura_ed25519 { + use super::*; + struct FakeRuntime; + impl_node_runtime_apis!(FakeRuntime, CustomBlock, sp_consensus_aura::ed25519::AuthorityId); +} diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/utils.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/utils.rs new file mode 100644 index 000000000000..442b87b5d775 --- /dev/null +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/utils.rs @@ -0,0 +1,220 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +pub(crate) mod imports { + pub use parachains_common::{AccountId, Balance, Nonce}; + pub use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; + pub use sp_runtime::{ + traits::Block as BlockT, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, + }; + pub use sp_weights::Weight; +} + +macro_rules! impl_node_runtime_apis { + ($runtime: ty, $block: tt, $aura_id: ty) => { + sp_api::impl_runtime_apis! { + impl sp_api::Core<$block> for $runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + + fn execute_block(_: $block) { + unimplemented!() + } + + fn initialize_block( + _: &<$block as BlockT>::Header + ) -> sp_runtime::ExtrinsicInclusionMode { + unimplemented!() + } + } + + impl sp_api::Metadata<$block> for $runtime { + fn metadata() -> OpaqueMetadata { + unimplemented!() + } + + fn metadata_at_version(_: u32) -> Option { + unimplemented!() + } + + fn metadata_versions() -> Vec { + unimplemented!() + } + } + + impl sp_consensus_aura::AuraApi<$block, $aura_id> for $runtime { + fn slot_duration() -> sp_consensus_aura::SlotDuration { + unimplemented!() + } + + fn authorities() -> Vec<$aura_id> { + unimplemented!() + } + } + + impl cumulus_primitives_aura::AuraUnincludedSegmentApi<$block> for $runtime { + fn can_build_upon( + _: <$block as BlockT>::Hash, + _: cumulus_primitives_aura::Slot, + ) -> bool { + unimplemented!() + } + } + + impl sp_block_builder::BlockBuilder<$block> for $runtime { + fn apply_extrinsic(_: <$block as BlockT>::Extrinsic) -> ApplyExtrinsicResult { + unimplemented!() + } + + fn finalize_block() -> <$block as BlockT>::Header { + unimplemented!() + } + + fn inherent_extrinsics( + _: sp_inherents::InherentData + ) -> Vec<<$block as BlockT>::Extrinsic> { + unimplemented!() + } + + fn check_inherents( + _: $block, + _: sp_inherents::InherentData + ) -> sp_inherents::CheckInherentsResult { + unimplemented!() + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<$block> for $runtime { + fn validate_transaction( + _: TransactionSource, + _: <$block as BlockT>::Extrinsic, + _: <$block as BlockT>::Hash, + ) -> TransactionValidity { + unimplemented!() + } + } + + impl sp_session::SessionKeys<$block> for $runtime { + fn generate_session_keys(_: Option>) -> Vec { + unimplemented!() + } + + fn decode_session_keys( + _: Vec, + ) -> Option, KeyTypeId)>> { + unimplemented!() + } + } + + impl + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< + $block, + Balance, + > for $runtime + { + fn query_info( + _: <$block as BlockT>::Extrinsic, + _: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + unimplemented!() + } + fn query_fee_details( + _: <$block as BlockT>::Extrinsic, + _: u32, + ) -> pallet_transaction_payment::FeeDetails { + unimplemented!() + } + fn query_weight_to_fee(_: Weight) -> Balance { + unimplemented!() + } + fn query_length_to_fee(_: u32) -> Balance { + unimplemented!() + } + } + + impl cumulus_primitives_core::CollectCollationInfo<$block> for $runtime { + fn collect_collation_info( + _: &<$block as BlockT>::Header + ) -> cumulus_primitives_core::CollationInfo { + unimplemented!() + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime<$block> for $runtime { + fn on_runtime_upgrade( + _: frame_try_runtime::UpgradeCheckSelect + ) -> (Weight, Weight) { + unimplemented!() + } + + fn execute_block( + _: $block, + _: bool, + _: bool, + _: frame_try_runtime::TryStateSelect, + ) -> Weight { + unimplemented!() + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi< + $block, + AccountId, + Nonce + > for $runtime { + fn account_nonce(_: AccountId) -> Nonce { + unimplemented!() + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark<$block> for $runtime { + fn benchmark_metadata(_: bool) -> ( + Vec, + Vec, + ) { + unimplemented!() + } + + fn dispatch_benchmark( + _: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + unimplemented!() + } + } + + impl sp_genesis_builder::GenesisBuilder<$block> for $runtime { + fn build_state(_: Vec) -> sp_genesis_builder::Result { + unimplemented!() + } + + fn get_preset(_id: &Option) -> Option> { + unimplemented!() + } + + fn preset_names() -> Vec { + unimplemented!() + } + } + } + }; +} + +pub(crate) use impl_node_runtime_apis; diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/lib.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/lib.rs index fc164a9d8907..6aa2f656a48b 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/lib.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/lib.rs @@ -39,11 +39,12 @@ //! //! For an example, see the `polkadot-parachain-bin` crate. +#![deny(missing_docs)] + mod cli; mod command; mod common; mod fake_runtime_api; -mod rpc; mod service; pub use cli::CliConfig; diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/service.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/service.rs index 057b8af9af52..303ec1e3b298 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/service.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/service.rs @@ -14,7 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use cumulus_client_cli::{CollatorOptions, ExportGenesisHeadCommand}; +use crate::{ + common::{ + aura::{AuraIdT, AuraRuntimeApi}, + rpc::{BuildEmptyRpcExtensions, BuildParachainRpcExtensions}, + spec::{BuildImportQueue, DynNodeSpec, NodeSpec, StartConsensus}, + types::{ + AccountId, Balance, Block, Hash, Nonce, ParachainBackend, ParachainBlockImport, + ParachainClient, + }, + ConstructNodeRuntimeApi, NodeBlock, NodeExtraArgs, + }, + fake_runtime_api::aura_sr25519::RuntimeApi as FakeRuntimeApi, +}; use cumulus_client_collator::service::{ CollatorService, ServiceInterface as CollatorServiceInterface, }; @@ -23,370 +35,45 @@ use cumulus_client_consensus_aura::collators::lookahead::{self as aura, Params a use cumulus_client_consensus_aura::collators::slot_based::{ self as slot_based, Params as SlotBasedParams, }; -use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport; use cumulus_client_consensus_proposer::{Proposer, ProposerInterface}; use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; #[allow(deprecated)] use cumulus_client_service::old_consensus; -use cumulus_client_service::{ - build_network, build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks, - BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams, -}; +use cumulus_client_service::CollatorSybilResistance; use cumulus_primitives_core::{relay_chain::ValidationCode, ParaId}; use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; - -use crate::{ - common::{ - aura::{AuraIdT, AuraRuntimeApi}, - ConstructNodeRuntimeApi, NodeExtraArgs, - }, - fake_runtime_api::aura::RuntimeApi as FakeRuntimeApi, - rpc::BuildRpcExtensions, -}; -pub use parachains_common::{AccountId, Balance, Block, Hash, Nonce}; - -use crate::rpc::{BuildEmptyRpcExtensions, BuildParachainRpcExtensions}; -use frame_benchmarking_cli::BlockCmd; -#[cfg(any(feature = "runtime-benchmarks"))] -use frame_benchmarking_cli::StorageCmd; use futures::prelude::*; use polkadot_primitives::CollatorPair; use prometheus_endpoint::Registry; -use sc_cli::{CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; use sc_client_api::BlockchainEvents; +use sc_client_db::DbHash; use sc_consensus::{ import_queue::{BasicQueue, Verifier as VerifierT}, - BlockImportParams, DefaultImportQueue, ImportQueue, + BlockImportParams, DefaultImportQueue, }; -use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; -use sc_network::{config::FullNetworkConfiguration, service::traits::NetworkBackend, NetworkBlock}; -use sc_service::{Configuration, Error, PartialComponents, TFullBackend, TFullClient, TaskManager}; -use sc_sysinfo::HwBench; -use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; +use sc_service::{Configuration, Error, TaskManager}; +use sc_telemetry::TelemetryHandle; use sc_transaction_pool::FullPool; use sp_api::ProvideRuntimeApi; use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; -use sp_runtime::{app_crypto::AppCrypto, traits::Header as HeaderT}; -use std::{marker::PhantomData, pin::Pin, sync::Arc, time::Duration}; - -#[cfg(not(feature = "runtime-benchmarks"))] -type HostFunctions = cumulus_client_service::ParachainHostFunctions; - -#[cfg(feature = "runtime-benchmarks")] -type HostFunctions = ( - cumulus_client_service::ParachainHostFunctions, - frame_benchmarking::benchmarking::HostFunctions, -); - -pub type ParachainClient = TFullClient>; - -pub type ParachainBackend = TFullBackend; - -type ParachainBlockImport = - TParachainBlockImport>, ParachainBackend>; - -/// Assembly of PartialComponents (enough to run chain ops subcommands) -pub type Service = PartialComponents< - ParachainClient, - ParachainBackend, - (), - sc_consensus::DefaultImportQueue, - sc_transaction_pool::FullPool>, - (ParachainBlockImport, Option, Option), ->; - -pub(crate) trait BuildImportQueue { - fn build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry_handle: Option, - task_manager: &TaskManager, - ) -> sc_service::error::Result>; -} - -pub(crate) trait StartConsensus -where - RuntimeApi: ConstructNodeRuntimeApi>, -{ - fn start_consensus( - client: Arc>, - block_import: ParachainBlockImport, - prometheus_registry: Option<&Registry>, - telemetry: Option, - task_manager: &TaskManager, - relay_chain_interface: Arc, - transaction_pool: Arc>>, - keystore: KeystorePtr, - relay_chain_slot_duration: Duration, - para_id: ParaId, - collator_key: CollatorPair, - overseer_handle: OverseerHandle, - announce_block: Arc>) + Send + Sync>, - backend: Arc, - node_extra_args: NodeExtraArgs, - ) -> Result<(), sc_service::Error>; -} - -pub(crate) trait NodeSpec { - type RuntimeApi: ConstructNodeRuntimeApi>; - - type BuildImportQueue: BuildImportQueue + 'static; - - type BuildRpcExtensions: BuildRpcExtensions< - ParachainClient, - ParachainBackend, - sc_transaction_pool::FullPool>, - > + 'static; - - type StartConsensus: StartConsensus + 'static; - - const SYBIL_RESISTANCE: CollatorSybilResistance; - - /// Starts a `ServiceBuilder` for a full service. - /// - /// Use this macro if you don't actually need the full service, but just the builder in order to - /// be able to perform chain operations. - fn new_partial(config: &Configuration) -> sc_service::error::Result> { - let telemetry = config - .telemetry_endpoints - .clone() - .filter(|x| !x.is_empty()) - .map(|endpoints| -> Result<_, sc_telemetry::Error> { - let worker = TelemetryWorker::new(16)?; - let telemetry = worker.handle().new_telemetry(endpoints); - Ok((worker, telemetry)) - }) - .transpose()?; - - let heap_pages = config.default_heap_pages.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| { - HeapAllocStrategy::Static { extra_pages: h as _ } - }); - - let executor = sc_executor::WasmExecutor::::builder() - .with_execution_method(config.wasm_method) - .with_max_runtime_instances(config.max_runtime_instances) - .with_runtime_cache_size(config.runtime_cache_size) - .with_onchain_heap_alloc_strategy(heap_pages) - .with_offchain_heap_alloc_strategy(heap_pages) - .build(); - - let (client, backend, keystore_container, task_manager) = - sc_service::new_full_parts_record_import::( - config, - telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), - executor, - true, - )?; - let client = Arc::new(client); - - let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); - - let telemetry = telemetry.map(|(worker, telemetry)| { - task_manager.spawn_handle().spawn("telemetry", None, worker.run()); - telemetry - }); - - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), - ); - - let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); - - let import_queue = Self::BuildImportQueue::build_import_queue( - client.clone(), - block_import.clone(), - config, - telemetry.as_ref().map(|telemetry| telemetry.handle()), - &task_manager, - )?; - - Ok(PartialComponents { - backend, - client, - import_queue, - keystore_container, - task_manager, - transaction_pool, - select_chain: (), - other: (block_import, telemetry, telemetry_worker_handle), - }) - } - - /// Start a node with the given parachain spec. - /// - /// This is the actual implementation that is abstract over the executor and the runtime api. - fn start_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, - node_extra_args: NodeExtraArgs, - ) -> Pin>>> - where - Net: NetworkBackend, - { - Box::pin(async move { - let parachain_config = prepare_node_config(parachain_config); - - let params = Self::new_partial(¶chain_config)?; - let (block_import, mut telemetry, telemetry_worker_handle) = params.other; - - let client = params.client.clone(); - let backend = params.backend.clone(); - - let mut task_manager = params.task_manager; - let (relay_chain_interface, collator_key) = build_relay_chain_interface( - polkadot_config, - ¶chain_config, - telemetry_worker_handle, - &mut task_manager, - collator_options.clone(), - hwbench.clone(), - ) - .await - .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; - - let validator = parachain_config.role.is_authority(); - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let transaction_pool = params.transaction_pool.clone(); - let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::<_, _, Net>::new( - ¶chain_config.network, - prometheus_registry.clone(), - ); - - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = - build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - net_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - sybil_resistance_level: Self::SYBIL_RESISTANCE, - }) - .await?; - - let rpc_builder = { - let client = client.clone(); - let transaction_pool = transaction_pool.clone(); - let backend_for_rpc = backend.clone(); - - Box::new(move |_| { - Self::BuildRpcExtensions::build_rpc_extensions( - client.clone(), - backend_for_rpc.clone(), - transaction_pool.clone(), - ) - }) - }; - - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_builder, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - config: parachain_config, - keystore: params.keystore_container.keystore(), - backend: backend.clone(), - network: network.clone(), - sync_service: sync_service.clone(), - system_rpc_tx, - tx_handler_controller, - telemetry: telemetry.as_mut(), - })?; - - if let Some(hwbench) = hwbench { - sc_sysinfo::print_hwbench(&hwbench); - if validator { - warn_if_slow_hardware(&hwbench); - } - - if let Some(ref mut telemetry) = telemetry { - let telemetry_handle = telemetry.handle(); - task_manager.spawn_handle().spawn( - "telemetry_hwbench", - None, - sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), - ); - } - } - - let announce_block = { - let sync_service = sync_service.clone(); - Arc::new(move |hash, data| sync_service.announce_block(hash, data)) - }; - - let relay_chain_slot_duration = Duration::from_secs(6); - - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; - - start_relay_chain_tasks(StartRelayChainTasksParams { - client: client.clone(), - announce_block: announce_block.clone(), - para_id, - relay_chain_interface: relay_chain_interface.clone(), - task_manager: &mut task_manager, - da_recovery_profile: if validator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, - import_queue: import_queue_service, - relay_chain_slot_duration, - recovery_handle: Box::new(overseer_handle.clone()), - sync_service, - })?; - - if validator { - Self::StartConsensus::start_consensus( - client.clone(), - block_import, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|t| t.handle()), - &task_manager, - relay_chain_interface.clone(), - transaction_pool, - params.keystore_container.keystore(), - relay_chain_slot_duration, - para_id, - collator_key.expect("Command line arguments do not allow this. qed"), - overseer_handle, - announce_block, - backend.clone(), - node_extra_args, - )?; - } - - start_network.start_network(); - - Ok(task_manager) - }) - } -} +use sp_runtime::{ + app_crypto::AppCrypto, + traits::{Block as BlockT, Header as HeaderT}, +}; +use std::{marker::PhantomData, sync::Arc, time::Duration}; /// Build the import queue for the shell runtime. -pub(crate) struct BuildShellImportQueue(PhantomData); +pub(crate) struct BuildShellImportQueue; -impl BuildImportQueue for BuildShellImportQueue { +impl BuildImportQueue, FakeRuntimeApi> for BuildShellImportQueue { fn build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, + client: Arc, FakeRuntimeApi>>, + block_import: ParachainBlockImport, FakeRuntimeApi>, config: &Configuration, _telemetry_handle: Option, task_manager: &TaskManager, - ) -> sc_service::error::Result> { + ) -> sc_service::error::Result>> { cumulus_client_consensus_relay_chain::import_queue( client, block_import, @@ -401,15 +88,16 @@ impl BuildImportQueue for BuildShellImportQueue pub(crate) struct ShellNode; impl NodeSpec for ShellNode { + type Block = Block; type RuntimeApi = FakeRuntimeApi; - type BuildImportQueue = BuildShellImportQueue; - type BuildRpcExtensions = BuildEmptyRpcExtensions; + type BuildImportQueue = BuildShellImportQueue; + type BuildRpcExtensions = BuildEmptyRpcExtensions, Self::RuntimeApi>; type StartConsensus = StartRelayChainConsensus; const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Unresistant; } -struct Verifier { +struct Verifier { client: Arc, aura_verifier: Box>, relay_chain_verifier: Box>, @@ -417,7 +105,7 @@ struct Verifier { } #[async_trait::async_trait] -impl VerifierT for Verifier +impl VerifierT for Verifier where Client: ProvideRuntimeApi + Send + Sync, Client::Api: AuraRuntimeApi, @@ -437,51 +125,53 @@ where /// Build the import queue for parachain runtimes that started with relay chain consensus and /// switched to aura. -pub(crate) struct BuildRelayToAuraImportQueue( - PhantomData<(RuntimeApi, AuraId)>, +pub(crate) struct BuildRelayToAuraImportQueue( + PhantomData<(Block, RuntimeApi, AuraId)>, ); -impl BuildImportQueue - for BuildRelayToAuraImportQueue +impl BuildImportQueue + for BuildRelayToAuraImportQueue where - RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi, AuraId: AuraIdT + Sync, { fn build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, + client: Arc>, + block_import: ParachainBlockImport, config: &Configuration, telemetry_handle: Option, task_manager: &TaskManager, ) -> sc_service::error::Result> { let verifier_client = client.clone(); - let aura_verifier = - cumulus_client_consensus_aura::build_verifier::<::Pair, _, _, _>( - cumulus_client_consensus_aura::BuildVerifierParams { - client: verifier_client.clone(), - create_inherent_data_providers: move |parent_hash, _| { - let cidp_client = verifier_client.clone(); - async move { - let slot_duration = cumulus_client_consensus_aura::slot_duration_at( - &*cidp_client, - parent_hash, - )?; - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - slot_duration, - ); - - Ok((slot, timestamp)) - } - }, - telemetry: telemetry_handle, - }, - ); + let aura_verifier = cumulus_client_consensus_aura::build_verifier::< + ::Pair, + _, + _, + _, + >(cumulus_client_consensus_aura::BuildVerifierParams { + client: verifier_client.clone(), + create_inherent_data_providers: move |parent_hash, _| { + let cidp_client = verifier_client.clone(); + async move { + let slot_duration = cumulus_client_consensus_aura::slot_duration_at( + &*cidp_client, + parent_hash, + )?; + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + } + }, + telemetry: telemetry_handle, + }); let relay_chain_verifier = Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })); @@ -503,35 +193,43 @@ where /// Uses the lookahead collator to support async backing. /// /// Start an aura powered parachain node. Some system chains use this. -pub(crate) struct AuraNode( - pub PhantomData<(RuntimeApi, AuraId, StartConsensus)>, +pub(crate) struct AuraNode( + pub PhantomData<(Block, RuntimeApi, AuraId, StartConsensus)>, ); -impl Default for AuraNode { +impl Default + for AuraNode +{ fn default() -> Self { Self(Default::default()) } } -impl NodeSpec for AuraNode +impl NodeSpec + for AuraNode where - RuntimeApi: ConstructNodeRuntimeApi>, + Block: NodeBlock, + RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + substrate_frame_rpc_system::AccountNonceApi, AuraId: AuraIdT + Sync, - StartConsensus: self::StartConsensus + 'static, + StartConsensus: self::StartConsensus + 'static, { + type Block = Block; type RuntimeApi = RuntimeApi; - type BuildImportQueue = BuildRelayToAuraImportQueue; - type BuildRpcExtensions = BuildParachainRpcExtensions; + type BuildImportQueue = BuildRelayToAuraImportQueue; + type BuildRpcExtensions = BuildParachainRpcExtensions; type StartConsensus = StartConsensus; const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Resistant; } -pub fn new_aura_node_spec(extra_args: &NodeExtraArgs) -> Box +pub fn new_aura_node_spec( + extra_args: &NodeExtraArgs, +) -> Box where - RuntimeApi: ConstructNodeRuntimeApi>, + Block: NodeBlock, + RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + substrate_frame_rpc_system::AccountNonceApi, @@ -539,15 +237,17 @@ where { if extra_args.use_slot_based_consensus { Box::new(AuraNode::< + Block, RuntimeApi, AuraId, - StartSlotBasedAuraConsensus, + StartSlotBasedAuraConsensus, >::default()) } else { Box::new(AuraNode::< + Block, RuntimeApi, AuraId, - StartLookaheadAuraConsensus, + StartLookaheadAuraConsensus, >::default()) } } @@ -556,22 +256,22 @@ where /// decides what is backed and included. pub(crate) struct StartRelayChainConsensus; -impl StartConsensus for StartRelayChainConsensus { +impl StartConsensus, FakeRuntimeApi> for StartRelayChainConsensus { fn start_consensus( - client: Arc>, - block_import: ParachainBlockImport, + client: Arc, FakeRuntimeApi>>, + block_import: ParachainBlockImport, FakeRuntimeApi>, prometheus_registry: Option<&Registry>, telemetry: Option, task_manager: &TaskManager, relay_chain_interface: Arc, - transaction_pool: Arc>>, + transaction_pool: Arc, ParachainClient, FakeRuntimeApi>>>, _keystore: KeystorePtr, _relay_chain_slot_duration: Duration, para_id: ParaId, collator_key: CollatorPair, overseer_handle: OverseerHandle, announce_block: Arc>) + Send + Sync>, - _backend: Arc, + _backend: Arc>>, _node_extra_args: NodeExtraArgs, ) -> Result<(), Error> { let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( @@ -592,12 +292,12 @@ impl StartConsensus for StartRelayChainConsensus { let relay_chain_interface = relay_chain_interface.clone(); async move { let parachain_inherent = - cumulus_client_parachain_inherent::ParachainInherentDataProvider::create_at( - relay_parent, - &relay_chain_interface, - &validation_data, - para_id, - ).await; + cumulus_client_parachain_inherent::ParachainInherentDataProvider::create_at( + relay_parent, + &relay_chain_interface, + &validation_data, + para_id, + ).await; let parachain_inherent = parachain_inherent.ok_or_else(|| { Box::::from( "Failed to create parachain inherent", @@ -629,23 +329,24 @@ impl StartConsensus for StartRelayChainConsensus { } /// Start consensus using the lookahead aura collator. -pub(crate) struct StartSlotBasedAuraConsensus( - PhantomData<(RuntimeApi, AuraId)>, +pub(crate) struct StartSlotBasedAuraConsensus( + PhantomData<(Block, RuntimeApi, AuraId)>, ); -impl StartSlotBasedAuraConsensus +impl, RuntimeApi, AuraId> + StartSlotBasedAuraConsensus where - RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi, AuraId: AuraIdT + Sync, { #[docify::export_content] fn launch_slot_based_collator( params: SlotBasedParams< - ParachainBlockImport, + ParachainBlockImport, CIDP, - ParachainClient, - ParachainBackend, + ParachainClient, + ParachainBackend, Arc, CHP, Proposer, @@ -675,28 +376,28 @@ where } } -impl StartConsensus - for StartSlotBasedAuraConsensus +impl, RuntimeApi, AuraId> StartConsensus + for StartSlotBasedAuraConsensus where - RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi, AuraId: AuraIdT + Sync, { fn start_consensus( - client: Arc>, - block_import: ParachainBlockImport, + client: Arc>, + block_import: ParachainBlockImport, prometheus_registry: Option<&Registry>, telemetry: Option, task_manager: &TaskManager, relay_chain_interface: Arc, - transaction_pool: Arc>>, + transaction_pool: Arc>>, keystore: KeystorePtr, relay_chain_slot_duration: Duration, para_id: ParaId, collator_key: CollatorPair, _overseer_handle: OverseerHandle, announce_block: Arc>) + Send + Sync>, - backend: Arc, + backend: Arc>, _node_extra_args: NodeExtraArgs, ) -> Result<(), Error> { let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( @@ -747,9 +448,10 @@ where /// Wait for the Aura runtime API to appear on chain. /// This is useful for chains that started out without Aura. Components that /// are depending on Aura functionality will wait until Aura appears in the runtime. -async fn wait_for_aura(client: Arc>) -where - RuntimeApi: ConstructNodeRuntimeApi>, +async fn wait_for_aura( + client: Arc>, +) where + RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi, AuraId: AuraIdT + Sync, { @@ -767,32 +469,32 @@ where } /// Start consensus using the lookahead aura collator. -pub(crate) struct StartLookaheadAuraConsensus( - PhantomData<(RuntimeApi, AuraId)>, +pub(crate) struct StartLookaheadAuraConsensus( + PhantomData<(Block, RuntimeApi, AuraId)>, ); -impl StartConsensus - for StartLookaheadAuraConsensus +impl, RuntimeApi, AuraId> StartConsensus + for StartLookaheadAuraConsensus where - RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi: ConstructNodeRuntimeApi>, RuntimeApi::RuntimeApi: AuraRuntimeApi, AuraId: AuraIdT + Sync, { fn start_consensus( - client: Arc>, - block_import: ParachainBlockImport, + client: Arc>, + block_import: ParachainBlockImport, prometheus_registry: Option<&Registry>, telemetry: Option, task_manager: &TaskManager, relay_chain_interface: Arc, - transaction_pool: Arc>>, + transaction_pool: Arc>>, keystore: KeystorePtr, relay_chain_slot_duration: Duration, para_id: ParaId, collator_key: CollatorPair, overseer_handle: OverseerHandle, announce_block: Arc>) + Send + Sync>, - backend: Arc, + backend: Arc>, node_extra_args: NodeExtraArgs, ) -> Result<(), Error> { let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( @@ -848,194 +550,3 @@ where Ok(()) } } - -/// Checks that the hardware meets the requirements and print a warning otherwise. -fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { - // Polkadot para-chains should generally use these requirements to ensure that the relay-chain - // will not take longer than expected to import its blocks. - if let Err(err) = frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench) { - log::warn!( - "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ - https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", - err - ); - } -} - -type SyncCmdResult = sc_cli::Result<()>; - -type AsyncCmdResult<'a> = - sc_cli::Result<(Pin + 'a>>, TaskManager)>; - -pub(crate) trait DynNodeSpec { - fn prepare_check_block_cmd( - self: Box, - config: Configuration, - cmd: &CheckBlockCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_export_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ExportBlocksCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_export_state_cmd( - self: Box, - config: Configuration, - cmd: &ExportStateCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_import_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ImportBlocksCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_revert_cmd( - self: Box, - config: Configuration, - cmd: &RevertCmd, - ) -> AsyncCmdResult<'_>; - - fn run_export_genesis_head_cmd( - self: Box, - config: Configuration, - cmd: &ExportGenesisHeadCommand, - ) -> SyncCmdResult; - - fn run_benchmark_block_cmd( - self: Box, - config: Configuration, - cmd: &BlockCmd, - ) -> SyncCmdResult; - - #[cfg(any(feature = "runtime-benchmarks"))] - fn run_benchmark_storage_cmd( - self: Box, - config: Configuration, - cmd: &StorageCmd, - ) -> SyncCmdResult; - - fn start_node( - self: Box, - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, - node_extra_args: NodeExtraArgs, - ) -> Pin>>>; -} - -impl DynNodeSpec for T -where - T: NodeSpec, -{ - fn prepare_check_block_cmd( - self: Box, - config: Configuration, - cmd: &CheckBlockCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) - } - - fn prepare_export_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ExportBlocksCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, config.database)), partial.task_manager)) - } - - fn prepare_export_state_cmd( - self: Box, - config: Configuration, - cmd: &ExportStateCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, config.chain_spec)), partial.task_manager)) - } - - fn prepare_import_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ImportBlocksCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) - } - - fn prepare_revert_cmd( - self: Box, - config: Configuration, - cmd: &RevertCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, partial.backend, None)), partial.task_manager)) - } - - fn run_export_genesis_head_cmd( - self: Box, - config: Configuration, - cmd: &ExportGenesisHeadCommand, - ) -> SyncCmdResult { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - cmd.run(partial.client) - } - - fn run_benchmark_block_cmd( - self: Box, - config: Configuration, - cmd: &BlockCmd, - ) -> SyncCmdResult { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - cmd.run(partial.client) - } - - #[cfg(any(feature = "runtime-benchmarks"))] - fn run_benchmark_storage_cmd( - self: Box, - config: Configuration, - cmd: &StorageCmd, - ) -> SyncCmdResult { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - let db = partial.backend.expose_db(); - let storage = partial.backend.expose_storage(); - - cmd.run(config, partial.client, db, storage) - } - - fn start_node( - self: Box, - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, - node_extra_args: NodeExtraArgs, - ) -> Pin>>> { - match parachain_config.network.network_backend { - sc_network::config::NetworkBackendType::Libp2p => - ::start_node::>( - parachain_config, - polkadot_config, - collator_options, - para_id, - hwbench, - node_extra_args, - ), - sc_network::config::NetworkBackendType::Litep2p => - ::start_node::( - parachain_config, - polkadot_config, - collator_options, - para_id, - hwbench, - node_extra_args, - ), - } - } -} diff --git a/cumulus/polkadot-parachain/src/chain_spec/mod.rs b/cumulus/polkadot-parachain/src/chain_spec/mod.rs index cd704b5bd938..82aec951704f 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/mod.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/mod.rs @@ -18,7 +18,9 @@ use cumulus_primitives_core::ParaId; use parachains_common::{AccountId, Signature}; use polkadot_parachain_lib::{ chain_spec::{GenericChainSpec, LoadSpec}, - runtime::{AuraConsensusId, Consensus, Runtime, RuntimeResolver as RuntimeResolverT}, + runtime::{ + AuraConsensusId, BlockNumber, Consensus, Runtime, RuntimeResolver as RuntimeResolverT, + }, }; use sc_chain_spec::ChainSpec; use sp_core::{Pair, Public}; @@ -289,7 +291,7 @@ impl RuntimeResolverT for RuntimeResolver { let legacy_runtime = LegacyRuntime::from_id(chain_spec.id()); Ok(match legacy_runtime { LegacyRuntime::AssetHubPolkadot => - Runtime::Omni(Consensus::Aura(AuraConsensusId::Ed25519)), + Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Ed25519)), LegacyRuntime::AssetHub | LegacyRuntime::BridgeHub(_) | LegacyRuntime::Collectives | @@ -297,7 +299,8 @@ impl RuntimeResolverT for RuntimeResolver { LegacyRuntime::People(_) | LegacyRuntime::Glutton | LegacyRuntime::Penpal | - LegacyRuntime::Omni => Runtime::Omni(Consensus::Aura(AuraConsensusId::Sr25519)), + LegacyRuntime::Omni => + Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Sr25519)), LegacyRuntime::Shell | LegacyRuntime::Seedling => Runtime::Shell, }) } diff --git a/prdoc/pr_5269.prdoc b/prdoc/pr_5269.prdoc new file mode 100644 index 000000000000..e4401f2406ce --- /dev/null +++ b/prdoc/pr_5269.prdoc @@ -0,0 +1,15 @@ +# 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: Added the possibility to build a parachain node with block number u64 + +doc: + - audience: Node Dev + description: | + Added the possibility to build a parachain node with block number u64. + +crates: + - name: polkadot-parachain-lib + bump: minor + - name: polkadot-parachain-bin + bump: patch