1use serde::{Deserialize, Serialize};
4use tendermint_proto::v0_38::types::{
5 SimpleValidator as RawSimpleValidator, ValidatorSet as RawValidatorSet,
6};
7use tendermint_proto::Protobuf;
8
9use crate::{
10 account,
11 crypto::signature::Verifier,
12 crypto::Sha256,
13 hash::Hash,
14 merkle::{self, MerkleHash},
15 prelude::*,
16 public_key::deserialize_public_key,
17 vote, Error, PublicKey, Signature,
18};
19
20#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
22#[serde(try_from = "RawValidatorSet")]
23pub struct Set {
24 validators: Vec<Info>,
25 proposer: Option<Info>,
26 total_voting_power: vote::Power,
27}
28
29impl Set {
30 pub const MAX_TOTAL_VOTING_POWER: u64 = (i64::MAX / 8) as u64;
31
32 pub fn new(validators: Vec<Info>, proposer: Option<Info>) -> Set {
34 Self::try_from_parts(validators, proposer, 0).unwrap()
35 }
36
37 fn try_from_parts(
38 mut validators: Vec<Info>,
39 proposer: Option<Info>,
40 unvalidated_total_voting_power: i64,
41 ) -> Result<Set, Error> {
42 let total_voting_power = validators
44 .iter()
45 .map(|v| v.power.value())
46 .fold(0u64, |acc, v| acc.saturating_add(v));
47
48 if total_voting_power > Self::MAX_TOTAL_VOTING_POWER {
49 return Err(Error::total_voting_power_overflow());
50 }
51
52 let total_voting_power: vote::Power = total_voting_power.try_into().unwrap();
54
55 if unvalidated_total_voting_power != 0 {
58 let given_val: vote::Power = unvalidated_total_voting_power.try_into()?;
59 if given_val != total_voting_power {
60 return Err(Error::total_voting_power_mismatch());
61 }
62 }
63
64 Self::sort_validators(&mut validators);
65
66 Ok(Set {
67 validators,
68 proposer,
69 total_voting_power,
70 })
71 }
72
73 pub fn without_proposer(validators: Vec<Info>) -> Set {
75 Self::new(validators, None)
76 }
77
78 pub fn with_proposer(
80 validators: Vec<Info>,
81 proposer_address: account::Id,
82 ) -> Result<Self, Error> {
83 let proposer = validators
85 .iter()
86 .find(|v| v.address == proposer_address)
87 .cloned()
88 .ok_or_else(|| Error::proposer_not_found(proposer_address))?;
89
90 Ok(Self::new(validators, Some(proposer)))
93 }
94
95 pub fn validators(&self) -> &Vec<Info> {
97 &self.validators
98 }
99
100 pub fn proposer(&self) -> &Option<Info> {
102 &self.proposer
103 }
104
105 pub fn total_voting_power(&self) -> vote::Power {
107 self.total_voting_power
108 }
109
110 fn sort_validators(vals: &mut [Info]) {
113 vals.sort_by_key(|v| (core::cmp::Reverse(v.power), v.address));
114 }
115
116 pub fn validator(&self, val_id: account::Id) -> Option<Info> {
118 self.validators
119 .iter()
120 .find(|val| val.address == val_id)
121 .cloned()
122 }
123
124 #[cfg(feature = "rust-crypto")]
126 pub fn hash(&self) -> Hash {
127 self.hash_with::<crate::crypto::default::Sha256>()
128 }
129
130 pub fn hash_with<H>(&self) -> Hash
132 where
133 H: MerkleHash + Sha256 + Default,
134 {
135 let validator_bytes: Vec<Vec<u8>> = self
136 .validators()
137 .iter()
138 .map(|validator| validator.hash_bytes())
139 .collect();
140
141 Hash::Sha256(merkle::simple_hash_from_byte_vectors::<H>(&validator_bytes))
142 }
143}
144
145#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
148pub struct Info {
149 pub address: account::Id,
151
152 pub pub_key: PublicKey,
154
155 #[serde(alias = "voting_power", alias = "total_voting_power")]
158 pub power: vote::Power,
159
160 pub name: Option<String>,
162
163 #[serde(skip)]
165 pub proposer_priority: ProposerPriority,
166}
167
168impl Info {
169 pub fn power(&self) -> u64 {
171 self.power.value()
172 }
173
174 pub fn verify_signature<V>(&self, sign_bytes: &[u8], signature: &Signature) -> Result<(), Error>
177 where
178 V: Verifier,
179 {
180 V::verify(self.pub_key, sign_bytes, signature)
181 .map_err(|_| Error::signature_invalid("Ed25519 signature verification failed".into()))
182 }
183
184 #[cfg(feature = "rust-crypto")]
185 pub fn new(pk: PublicKey, vp: vote::Power) -> Info {
187 Info {
188 address: account::Id::from(pk),
189 pub_key: pk,
190 power: vp,
191 name: None,
192 proposer_priority: ProposerPriority::default(),
193 }
194 }
195}
196
197#[derive(Clone, PartialEq, Eq)]
203pub struct SimpleValidator {
204 pub pub_key: PublicKey,
206 pub voting_power: vote::Power,
208}
209
210impl From<&Info> for SimpleValidator {
212 fn from(info: &Info) -> SimpleValidator {
213 SimpleValidator {
214 pub_key: info.pub_key,
215 voting_power: info.power,
216 }
217 }
218}
219
220impl Info {
221 pub fn hash_bytes(&self) -> Vec<u8> {
224 Protobuf::<RawSimpleValidator>::encode_vec(SimpleValidator::from(self))
225 }
226}
227
228#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Default)]
231pub struct ProposerPriority(i64);
232
233impl From<i64> for ProposerPriority {
234 fn from(value: i64) -> Self {
235 ProposerPriority(value)
236 }
237}
238
239impl From<ProposerPriority> for i64 {
240 fn from(priority: ProposerPriority) -> i64 {
241 priority.value()
242 }
243}
244
245impl ProposerPriority {
246 pub fn value(self) -> i64 {
248 self.0
249 }
250}
251
252#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
258pub struct Update {
259 #[serde(deserialize_with = "deserialize_public_key")]
261 pub pub_key: PublicKey,
262
263 #[serde(default)]
265 pub power: vote::Power,
266}
267
268tendermint_pb_modules! {
273 use pb::{
274 abci::ValidatorUpdate as RawValidatorUpdate,
275 types::{
276 SimpleValidator as RawSimpleValidator, Validator as RawValidator,
277 ValidatorSet as RawValidatorSet,
278 },
279 };
280 use super::{Info, Set, SimpleValidator, Update};
281 use crate::{prelude::*, Error};
282
283 impl Protobuf<RawValidatorSet> for Set {}
284
285 impl TryFrom<RawValidatorSet> for Set {
286 type Error = Error;
287
288 fn try_from(value: RawValidatorSet) -> Result<Self, Self::Error> {
289 let validators = value
290 .validators
291 .into_iter()
292 .map(TryInto::try_into)
293 .collect::<Result<Vec<_>, _>>()?;
294
295 let proposer = value.proposer.map(TryInto::try_into).transpose()?;
296
297 Self::try_from_parts(validators, proposer, value.total_voting_power)
298 }
299 }
300
301 impl From<Set> for RawValidatorSet {
302 fn from(value: Set) -> Self {
303 RawValidatorSet {
304 validators: value.validators.into_iter().map(Into::into).collect(),
305 proposer: value.proposer.map(Into::into),
306 total_voting_power: value.total_voting_power.into(),
307 }
308 }
309 }
310
311 impl TryFrom<RawValidator> for Info {
312 type Error = Error;
313
314 fn try_from(value: RawValidator) -> Result<Self, Self::Error> {
315 Ok(Info {
316 address: value.address.try_into()?,
317 pub_key: value
318 .pub_key
319 .ok_or_else(Error::missing_public_key)?
320 .try_into()?,
321 power: value.voting_power.try_into()?,
322 name: None,
323 proposer_priority: value.proposer_priority.into(),
324 })
325 }
326 }
327
328 impl From<Info> for RawValidator {
329 fn from(value: Info) -> Self {
330 RawValidator {
331 address: value.address.into(),
332 pub_key: Some(value.pub_key.into()),
333 voting_power: value.power.into(),
334 proposer_priority: value.proposer_priority.into(),
335 }
336 }
337 }
338
339 impl Protobuf<RawSimpleValidator> for SimpleValidator {}
340
341 impl TryFrom<RawSimpleValidator> for SimpleValidator {
342 type Error = Error;
343
344 fn try_from(value: RawSimpleValidator) -> Result<Self, Self::Error> {
345 Ok(SimpleValidator {
346 pub_key: value.pub_key
347 .ok_or_else(Error::missing_public_key)?
348 .try_into()?,
349 voting_power: value.voting_power.try_into()?,
350 })
351 }
352 }
353
354 impl From<SimpleValidator> for RawSimpleValidator {
355 fn from(value: SimpleValidator) -> Self {
356 RawSimpleValidator {
357 pub_key: Some(value.pub_key.into()),
358 voting_power: value.voting_power.into(),
359 }
360 }
361 }
362
363 impl Protobuf<RawValidatorUpdate> for Update {}
364
365 impl From<Update> for RawValidatorUpdate {
366 fn from(vu: Update) -> Self {
367 Self {
368 pub_key: Some(vu.pub_key.into()),
369 power: vu.power.into(),
370 }
371 }
372 }
373
374 impl TryFrom<RawValidatorUpdate> for Update {
375 type Error = Error;
376
377 fn try_from(vu: RawValidatorUpdate) -> Result<Self, Self::Error> {
378 Ok(Self {
379 pub_key: vu
380 .pub_key
381 .ok_or_else(Error::missing_public_key)?
382 .try_into()?,
383 power: vu.power.try_into()?,
384 })
385 }
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392
393 #[cfg(feature = "rust-crypto")]
394 mod crypto {
395 use super::*;
396
397 fn make_validator(pk: Vec<u8>, vp: u64) -> Info {
399 let pk = PublicKey::from_raw_ed25519(&pk).unwrap();
400 Info::new(pk, vote::Power::try_from(vp).unwrap())
401 }
402
403 #[test]
404 fn test_validator_set() {
405 let v1 = make_validator(
435 vec![
436 48, 163, 55, 132, 231, 147, 230, 163, 56, 158, 127, 218, 179, 139, 212, 103,
437 218, 89, 122, 126, 229, 88, 84, 48, 32, 0, 185, 174, 63, 72, 203, 52,
438 ],
439 148_151_478_422_287_875,
440 );
441 let v2 = make_validator(
442 vec![
443 54, 253, 174, 153, 121, 74, 145, 180, 111, 16, 214, 48, 193, 109, 104, 134, 55,
444 162, 151, 16, 182, 114, 125, 135, 32, 195, 236, 248, 64, 112, 74, 101,
445 ],
446 158_095_448_483_785_107,
447 );
448 let v3 = make_validator(
449 vec![
450 182, 205, 13, 86, 147, 27, 65, 49, 160, 118, 11, 180, 117, 35, 206, 35, 68, 19,
451 27, 173, 69, 92, 204, 224, 200, 51, 249, 81, 105, 128, 112, 244,
452 ],
453 770_561_664_770_006_272,
454 );
455 let hash_expect = vec![
456 11, 64, 107, 4, 234, 81, 232, 75, 204, 199, 160, 114, 229, 97, 243, 95, 118, 213,
457 17, 22, 57, 84, 71, 122, 200, 169, 192, 252, 41, 148, 223, 180,
458 ];
459
460 let val_set = Set::without_proposer(vec![v1.clone(), v2.clone(), v3.clone()]);
461 let hash = val_set.hash();
462 assert_eq!(hash_expect, hash.as_bytes().to_vec());
463
464 let not_in_set = make_validator(
465 vec![
466 110, 147, 87, 120, 27, 218, 66, 209, 81, 4, 169, 153, 64, 163, 137, 89, 168,
467 97, 219, 233, 42, 119, 24, 61, 47, 59, 76, 31, 182, 60, 13, 4,
468 ],
469 10_000_000_000_000_000,
470 );
471
472 assert_eq!(val_set.validator(v1.address).unwrap(), v1);
473 assert_eq!(val_set.validator(v2.address).unwrap(), v2);
474 assert_eq!(val_set.validator(v3.address).unwrap(), v3);
475 assert_eq!(val_set.validator(not_in_set.address), None);
476 assert_eq!(
477 val_set.total_voting_power().value(),
478 148_151_478_422_287_875 + 158_095_448_483_785_107 + 770_561_664_770_006_272
479 );
480 }
481 }
482
483 #[test]
484 fn deserialize_validator_updates() {
485 const FMT1: &str = r#"{
486 "pub_key": {
487 "Sum": {
488 "type": "tendermint.crypto.PublicKey_Ed25519",
489 "value": {
490 "ed25519": "VqJCr3vjQdffcLIG6RMBl2MgXDFYNY6b3Joaa43gV3o="
491 }
492 }
493 },
494 "power": "573929"
495 }"#;
496 const FMT2: &str = r#"{
497 "pub_key": {
498 "type": "tendermint/PubKeyEd25519",
499 "value": "VqJCr3vjQdffcLIG6RMBl2MgXDFYNY6b3Joaa43gV3o="
500 },
501 "power": "573929"
502 }"#;
503
504 let update1 = serde_json::from_str::<Update>(FMT1).unwrap();
505 let update2 = serde_json::from_str::<Update>(FMT2).unwrap();
506
507 assert_eq!(u64::from(update1.power), 573929);
508 assert_eq!(update1, update2);
509 }
510
511 #[test]
512 fn validator_set_deserialize_all_fields() {
513 const VSET: &str = r#"{
514 "validators": [
515 {
516 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
517 "pub_key": {
518 "type": "tendermint/PubKeyEd25519",
519 "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
520 },
521 "voting_power": "50",
522 "proposer_priority": "-150"
523 },
524 {
525 "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
526 "pub_key": {
527 "type": "tendermint/PubKeyEd25519",
528 "value": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4="
529 },
530 "voting_power": "42",
531 "proposer_priority": "50"
532 }
533 ],
534 "proposer": {
535 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
536 "pub_key": {
537 "type": "tendermint/PubKeyEd25519",
538 "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
539 },
540 "voting_power": "50",
541 "proposer_priority": "-150"
542 },
543 "total_voting_power": "92"
544 }"#;
545
546 let vset = serde_json::from_str::<Set>(VSET).unwrap();
547 assert_eq!(vset.total_voting_power().value(), 92);
548 }
549
550 #[test]
551 fn validator_set_deserialize_no_total_voting_power() {
552 const VSET: &str = r#"{
553 "validators": [
554 {
555 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
556 "pub_key": {
557 "type": "tendermint/PubKeyEd25519",
558 "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
559 },
560 "voting_power": "50",
561 "proposer_priority": "-150"
562 },
563 {
564 "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
565 "pub_key": {
566 "type": "tendermint/PubKeyEd25519",
567 "value": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4="
568 },
569 "voting_power": "42",
570 "proposer_priority": "50"
571 }
572 ],
573 "proposer": {
574 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
575 "pub_key": {
576 "type": "tendermint/PubKeyEd25519",
577 "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
578 },
579 "voting_power": "50",
580 "proposer_priority": "-150"
581 }
582 }"#;
583
584 let vset = serde_json::from_str::<Set>(VSET).unwrap();
585 assert_eq!(vset.total_voting_power().value(), 92);
586 }
587
588 #[test]
589 fn validator_set_deserialize_total_voting_power_mismatch() {
590 const VSET: &str = r#"{
591 "validators": [
592 {
593 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
594 "pub_key": {
595 "type": "tendermint/PubKeyEd25519",
596 "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
597 },
598 "voting_power": "50",
599 "proposer_priority": "-150"
600 },
601 {
602 "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
603 "pub_key": {
604 "type": "tendermint/PubKeyEd25519",
605 "value": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4="
606 },
607 "voting_power": "42",
608 "proposer_priority": "50"
609 }
610 ],
611 "proposer": {
612 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
613 "pub_key": {
614 "type": "tendermint/PubKeyEd25519",
615 "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
616 },
617 "voting_power": "50",
618 "proposer_priority": "-150"
619 },
620 "total_voting_power": "100"
621 }"#;
622
623 let err = serde_json::from_str::<Set>(VSET).unwrap_err();
624 assert!(
625 err.to_string()
626 .contains("total voting power in validator set does not match the sum of participants' powers"),
627 "{err}"
628 );
629 }
630
631 #[test]
632 fn validator_set_deserialize_total_voting_power_exceeds_limit() {
633 const VSET: &str = r#"{
634 "validators": [
635 {
636 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
637 "pub_key": {
638 "type": "tendermint/PubKeyEd25519",
639 "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
640 },
641 "voting_power": "576460752303423488",
642 "proposer_priority": "-150"
643 },
644 {
645 "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
646 "pub_key": {
647 "type": "tendermint/PubKeyEd25519",
648 "value": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4="
649 },
650 "voting_power": "576460752303423488",
651 "proposer_priority": "50"
652 }
653 ],
654 "proposer": {
655 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
656 "pub_key": {
657 "type": "tendermint/PubKeyEd25519",
658 "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
659 },
660 "voting_power": "50",
661 "proposer_priority": "-150"
662 },
663 "total_voting_power": "92"
664 }"#;
665
666 let err = serde_json::from_str::<Set>(VSET).unwrap_err();
667 assert!(
668 err.to_string()
669 .contains("total voting power in validator set exceeds the allowed maximum"),
670 "{err}"
671 );
672 }
673
674 #[test]
675 fn validator_set_deserialize_total_voting_power_overflow() {
676 const VSET: &str = r#"{
677 "validators": [
678 {
679 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
680 "pub_key": {
681 "type": "tendermint/PubKeyEd25519",
682 "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
683 },
684 "voting_power": "6148914691236517205",
685 "proposer_priority": "-150"
686 },
687 {
688 "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
689 "pub_key": {
690 "type": "tendermint/PubKeyEd25519",
691 "value": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4="
692 },
693 "voting_power": "6148914691236517205",
694 "proposer_priority": "50"
695 },
696 {
697 "address": "044EB1BB5D4C1CDB90029648439AEB10431FF295",
698 "pub_key": {
699 "type": "tendermint/PubKeyEd25519",
700 "value": "Wc790fkCDAi7LvZ4UIBAIJSNI+Rp2aU80/8l+idZ/wI="
701 },
702 "voting_power": "6148914691236517206",
703 "proposer_priority": "50"
704 }
705 ],
706 "proposer": {
707 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
708 "pub_key": {
709 "type": "tendermint/PubKeyEd25519",
710 "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
711 },
712 "voting_power": "50",
713 "proposer_priority": "-150"
714 }
715 }"#;
716
717 let err = serde_json::from_str::<Set>(VSET).unwrap_err();
718 assert!(
719 err.to_string()
720 .contains("total voting power in validator set exceeds the allowed maximum"),
721 "{err}"
722 );
723 }
724}