1use cometbft_proto::abci::v1::ValidatorUpdate as RawValidatorUpdate;
4use cometbft_proto::types::v1::{
5 SimpleValidator as RawSimpleValidator, Validator as RawValidator,
6 ValidatorSet as RawValidatorSet,
7};
8use cometbft_proto::Protobuf;
9use serde::{Deserialize, Serialize};
10
11use crate::{
12 account,
13 crypto::signature::Verifier,
14 crypto::Sha256,
15 hash::Hash,
16 merkle::{self, MerkleHash},
17 prelude::*,
18 public_key::deserialize_public_key,
19 vote, Error, PublicKey, Signature,
20};
21
22#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(try_from = "RawValidatorSet")]
25pub struct Set {
26 pub validators: Vec<Info>,
28 pub proposer: Option<Info>,
30 pub total_voting_power: vote::Power,
32}
33
34impl Set {
35 pub const MAX_TOTAL_VOTING_POWER: u64 = (i64::MAX / 8) as u64;
36
37 pub fn new(validators: Vec<Info>, proposer: Option<Info>) -> Set {
39 Self::try_from_parts(validators, proposer, 0).unwrap()
40 }
41
42 fn try_from_parts(
43 mut validators: Vec<Info>,
44 proposer: Option<Info>,
45 unvalidated_total_voting_power: i64,
46 ) -> Result<Set, Error> {
47 let total_voting_power = validators
49 .iter()
50 .map(|v| v.power.value())
51 .fold(0u64, |acc, v| acc.saturating_add(v));
52
53 if total_voting_power > Self::MAX_TOTAL_VOTING_POWER {
54 return Err(Error::total_voting_power_overflow());
55 }
56
57 let total_voting_power: vote::Power = total_voting_power.try_into().unwrap();
59
60 if unvalidated_total_voting_power != 0 {
63 let given_val: vote::Power = unvalidated_total_voting_power.try_into()?;
64 if given_val != total_voting_power {
65 return Err(Error::total_voting_power_mismatch());
66 }
67 }
68
69 Self::sort_validators(&mut validators);
70
71 Ok(Set {
72 validators,
73 proposer,
74 total_voting_power,
75 })
76 }
77
78 pub fn without_proposer(validators: Vec<Info>) -> Set {
80 Self::new(validators, None)
81 }
82
83 pub fn with_proposer(
85 validators: Vec<Info>,
86 proposer_address: account::Id,
87 ) -> Result<Self, Error> {
88 let proposer = validators
90 .iter()
91 .find(|v| v.address == proposer_address)
92 .cloned()
93 .ok_or_else(|| Error::proposer_not_found(proposer_address))?;
94
95 Ok(Self::new(validators, Some(proposer)))
98 }
99
100 pub fn validators(&self) -> &Vec<Info> {
102 &self.validators
103 }
104
105 pub fn proposer(&self) -> &Option<Info> {
107 &self.proposer
108 }
109
110 pub fn total_voting_power(&self) -> vote::Power {
112 self.total_voting_power
113 }
114
115 fn sort_validators(vals: &mut [Info]) {
118 vals.sort_by_key(|v| (core::cmp::Reverse(v.power), v.address));
119 }
120
121 pub fn validator(&self, val_id: account::Id) -> Option<Info> {
123 self.validators
124 .iter()
125 .find(|val| val.address == val_id)
126 .cloned()
127 }
128
129 #[cfg(feature = "rust-crypto")]
131 pub fn hash(&self) -> Hash {
132 self.hash_with::<crate::crypto::default::Sha256>()
133 }
134
135 pub fn hash_with<H>(&self) -> Hash
137 where
138 H: MerkleHash + Sha256 + Default,
139 {
140 let validator_bytes: Vec<Vec<u8>> = self
141 .validators()
142 .iter()
143 .map(|validator| validator.hash_bytes())
144 .collect();
145
146 Hash::Sha256(merkle::simple_hash_from_byte_vectors::<H>(&validator_bytes))
147 }
148}
149
150#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
152#[serde(into = "RawValidator")]
153pub struct Info {
154 pub address: account::Id,
156
157 pub pub_key: PublicKey,
159
160 #[serde(alias = "voting_power", alias = "total_voting_power")]
163 pub power: vote::Power,
164
165 pub name: Option<String>,
167
168 #[serde(skip)]
170 pub proposer_priority: ProposerPriority,
171}
172
173impl Info {
174 pub fn power(&self) -> u64 {
176 self.power.value()
177 }
178
179 pub fn verify_signature<V>(&self, sign_bytes: &[u8], signature: &Signature) -> Result<(), Error>
182 where
183 V: Verifier,
184 {
185 V::verify(self.pub_key, sign_bytes, signature)
186 .map_err(|_| Error::signature_invalid("Ed25519 signature verification failed".into()))
187 }
188
189 #[cfg(feature = "rust-crypto")]
190 pub fn new(pk: PublicKey, vp: vote::Power) -> Info {
192 Info {
193 address: account::Id::from(pk),
194 pub_key: pk,
195 power: vp,
196 name: None,
197 proposer_priority: ProposerPriority::default(),
198 }
199 }
200}
201
202#[derive(Clone, PartialEq, Eq)]
208pub struct SimpleValidator {
209 pub pub_key: PublicKey,
211 pub voting_power: vote::Power,
213}
214
215impl From<&Info> for SimpleValidator {
217 fn from(info: &Info) -> SimpleValidator {
218 SimpleValidator {
219 pub_key: info.pub_key,
220 voting_power: info.power,
221 }
222 }
223}
224
225impl Info {
226 pub fn hash_bytes(&self) -> Vec<u8> {
229 Protobuf::<RawSimpleValidator>::encode_vec(SimpleValidator::from(self))
230 }
231}
232
233#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Default)]
236pub struct ProposerPriority(i64);
237
238impl From<i64> for ProposerPriority {
239 fn from(value: i64) -> Self {
240 ProposerPriority(value)
241 }
242}
243
244impl From<ProposerPriority> for i64 {
245 fn from(priority: ProposerPriority) -> i64 {
246 priority.value()
247 }
248}
249
250impl ProposerPriority {
251 pub fn value(self) -> i64 {
253 self.0
254 }
255}
256
257#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
263#[serde(into = "RawValidatorUpdate")]
264pub struct Update {
265 #[serde(deserialize_with = "deserialize_public_key")]
267 pub pub_key: PublicKey,
268
269 #[serde(default)]
271 pub power: vote::Power,
272}
273
274cometbft_old_pb_modules! {
279 use pb::{
280 abci::ValidatorUpdate as RawValidatorUpdate,
281 types::{
282 SimpleValidator as RawSimpleValidator, Validator as RawValidator,
283 ValidatorSet as RawValidatorSet,
284 },
285 };
286 use super::{Info, Set, SimpleValidator, Update};
287 use crate::{prelude::*, Error, account};
288
289 impl Protobuf<RawValidatorSet> for Set {}
290
291 impl TryFrom<RawValidatorSet> for Set {
292 type Error = Error;
293
294 fn try_from(value: RawValidatorSet) -> Result<Self, Self::Error> {
295 let validators = value
296 .validators
297 .into_iter()
298 .map(TryInto::try_into)
299 .collect::<Result<Vec<_>, _>>()?;
300
301 let proposer = value.proposer.map(TryInto::try_into).transpose()?;
302
303 Self::try_from_parts(validators, proposer, value.total_voting_power)
304 }
305 }
306
307 impl From<Set> for RawValidatorSet {
308 fn from(value: Set) -> Self {
309 RawValidatorSet {
310 validators: value.validators.into_iter().map(Into::into).collect(),
311 proposer: value.proposer.map(Into::into),
312 total_voting_power: value.total_voting_power.into(),
313 }
314 }
315 }
316
317 impl TryFrom<RawValidator> for Info {
318 type Error = Error;
319
320 fn try_from(value: RawValidator) -> Result<Self, Self::Error> {
321 let raw_pub_key = value
322 .pub_key
323 .ok_or_else(Error::missing_public_key)?;
324 let address = value.address.try_into()?;
325 if account::Id::try_from(raw_pub_key.clone())? != address {
326 return Err(Error::invalid_validator_address());
327 }
328
329 let pub_key = raw_pub_key.try_into()?;
330
331 Ok(Info {
332 address,
333 pub_key,
334 power: value.voting_power.try_into()?,
335 name: None,
336 proposer_priority: value.proposer_priority.into(),
337 })
338 }
339 }
340
341 impl From<Info> for RawValidator {
342 fn from(value: Info) -> Self {
343 RawValidator {
344 address: value.address.into(),
345 pub_key: Some(value.pub_key.into()),
346 voting_power: value.power.into(),
347 proposer_priority: value.proposer_priority.into(),
348 }
349 }
350 }
351
352 impl Protobuf<RawSimpleValidator> for SimpleValidator {}
353
354 impl TryFrom<RawSimpleValidator> for SimpleValidator {
355 type Error = Error;
356
357 fn try_from(value: RawSimpleValidator) -> Result<Self, Self::Error> {
358 Ok(SimpleValidator {
359 pub_key: value.pub_key
360 .ok_or_else(Error::missing_public_key)?
361 .try_into()?,
362 voting_power: value.voting_power.try_into()?,
363 })
364 }
365 }
366
367 impl From<SimpleValidator> for RawSimpleValidator {
368 fn from(value: SimpleValidator) -> Self {
369 RawSimpleValidator {
370 pub_key: Some(value.pub_key.into()),
371 voting_power: value.voting_power.into(),
372 }
373 }
374 }
375
376 impl Protobuf<RawValidatorUpdate> for Update {}
377
378 impl From<Update> for RawValidatorUpdate {
379 fn from(vu: Update) -> Self {
380 Self {
381 pub_key: Some(vu.pub_key.into()),
382 power: vu.power.into(),
383 }
384 }
385 }
386
387 impl TryFrom<RawValidatorUpdate> for Update {
388 type Error = Error;
389
390 fn try_from(vu: RawValidatorUpdate) -> Result<Self, Self::Error> {
391 Ok(Self {
392 pub_key: vu
393 .pub_key
394 .ok_or_else(Error::missing_public_key)?
395 .try_into()?,
396 power: vu.power.try_into()?,
397 })
398 }
399 }
400}
401
402mod v1 {
403 use super::{Info, Set, SimpleValidator, Update};
404 use crate::{account, prelude::*, Error, PublicKey};
405 use cometbft_proto::abci::v1::ValidatorUpdate as RawValidatorUpdate;
406 use cometbft_proto::types::v1::{
407 SimpleValidator as RawSimpleValidator, Validator as RawValidator,
408 ValidatorSet as RawValidatorSet,
409 };
410 use cometbft_proto::Protobuf;
411
412 impl Protobuf<RawValidatorSet> for Set {}
413
414 impl TryFrom<RawValidatorSet> for Set {
415 type Error = Error;
416
417 fn try_from(value: RawValidatorSet) -> Result<Self, Self::Error> {
418 let validators = value
419 .validators
420 .into_iter()
421 .map(TryInto::try_into)
422 .collect::<Result<Vec<_>, _>>()?;
423
424 let proposer = value.proposer.map(TryInto::try_into).transpose()?;
425
426 Self::try_from_parts(validators, proposer, value.total_voting_power)
427 }
428 }
429
430 impl From<Set> for RawValidatorSet {
431 fn from(value: Set) -> Self {
432 RawValidatorSet {
433 validators: value.validators.into_iter().map(Into::into).collect(),
434 proposer: value.proposer.map(Into::into),
435 total_voting_power: value.total_voting_power.into(),
436 }
437 }
438 }
439
440 impl TryFrom<RawValidator> for Info {
441 type Error = Error;
442
443 fn try_from(value: RawValidator) -> Result<Self, Self::Error> {
444 let address = value.address.try_into()?;
445 if account::v1::try_from_type_and_bytes(&value.pub_key_type, &value.pub_key_bytes)?
446 != address
447 {
448 return Err(Error::invalid_validator_address());
449 }
450
451 let pub_key =
452 PublicKey::try_from_type_and_bytes(&value.pub_key_type, &value.pub_key_bytes)?;
453
454 Ok(Info {
455 address,
456 pub_key,
457 power: value.voting_power.try_into()?,
458 name: None,
459 proposer_priority: value.proposer_priority.into(),
460 })
461 }
462 }
463
464 impl From<Info> for RawValidator {
465 fn from(value: Info) -> Self {
466 #[allow(deprecated)]
467 RawValidator {
468 address: value.address.into(),
469 pub_key: None, voting_power: value.power.into(),
471 proposer_priority: value.proposer_priority.into(),
472 pub_key_bytes: value.pub_key.to_bytes(),
473 pub_key_type: value.pub_key.type_str().to_owned(),
474 }
475 }
476 }
477
478 impl Protobuf<RawSimpleValidator> for SimpleValidator {}
479
480 impl TryFrom<RawSimpleValidator> for SimpleValidator {
481 type Error = Error;
482
483 fn try_from(value: RawSimpleValidator) -> Result<Self, Self::Error> {
484 Ok(SimpleValidator {
485 pub_key: value
486 .pub_key
487 .ok_or_else(Error::missing_public_key)?
488 .try_into()?,
489 voting_power: value.voting_power.try_into()?,
490 })
491 }
492 }
493
494 impl From<SimpleValidator> for RawSimpleValidator {
495 fn from(value: SimpleValidator) -> Self {
496 RawSimpleValidator {
497 pub_key: Some(value.pub_key.into()),
498 voting_power: value.voting_power.into(),
499 }
500 }
501 }
502
503 impl Protobuf<RawValidatorUpdate> for Update {}
504
505 impl From<Update> for RawValidatorUpdate {
506 fn from(vu: Update) -> Self {
507 Self {
508 power: vu.power.into(),
509 pub_key_bytes: vu.pub_key.to_bytes().into(),
510 pub_key_type: vu.pub_key.type_str().to_owned(),
511 }
512 }
513 }
514
515 impl TryFrom<RawValidatorUpdate> for Update {
516 type Error = Error;
517
518 fn try_from(vu: RawValidatorUpdate) -> Result<Self, Self::Error> {
519 let pub_key_type: String = vu.pub_key_type;
520 let pub_key_bytes = Vec::from(vu.pub_key_bytes);
521
522 Ok(Self {
523 pub_key: PublicKey::try_from_type_and_bytes(&pub_key_type, &pub_key_bytes)?,
524 power: vu.power.try_into()?,
525 })
526 }
527 }
528}
529
530mod v1beta1 {
531 use super::{Info, Set, SimpleValidator, Update};
532 use crate::{prelude::*, Error};
533 use cometbft_proto::abci::v1beta1::ValidatorUpdate as RawValidatorUpdate;
534 use cometbft_proto::types::v1beta1::{
535 SimpleValidator as RawSimpleValidator, Validator as RawValidator,
536 ValidatorSet as RawValidatorSet,
537 };
538 use cometbft_proto::Protobuf;
539
540 impl Protobuf<RawValidatorSet> for Set {}
541
542 impl TryFrom<RawValidatorSet> for Set {
543 type Error = Error;
544
545 fn try_from(value: RawValidatorSet) -> Result<Self, Self::Error> {
546 let validators = value
547 .validators
548 .into_iter()
549 .map(TryInto::try_into)
550 .collect::<Result<Vec<_>, _>>()?;
551
552 let proposer = value.proposer.map(TryInto::try_into).transpose()?;
553
554 Self::try_from_parts(validators, proposer, value.total_voting_power)
555 }
556 }
557
558 impl From<Set> for RawValidatorSet {
559 fn from(value: Set) -> Self {
560 RawValidatorSet {
561 validators: value.validators.into_iter().map(Into::into).collect(),
562 proposer: value.proposer.map(Into::into),
563 total_voting_power: value.total_voting_power.into(),
564 }
565 }
566 }
567
568 impl TryFrom<RawValidator> for Info {
569 type Error = Error;
570
571 fn try_from(value: RawValidator) -> Result<Self, Self::Error> {
572 Ok(Info {
573 address: value.address.try_into()?,
574 pub_key: value
575 .pub_key
576 .ok_or_else(Error::missing_public_key)?
577 .try_into()?,
578 power: value.voting_power.try_into()?,
579 name: None,
580 proposer_priority: value.proposer_priority.into(),
581 })
582 }
583 }
584
585 impl From<Info> for RawValidator {
586 fn from(value: Info) -> Self {
587 RawValidator {
588 address: value.address.into(),
589 pub_key: Some(value.pub_key.into()),
590 voting_power: value.power.into(),
591 proposer_priority: value.proposer_priority.into(),
592 }
593 }
594 }
595
596 impl Protobuf<RawSimpleValidator> for SimpleValidator {}
597
598 impl TryFrom<RawSimpleValidator> for SimpleValidator {
599 type Error = Error;
600
601 fn try_from(value: RawSimpleValidator) -> Result<Self, Self::Error> {
602 Ok(SimpleValidator {
603 pub_key: value
604 .pub_key
605 .ok_or_else(Error::missing_public_key)?
606 .try_into()?,
607 voting_power: value.voting_power.try_into()?,
608 })
609 }
610 }
611
612 impl From<SimpleValidator> for RawSimpleValidator {
613 fn from(value: SimpleValidator) -> Self {
614 RawSimpleValidator {
615 pub_key: Some(value.pub_key.into()),
616 voting_power: value.voting_power.into(),
617 }
618 }
619 }
620
621 impl Protobuf<RawValidatorUpdate> for Update {}
622
623 impl From<Update> for RawValidatorUpdate {
624 fn from(vu: Update) -> Self {
625 Self {
626 pub_key: Some(vu.pub_key.into()),
627 power: vu.power.into(),
628 }
629 }
630 }
631
632 impl TryFrom<RawValidatorUpdate> for Update {
633 type Error = Error;
634
635 fn try_from(vu: RawValidatorUpdate) -> Result<Self, Self::Error> {
636 Ok(Self {
637 pub_key: vu
638 .pub_key
639 .ok_or_else(Error::missing_public_key)?
640 .try_into()?,
641 power: vu.power.try_into()?,
642 })
643 }
644 }
645}
646
647#[cfg(test)]
648mod tests {
649 use super::*;
650
651 #[cfg(feature = "rust-crypto")]
652 mod crypto {
653 use super::*;
654
655 fn make_validator(pk: Vec<u8>, vp: u64) -> Info {
657 let pk = PublicKey::from_raw_ed25519(&pk).unwrap();
658 Info::new(pk, vote::Power::try_from(vp).unwrap())
659 }
660
661 #[test]
662 fn test_validator_set() {
663 let v1 = make_validator(
693 vec![
694 48, 163, 55, 132, 231, 147, 230, 163, 56, 158, 127, 218, 179, 139, 212, 103,
695 218, 89, 122, 126, 229, 88, 84, 48, 32, 0, 185, 174, 63, 72, 203, 52,
696 ],
697 148_151_478_422_287_875,
698 );
699 let v2 = make_validator(
700 vec![
701 54, 253, 174, 153, 121, 74, 145, 180, 111, 16, 214, 48, 193, 109, 104, 134, 55,
702 162, 151, 16, 182, 114, 125, 135, 32, 195, 236, 248, 64, 112, 74, 101,
703 ],
704 158_095_448_483_785_107,
705 );
706 let v3 = make_validator(
707 vec![
708 182, 205, 13, 86, 147, 27, 65, 49, 160, 118, 11, 180, 117, 35, 206, 35, 68, 19,
709 27, 173, 69, 92, 204, 224, 200, 51, 249, 81, 105, 128, 112, 244,
710 ],
711 770_561_664_770_006_272,
712 );
713 let hash_expect = vec![
714 11, 64, 107, 4, 234, 81, 232, 75, 204, 199, 160, 114, 229, 97, 243, 95, 118, 213,
715 17, 22, 57, 84, 71, 122, 200, 169, 192, 252, 41, 148, 223, 180,
716 ];
717
718 let val_set = Set::without_proposer(vec![v1.clone(), v2.clone(), v3.clone()]);
719 let hash = val_set.hash();
720 assert_eq!(hash_expect, hash.as_bytes().to_vec());
721
722 let not_in_set = make_validator(
723 vec![
724 110, 147, 87, 120, 27, 218, 66, 209, 81, 4, 169, 153, 64, 163, 137, 89, 168,
725 97, 219, 233, 42, 119, 24, 61, 47, 59, 76, 31, 182, 60, 13, 4,
726 ],
727 10_000_000_000_000_000,
728 );
729
730 assert_eq!(val_set.validator(v1.address).unwrap(), v1);
731 assert_eq!(val_set.validator(v2.address).unwrap(), v2);
732 assert_eq!(val_set.validator(v3.address).unwrap(), v3);
733 assert_eq!(val_set.validator(not_in_set.address), None);
734 assert_eq!(
735 val_set.total_voting_power().value(),
736 148_151_478_422_287_875 + 158_095_448_483_785_107 + 770_561_664_770_006_272
737 );
738 }
739 }
740
741 #[test]
742 fn deserialize_validator_updates() {
743 const FMT1: &str = r#"{
744 "pub_key": {
745 "Sum": {
746 "type": "tendermint.crypto.PublicKey_Ed25519",
747 "value": {
748 "ed25519": "VqJCr3vjQdffcLIG6RMBl2MgXDFYNY6b3Joaa43gV3o="
749 }
750 }
751 },
752 "power": "573929"
753 }"#;
754 const FMT2: &str = r#"{
755 "pub_key": {
756 "type": "tendermint/PubKeyEd25519",
757 "value": "VqJCr3vjQdffcLIG6RMBl2MgXDFYNY6b3Joaa43gV3o="
758 },
759 "power": "573929"
760 }"#;
761
762 let update1 = serde_json::from_str::<Update>(FMT1).unwrap();
763 let update2 = serde_json::from_str::<Update>(FMT2).unwrap();
764
765 assert_eq!(u64::from(update1.power), 573929);
766 assert_eq!(update1, update2);
767 }
768
769 #[test]
770 fn validator_set_deserialize_all_fields() {
771 const VSET: &str = r#"{
772 "validators": [
773 {
774 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
775 "voting_power": "50",
776 "proposer_priority": "-150",
777 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
778 "pub_key_type": "tendermint/PubKeyEd25519"
779 },
780 {
781 "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
782 "voting_power": "42",
783 "proposer_priority": "50",
784 "pub_key_bytes": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4=",
785 "pub_key_type": "tendermint/PubKeyEd25519"
786 }
787 ],
788 "proposer": {
789 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
790 "voting_power": "50",
791 "proposer_priority": "-150",
792 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
793 "pub_key_type": "tendermint/PubKeyEd25519"
794 },
795 "total_voting_power": "92"
796 }"#;
797
798 let vset = serde_json::from_str::<Set>(VSET).unwrap();
799 assert_eq!(vset.total_voting_power().value(), 92);
800 }
801
802 #[test]
803 fn validator_set_deserialize_no_total_voting_power() {
804 const VSET: &str = r#"{
805 "validators": [
806 {
807 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
808 "voting_power": "50",
809 "proposer_priority": "-150",
810 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
811 "pub_key_type": "tendermint/PubKeyEd25519"
812 },
813 {
814 "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
815 "voting_power": "42",
816 "proposer_priority": "50",
817 "pub_key_bytes": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4=",
818 "pub_key_type": "tendermint/PubKeyEd25519"
819 }
820 ],
821 "proposer": {
822 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
823 "voting_power": "50",
824 "proposer_priority": "-150",
825 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
826 "pub_key_type": "tendermint/PubKeyEd25519"
827 }
828 }"#;
829
830 let vset = serde_json::from_str::<Set>(VSET).unwrap();
831 assert_eq!(vset.total_voting_power().value(), 92);
832 }
833
834 #[test]
835 fn validator_set_deserialize_total_voting_power_mismatch() {
836 const VSET: &str = r#"{
837 "validators": [
838 {
839 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
840 "voting_power": "50",
841 "proposer_priority": "-150",
842 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
843 "pub_key_type": "tendermint/PubKeyEd25519"
844 },
845 {
846 "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
847 "voting_power": "42",
848 "proposer_priority": "50",
849 "pub_key_bytes": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4=",
850 "pub_key_type": "tendermint/PubKeyEd25519"
851 }
852 ],
853 "proposer": {
854 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
855 "voting_power": "50",
856 "proposer_priority": "-150",
857 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
858 "pub_key_type": "tendermint/PubKeyEd25519"
859 },
860 "total_voting_power": "100"
861 }"#;
862
863 let err = serde_json::from_str::<Set>(VSET).unwrap_err();
864 assert!(
865 err.to_string()
866 .contains("total voting power in validator set does not match the sum of participants' powers"),
867 "{err}"
868 );
869 }
870
871 #[test]
872 fn validator_set_deserialize_total_voting_power_exceeds_limit() {
873 const VSET: &str = r#"{
874 "validators": [
875 {
876 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
877 "voting_power": "576460752303423488",
878 "proposer_priority": "-150",
879 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
880 "pub_key_type": "tendermint/PubKeyEd25519"
881 },
882 {
883 "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
884 "voting_power": "576460752303423488",
885 "proposer_priority": "50",
886 "pub_key_bytes": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4=",
887 "pub_key_type": "tendermint/PubKeyEd25519"
888 }
889 ],
890 "proposer": {
891 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
892 "voting_power": "50",
893 "proposer_priority": "-150",
894 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
895 "pub_key_type": "tendermint/PubKeyEd25519"
896 },
897 "total_voting_power": "92"
898 }"#;
899
900 let err = serde_json::from_str::<Set>(VSET).unwrap_err();
901 assert!(
902 err.to_string()
903 .contains("total voting power in validator set exceeds the allowed maximum"),
904 "{err}"
905 );
906 }
907
908 #[test]
909 fn validator_set_deserialize_total_voting_power_overflow() {
910 const VSET: &str = r#"{
911 "validators": [
912 {
913 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
914 "voting_power": "6148914691236517205",
915 "proposer_priority": "-150",
916 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
917 "pub_key_type": "tendermint/PubKeyEd25519"
918 },
919 {
920 "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
921 "voting_power": "6148914691236517205",
922 "proposer_priority": "50",
923 "pub_key_bytes": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4=",
924 "pub_key_type": "tendermint/PubKeyEd25519"
925 },
926 {
927 "address": "044EB1BB5D4C1CDB90029648439AEB10431FF295",
928 "voting_power": "6148914691236517206",
929 "proposer_priority": "50",
930 "pub_key_bytes": "Wc790fkCDAi7LvZ4UIBAIJSNI+Rp2aU80/8l+idZ/wI=",
931 "pub_key_type": "tendermint/PubKeyEd25519"
932 }
933 ],
934 "proposer": {
935 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
936 "voting_power": "50",
937 "proposer_priority": "-150",
938 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
939 "pub_key_type": "tendermint/PubKeyEd25519"
940 }
941 }"#;
942
943 let err = serde_json::from_str::<Set>(VSET).unwrap_err();
944 assert!(
945 err.to_string()
946 .contains("total voting power in validator set exceeds the allowed maximum"),
947 "{err}"
948 );
949 }
950
951 #[test]
952 fn validator_set_deserialize_invalid_validator_address() {
953 const VSET: &str = r#"{
954 "validators": [
955 {
956 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A22",
957 "pub_key_type": "tendermint/PubKeyEd25519",
958 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
959 "voting_power": "50",
960 "proposer_priority": "-150"
961 }
962 ],
963 "proposer": {
964 "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A22",
965 "pub_key_type": "tendermint/PubKeyEd25519",
966 "pub_key_bytes": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc=",
967 "voting_power": "50",
968 "proposer_priority": "-150"
969 },
970 "total_voting_power": "50"
971 }"#;
972
973 let err = serde_json::from_str::<Set>(VSET).unwrap_err();
974 assert!(
975 err.to_string().contains("invalid validator address"),
976 "{err}"
977 );
978 }
979}