mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
enable disputes for known chains, except for polkadot (#4464)
* enable disputes, for all known chains but polkadot * chore: fmt * don't propagate disputes either * review * remove disputes feature * remove superfluous line * Update node/service/src/lib.rs Co-authored-by: Andronik Ordian <write@reusable.software> * fixup * allow being a dummy * rialto * add an enum, to make things work better * overseer * fix test * comments * move condition out * excess arg Co-authored-by: Andronik Ordian <write@reusable.software>
This commit is contained in:
committed by
GitHub
parent
fad55b95fa
commit
2457c26a08
@@ -196,7 +196,7 @@ test-build-linux-stable:
|
||||
- ./scripts/gitlab/test_linux_stable.sh
|
||||
# we're using the bin built here, instead of having a parallel `build-linux-release`
|
||||
# disputes feature is needed for zombie-net parachains malus test
|
||||
- time cargo build --release --verbose --bin polkadot --features "disputes"
|
||||
- time cargo build --release --verbose --bin polkadot
|
||||
- sccache -s
|
||||
# pack artifacts
|
||||
- mkdir -p ./artifacts
|
||||
@@ -277,7 +277,7 @@ build-malus:
|
||||
- if: $CI_COMMIT_REF_NAME == "master"
|
||||
- if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs
|
||||
script:
|
||||
- time cargo build --release --verbose -p polkadot-test-malus --features disputes
|
||||
- time cargo build --release --verbose -p polkadot-test-malus
|
||||
- sccache -s
|
||||
# pack artifacts
|
||||
- mkdir -p ./artifacts
|
||||
|
||||
+1
-1
@@ -117,9 +117,9 @@ panic = "unwind"
|
||||
[features]
|
||||
runtime-benchmarks= [ "polkadot-cli/runtime-benchmarks" ]
|
||||
try-runtime = [ "polkadot-cli/try-runtime" ]
|
||||
disputes = [ "polkadot-cli/disputes" ]
|
||||
runtime-metrics = [ "polkadot-cli/runtime-metrics" ]
|
||||
|
||||
|
||||
# Configuration for building a .deb package - for use with `cargo-deb`
|
||||
[package.metadata.deb]
|
||||
name = "polkadot"
|
||||
|
||||
@@ -30,6 +30,7 @@ use polkadot_node_core_av_store::Config as AvailabilityConfig;
|
||||
use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig;
|
||||
use polkadot_node_core_chain_selection::Config as ChainSelectionConfig;
|
||||
use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig;
|
||||
use polkadot_node_core_provisioner::ProvisionerConfig;
|
||||
use polkadot_node_network_protocol::request_response::{v1 as request_v1, IncomingRequestReceiver};
|
||||
use polkadot_overseer::{
|
||||
metrics::Metrics as OverseerMetrics, BlockInfo, MetricsTrait, Overseer, OverseerBuilder,
|
||||
@@ -108,6 +109,8 @@ where
|
||||
pub chain_selection_config: ChainSelectionConfig,
|
||||
/// Configuration for the dispute coordinator subsystem.
|
||||
pub dispute_coordinator_config: DisputeCoordinatorConfig,
|
||||
/// Configuration for the provisioner subsystem.
|
||||
pub disputes_enabled: bool,
|
||||
}
|
||||
|
||||
/// Obtain a prepared `OverseerBuilder`, that is initialized
|
||||
@@ -133,6 +136,7 @@ pub fn prepared_overseer_builder<Spawner, RuntimeClient>(
|
||||
candidate_validation_config,
|
||||
chain_selection_config,
|
||||
dispute_coordinator_config,
|
||||
disputes_enabled,
|
||||
}: OverseerGenArgs<'_, Spawner, RuntimeClient>,
|
||||
) -> Result<
|
||||
OverseerBuilder<
|
||||
@@ -218,7 +222,7 @@ where
|
||||
Box::new(network_service.clone()),
|
||||
Metrics::register(registry)?,
|
||||
))
|
||||
.provisioner(ProvisionerSubsystem::new(spawner.clone(), (), Metrics::register(registry)?))
|
||||
.provisioner(ProvisionerSubsystem::new(spawner.clone(), ProvisionerConfig { disputes_enabled }, Metrics::register(registry)?))
|
||||
.runtime_api(RuntimeApiSubsystem::new(
|
||||
runtime_client.clone(),
|
||||
Metrics::register(registry)?,
|
||||
|
||||
@@ -473,6 +473,7 @@ where
|
||||
slot_duration_millis: slot_duration.as_millis() as u64,
|
||||
};
|
||||
|
||||
|
||||
let candidate_validation_config = CandidateValidationConfig {
|
||||
artifacts_cache_path: config
|
||||
.database
|
||||
@@ -581,6 +582,7 @@ where
|
||||
dispute_req_receiver,
|
||||
pov_req_receiver,
|
||||
statement_req_receiver,
|
||||
disputes_enabled: false,
|
||||
},
|
||||
)?;
|
||||
let handle = Handle::new(overseer_handle);
|
||||
|
||||
@@ -66,5 +66,4 @@ westend-native = [ "service/westend-native" ]
|
||||
rococo-native = [ "service/rococo-native" ]
|
||||
|
||||
malus = [ "full-node", "service/malus" ]
|
||||
disputes = [ "service/disputes" ]
|
||||
runtime-metrics = ["service/runtime-metrics", "polkadot-node-metrics/runtime-metrics"]
|
||||
|
||||
@@ -16,45 +16,29 @@
|
||||
|
||||
//! Implements the dispute coordinator subsystem (dummy implementation).
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use polkadot_node_subsystem::{
|
||||
errors::{ChainApiError, RuntimeApiError},
|
||||
messages::DisputeCoordinatorMessage,
|
||||
overseer, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemContext, SubsystemError,
|
||||
messages::DisputeCoordinatorMessage, overseer, FromOverseer, OverseerSignal, SpawnedSubsystem,
|
||||
SubsystemContext, SubsystemError,
|
||||
};
|
||||
use polkadot_primitives::v1::BlockNumber;
|
||||
|
||||
use futures::{channel::oneshot, prelude::*};
|
||||
use kvdb::KeyValueDB;
|
||||
use parity_scale_codec::{Decode, Encode, Error as CodecError};
|
||||
use sc_keystore::LocalKeystore;
|
||||
use futures::prelude::*;
|
||||
|
||||
use crate::metrics::Metrics;
|
||||
use crate::error::{Error, Result};
|
||||
|
||||
const LOG_TARGET: &str = "parachain::dispute-coordinator";
|
||||
|
||||
/// Timestamp based on the 1 Jan 1970 UNIX base, which is persistent across node restarts and OS reboots.
|
||||
type Timestamp = u64;
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
enum Participation {}
|
||||
|
||||
struct State {}
|
||||
|
||||
/// Configuration for the dispute coordinator subsystem.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Config {
|
||||
/// The data column in the store to use for dispute data.
|
||||
pub col_data: u32,
|
||||
}
|
||||
|
||||
/// An implementation of the dispute coordinator subsystem.
|
||||
pub struct DisputeCoordinatorSubsystem {}
|
||||
|
||||
impl DisputeCoordinatorSubsystem {
|
||||
/// Create a new instance of the subsystem.
|
||||
pub fn new(_: Arc<dyn KeyValueDB>, _: Config, _: Arc<LocalKeystore>, _: Metrics) -> Self {
|
||||
pub fn new() -> Self {
|
||||
DisputeCoordinatorSubsystem {}
|
||||
}
|
||||
}
|
||||
@@ -71,109 +55,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
RuntimeApi(#[from] RuntimeApiError),
|
||||
|
||||
#[error(transparent)]
|
||||
ChainApi(#[from] ChainApiError),
|
||||
|
||||
#[error(transparent)]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
Oneshot(#[from] oneshot::Canceled),
|
||||
|
||||
#[error("Oneshot send failed")]
|
||||
OneshotSend,
|
||||
|
||||
#[error(transparent)]
|
||||
Subsystem(#[from] SubsystemError),
|
||||
|
||||
#[error(transparent)]
|
||||
Codec(#[from] CodecError),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
fn trace(&self) {
|
||||
match self {
|
||||
// don't spam the log with spurious errors
|
||||
Self::RuntimeApi(_) | Self::Oneshot(_) =>
|
||||
tracing::debug!(target: LOG_TARGET, err = ?self),
|
||||
// it's worth reporting otherwise
|
||||
_ => tracing::warn!(target: LOG_TARGET, err = ?self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The status of dispute. This is a state machine which can be altered by the
|
||||
/// helper methods.
|
||||
#[derive(Debug, Clone, Copy, Encode, Decode, PartialEq)]
|
||||
pub enum DisputeStatus {
|
||||
/// The dispute is active and unconcluded.
|
||||
#[codec(index = 0)]
|
||||
Active,
|
||||
/// The dispute has been concluded in favor of the candidate
|
||||
/// since the given timestamp.
|
||||
#[codec(index = 1)]
|
||||
ConcludedFor(Timestamp),
|
||||
/// The dispute has been concluded against the candidate
|
||||
/// since the given timestamp.
|
||||
///
|
||||
/// This takes precedence over `ConcludedFor` in the case that
|
||||
/// both are true, which is impossible unless a large amount of
|
||||
/// validators are participating on both sides.
|
||||
#[codec(index = 2)]
|
||||
ConcludedAgainst(Timestamp),
|
||||
}
|
||||
|
||||
impl DisputeStatus {
|
||||
/// Initialize the status to the active state.
|
||||
pub fn active() -> DisputeStatus {
|
||||
DisputeStatus::Active
|
||||
}
|
||||
|
||||
/// Transition the status to a new status after observing the dispute has concluded for the candidate.
|
||||
/// This may be a no-op if the status was already concluded.
|
||||
pub fn concluded_for(self, now: Timestamp) -> DisputeStatus {
|
||||
match self {
|
||||
DisputeStatus::Active => DisputeStatus::ConcludedFor(now),
|
||||
DisputeStatus::ConcludedFor(at) => DisputeStatus::ConcludedFor(std::cmp::min(at, now)),
|
||||
against => against,
|
||||
}
|
||||
}
|
||||
|
||||
/// Transition the status to a new status after observing the dispute has concluded against the candidate.
|
||||
/// This may be a no-op if the status was already concluded.
|
||||
pub fn concluded_against(self, now: Timestamp) -> DisputeStatus {
|
||||
match self {
|
||||
DisputeStatus::Active => DisputeStatus::ConcludedAgainst(now),
|
||||
DisputeStatus::ConcludedFor(at) =>
|
||||
DisputeStatus::ConcludedAgainst(std::cmp::min(at, now)),
|
||||
DisputeStatus::ConcludedAgainst(at) =>
|
||||
DisputeStatus::ConcludedAgainst(std::cmp::min(at, now)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the disputed candidate is possibly invalid.
|
||||
pub fn is_possibly_invalid(&self) -> bool {
|
||||
match self {
|
||||
DisputeStatus::Active | DisputeStatus::ConcludedAgainst(_) => true,
|
||||
DisputeStatus::ConcludedFor(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Yields the timestamp this dispute concluded at, if any.
|
||||
pub fn concluded_at(&self) -> Option<Timestamp> {
|
||||
match self {
|
||||
DisputeStatus::Active => None,
|
||||
DisputeStatus::ConcludedFor(at) | DisputeStatus::ConcludedAgainst(at) => Some(*at),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn run<Context>(subsystem: DisputeCoordinatorSubsystem, mut ctx: Context)
|
||||
where
|
||||
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
|
||||
@@ -182,13 +63,10 @@ where
|
||||
loop {
|
||||
let res = run_until_error(&mut ctx, &subsystem).await;
|
||||
match res {
|
||||
Err(e) => {
|
||||
e.trace();
|
||||
|
||||
if let Error::Subsystem(SubsystemError::Context(_)) = e {
|
||||
Err(e) =>
|
||||
if let Error::Fatal(_) = e {
|
||||
break
|
||||
}
|
||||
},
|
||||
},
|
||||
Ok(()) => {
|
||||
tracing::info!(target: LOG_TARGET, "received `Conclude` signal, exiting");
|
||||
break
|
||||
@@ -197,10 +75,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_until_error<Context>(
|
||||
ctx: &mut Context,
|
||||
_: &DisputeCoordinatorSubsystem,
|
||||
) -> Result<(), Error>
|
||||
async fn run_until_error<Context>(ctx: &mut Context, _: &DisputeCoordinatorSubsystem) -> Result<()>
|
||||
where
|
||||
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
|
||||
Context: SubsystemContext<Message = DisputeCoordinatorMessage>,
|
||||
@@ -221,7 +96,7 @@ async fn handle_incoming(
|
||||
_: &mut impl SubsystemContext,
|
||||
_: &mut State,
|
||||
message: DisputeCoordinatorMessage,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<()> {
|
||||
match message {
|
||||
DisputeCoordinatorMessage::ImportStatements { .. } => { /* just drop confirmation */ },
|
||||
DisputeCoordinatorMessage::RecentDisputes(tx) => {
|
||||
|
||||
+3
-12
@@ -23,8 +23,8 @@ use polkadot_node_subsystem::{
|
||||
};
|
||||
use polkadot_node_subsystem_util::{rolling_session_window::SessionsUnavailable, runtime};
|
||||
|
||||
use super::{db, participation};
|
||||
use crate::real::{CodecError, LOG_TARGET};
|
||||
use crate::LOG_TARGET;
|
||||
use parity_scale_codec::Error as CodecError;
|
||||
|
||||
/// Errors for this subsystem.
|
||||
#[derive(Debug, Error)]
|
||||
@@ -126,16 +126,7 @@ pub enum NonFatal {
|
||||
Runtime(#[from] runtime::NonFatal),
|
||||
|
||||
#[error(transparent)]
|
||||
QueueError(#[from] participation::QueueError),
|
||||
}
|
||||
|
||||
impl From<db::v1::Error> for Error {
|
||||
fn from(err: db::v1::Error) -> Self {
|
||||
match err {
|
||||
db::v1::Error::Io(io) => Self::NonFatal(NonFatal::Io(io)),
|
||||
db::v1::Error::Codec(e) => Self::NonFatal(NonFatal::Codec(e)),
|
||||
}
|
||||
}
|
||||
QueueError(#[from] crate::real::participation::QueueError),
|
||||
}
|
||||
|
||||
/// Utility for eating top level errors and log them.
|
||||
@@ -25,14 +25,67 @@
|
||||
//! another node, this will trigger the dispute participation subsystem to recover and validate the block and call
|
||||
//! back to this subsystem.
|
||||
|
||||
/// Metrics types.
|
||||
mod metrics;
|
||||
|
||||
#[cfg(feature = "disputes")]
|
||||
mod real;
|
||||
#[cfg(feature = "disputes")]
|
||||
pub use real::*;
|
||||
/// Common error types for this subsystem.
|
||||
mod error;
|
||||
|
||||
#[cfg(not(feature = "disputes"))]
|
||||
/// Status tracking of disputes (`DisputeStatus`).
|
||||
mod status;
|
||||
|
||||
/// Dummy implementation.
|
||||
mod dummy;
|
||||
#[cfg(not(feature = "disputes"))]
|
||||
pub use dummy::*;
|
||||
/// The real implementation.
|
||||
mod real;
|
||||
|
||||
use kvdb::KeyValueDB;
|
||||
use metrics::Metrics;
|
||||
use polkadot_node_subsystem::{
|
||||
messages::DisputeCoordinatorMessage, overseer, SpawnedSubsystem, SubsystemContext,
|
||||
SubsystemError,
|
||||
};
|
||||
use sc_keystore::LocalKeystore;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use self::real::Config;
|
||||
|
||||
pub(crate) const LOG_TARGET: &str = "parachain::dispute-coordinator";
|
||||
|
||||
/// The disputes coordinator subsystem, abstracts `dummy` and `real` implementations.
|
||||
pub enum DisputeCoordinatorSubsystem {
|
||||
Dummy(dummy::DisputeCoordinatorSubsystem),
|
||||
Real(real::DisputeCoordinatorSubsystem),
|
||||
}
|
||||
|
||||
impl DisputeCoordinatorSubsystem {
|
||||
/// Create a new dummy instance.
|
||||
pub fn dummy() -> Self {
|
||||
DisputeCoordinatorSubsystem::Dummy(dummy::DisputeCoordinatorSubsystem::new())
|
||||
}
|
||||
|
||||
/// Create a new instance of the subsystem.
|
||||
pub fn new(
|
||||
store: Arc<dyn KeyValueDB>,
|
||||
config: real::Config,
|
||||
keystore: Arc<LocalKeystore>,
|
||||
metrics: Metrics,
|
||||
) -> Self {
|
||||
DisputeCoordinatorSubsystem::Real(real::DisputeCoordinatorSubsystem::new(
|
||||
store, config, keystore, metrics,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Context> overseer::Subsystem<Context, SubsystemError> for DisputeCoordinatorSubsystem
|
||||
where
|
||||
Context: SubsystemContext<Message = DisputeCoordinatorMessage>,
|
||||
Context: overseer::SubsystemContext<Message = DisputeCoordinatorMessage>,
|
||||
{
|
||||
fn start(self, ctx: Context) -> SpawnedSubsystem {
|
||||
match self {
|
||||
DisputeCoordinatorSubsystem::Dummy(dummy) => dummy.start(ctx),
|
||||
DisputeCoordinatorSubsystem::Real(real) => real.start(ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,12 @@ use polkadot_node_subsystem_util::metrics::{self, prometheus};
|
||||
#[derive(Clone)]
|
||||
struct MetricsInner {
|
||||
/// Number of opened disputes.
|
||||
#[cfg(feature = "disputes")]
|
||||
open: prometheus::Counter<prometheus::U64>,
|
||||
/// Votes of all disputes.
|
||||
#[cfg(feature = "disputes")]
|
||||
votes: prometheus::CounterVec<prometheus::U64>,
|
||||
/// Conclusion across all disputes.
|
||||
#[cfg(feature = "disputes")]
|
||||
concluded: prometheus::CounterVec<prometheus::U64>,
|
||||
/// Number of participations that have been queued.
|
||||
#[cfg(feature = "disputes")]
|
||||
queued_participations: prometheus::CounterVec<prometheus::U64>,
|
||||
}
|
||||
|
||||
@@ -36,7 +32,6 @@ struct MetricsInner {
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Metrics(Option<MetricsInner>);
|
||||
|
||||
#[cfg(feature = "disputes")]
|
||||
impl Metrics {
|
||||
pub(crate) fn on_open(&self) {
|
||||
if let Some(metrics) = &self.0 {
|
||||
@@ -82,13 +77,6 @@ impl Metrics {
|
||||
}
|
||||
|
||||
impl metrics::Metrics for Metrics {
|
||||
#[cfg(not(feature = "disputes"))]
|
||||
fn try_register(_registry: &prometheus::Registry) -> Result<Self, prometheus::PrometheusError> {
|
||||
let metrics = MetricsInner {};
|
||||
Ok(Metrics(Some(metrics)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "disputes")]
|
||||
fn try_register(registry: &prometheus::Registry) -> Result<Self, prometheus::PrometheusError> {
|
||||
let metrics = MetricsInner {
|
||||
open: prometheus::register(
|
||||
|
||||
@@ -26,10 +26,8 @@ use polkadot_primitives::v1::{CandidateHash, SessionIndex};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::{
|
||||
db::v1::{CandidateVotes, RecentDisputes},
|
||||
error::FatalResult,
|
||||
};
|
||||
use super::db::v1::{CandidateVotes, RecentDisputes};
|
||||
use crate::error::FatalResult;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BackendWriteOp {
|
||||
|
||||
@@ -27,10 +27,13 @@ use std::sync::Arc;
|
||||
use kvdb::{DBTransaction, KeyValueDB};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
|
||||
use crate::real::{
|
||||
backend::{Backend, BackendWriteOp, OverlayedBackend},
|
||||
use crate::{
|
||||
error::{Fatal, FatalResult},
|
||||
status::DisputeStatus,
|
||||
};
|
||||
|
||||
use crate::real::{
|
||||
backend::{Backend, BackendWriteOp, OverlayedBackend},
|
||||
DISPUTE_WINDOW,
|
||||
};
|
||||
|
||||
@@ -162,6 +165,15 @@ pub enum Error {
|
||||
Codec(#[from] parity_scale_codec::Error),
|
||||
}
|
||||
|
||||
impl From<Error> for crate::error::Error {
|
||||
fn from(err: Error) -> Self {
|
||||
match err {
|
||||
Error::Io(io) => Self::NonFatal(crate::error::NonFatal::Io(io)),
|
||||
Error::Codec(e) => Self::NonFatal(crate::error::NonFatal::Codec(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Result alias for DB errors.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
|
||||
@@ -45,19 +45,22 @@ use polkadot_primitives::v1::{
|
||||
ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature,
|
||||
};
|
||||
|
||||
use crate::{metrics::Metrics, DisputeCoordinatorSubsystem};
|
||||
use crate::{metrics::Metrics, real::DisputeCoordinatorSubsystem, LOG_TARGET};
|
||||
|
||||
use crate::{
|
||||
error::{log_error, Fatal, FatalResult, NonFatal, NonFatalResult, Result},
|
||||
status::{get_active_with_status, Clock, DisputeStatus, Timestamp},
|
||||
};
|
||||
|
||||
use super::{
|
||||
backend::Backend,
|
||||
db,
|
||||
error::{log_error, Fatal, FatalResult, NonFatal, NonFatalResult, Result},
|
||||
ordering::{CandidateComparator, OrderingProvider},
|
||||
participation::{
|
||||
self, Participation, ParticipationRequest, ParticipationStatement, WorkerMessageReceiver,
|
||||
},
|
||||
spam_slots::SpamSlots,
|
||||
status::{get_active_with_status, Clock, DisputeStatus, Timestamp},
|
||||
OverlayedBackend, LOG_TARGET,
|
||||
OverlayedBackend,
|
||||
};
|
||||
|
||||
/// After the first active leaves update we transition to `Initialized` state.
|
||||
|
||||
@@ -28,7 +28,6 @@ use std::{collections::HashSet, sync::Arc};
|
||||
|
||||
use futures::FutureExt;
|
||||
use kvdb::KeyValueDB;
|
||||
use parity_scale_codec::Error as CodecError;
|
||||
|
||||
use sc_keystore::LocalKeystore;
|
||||
|
||||
@@ -40,24 +39,23 @@ use polkadot_node_subsystem::{
|
||||
use polkadot_node_subsystem_util::rolling_session_window::RollingSessionWindow;
|
||||
use polkadot_primitives::v1::{ValidatorIndex, ValidatorPair};
|
||||
|
||||
use crate::metrics::Metrics;
|
||||
use backend::{Backend, OverlayedBackend};
|
||||
use db::v1::DbBackend;
|
||||
use error::{FatalResult, Result};
|
||||
|
||||
use self::{
|
||||
error::{Error, NonFatal},
|
||||
ordering::CandidateComparator,
|
||||
participation::ParticipationRequest,
|
||||
spam_slots::{SpamSlots, UnconfirmedDisputes},
|
||||
use crate::{
|
||||
error::{Error, FatalResult, NonFatal, Result},
|
||||
metrics::Metrics,
|
||||
status::{get_active_with_status, SystemClock},
|
||||
};
|
||||
|
||||
mod backend;
|
||||
mod db;
|
||||
use backend::{Backend, OverlayedBackend};
|
||||
use db::v1::DbBackend;
|
||||
|
||||
/// Common error types for this subsystem.
|
||||
mod error;
|
||||
use self::{
|
||||
ordering::CandidateComparator,
|
||||
participation::ParticipationRequest,
|
||||
spam_slots::{SpamSlots, UnconfirmedDisputes},
|
||||
};
|
||||
|
||||
pub(crate) mod backend;
|
||||
pub(crate) mod db;
|
||||
|
||||
/// Subsystem after receiving the first active leaf.
|
||||
mod initialized;
|
||||
@@ -90,17 +88,15 @@ mod spam_slots;
|
||||
/// participation requests, such that most important/urgent disputes will be resolved and processed
|
||||
/// first and more importantly it will order requests in a way so disputes will get resolved, even
|
||||
/// if there are lots of them.
|
||||
mod participation;
|
||||
pub(crate) mod participation;
|
||||
|
||||
/// Status tracking of disputes (`DisputeStatus`).
|
||||
mod status;
|
||||
use status::Clock;
|
||||
use crate::status::Clock;
|
||||
|
||||
use crate::LOG_TARGET;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
const LOG_TARGET: &str = "parachain::dispute-coordinator";
|
||||
|
||||
/// An implementation of the dispute coordinator subsystem.
|
||||
pub struct DisputeCoordinatorSubsystem {
|
||||
config: Config,
|
||||
|
||||
@@ -28,7 +28,7 @@ use polkadot_node_subsystem::{
|
||||
use polkadot_node_subsystem_util::runtime::get_candidate_events;
|
||||
use polkadot_primitives::v1::{BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, Hash};
|
||||
|
||||
use super::{
|
||||
use crate::{
|
||||
error::{Fatal, FatalResult, Result},
|
||||
LOG_TARGET,
|
||||
};
|
||||
|
||||
@@ -29,13 +29,13 @@ use polkadot_node_subsystem::{
|
||||
use polkadot_node_subsystem_util::runtime::get_validation_code_by_hash;
|
||||
use polkadot_primitives::v1::{BlockNumber, CandidateHash, CandidateReceipt, Hash, SessionIndex};
|
||||
|
||||
use crate::real::LOG_TARGET;
|
||||
|
||||
use super::{
|
||||
use crate::{
|
||||
error::{Fatal, FatalResult, NonFatal, Result},
|
||||
ordering::CandidateComparator,
|
||||
LOG_TARGET,
|
||||
};
|
||||
|
||||
use super::ordering::CandidateComparator;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -65,15 +65,12 @@ use crate::{
|
||||
real::{
|
||||
backend::Backend,
|
||||
participation::{participation_full_happy_path, participation_missing_availability},
|
||||
status::ACTIVE_DURATION_SECS,
|
||||
Config, DisputeCoordinatorSubsystem,
|
||||
},
|
||||
Config, DisputeCoordinatorSubsystem,
|
||||
status::{Clock, Timestamp, ACTIVE_DURATION_SECS},
|
||||
};
|
||||
|
||||
use super::{
|
||||
db::v1::DbBackend,
|
||||
status::{Clock, Timestamp},
|
||||
};
|
||||
use super::db::v1::DbBackend;
|
||||
|
||||
const TEST_TIMEOUT: Duration = Duration::from_secs(2);
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use polkadot_primitives::v1::{CandidateHash, SessionIndex};
|
||||
|
||||
use crate::real::LOG_TARGET;
|
||||
use crate::LOG_TARGET;
|
||||
|
||||
/// The choice here is fairly arbitrary. But any dispute that concluded more than a few minutes ago
|
||||
/// is not worth considering anymore. Changing this value has little to no bearing on consensus,
|
||||
@@ -148,10 +148,19 @@ pub enum Error {
|
||||
BackedCandidateOrderingProblem,
|
||||
}
|
||||
|
||||
/// Provisioner run arguments.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ProvisionerConfig {
|
||||
/// If enabled, dispute votes will be provided to `fn create_inherent`, otherwise not.
|
||||
/// Long term we will obviously always want disputes to be enabled, this option exists for testing purposes
|
||||
/// and will be removed in the near future.
|
||||
pub disputes_enabled: bool,
|
||||
}
|
||||
|
||||
impl JobTrait for ProvisionerJob {
|
||||
type ToJob = ProvisionerMessage;
|
||||
type Error = Error;
|
||||
type RunArgs = ();
|
||||
type RunArgs = ProvisionerConfig;
|
||||
type Metrics = Metrics;
|
||||
|
||||
const NAME: &'static str = "provisioner-job";
|
||||
@@ -161,17 +170,21 @@ impl JobTrait for ProvisionerJob {
|
||||
// this function is in charge of creating and executing the job's main loop
|
||||
fn run<S: SubsystemSender>(
|
||||
leaf: ActivatedLeaf,
|
||||
_run_args: Self::RunArgs,
|
||||
run_args: Self::RunArgs,
|
||||
metrics: Self::Metrics,
|
||||
receiver: mpsc::Receiver<ProvisionerMessage>,
|
||||
mut sender: JobSender<S>,
|
||||
) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>> {
|
||||
let span = leaf.span.clone();
|
||||
async move {
|
||||
let span = leaf.span.clone();
|
||||
let job = ProvisionerJob::new(leaf, metrics, receiver);
|
||||
|
||||
job.run_loop(sender.subsystem_sender(), PerLeafSpan::new(span, "provisioner"))
|
||||
.await
|
||||
job.run_loop(
|
||||
sender.subsystem_sender(),
|
||||
run_args.disputes_enabled,
|
||||
PerLeafSpan::new(span, "provisioner"),
|
||||
)
|
||||
.await
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
@@ -197,6 +210,7 @@ impl ProvisionerJob {
|
||||
async fn run_loop(
|
||||
mut self,
|
||||
sender: &mut impl SubsystemSender,
|
||||
disputes_enabled: bool,
|
||||
span: PerLeafSpan,
|
||||
) -> Result<(), Error> {
|
||||
use ProvisionerMessage::{ProvisionableData, RequestInherentData};
|
||||
@@ -208,7 +222,7 @@ impl ProvisionerJob {
|
||||
let _timer = self.metrics.time_request_inherent_data();
|
||||
|
||||
if self.inherent_after.is_ready() {
|
||||
self.send_inherent_data(sender, vec![return_sender]).await;
|
||||
self.send_inherent_data(sender, vec![return_sender], disputes_enabled).await;
|
||||
} else {
|
||||
self.awaiting_inherent.push(return_sender);
|
||||
}
|
||||
@@ -225,7 +239,7 @@ impl ProvisionerJob {
|
||||
let _span = span.child("send-inherent-data");
|
||||
let return_senders = std::mem::take(&mut self.awaiting_inherent);
|
||||
if !return_senders.is_empty() {
|
||||
self.send_inherent_data(sender, return_senders).await;
|
||||
self.send_inherent_data(sender, return_senders, disputes_enabled).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,6 +252,7 @@ impl ProvisionerJob {
|
||||
&mut self,
|
||||
sender: &mut impl SubsystemSender,
|
||||
return_senders: Vec<oneshot::Sender<ProvisionerInherentData>>,
|
||||
disputes_enabled: bool,
|
||||
) {
|
||||
if let Err(err) = send_inherent_data(
|
||||
&self.leaf,
|
||||
@@ -245,6 +260,7 @@ impl ProvisionerJob {
|
||||
&self.backed_candidates,
|
||||
return_senders,
|
||||
sender,
|
||||
disputes_enabled,
|
||||
&self.metrics,
|
||||
)
|
||||
.await
|
||||
@@ -300,6 +316,7 @@ async fn send_inherent_data(
|
||||
candidates: &[CandidateReceipt],
|
||||
return_senders: Vec<oneshot::Sender<ProvisionerInherentData>>,
|
||||
from_job: &mut impl SubsystemSender,
|
||||
disputes_enabled: bool,
|
||||
metrics: &Metrics,
|
||||
) -> Result<(), Error> {
|
||||
let availability_cores = request_availability_cores(leaf.hash, from_job)
|
||||
@@ -307,7 +324,9 @@ async fn send_inherent_data(
|
||||
.await
|
||||
.map_err(|err| Error::CanceledAvailabilityCores(err))??;
|
||||
|
||||
let disputes = select_disputes(from_job, metrics).await?;
|
||||
let disputes =
|
||||
if disputes_enabled { select_disputes(from_job, metrics).await? } else { vec![] };
|
||||
|
||||
// Only include bitfields on fresh leaves. On chain reversions, we want to make sure that
|
||||
// there will be at least one block, which cannot get disputed, so the chain can make progress.
|
||||
let bitfields = match leaf.status {
|
||||
|
||||
@@ -34,8 +34,7 @@ futures-timer = "3.0.2"
|
||||
tracing = "0.1.26"
|
||||
|
||||
[features]
|
||||
default = [] # we do not enable disputes by default to avoid feature leak
|
||||
disputes = ["polkadot-cli/disputes"]
|
||||
default = []
|
||||
|
||||
[dev-dependencies]
|
||||
polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" }
|
||||
|
||||
@@ -202,7 +202,7 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
|
||||
Fn(SubsystemInitFn<T>),
|
||||
/// Directly initialize the subsystem with the given subsystem type `T`.
|
||||
Value(T),
|
||||
/// Subsystem field does not have value just yet.
|
||||
/// Subsystem field does not have a value just yet.
|
||||
Uninitialized
|
||||
}
|
||||
|
||||
|
||||
@@ -178,12 +178,11 @@ try-runtime = [
|
||||
"rococo-runtime/try-runtime",
|
||||
]
|
||||
malus = ["full-node"]
|
||||
disputes = ["polkadot-node-core-dispute-coordinator/disputes"]
|
||||
runtime-metrics = [
|
||||
"polkadot-client/runtime-metrics",
|
||||
"polkadot-client/runtime-metrics",
|
||||
"rococo-runtime/runtime-metrics",
|
||||
"westend-runtime/runtime-metrics",
|
||||
"kusama-runtime/runtime-metrics",
|
||||
"polkadot-runtime/runtime-metrics",
|
||||
"polkadot-runtime-parachains/runtime-metrics"
|
||||
]
|
||||
]
|
||||
|
||||
@@ -29,7 +29,7 @@ pub mod overseer;
|
||||
#[cfg(feature = "full-node")]
|
||||
pub use self::overseer::{OverseerGen, OverseerGenArgs, RealOverseerGen};
|
||||
|
||||
#[cfg(all(test, feature = "disputes"))]
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[cfg(feature = "full-node")]
|
||||
@@ -721,6 +721,12 @@ where
|
||||
let auth_or_collator = role.is_authority() || is_collator.is_collator();
|
||||
let requires_overseer_for_chain_sel = local_keystore.is_some() && auth_or_collator;
|
||||
|
||||
let disputes_enabled = chain_spec.is_rococo() ||
|
||||
chain_spec.is_kusama() ||
|
||||
chain_spec.is_westend() ||
|
||||
chain_spec.is_versi() ||
|
||||
chain_spec.is_wococo();
|
||||
|
||||
let select_chain = if requires_overseer_for_chain_sel {
|
||||
let metrics =
|
||||
polkadot_node_subsystem_util::metrics::Metrics::register(prometheus_registry.as_ref())?;
|
||||
@@ -729,6 +735,7 @@ where
|
||||
basics.backend.clone(),
|
||||
overseer_handle.clone(),
|
||||
metrics,
|
||||
disputes_enabled,
|
||||
)
|
||||
} else {
|
||||
SelectRelayChain::new_longest_chain(basics.backend.clone())
|
||||
@@ -952,6 +959,7 @@ where
|
||||
candidate_validation_config,
|
||||
chain_selection_config,
|
||||
dispute_coordinator_config,
|
||||
disputes_enabled,
|
||||
},
|
||||
)
|
||||
.map_err(|e| {
|
||||
|
||||
@@ -22,6 +22,7 @@ use polkadot_node_core_av_store::Config as AvailabilityConfig;
|
||||
use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig;
|
||||
use polkadot_node_core_chain_selection::Config as ChainSelectionConfig;
|
||||
use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig;
|
||||
use polkadot_node_core_provisioner::ProvisionerConfig;
|
||||
use polkadot_node_network_protocol::request_response::{v1 as request_v1, IncomingRequestReceiver};
|
||||
#[cfg(any(feature = "malus", test))]
|
||||
pub use polkadot_overseer::{
|
||||
@@ -106,6 +107,8 @@ where
|
||||
pub chain_selection_config: ChainSelectionConfig,
|
||||
/// Configuration for the dispute coordinator subsystem.
|
||||
pub dispute_coordinator_config: DisputeCoordinatorConfig,
|
||||
/// Enable to disputes.
|
||||
pub disputes_enabled: bool,
|
||||
}
|
||||
|
||||
/// Obtain a prepared `OverseerBuilder`, that is initialized
|
||||
@@ -132,6 +135,7 @@ pub fn prepared_overseer_builder<'a, Spawner, RuntimeClient>(
|
||||
candidate_validation_config,
|
||||
chain_selection_config,
|
||||
dispute_coordinator_config,
|
||||
disputes_enabled,
|
||||
}: OverseerGenArgs<'a, Spawner, RuntimeClient>,
|
||||
) -> Result<
|
||||
OverseerBuilder<
|
||||
@@ -228,7 +232,11 @@ where
|
||||
Box::new(network_service.clone()),
|
||||
Metrics::register(registry)?,
|
||||
))
|
||||
.provisioner(ProvisionerSubsystem::new(spawner.clone(), (), Metrics::register(registry)?))
|
||||
.provisioner(ProvisionerSubsystem::new(
|
||||
spawner.clone(),
|
||||
ProvisionerConfig { disputes_enabled },
|
||||
Metrics::register(registry)?,
|
||||
))
|
||||
.runtime_api(RuntimeApiSubsystem::new(
|
||||
runtime_client.clone(),
|
||||
Metrics::register(registry)?,
|
||||
@@ -251,12 +259,16 @@ where
|
||||
keystore.clone(),
|
||||
authority_discovery_service.clone(),
|
||||
))
|
||||
.dispute_coordinator(DisputeCoordinatorSubsystem::new(
|
||||
parachains_db.clone(),
|
||||
dispute_coordinator_config,
|
||||
keystore.clone(),
|
||||
Metrics::register(registry)?,
|
||||
))
|
||||
.dispute_coordinator(if disputes_enabled {
|
||||
DisputeCoordinatorSubsystem::new(
|
||||
parachains_db.clone(),
|
||||
dispute_coordinator_config,
|
||||
keystore.clone(),
|
||||
Metrics::register(registry)?,
|
||||
)
|
||||
} else {
|
||||
DisputeCoordinatorSubsystem::dummy()
|
||||
})
|
||||
.dispute_distribution(DisputeDistributionSubsystem::new(
|
||||
keystore.clone(),
|
||||
dispute_req_receiver,
|
||||
@@ -319,8 +331,15 @@ impl OverseerGen for RealOverseerGen {
|
||||
RuntimeClient::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
|
||||
Spawner: 'static + SpawnNamed + Clone + Unpin,
|
||||
{
|
||||
prepared_overseer_builder(args)?
|
||||
.build_with_connector(connector)
|
||||
.map_err(|e| e.into())
|
||||
let disputes_enabled = args.disputes_enabled;
|
||||
let builder = prepared_overseer_builder(args)?;
|
||||
if disputes_enabled {
|
||||
builder
|
||||
.dispute_coordinator(DisputeCoordinatorSubsystem::dummy())
|
||||
.build_with_connector(connector)
|
||||
} else {
|
||||
builder.build_with_connector(connector)
|
||||
}
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,11 +161,16 @@ where
|
||||
|
||||
/// Create a new [`SelectRelayChain`] wrapping the given chain backend
|
||||
/// and a handle to the overseer.
|
||||
pub fn new_disputes_aware(backend: Arc<B>, overseer: Handle, metrics: Metrics) -> Self {
|
||||
pub fn new_disputes_aware(
|
||||
backend: Arc<B>,
|
||||
overseer: Handle,
|
||||
metrics: Metrics,
|
||||
disputes_enabled: bool,
|
||||
) -> Self {
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
"Using {} chain selection algorithm",
|
||||
if cfg!(feature = "disputes") {
|
||||
if disputes_enabled {
|
||||
"dispute aware relay"
|
||||
} else {
|
||||
// no disputes are queried, that logic is disabled
|
||||
@@ -176,7 +181,10 @@ where
|
||||
SelectRelayChain {
|
||||
longest_chain: sc_consensus::LongestChain::new(backend.clone()),
|
||||
selection: IsDisputesAwareWithOverseer::Yes(SelectRelayChainInner::new(
|
||||
backend, overseer, metrics,
|
||||
backend,
|
||||
overseer,
|
||||
metrics,
|
||||
disputes_enabled,
|
||||
)),
|
||||
}
|
||||
}
|
||||
@@ -233,6 +241,7 @@ where
|
||||
pub struct SelectRelayChainInner<B, OH> {
|
||||
backend: Arc<B>,
|
||||
overseer: OH,
|
||||
disputes_enabled: bool,
|
||||
metrics: Metrics,
|
||||
}
|
||||
|
||||
@@ -243,8 +252,8 @@ where
|
||||
{
|
||||
/// Create a new [`SelectRelayChainInner`] wrapping the given chain backend
|
||||
/// and a handle to the overseer.
|
||||
pub fn new(backend: Arc<B>, overseer: OH, metrics: Metrics) -> Self {
|
||||
SelectRelayChainInner { backend, overseer, metrics }
|
||||
pub fn new(backend: Arc<B>, overseer: OH, metrics: Metrics, disputes_enabled: bool) -> Self {
|
||||
SelectRelayChainInner { backend, overseer, metrics, disputes_enabled }
|
||||
}
|
||||
|
||||
fn block_header(&self, hash: Hash) -> Result<PolkadotHeader, ConsensusError> {
|
||||
@@ -282,6 +291,7 @@ where
|
||||
backend: self.backend.clone(),
|
||||
overseer: self.overseer.clone(),
|
||||
metrics: self.metrics.clone(),
|
||||
disputes_enabled: self.disputes_enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -371,7 +381,7 @@ where
|
||||
let mut overseer = self.overseer.clone();
|
||||
tracing::trace!(target: LOG_TARGET, ?best_leaf, "Longest chain");
|
||||
|
||||
let subchain_head = if cfg!(feature = "disputes") {
|
||||
let subchain_head = if self.disputes_enabled {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
overseer
|
||||
.send_msg(
|
||||
@@ -476,7 +486,7 @@ where
|
||||
let lag = initial_leaf_number.saturating_sub(subchain_number);
|
||||
self.metrics.note_approval_checking_finality_lag(lag);
|
||||
|
||||
let (lag, subchain_head) = if cfg!(feature = "disputes") {
|
||||
let (lag, subchain_head) = if self.disputes_enabled {
|
||||
// Prevent sending flawed data to the dispute-coordinator.
|
||||
if Some(subchain_block_descriptions.len() as _) !=
|
||||
subchain_number.checked_sub(target_number)
|
||||
|
||||
@@ -83,6 +83,7 @@ fn test_harness<T: Future<Output = VirtualOverseer>>(
|
||||
Arc::new(case_vars.chain.clone()),
|
||||
context.sender().clone(),
|
||||
Default::default(),
|
||||
true,
|
||||
);
|
||||
|
||||
let target_hash = case_vars.target_block.clone();
|
||||
|
||||
@@ -4,6 +4,5 @@ set -eux
|
||||
#shellcheck source=../common/lib.sh
|
||||
source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../common/lib.sh"
|
||||
|
||||
time cargo test --release --locked -p polkadot-node-core-dispute-coordinator --features disputes
|
||||
# Builds with the runtime benchmarks/metrics features are only to be used for testing.
|
||||
time cargo test --workspace --release --verbose --locked --features=runtime-benchmarks,runtime-metrics
|
||||
|
||||
Reference in New Issue
Block a user