1use std::{borrow::Cow, collections::BTreeMap, str::FromStr};
6
7use allocative::Allocative;
8use linera_base::{
9 crypto::{AccountPublicKey, CryptoError, ValidatorPublicKey},
10 data_types::ArithmeticError,
11};
12use serde::{Deserialize, Serialize};
13
14use crate::policy::ResourceControlPolicy;
15
16#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Debug)]
18pub struct ValidatorName(pub ValidatorPublicKey);
19
20impl Serialize for ValidatorName {
21 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
22 where
23 S: serde::ser::Serializer,
24 {
25 if serializer.is_human_readable() {
26 serializer.serialize_str(&self.to_string())
27 } else {
28 serializer.serialize_newtype_struct("ValidatorName", &self.0)
29 }
30 }
31}
32
33impl<'de> Deserialize<'de> for ValidatorName {
34 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
35 where
36 D: serde::de::Deserializer<'de>,
37 {
38 if deserializer.is_human_readable() {
39 let s = String::deserialize(deserializer)?;
40 let value = Self::from_str(&s).map_err(serde::de::Error::custom)?;
41 Ok(value)
42 } else {
43 #[derive(Deserialize)]
44 #[serde(rename = "ValidatorName")]
45 struct ValidatorNameDerived(ValidatorPublicKey);
46
47 let value = ValidatorNameDerived::deserialize(deserializer)?;
48 Ok(Self(value.0))
49 }
50 }
51}
52
53#[derive(Eq, PartialEq, Hash, Clone, Debug, Serialize, Deserialize, Allocative)]
55pub struct ValidatorState {
56 pub network_address: String,
58 pub votes: u64,
60 pub account_public_key: AccountPublicKey,
62}
63
64#[derive(Eq, PartialEq, Hash, Clone, Debug, Default, Allocative)]
66#[cfg_attr(with_graphql, derive(async_graphql::InputObject))]
67pub struct Committee {
68 pub validators: BTreeMap<ValidatorPublicKey, ValidatorState>,
70 total_votes: u64,
72 quorum_threshold: u64,
74 validity_threshold: u64,
77 policy: ResourceControlPolicy,
79}
80
81impl Serialize for Committee {
82 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
83 where
84 S: serde::ser::Serializer,
85 {
86 if serializer.is_human_readable() {
87 CommitteeFull::from(self).serialize(serializer)
88 } else {
89 CommitteeMinimal::from(self).serialize(serializer)
90 }
91 }
92}
93
94impl<'de> Deserialize<'de> for Committee {
95 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
96 where
97 D: serde::de::Deserializer<'de>,
98 {
99 if deserializer.is_human_readable() {
100 let committee_full = CommitteeFull::deserialize(deserializer)?;
101 Committee::try_from(committee_full).map_err(serde::de::Error::custom)
102 } else {
103 let committee_minimal = CommitteeMinimal::deserialize(deserializer)?;
104 Committee::try_from(committee_minimal).map_err(serde::de::Error::custom)
105 }
106 }
107}
108
109#[derive(Serialize, Deserialize)]
110#[serde(rename = "Committee")]
111struct CommitteeFull<'a> {
112 validators: Cow<'a, BTreeMap<ValidatorPublicKey, ValidatorState>>,
113 total_votes: u64,
114 quorum_threshold: u64,
115 validity_threshold: u64,
116 policy: Cow<'a, ResourceControlPolicy>,
117}
118
119#[derive(Serialize, Deserialize)]
120#[serde(rename = "Committee")]
121struct CommitteeMinimal<'a> {
122 validators: Cow<'a, BTreeMap<ValidatorPublicKey, ValidatorState>>,
123 policy: Cow<'a, ResourceControlPolicy>,
124}
125
126impl TryFrom<CommitteeFull<'static>> for Committee {
127 type Error = String;
128
129 fn try_from(committee_full: CommitteeFull) -> Result<Committee, Self::Error> {
130 let CommitteeFull {
131 validators,
132 total_votes,
133 quorum_threshold,
134 validity_threshold,
135 policy,
136 } = committee_full;
137 let committee = Committee::new(validators.into_owned(), policy.into_owned())
138 .map_err(|e| e.to_string())?;
139 if total_votes != committee.total_votes {
140 Err(format!(
141 "invalid committee: total_votes is {}; should be {}",
142 total_votes, committee.total_votes,
143 ))
144 } else if quorum_threshold != committee.quorum_threshold {
145 Err(format!(
146 "invalid committee: quorum_threshold is {}; should be {}",
147 quorum_threshold, committee.quorum_threshold,
148 ))
149 } else if validity_threshold != committee.validity_threshold {
150 Err(format!(
151 "invalid committee: validity_threshold is {}; should be {}",
152 validity_threshold, committee.validity_threshold,
153 ))
154 } else {
155 Ok(committee)
156 }
157 }
158}
159
160impl<'a> From<&'a Committee> for CommitteeFull<'a> {
161 fn from(committee: &'a Committee) -> CommitteeFull<'a> {
162 let Committee {
163 validators,
164 total_votes,
165 quorum_threshold,
166 validity_threshold,
167 policy,
168 } = committee;
169 CommitteeFull {
170 validators: Cow::Borrowed(validators),
171 total_votes: *total_votes,
172 quorum_threshold: *quorum_threshold,
173 validity_threshold: *validity_threshold,
174 policy: Cow::Borrowed(policy),
175 }
176 }
177}
178
179impl TryFrom<CommitteeMinimal<'static>> for Committee {
180 type Error = ArithmeticError;
181
182 fn try_from(committee_min: CommitteeMinimal) -> Result<Committee, ArithmeticError> {
183 let CommitteeMinimal { validators, policy } = committee_min;
184 Committee::new(validators.into_owned(), policy.into_owned())
185 }
186}
187
188impl<'a> From<&'a Committee> for CommitteeMinimal<'a> {
189 fn from(committee: &'a Committee) -> CommitteeMinimal<'a> {
190 let Committee {
191 validators,
192 total_votes: _,
193 quorum_threshold: _,
194 validity_threshold: _,
195 policy,
196 } = committee;
197 CommitteeMinimal {
198 validators: Cow::Borrowed(validators),
199 policy: Cow::Borrowed(policy),
200 }
201 }
202}
203
204impl std::fmt::Display for ValidatorName {
205 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
206 self.0.fmt(f)
207 }
208}
209
210impl std::str::FromStr for ValidatorName {
211 type Err = CryptoError;
212
213 fn from_str(s: &str) -> Result<Self, Self::Err> {
214 Ok(ValidatorName(ValidatorPublicKey::from_str(s)?))
215 }
216}
217
218impl From<ValidatorPublicKey> for ValidatorName {
219 fn from(value: ValidatorPublicKey) -> Self {
220 Self(value)
221 }
222}
223
224impl Committee {
225 pub fn new(
226 validators: BTreeMap<ValidatorPublicKey, ValidatorState>,
227 policy: ResourceControlPolicy,
228 ) -> Result<Self, ArithmeticError> {
229 let mut total_votes: u64 = 0;
230 for state in validators.values() {
231 total_votes = total_votes
232 .checked_add(state.votes)
233 .ok_or(ArithmeticError::Overflow)?;
234 }
235 let validity_threshold = total_votes.div_ceil(3);
238 let quorum_threshold = total_votes
241 .checked_add(validity_threshold)
242 .ok_or(ArithmeticError::Overflow)?
243 .div_ceil(2);
244
245 Ok(Committee {
246 validators,
247 total_votes,
248 quorum_threshold,
249 validity_threshold,
250 policy,
251 })
252 }
253
254 #[cfg(with_testing)]
255 pub fn make_simple(keys: Vec<(ValidatorPublicKey, AccountPublicKey)>) -> Self {
256 let map = keys
257 .into_iter()
258 .map(|(validator_key, account_key)| {
259 (
260 validator_key,
261 ValidatorState {
262 network_address: "Tcp:localhost:8080".to_string(),
263 votes: 100,
264 account_public_key: account_key,
265 },
266 )
267 })
268 .collect();
269 Committee::new(map, ResourceControlPolicy::default())
270 .expect("test committee votes should not overflow")
271 }
272
273 pub fn weight(&self, author: &ValidatorPublicKey) -> u64 {
274 match self.validators.get(author) {
275 Some(state) => state.votes,
276 None => 0,
277 }
278 }
279
280 pub fn keys_and_weights(&self) -> impl Iterator<Item = (ValidatorPublicKey, u64)> + '_ {
281 self.validators
282 .iter()
283 .map(|(name, validator)| (*name, validator.votes))
284 }
285
286 pub fn account_keys_and_weights(&self) -> impl Iterator<Item = (AccountPublicKey, u64)> + '_ {
287 self.validators
288 .values()
289 .map(|validator| (validator.account_public_key, validator.votes))
290 }
291
292 pub fn network_address(&self, author: &ValidatorPublicKey) -> Option<&str> {
293 self.validators
294 .get(author)
295 .map(|state| state.network_address.as_ref())
296 }
297
298 pub fn quorum_threshold(&self) -> u64 {
299 self.quorum_threshold
300 }
301
302 pub fn validity_threshold(&self) -> u64 {
303 self.validity_threshold
304 }
305
306 pub fn validators(&self) -> &BTreeMap<ValidatorPublicKey, ValidatorState> {
307 &self.validators
308 }
309
310 pub fn validator_addresses(&self) -> impl Iterator<Item = (ValidatorPublicKey, &str)> {
311 self.validators
312 .iter()
313 .map(|(name, validator)| (*name, &*validator.network_address))
314 }
315
316 pub fn total_votes(&self) -> u64 {
317 self.total_votes
318 }
319
320 pub fn policy(&self) -> &ResourceControlPolicy {
321 &self.policy
322 }
323
324 pub fn policy_mut(&mut self) -> &mut ResourceControlPolicy {
326 &mut self.policy
327 }
328}