Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Improved dispute votes import in provisioner #5567

Merged
merged 35 commits into from
Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
855d6da
Add `DisputeState` to `DisputeCoordinatorMessage::RecentDisputes`
tdimitrov May 14, 2022
396187e
Move dummy_signature() in primitives/test-helpers
tdimitrov May 11, 2022
23013f4
Enable staging runtime api on Rococo
tdimitrov May 25, 2022
140c1e8
Implementation
tdimitrov May 16, 2022
040d1fb
Fix staging api usage
tdimitrov Aug 24, 2022
b8f6566
Fix `get_disputes` runtime function implementation
tdimitrov Aug 24, 2022
1be7983
Fix compilation error
tdimitrov Aug 24, 2022
60c1ddb
Fix arithmetic operations in tests
tdimitrov Aug 25, 2022
e1654e7
Use smaller test data
tdimitrov Aug 25, 2022
e3179cb
Rename `RuntimeApiRequest::StagingDisputes` to `RuntimeApiRequest::Di…
tdimitrov Aug 25, 2022
7e3bab7
Remove `staging-client` feature flag
tdimitrov Aug 25, 2022
24ae8ce
fmt
tdimitrov Aug 25, 2022
00bd01b
Remove `vstaging` feature flag
tdimitrov Aug 25, 2022
c771aa6
Some comments regarding the staging api
tdimitrov Aug 25, 2022
543b4ef
Rename dispute selection modules in provisioner
tdimitrov Aug 25, 2022
98ee76f
Comments for staging api
tdimitrov Aug 25, 2022
1884262
Comments
tdimitrov Aug 25, 2022
e6a6843
Additional logging
tdimitrov Aug 25, 2022
5f8b462
Code review feedback
tdimitrov Aug 29, 2022
95b0096
Code review feedback
tdimitrov Aug 30, 2022
0f9cf6a
Fix metrics
tdimitrov Aug 30, 2022
308a363
get_disputes -> disputes
tdimitrov Aug 30, 2022
a969eba
Get time only once during partitioning
tdimitrov Aug 30, 2022
57e1b88
Fix partitioning
tdimitrov Aug 30, 2022
db34125
Comments
tdimitrov Aug 31, 2022
d2af967
Reduce the number of hardcoded api versions
tdimitrov Aug 31, 2022
1366d90
Code review feedback
tdimitrov Aug 31, 2022
aeef116
Unused import
tdimitrov Sep 1, 2022
fd24899
Comments
tdimitrov Sep 5, 2022
49a7b24
More precise log messages
tdimitrov Sep 14, 2022
3b018cf
Code review feedback
tdimitrov Sep 16, 2022
58a0f01
Code review feedback
tdimitrov Sep 16, 2022
babd20d
Code review feedback - remove `trait VoteType`
tdimitrov Sep 16, 2022
a477226
Code review feedback
tdimitrov Sep 16, 2022
9eeedbb
Trace log for DisputeCoordinatorMessage::QueryCandidateVotes counter …
tdimitrov Sep 16, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

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

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ try-runtime = [ "polkadot-cli/try-runtime" ]
fast-runtime = [ "polkadot-cli/fast-runtime" ]
runtime-metrics = [ "polkadot-cli/runtime-metrics" ]
pyroscope = ["polkadot-cli/pyroscope"]
staging-client = ["polkadot-cli/staging-client"]

# Configuration for building a .deb package - for use with `cargo-deb`
[package.metadata.deb]
Expand Down
1 change: 0 additions & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,3 @@ rococo-native = ["service/rococo-native"]

malus = ["full-node", "service/malus"]
runtime-metrics = ["service/runtime-metrics", "polkadot-node-metrics/runtime-metrics"]
staging-client = ["service/staging-client"]
2 changes: 1 addition & 1 deletion node/core/dispute-coordinator/src/db/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

//! `V1` database for the dispute coordinator.

use polkadot_node_primitives::DisputeStatus;
use polkadot_node_subsystem::{SubsystemError, SubsystemResult};
use polkadot_node_subsystem_util::database::{DBTransaction, Database};
use polkadot_primitives::v2::{
Expand All @@ -31,7 +32,6 @@ use crate::{
backend::{Backend, BackendWriteOp, OverlayedBackend},
error::{FatalError, FatalResult},
metrics::Metrics,
status::DisputeStatus,
DISPUTE_WINDOW, LOG_TARGET,
};

Expand Down
10 changes: 6 additions & 4 deletions node/core/dispute-coordinator/src/initialized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use futures::{
use sc_keystore::LocalKeystore;

use polkadot_node_primitives::{
CandidateVotes, DisputeMessage, DisputeMessageCheckError, SignedDisputeStatement,
DISPUTE_WINDOW,
CandidateVotes, DisputeMessage, DisputeMessageCheckError, DisputeStatus,
SignedDisputeStatement, Timestamp, DISPUTE_WINDOW,
};
use polkadot_node_subsystem::{
messages::{
Expand All @@ -49,7 +49,7 @@ use crate::{
error::{log_error, Error, FatalError, FatalResult, JfyiError, JfyiResult, Result},
import::{CandidateEnvironment, CandidateVoteState},
metrics::Metrics,
status::{get_active_with_status, Clock, DisputeStatus, Timestamp},
status::{get_active_with_status, Clock},
DisputeCoordinatorSubsystem, LOG_TARGET,
};

Expand Down Expand Up @@ -599,7 +599,9 @@ impl Initialized {
};
gum::trace!(target: LOG_TARGET, "Loaded recent disputes from db");

let _ = tx.send(recent_disputes.keys().cloned().collect());
let _ = tx.send(
recent_disputes.into_iter().map(|(k, v)| (k.0, k.1, v)).collect::<Vec<_>>(),
);
},
DisputeCoordinatorMessage::ActiveDisputes(tx) => {
// Return error if session information is missing.
Expand Down
113 changes: 3 additions & 110 deletions node/core/dispute-coordinator/src/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,125 +14,18 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

use std::time::{SystemTime, UNIX_EPOCH};

use parity_scale_codec::{Decode, Encode};
use polkadot_node_primitives::{dispute_is_inactive, DisputeStatus, Timestamp};
use polkadot_primitives::v2::{CandidateHash, SessionIndex};
use std::time::{SystemTime, UNIX_EPOCH};

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,
/// and really only affects the work that the node might do on startup during periods of many
/// disputes.
pub const ACTIVE_DURATION_SECS: Timestamp = 180;

/// Timestamp based on the 1 Jan 1970 UNIX base, which is persistent across node restarts and OS reboots.
pub type Timestamp = u64;

/// 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),
/// Dispute has been confirmed (more than `byzantine_threshold` have already participated/ or
/// we have seen the candidate included already/participated successfully ourselves).
#[codec(index = 3)]
Confirmed,
}

impl DisputeStatus {
/// Initialize the status to the active state.
pub fn active() -> DisputeStatus {
DisputeStatus::Active
}

/// Move status to confirmed status, if not yet concluded/confirmed already.
pub fn confirm(self) -> DisputeStatus {
match self {
DisputeStatus::Active => DisputeStatus::Confirmed,
DisputeStatus::Confirmed => DisputeStatus::Confirmed,
DisputeStatus::ConcludedFor(_) | DisputeStatus::ConcludedAgainst(_) => self,
}
}

/// Check whether the dispute is not a spam dispute.
pub fn is_confirmed_concluded(&self) -> bool {
match self {
&DisputeStatus::Confirmed |
&DisputeStatus::ConcludedFor(_) |
DisputeStatus::ConcludedAgainst(_) => true,
&DisputeStatus::Active => false,
}
}

/// 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::Confirmed => 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::Confirmed =>
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::Confirmed |
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 | DisputeStatus::Confirmed => None,
DisputeStatus::ConcludedFor(at) | DisputeStatus::ConcludedAgainst(at) => Some(*at),
}
}
}

/// Get active disputes as iterator, preserving its `DisputeStatus`.
pub fn get_active_with_status(
recent_disputes: impl Iterator<Item = ((SessionIndex, CandidateHash), DisputeStatus)>,
now: Timestamp,
) -> impl Iterator<Item = ((SessionIndex, CandidateHash), DisputeStatus)> {
recent_disputes.filter_map(move |(disputed, status)| {
status
.concluded_at()
.filter(|at| *at + ACTIVE_DURATION_SECS < now)
.map_or(Some((disputed, status)), |_| None)
})
recent_disputes.filter(move |(_, status)| !dispute_is_inactive(status, &now))
}

pub trait Clock: Send + Sync {
Expand Down
3 changes: 2 additions & 1 deletion node/core/dispute-coordinator/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ use sp_keyring::Sr25519Keyring;
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};

use ::test_helpers::{dummy_candidate_receipt_bad_sig, dummy_digest, dummy_hash};
use polkadot_node_primitives::{Timestamp, ACTIVE_DURATION_SECS};
use polkadot_node_subsystem::{
jaeger,
messages::{AllMessages, BlockDescription, RuntimeApiMessage, RuntimeApiRequest},
Expand All @@ -66,7 +67,7 @@ use crate::{
backend::Backend,
metrics::Metrics,
participation::{participation_full_happy_path, participation_missing_availability},
status::{Clock, Timestamp, ACTIVE_DURATION_SECS},
status::Clock,
Config, DisputeCoordinatorSubsystem,
};

Expand Down
5 changes: 1 addition & 4 deletions node/core/provisioner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,12 @@ polkadot-primitives = { path = "../../../primitives" }
polkadot-node-primitives = { path = "../../primitives" }
polkadot-node-subsystem = { path = "../../subsystem" }
polkadot-node-subsystem-util = { path = "../../subsystem-util" }
futures-timer = "3.0.2"
rand = "0.8.5"
futures-timer = "3.0.2"
fatality = "0.0.6"

[dev-dependencies]
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../../primitives/test-helpers" }

[features]
staging-client = []
53 changes: 53 additions & 0 deletions node/core/provisioner/src/disputes/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2017-2022 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/>.

//! The disputes module is responsible for selecting dispute votes to be sent with the inherent data. It contains two
//! different implementations, extracted in two separate modules - `random_selection` and `prioritized_selection`. Which
//! implementation will be executed depends on the version of the runtime. Runtime v2 supports `random_selection`. Runtime
//! v3 and above - `prioritized_selection`. The entrypoint to these implementations is the `select_disputes` function.
//! prioritized_selection` is considered superior and will be the default one in the future. Refer to the documentation of
//! the modules for more details about each implementation.
tdimitrov marked this conversation as resolved.
Show resolved Hide resolved

use crate::LOG_TARGET;
use futures::channel::oneshot;
use polkadot_node_primitives::CandidateVotes;
use polkadot_node_subsystem::{messages::DisputeCoordinatorMessage, overseer};
use polkadot_primitives::v2::{CandidateHash, SessionIndex};

/// Request the relevant dispute statements for a set of disputes identified by `CandidateHash` and the `SessionIndex`.
async fn request_votes(
sender: &mut impl overseer::ProvisionerSenderTrait,
disputes_to_query: Vec<(SessionIndex, CandidateHash)>,
) -> Vec<(SessionIndex, CandidateHash, CandidateVotes)> {
let (tx, rx) = oneshot::channel();
// Bounded by block production - `ProvisionerMessage::RequestInherentData`.
sender.send_unbounded_message(DisputeCoordinatorMessage::QueryCandidateVotes(
disputes_to_query,
tx,
));

match rx.await {
Ok(v) => v,
Err(oneshot::Canceled) => {
gum::warn!(target: LOG_TARGET, "Unable to query candidate votes");
Vec::new()
},
}
}

pub(crate) mod prioritized_selection;

pub(crate) mod random_selection;
Loading