backport to master: Handling of disabled validators in backing subsystem (#1259) (#2764)

#1259 was merged into a feature branch, but we've decided to merge
node-side changes for disabling straight into master.
This is a dependency of #1841 and #2637.

---------

Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io>
This commit is contained in:
ordian
2024-01-08 20:58:30 +01:00
committed by GitHub
parent 4fdab499c4
commit a02b53475b
7 changed files with 575 additions and 74 deletions
+78 -2
View File
@@ -55,6 +55,7 @@ use sp_core::ByteArray;
use sp_keystore::{Error as KeystoreError, KeystorePtr};
use std::time::Duration;
use thiserror::Error;
use vstaging::get_disabled_validators_with_fallback;
pub use metered;
pub use polkadot_node_network_protocol::MIN_GOSSIP_PEERS;
@@ -79,6 +80,9 @@ pub mod inclusion_emulator;
/// Convenient and efficient runtime info access.
pub mod runtime;
/// Helpers for working with unreleased runtime calls
pub mod vstaging;
/// Nested message sending
///
/// Useful for having mostly synchronous code, with submodules spawning short lived asynchronous
@@ -92,6 +96,8 @@ mod determine_new_blocks;
#[cfg(test)]
mod tests;
const LOG_TARGET: &'static str = "parachain::subsystem-util";
/// Duration a job will wait after sending a stop signal before hard-aborting.
pub const JOB_GRACEFUL_STOP_DURATION: Duration = Duration::from_secs(1);
/// Capacity of channels to and from individual jobs
@@ -157,6 +163,62 @@ where
rx
}
/// Verifies if `ParachainHost` runtime api is at least at version `required_runtime_version`. This
/// method is used to determine if a given runtime call is supported by the runtime.
pub async fn has_required_runtime<Sender>(
sender: &mut Sender,
relay_parent: Hash,
required_runtime_version: u32,
) -> bool
where
Sender: SubsystemSender<RuntimeApiMessage>,
{
gum::trace!(target: LOG_TARGET, ?relay_parent, "Fetching ParachainHost runtime api version");
let (tx, rx) = oneshot::channel();
sender
.send_message(RuntimeApiMessage::Request(relay_parent, RuntimeApiRequest::Version(tx)))
.await;
match rx.await {
Result::Ok(Ok(runtime_version)) => {
gum::trace!(
target: LOG_TARGET,
?relay_parent,
?runtime_version,
?required_runtime_version,
"Fetched ParachainHost runtime api version"
);
runtime_version >= required_runtime_version
},
Result::Ok(Err(RuntimeApiError::Execution { source: error, .. })) => {
gum::trace!(
target: LOG_TARGET,
?relay_parent,
?error,
"Execution error while fetching ParachainHost runtime api version"
);
false
},
Result::Ok(Err(RuntimeApiError::NotSupported { .. })) => {
gum::trace!(
target: LOG_TARGET,
?relay_parent,
"NotSupported error while fetching ParachainHost runtime api version"
);
false
},
Result::Err(_) => {
gum::trace!(
target: LOG_TARGET,
?relay_parent,
"Cancelled error while fetching ParachainHost runtime api version"
);
false
},
}
}
/// Construct specialized request functions for the runtime.
///
/// These would otherwise get pretty repetitive.
@@ -378,6 +440,7 @@ pub struct Validator {
signing_context: SigningContext,
key: ValidatorId,
index: ValidatorIndex,
disabled: bool,
}
impl Validator {
@@ -399,7 +462,12 @@ impl Validator {
let validators = validators?;
Self::construct(&validators, signing_context, keystore)
// TODO: https://github.com/paritytech/polkadot-sdk/issues/1940
// When `DisabledValidators` is released remove this and add a
// `request_disabled_validators` call here
let disabled_validators = get_disabled_validators_with_fallback(sender, parent).await?;
Self::construct(&validators, &disabled_validators, signing_context, keystore)
}
/// Construct a validator instance without performing runtime fetches.
@@ -407,13 +475,16 @@ impl Validator {
/// This can be useful if external code also needs the same data.
pub fn construct(
validators: &[ValidatorId],
disabled_validators: &[ValidatorIndex],
signing_context: SigningContext,
keystore: KeystorePtr,
) -> Result<Self, Error> {
let (key, index) =
signing_key_and_index(validators, &keystore).ok_or(Error::NotAValidator)?;
Ok(Validator { signing_context, key, index })
let disabled = disabled_validators.iter().any(|d: &ValidatorIndex| *d == index);
Ok(Validator { signing_context, key, index, disabled })
}
/// Get this validator's id.
@@ -426,6 +497,11 @@ impl Validator {
self.index
}
/// Get the enabled/disabled state of this validator
pub fn disabled(&self) -> bool {
self.disabled
}
/// Get the current signing context.
pub fn signing_context(&self) -> &SigningContext {
&self.signing_context
@@ -0,0 +1,56 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Contains helpers for staging runtime calls.
//!
//! This module is intended to contain common boiler plate code handling unreleased runtime API
//! calls.
use polkadot_node_subsystem_types::messages::{RuntimeApiMessage, RuntimeApiRequest};
use polkadot_overseer::SubsystemSender;
use polkadot_primitives::{Hash, ValidatorIndex};
use crate::{has_required_runtime, request_disabled_validators, Error};
const LOG_TARGET: &'static str = "parachain::subsystem-util-vstaging";
// TODO: https://github.com/paritytech/polkadot-sdk/issues/1940
/// Returns disabled validators list if the runtime supports it. Otherwise logs a debug messages and
/// returns an empty vec.
/// Once runtime ver `DISABLED_VALIDATORS_RUNTIME_REQUIREMENT` is released remove this function and
/// replace all usages with `request_disabled_validators`
pub async fn get_disabled_validators_with_fallback<Sender: SubsystemSender<RuntimeApiMessage>>(
sender: &mut Sender,
relay_parent: Hash,
) -> Result<Vec<ValidatorIndex>, Error> {
let disabled_validators = if has_required_runtime(
sender,
relay_parent,
RuntimeApiRequest::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT,
)
.await
{
request_disabled_validators(relay_parent, sender)
.await
.await
.map_err(Error::Oneshot)??
} else {
gum::debug!(target: LOG_TARGET, "Runtime doesn't support `DisabledValidators` - continuing with an empty disabled validators set");
vec![]
};
Ok(disabled_validators)
}