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}