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			},
109			DisputeStatus::ConcludedFor(at) => {
110				DisputeStatus::ConcludedAgainst(std::cmp::min(at, now))
111			},
112			DisputeStatus::ConcludedAgainst(at) => {
113				DisputeStatus::ConcludedAgainst(std::cmp::min(at, now))
114			},
115		}
116	}
117
118	/// Whether the disputed candidate is possibly invalid.
119	pub fn is_possibly_invalid(&self) -> bool {
120		match self {
121			DisputeStatus::Active |
122			DisputeStatus::Confirmed |
123			DisputeStatus::ConcludedAgainst(_) => true,
124			DisputeStatus::ConcludedFor(_) => false,
125		}
126	}
127
128	/// Yields the timestamp this dispute concluded at, if any.
129	pub fn concluded_at(&self) -> Option<Timestamp> {
130		match self {
131			DisputeStatus::Active | DisputeStatus::Confirmed => None,
132			DisputeStatus::ConcludedFor(at) | DisputeStatus::ConcludedAgainst(at) => Some(*at),
133		}
134	}
135}
136
137/// The choice here is fairly arbitrary. But any dispute that concluded more than a few minutes ago
138/// is not worth considering anymore. Changing this value has little to no bearing on consensus,
139/// and really only affects the work that the node might do on startup during periods of many
140/// disputes.
141pub const ACTIVE_DURATION_SECS: Timestamp = 180;
142
143/// Returns true if the dispute has concluded for longer than [`ACTIVE_DURATION_SECS`].
144pub fn dispute_is_inactive(status: &DisputeStatus, now: &Timestamp) -> bool {
145	let at = status.concluded_at();
146
147	at.is_some() && at.unwrap() + ACTIVE_DURATION_SECS < *now
148}