polkadot_node_core_dispute_coordinator/
backend.rs1use polkadot_primitives::{CandidateHash, SessionIndex};
25
26use std::collections::HashMap;
27
28use super::db::v1::{CandidateVotes, RecentDisputes};
29use crate::error::FatalResult;
30
31#[derive(Debug)]
32pub enum BackendWriteOp {
33 WriteEarliestSession(SessionIndex),
34 WriteRecentDisputes(RecentDisputes),
35 WriteCandidateVotes(SessionIndex, CandidateHash, CandidateVotes),
36 DeleteCandidateVotes(SessionIndex, CandidateHash),
37}
38
39pub trait Backend {
41 fn load_earliest_session(&self) -> FatalResult<Option<SessionIndex>>;
43
44 fn load_recent_disputes(&self) -> FatalResult<Option<RecentDisputes>>;
46
47 fn load_candidate_votes(
49 &self,
50 session: SessionIndex,
51 candidate_hash: &CandidateHash,
52 ) -> FatalResult<Option<CandidateVotes>>;
53
54 fn write<I>(&mut self, ops: I) -> FatalResult<()>
57 where
58 I: IntoIterator<Item = BackendWriteOp>;
59}
60
61pub struct OverlayedBackend<'a, B: 'a> {
67 inner: &'a B,
68
69 earliest_session: Option<SessionIndex>,
71 recent_disputes: Option<RecentDisputes>,
73 candidate_votes: HashMap<(SessionIndex, CandidateHash), Option<CandidateVotes>>,
75}
76
77impl<'a, B: 'a + Backend> OverlayedBackend<'a, B> {
78 pub fn new(backend: &'a B) -> Self {
79 Self {
80 inner: backend,
81 earliest_session: None,
82 recent_disputes: None,
83 candidate_votes: HashMap::new(),
84 }
85 }
86
87 pub fn is_empty(&self) -> bool {
89 self.earliest_session.is_none() &&
90 self.recent_disputes.is_none() &&
91 self.candidate_votes.is_empty()
92 }
93
94 pub fn load_earliest_session(&self) -> FatalResult<Option<SessionIndex>> {
96 if let Some(val) = self.earliest_session {
97 return Ok(Some(val))
98 }
99
100 self.inner.load_earliest_session()
101 }
102
103 pub fn load_recent_disputes(&self) -> FatalResult<Option<RecentDisputes>> {
105 if let Some(val) = &self.recent_disputes {
106 return Ok(Some(val.clone()))
107 }
108
109 self.inner.load_recent_disputes()
110 }
111
112 pub fn load_candidate_votes(
114 &self,
115 session: SessionIndex,
116 candidate_hash: &CandidateHash,
117 ) -> FatalResult<Option<CandidateVotes>> {
118 if let Some(val) = self.candidate_votes.get(&(session, *candidate_hash)) {
119 return Ok(val.clone())
120 }
121
122 self.inner.load_candidate_votes(session, candidate_hash)
123 }
124
125 pub fn write_earliest_session(&mut self, session: SessionIndex) {
129 self.earliest_session = Some(session);
130 }
131
132 pub fn write_recent_disputes(&mut self, recent_disputes: RecentDisputes) {
136 self.recent_disputes = Some(recent_disputes)
137 }
138
139 pub fn write_candidate_votes(
143 &mut self,
144 session: SessionIndex,
145 candidate_hash: CandidateHash,
146 votes: CandidateVotes,
147 ) {
148 self.candidate_votes.insert((session, candidate_hash), Some(votes));
149 }
150
151 pub fn into_write_ops(self) -> impl Iterator<Item = BackendWriteOp> {
153 let earliest_session_ops = self
154 .earliest_session
155 .map(|s| BackendWriteOp::WriteEarliestSession(s))
156 .into_iter();
157
158 let recent_dispute_ops =
159 self.recent_disputes.map(|d| BackendWriteOp::WriteRecentDisputes(d)).into_iter();
160
161 let candidate_vote_ops =
162 self.candidate_votes
163 .into_iter()
164 .map(|((session, candidate), votes)| match votes {
165 Some(votes) => BackendWriteOp::WriteCandidateVotes(session, candidate, votes),
166 None => BackendWriteOp::DeleteCandidateVotes(session, candidate),
167 });
168
169 earliest_session_ops.chain(recent_dispute_ops).chain(candidate_vote_ops)
170 }
171}