referrerpolicy=no-referrer-when-downgrade

polkadot_node_primitives/disputes/
status.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17use codec::{Decode, Encode};
18
19/// Timestamp based on the 1 Jan 1970 UNIX base, which is persistent across node restarts and OS
20/// reboots.
21pub type Timestamp = u64;
22
23/// The status of dispute.
24///
25/// As managed by the dispute coordinator.
26///
27/// NOTE: This status is persisted to the database, any changes have to be versioned and a db
28/// migration will be needed.
29#[derive(Debug, Clone, Copy, Encode, Decode, PartialEq)]
30pub enum DisputeStatus {
31	/// The dispute is active and unconcluded.
32	#[codec(index = 0)]
33	Active,
34	/// The dispute has been concluded in favor of the candidate
35	/// since the given timestamp.
36	#[codec(index = 1)]
37	ConcludedFor(Timestamp),
38	/// The dispute has been concluded against the candidate
39	/// since the given timestamp.
40	///
41	/// This takes precedence over `ConcludedFor` in the case that
42	/// both are true, which is impossible unless a large amount of
43	/// validators are participating on both sides.
44	#[codec(index = 2)]
45	ConcludedAgainst(Timestamp),
46	/// Dispute has been confirmed (more than `byzantine_threshold` have already participated/ or
47	/// we have seen the candidate included already/participated successfully ourselves).
48	#[codec(index = 3)]
49	Confirmed,
50}
51
52impl DisputeStatus {
53	/// Initialize the status to the active state.
54	pub fn active() -> DisputeStatus {
55		DisputeStatus::Active
56	}
57
58	/// Move status to confirmed status, if not yet concluded/confirmed already.
59	pub fn confirm(self) -> DisputeStatus {
60		match self {
61			DisputeStatus::Active => DisputeStatus::Confirmed,
62			DisputeStatus::Confirmed => DisputeStatus::Confirmed,
63			DisputeStatus::ConcludedFor(_) | DisputeStatus::ConcludedAgainst(_) => self,
64		}
65	}
66
67	/// Check whether the dispute is not a spam dispute.
68	pub fn is_confirmed_concluded(&self) -> bool {
69		match self {
70			&DisputeStatus::Confirmed |
71			&DisputeStatus::ConcludedFor(_) |
72			DisputeStatus::ConcludedAgainst(_) => true,
73			&DisputeStatus::Active => false,
74		}
75	}
76
77	/// Concluded valid?
78	pub fn has_concluded_for(&self) -> bool {
79		match self {
80			&DisputeStatus::ConcludedFor(_) => true,
81			_ => false,
82		}
83	}
84	/// Concluded invalid?
85	pub fn has_concluded_against(&self) -> bool {
86		match self {
87			&DisputeStatus::ConcludedAgainst(_) => true,
88			_ => false,
89		}
90	}
91
92	/// Transition the status to a new status after observing the dispute has concluded for the
93	/// candidate. This may be a no-op if the status was already concluded.
94	pub fn conclude_for(self, now: Timestamp) -> DisputeStatus {
95		match self {
96			DisputeStatus::Active | DisputeStatus::Confirmed => DisputeStatus::ConcludedFor(now),
97			DisputeStatus::ConcludedFor(at) => DisputeStatus::ConcludedFor(std::cmp::min(at, now)),
98			against => against,
99		}
100	}
101
102	/// Transition the status to a new status after observing the dispute has concluded against the
103	/// candidate. This may be a no-op if the status was already concluded.
104	pub fn conclude_against(self, now: Timestamp) -> DisputeStatus {
105		match self {
106			DisputeStatus::Active | DisputeStatus::Confirmed =>
107				DisputeStatus::ConcludedAgainst(now),
108			DisputeStatus::ConcludedFor(at) =>
109				DisputeStatus::ConcludedAgainst(std::cmp::min(at, now)),
110			DisputeStatus::ConcludedAgainst(at) =>
111				DisputeStatus::ConcludedAgainst(std::cmp::min(at, now)),
112		}
113	}
114
115	/// Whether the disputed candidate is possibly invalid.
116	pub fn is_possibly_invalid(&self) -> bool {
117		match self {
118			DisputeStatus::Active |
119			DisputeStatus::Confirmed |
120			DisputeStatus::ConcludedAgainst(_) => true,
121			DisputeStatus::ConcludedFor(_) => false,
122		}
123	}
124
125	/// Yields the timestamp this dispute concluded at, if any.
126	pub fn concluded_at(&self) -> Option<Timestamp> {
127		match self {
128			DisputeStatus::Active | DisputeStatus::Confirmed => None,
129			DisputeStatus::ConcludedFor(at) | DisputeStatus::ConcludedAgainst(at) => Some(*at),
130		}
131	}
132}
133
134/// The choice here is fairly arbitrary. But any dispute that concluded more than a few minutes ago
135/// is not worth considering anymore. Changing this value has little to no bearing on consensus,
136/// and really only affects the work that the node might do on startup during periods of many
137/// disputes.
138pub const ACTIVE_DURATION_SECS: Timestamp = 180;
139
140/// Returns true if the dispute has concluded for longer than [`ACTIVE_DURATION_SECS`].
141pub fn dispute_is_inactive(status: &DisputeStatus, now: &Timestamp) -> bool {
142	let at = status.concluded_at();
143
144	at.is_some() && at.unwrap() + ACTIVE_DURATION_SECS < *now
145}