Skip to content

Commit

Permalink
add NodeFeatures field to HostConfiguration and runtime API (#2177)
Browse files Browse the repository at this point in the history
Adds a `NodeFeatures` bitfield value to the runtime `HostConfiguration`,
with the purpose of coordinating the enabling of node-side features,
such as: #628 and
#598.
These are features that require all validators enable them at the same
time, assuming all/most nodes have upgraded their node versions.

This PR doesn't add any feature yet. These are coming in future PRs.

Also adds a runtime API for querying the state of the client features
and an extrinsic for setting/unsetting a feature by its index in the bitfield.

Note: originally part of:
#1644, but posted as
standalone to be reused by other PRs until the initial PR is merged
  • Loading branch information
alindima committed Nov 14, 2023
1 parent 31c38ce commit fc12f43
Show file tree
Hide file tree
Showing 25 changed files with 709 additions and 131 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use polkadot_overseer::RuntimeApiSubsystemClient;
use polkadot_primitives::{
async_backing::{AsyncBackingParams, BackingState},
slashing,
vstaging::NodeFeatures,
};
use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError};
use sp_api::{ApiError, RuntimeApiInfo};
Expand Down Expand Up @@ -364,6 +365,10 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient {
) -> Result<Option<BackingState>, ApiError> {
Ok(self.rpc_client.parachain_host_para_backing_state(at, para_id).await?)
}

async fn node_features(&self, at: Hash) -> Result<NodeFeatures, ApiError> {
Ok(self.rpc_client.parachain_host_node_features(at).await?)
}
}

#[async_trait::async_trait]
Expand Down
12 changes: 11 additions & 1 deletion cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ use parity_scale_codec::{Decode, Encode};
use cumulus_primitives_core::{
relay_chain::{
async_backing::{AsyncBackingParams, BackingState},
slashing, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash,
slashing,
vstaging::NodeFeatures,
BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash,
CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo,
Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, OccupiedCoreAssumption,
PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode,
Expand Down Expand Up @@ -597,6 +599,14 @@ impl RelayChainRpcClient {
.await
}

pub async fn parachain_host_node_features(
&self,
at: RelayHash,
) -> Result<NodeFeatures, RelayChainError> {
self.call_remote_runtime_function("ParachainHost_node_features", at, None::<()>)
.await
}

pub async fn parachain_host_disabled_validators(
&self,
at: RelayHash,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use emulated_integration_tests_common::{

// Rococo declaration
decl_test_relay_chains! {
#[api_version(8)]
#[api_version(9)]
pub struct Rococo {
genesis = genesis::genesis(),
on_init = (),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use emulated_integration_tests_common::{

// Westend declaration
decl_test_relay_chains! {
#[api_version(8)]
#[api_version(9)]
pub struct Westend {
genesis = genesis::genesis(),
on_init = (),
Expand Down
20 changes: 19 additions & 1 deletion polkadot/node/core/runtime-api/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use schnellru::{ByLength, LruMap};
use sp_consensus_babe::Epoch;

use polkadot_primitives::{
async_backing, slashing, AuthorityDiscoveryId, BlockNumber, CandidateCommitments,
async_backing, slashing, vstaging, AuthorityDiscoveryId, BlockNumber, CandidateCommitments,
CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState,
ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage,
InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement,
Expand Down Expand Up @@ -67,6 +67,7 @@ pub(crate) struct RequestResultCache {
disabled_validators: LruMap<Hash, Vec<ValidatorIndex>>,
para_backing_state: LruMap<(Hash, ParaId), Option<async_backing::BackingState>>,
async_backing_params: LruMap<Hash, async_backing::AsyncBackingParams>,
node_features: LruMap<SessionIndex, vstaging::NodeFeatures>,
}

impl Default for RequestResultCache {
Expand Down Expand Up @@ -100,6 +101,7 @@ impl Default for RequestResultCache {
disabled_validators: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
para_backing_state: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
async_backing_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
node_features: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)),
}
}
}
Expand Down Expand Up @@ -446,6 +448,21 @@ impl RequestResultCache {
self.minimum_backing_votes.insert(session_index, minimum_backing_votes);
}

pub(crate) fn node_features(
&mut self,
session_index: SessionIndex,
) -> Option<&vstaging::NodeFeatures> {
self.node_features.get(&session_index).map(|f| &*f)
}

pub(crate) fn cache_node_features(
&mut self,
session_index: SessionIndex,
features: vstaging::NodeFeatures,
) {
self.node_features.insert(session_index, features);
}

pub(crate) fn disabled_validators(
&mut self,
relay_parent: &Hash,
Expand Down Expand Up @@ -540,4 +557,5 @@ pub(crate) enum RequestResult {
DisabledValidators(Hash, Vec<ValidatorIndex>),
ParaBackingState(Hash, ParaId, Option<async_backing::BackingState>),
AsyncBackingParams(Hash, async_backing::AsyncBackingParams),
NodeFeatures(SessionIndex, vstaging::NodeFeatures),
}
23 changes: 22 additions & 1 deletion polkadot/node/core/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ where
.cache_para_backing_state((relay_parent, para_id), constraints),
AsyncBackingParams(relay_parent, params) =>
self.requests_cache.cache_async_backing_params(relay_parent, params),
NodeFeatures(session_index, params) =>
self.requests_cache.cache_node_features(session_index, params),
}
}

Expand Down Expand Up @@ -313,6 +315,15 @@ where
Some(Request::MinimumBackingVotes(index, sender))
}
},
Request::NodeFeatures(index, sender) => {
if let Some(value) = self.requests_cache.node_features(index) {
self.metrics.on_cached_request();
let _ = sender.send(Ok(value.clone()));
None
} else {
Some(Request::NodeFeatures(index, sender))
}
},
}
}

Expand Down Expand Up @@ -408,6 +419,9 @@ where

macro_rules! query {
($req_variant:ident, $api_name:ident ($($param:expr),*), ver = $version:expr, $sender:expr) => {{
query!($req_variant, $api_name($($param),*), ver = $version, $sender, result = ( relay_parent $(, $param )* ) )
}};
($req_variant:ident, $api_name:ident ($($param:expr),*), ver = $version:expr, $sender:expr, result = ( $($results:expr),* ) ) => {{
let sender = $sender;
let version: u32 = $version; // enforce type for the version expression
let runtime_version = client.api_version_parachain_host(relay_parent).await
Expand Down Expand Up @@ -441,7 +455,7 @@ where
metrics.on_request(res.is_ok());
let _ = sender.send(res.clone());

res.ok().map(|res| RequestResult::$req_variant(relay_parent, $( $param, )* res))
res.ok().map(|res| RequestResult::$req_variant($( $results, )* res))
}}
}

Expand Down Expand Up @@ -591,5 +605,12 @@ where
sender
)
},
Request::NodeFeatures(index, sender) => query!(
NodeFeatures,
node_features(),
ver = Request::NODE_FEATURES_RUNTIME_REQUIREMENT,
sender,
result = (index)
),
}
}
16 changes: 10 additions & 6 deletions polkadot/node/core/runtime-api/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ use polkadot_node_primitives::{BabeAllowedSlots, BabeEpoch, BabeEpochConfigurati
use polkadot_node_subsystem::SpawnGlue;
use polkadot_node_subsystem_test_helpers::make_subsystem_context;
use polkadot_primitives::{
async_backing, slashing, AuthorityDiscoveryId, BlockNumber, CandidateCommitments,
CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState,
ExecutorParams, GroupRotationInfo, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage,
OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes,
SessionIndex, SessionInfo, Slot, ValidationCode, ValidationCodeHash, ValidatorId,
ValidatorIndex, ValidatorSignature,
async_backing, slashing, vstaging::NodeFeatures, AuthorityDiscoveryId, BlockNumber,
CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState,
DisputeState, ExecutorParams, GroupRotationInfo, Id as ParaId, InboundDownwardMessage,
InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement,
ScrapedOnChainVotes, SessionIndex, SessionInfo, Slot, ValidationCode, ValidationCodeHash,
ValidatorId, ValidatorIndex, ValidatorSignature,
};
use sp_api::ApiError;
use sp_core::testing::TaskExecutor;
Expand Down Expand Up @@ -269,6 +269,10 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient {
todo!("Not required for tests")
}

async fn node_features(&self, _: Hash) -> Result<NodeFeatures, ApiError> {
todo!("Not required for tests")
}

async fn disabled_validators(&self, _: Hash) -> Result<Vec<ValidatorIndex>, ApiError> {
todo!("Not required for tests")
}
Expand Down
17 changes: 11 additions & 6 deletions polkadot/node/subsystem-types/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ use polkadot_node_primitives::{
ValidationResult,
};
use polkadot_primitives::{
async_backing, slashing, AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateEvent,
CandidateHash, CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt,
CoreState, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash,
Header as BlockHeader, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage,
MultiDisputeStatementSet, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement,
PvfExecTimeoutKind, SessionIndex, SessionInfo, SignedAvailabilityBitfield,
async_backing, slashing, vstaging::NodeFeatures, AuthorityDiscoveryId, BackedCandidate,
BlockNumber, CandidateEvent, CandidateHash, CandidateIndex, CandidateReceipt, CollatorId,
CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupIndex,
GroupRotationInfo, Hash, Header as BlockHeader, Id as ParaId, InboundDownwardMessage,
InboundHrmpMessage, MultiDisputeStatementSet, OccupiedCoreAssumption, PersistedValidationData,
PvfCheckStatement, PvfExecTimeoutKind, SessionIndex, SessionInfo, SignedAvailabilityBitfield,
SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex,
ValidatorSignature,
};
Expand Down Expand Up @@ -718,6 +718,8 @@ pub enum RuntimeApiRequest {
///
/// If it's not supported by the Runtime, the async backing is said to be disabled.
AsyncBackingParams(RuntimeApiSender<async_backing::AsyncBackingParams>),
/// Get the node features.
NodeFeatures(SessionIndex, RuntimeApiSender<NodeFeatures>),
}

impl RuntimeApiRequest {
Expand Down Expand Up @@ -746,6 +748,9 @@ impl RuntimeApiRequest {

/// `DisabledValidators`
pub const DISABLED_VALIDATORS_RUNTIME_REQUIREMENT: u32 = 8;

/// `Node features`
pub const NODE_FEATURES_RUNTIME_REQUIREMENT: u32 = 9;
}

/// A message to the Runtime API subsystem.
Expand Down
22 changes: 16 additions & 6 deletions polkadot/node/subsystem-types/src/runtime_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

use async_trait::async_trait;
use polkadot_primitives::{
async_backing, runtime_api::ParachainHost, slashing, Block, BlockNumber, CandidateCommitments,
CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState,
ExecutorParams, GroupRotationInfo, Hash, Id, InboundDownwardMessage, InboundHrmpMessage,
OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes,
SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex,
ValidatorSignature,
async_backing, runtime_api::ParachainHost, slashing, vstaging, Block, BlockNumber,
CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState,
DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id, InboundDownwardMessage,
InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement,
ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash,
ValidatorId, ValidatorIndex, ValidatorSignature,
};
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
use sp_api::{ApiError, ApiExt, ProvideRuntimeApi};
Expand Down Expand Up @@ -257,8 +257,14 @@ pub trait RuntimeApiSubsystemClient {
) -> Result<Option<async_backing::BackingState>, ApiError>;

// === v8 ===

/// Gets the disabled validators at a specific block height
async fn disabled_validators(&self, at: Hash) -> Result<Vec<ValidatorIndex>, ApiError>;

// === v9 ===

/// Get the node features.
async fn node_features(&self, at: Hash) -> Result<vstaging::NodeFeatures, ApiError>;
}

/// Default implementation of [`RuntimeApiSubsystemClient`] using the client.
Expand Down Expand Up @@ -508,6 +514,10 @@ where
self.client.runtime_api().async_backing_params(at)
}

async fn node_features(&self, at: Hash) -> Result<vstaging::NodeFeatures, ApiError> {
self.client.runtime_api().node_features(at)
}

async fn disabled_validators(&self, at: Hash) -> Result<Vec<ValidatorIndex>, ApiError> {
self.client.runtime_api().disabled_validators(at)
}
Expand Down
33 changes: 31 additions & 2 deletions polkadot/node/subsystem-util/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ use polkadot_node_subsystem::{
};
use polkadot_node_subsystem_types::UnpinHandle;
use polkadot_primitives::{
slashing, AsyncBackingParams, CandidateEvent, CandidateHash, CoreState, EncodeAs,
ExecutorParams, GroupIndex, GroupRotationInfo, Hash, IndexedVec, OccupiedCore,
slashing, vstaging::NodeFeatures, AsyncBackingParams, CandidateEvent, CandidateHash, CoreState,
EncodeAs, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, IndexedVec, OccupiedCore,
ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, SigningContext, UncheckedSigned,
ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, LEGACY_MIN_BACKING_VOTES,
};
Expand Down Expand Up @@ -507,3 +507,32 @@ pub async fn request_min_backing_votes(
min_backing_votes_res
}
}

/// Request the node features enabled in the runtime.
/// Pass in the session index for caching purposes, as it should only change on session boundaries.
/// Prior to runtime API version 9, just return `None`.
pub async fn request_node_features(
parent: Hash,
session_index: SessionIndex,
sender: &mut impl overseer::SubsystemSender<RuntimeApiMessage>,
) -> Result<Option<NodeFeatures>> {
let res = recv_runtime(
request_from_runtime(parent, sender, |tx| {
RuntimeApiRequest::NodeFeatures(session_index, tx)
})
.await,
)
.await;

if let Err(Error::RuntimeRequest(RuntimeApiError::NotSupported { .. })) = res {
gum::trace!(
target: LOG_TARGET,
?parent,
"Querying the node features from the runtime is not supported by the current Runtime API",
);

Ok(None)
} else {
res.map(Some)
}
}
2 changes: 1 addition & 1 deletion polkadot/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license.workspace = true
description = "Shared primitives used by Polkadot runtime"

[dependencies]
bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] }
bitvec = { version = "1.0.0", default-features = false, features = ["alloc", "serde"] }
hex-literal = "0.4.1"
parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] }
scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive", "serde"] }
Expand Down
15 changes: 11 additions & 4 deletions polkadot/primitives/src/runtime_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@
//! separated from the stable primitives.

use crate::{
async_backing, slashing, AsyncBackingParams, BlockNumber, CandidateCommitments, CandidateEvent,
CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams,
GroupRotationInfo, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement,
ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex,
async_backing, slashing, vstaging, AsyncBackingParams, BlockNumber, CandidateCommitments,
CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState,
ExecutorParams, GroupRotationInfo, OccupiedCoreAssumption, PersistedValidationData,
PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex,
ValidatorSignature,
};
use parity_scale_codec::{Decode, Encode};
Expand Down Expand Up @@ -264,5 +264,12 @@ sp_api::decl_runtime_apis! {
/// Returns a list of all disabled validators at the given block.
#[api_version(8)]
fn disabled_validators() -> Vec<ValidatorIndex>;

/***** Added in v9 *****/

/// Get node features.
/// This is a staging method! Do not use on production runtimes!
#[api_version(9)]
fn node_features() -> vstaging::NodeFeatures;
}
}
5 changes: 5 additions & 0 deletions polkadot/primitives/src/vstaging/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@
//! Staging Primitives.

// Put any primitives used by staging APIs functions here

use bitvec::vec::BitVec;

/// Bit indices in the `HostConfiguration.node_features` that correspond to different node features.
pub type NodeFeatures = BitVec<u8, bitvec::order::Lsb0>;

0 comments on commit fc12f43

Please sign in to comment.