tendermint/
validator.rs

1//! Tendermint validators
2
3use 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/// Validator set contains a vector of validators
21#[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    /// Constructor
33    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        // Compute the total voting power
43        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        // The conversion cannot fail as we have validated against a smaller limit.
53        let total_voting_power: vote::Power = total_voting_power.try_into().unwrap();
54
55        // If the given total voting power is not the default value,
56        // validate it against the sum of voting powers of the participants.
57        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    /// Convenience constructor for cases where there is no proposer
74    pub fn without_proposer(validators: Vec<Info>) -> Set {
75        Self::new(validators, None)
76    }
77
78    /// Convenience constructor for cases where there is a proposer
79    pub fn with_proposer(
80        validators: Vec<Info>,
81        proposer_address: account::Id,
82    ) -> Result<Self, Error> {
83        // Get the proposer.
84        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        // Create the validator set with the given proposer.
91        // This is required by IBC on-chain validation.
92        Ok(Self::new(validators, Some(proposer)))
93    }
94
95    /// Get Info of the underlying validators.
96    pub fn validators(&self) -> &Vec<Info> {
97        &self.validators
98    }
99
100    /// Get proposer
101    pub fn proposer(&self) -> &Option<Info> {
102        &self.proposer
103    }
104
105    /// Get total voting power
106    pub fn total_voting_power(&self) -> vote::Power {
107        self.total_voting_power
108    }
109
110    /// Sort the validators according to the current Tendermint requirements
111    /// (v. 0.34 -> first by validator power, descending, then by address, ascending)
112    fn sort_validators(vals: &mut [Info]) {
113        vals.sort_by_key(|v| (core::cmp::Reverse(v.power), v.address));
114    }
115
116    /// Returns the validator with the given Id if its in the Set.
117    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    /// Compute the hash of this validator set.
125    #[cfg(feature = "rust-crypto")]
126    pub fn hash(&self) -> Hash {
127        self.hash_with::<crate::crypto::default::Sha256>()
128    }
129
130    /// Hash this header with a SHA256 hasher provided by a crypto provider.
131    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/// Validator information
146// Todo: Remove address and make it into a function that generates it on the fly from pub_key.
147#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
148pub struct Info {
149    /// Validator account address
150    pub address: account::Id,
151
152    /// Validator public key
153    pub pub_key: PublicKey,
154
155    /// Validator voting power
156    // Compatibility with genesis.json https://github.com/tendermint/tendermint/issues/5549
157    #[serde(alias = "voting_power", alias = "total_voting_power")]
158    pub power: vote::Power,
159
160    /// Validator name
161    pub name: Option<String>,
162
163    /// Validator proposer priority
164    #[serde(skip)]
165    pub proposer_priority: ProposerPriority,
166}
167
168impl Info {
169    /// Return the voting power of the validator.
170    pub fn power(&self) -> u64 {
171        self.power.value()
172    }
173
174    /// Verify the given signature against the given sign_bytes using the validators
175    /// public key.
176    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    /// Create a new validator.
186    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/// SimpleValidator is the form of the validator used for computing the Merkle tree.
198/// It does not include the address, as that is redundant with the pubkey,
199/// nor the proposer priority, as that changes with every block even if the validator set didn't.
200/// It contains only the pubkey and the voting power.
201/// TODO: currently only works for Ed25519 pubkeys
202#[derive(Clone, PartialEq, Eq)]
203pub struct SimpleValidator {
204    /// Public key
205    pub pub_key: PublicKey,
206    /// Voting power
207    pub voting_power: vote::Power,
208}
209
210/// Info -> SimpleValidator
211impl 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    /// Returns the bytes to be hashed into the Merkle tree -
222    /// the leaves of the tree.
223    pub fn hash_bytes(&self) -> Vec<u8> {
224        Protobuf::<RawSimpleValidator>::encode_vec(SimpleValidator::from(self))
225    }
226}
227
228// Todo: Is there more knowledge/restrictions about proposerPriority?
229/// Proposer priority
230#[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    /// Get the current proposer priority
247    pub fn value(self) -> i64 {
248        self.0
249    }
250}
251
252/// A change to the validator set.
253///
254/// Used to inform Tendermint of changes to the validator set.
255///
256/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#validatorupdate)
257#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
258pub struct Update {
259    /// Validator public key
260    #[serde(deserialize_with = "deserialize_public_key")]
261    pub pub_key: PublicKey,
262
263    /// New voting power
264    #[serde(default)]
265    pub power: vote::Power,
266}
267
268// =============================================================================
269// Protobuf conversions
270// =============================================================================
271
272tendermint_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        // make a validator
398        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            // test vector generated by Go code
406            // import (
407            // "fmt"
408            // "github.com/tendermint/tendermint/crypto/ed25519"
409            // "github.com/tendermint/tendermint/types"
410            // "strings"
411            // )
412            // func testValSet() {
413            // pk1 := ed25519.GenPrivKeyFromSecret([]byte{4, 211, 14, 157, 10, 0, 205, 9, 10, 116, 207,
414            // 161, 4, 211, 190, 37, 108, 88, 202, 168, 63, 135, 0, 141, 53, 55, 254, 57, 40, 184, 20,
415            // 242}) pk2 := ed25519.GenPrivKeyFromSecret([]byte{99, 231, 126, 151, 159, 236, 2,
416            // 229, 33, 44, 200, 248, 147, 176, 13, 127, 105, 76, 49, 83, 25, 101, 44, 57, 20, 215, 166,
417            // 188, 134, 94, 56, 165}) pk3 := ed25519.GenPrivKeyFromSecret([]byte{54, 253, 151,
418            // 16, 182, 114, 125, 12, 74, 101, 54, 253, 174, 153, 121, 74, 145, 180, 111, 16, 214, 48,
419            // 193, 109, 104, 134, 55, 162, 151, 16, 182, 114}) not_in_set :=
420            // ed25519.GenPrivKeyFromSecret([]byte{121, 74, 145, 180, 111, 16, 214, 48, 193, 109, 35,
421            // 68, 19, 27, 173, 69, 92, 204, 127, 218, 234, 81, 232, 75, 204, 199, 48, 163, 55, 132,
422            // 231, 147}) fmt.Println("pk1: ", strings.Join(strings.Split(fmt.Sprintf("%v",
423            // pk1.PubKey().Bytes()), " "), ", ")) fmt.Println("pk2:",
424            // strings.Join(strings.Split(fmt.Sprintf("%v", pk2.PubKey().Bytes()), " "), ", "))
425            // fmt.Println("pk3: ", strings.Join(strings.Split(fmt.Sprintf("%v", pk3.PubKey().Bytes()),
426            // " "), ", ")) fmt.Println("not_in_set: ",
427            // strings.Join(strings.Split(fmt.Sprintf("%v", not_in_set.PubKey().Bytes()), " "), ", "))
428            // v1 := types.NewValidator(pk1.PubKey(), 148151478422287875)
429            // v2 := types.NewValidator(pk2.PubKey(), 158095448483785107)
430            // v3 := types.NewValidator(pk3.PubKey(), 770561664770006272)
431            // set := types.NewValidatorSet([]*types.Validator{v1, v2, v3})
432            // fmt.Println("Hash:", strings.Join(strings.Split(fmt.Sprintf("%v", set.Hash()), " "), ",
433            // ")) }
434            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}