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
25    pub validators: Vec<Info>,
26    // Proposer
27    pub proposer: Option<Info>,
28    // Total voting power
29    pub total_voting_power: vote::Power,
30}
31
32impl Set {
33    pub const MAX_TOTAL_VOTING_POWER: u64 = (i64::MAX / 8) as u64;
34
35    /// Constructor
36    pub fn new(validators: Vec<Info>, proposer: Option<Info>) -> Set {
37        Self::try_from_parts(validators, proposer, 0).unwrap()
38    }
39
40    fn try_from_parts(
41        mut validators: Vec<Info>,
42        proposer: Option<Info>,
43        unvalidated_total_voting_power: i64,
44    ) -> Result<Set, Error> {
45        // Compute the total voting power
46        let total_voting_power = validators
47            .iter()
48            .map(|v| v.power.value())
49            .fold(0u64, |acc, v| acc.saturating_add(v));
50
51        if total_voting_power > Self::MAX_TOTAL_VOTING_POWER {
52            return Err(Error::total_voting_power_overflow());
53        }
54
55        // The conversion cannot fail as we have validated against a smaller limit.
56        let total_voting_power: vote::Power = total_voting_power.try_into().unwrap();
57
58        // If the given total voting power is not the default value,
59        // validate it against the sum of voting powers of the participants.
60        if unvalidated_total_voting_power != 0 {
61            let given_val: vote::Power = unvalidated_total_voting_power.try_into()?;
62            if given_val != total_voting_power {
63                return Err(Error::total_voting_power_mismatch());
64            }
65        }
66
67        Self::sort_validators(&mut validators);
68
69        Ok(Set {
70            validators,
71            proposer,
72            total_voting_power,
73        })
74    }
75
76    /// Convenience constructor for cases where there is no proposer
77    pub fn without_proposer(validators: Vec<Info>) -> Set {
78        Self::new(validators, None)
79    }
80
81    /// Convenience constructor for cases where there is a proposer
82    pub fn with_proposer(
83        validators: Vec<Info>,
84        proposer_address: account::Id,
85    ) -> Result<Self, Error> {
86        // Get the proposer.
87        let proposer = validators
88            .iter()
89            .find(|v| v.address == proposer_address)
90            .cloned()
91            .ok_or_else(|| Error::proposer_not_found(proposer_address))?;
92
93        // Create the validator set with the given proposer.
94        // This is required by IBC on-chain validation.
95        Ok(Self::new(validators, Some(proposer)))
96    }
97
98    /// Get Info of the underlying validators.
99    pub fn validators(&self) -> &Vec<Info> {
100        &self.validators
101    }
102
103    /// Get proposer
104    pub fn proposer(&self) -> &Option<Info> {
105        &self.proposer
106    }
107
108    /// Get total voting power
109    pub fn total_voting_power(&self) -> vote::Power {
110        self.total_voting_power
111    }
112
113    /// Sort the validators according to the current Tendermint requirements
114    /// (v. 0.34 -> first by validator power, descending, then by address, ascending)
115    fn sort_validators(vals: &mut [Info]) {
116        vals.sort_by_key(|v| (core::cmp::Reverse(v.power), v.address));
117    }
118
119    /// Returns the validator with the given Id if its in the Set.
120    pub fn validator(&self, val_id: account::Id) -> Option<Info> {
121        self.validators
122            .iter()
123            .find(|val| val.address == val_id)
124            .cloned()
125    }
126
127    /// Compute the hash of this validator set.
128    #[cfg(feature = "rust-crypto")]
129    pub fn hash(&self) -> Hash {
130        self.hash_with::<crate::crypto::default::Sha256>()
131    }
132
133    /// Hash this header with a SHA256 hasher provided by a crypto provider.
134    pub fn hash_with<H>(&self) -> Hash
135    where
136        H: MerkleHash + Sha256 + Default,
137    {
138        let validator_bytes: Vec<Vec<u8>> = self
139            .validators()
140            .iter()
141            .map(|validator| validator.hash_bytes())
142            .collect();
143
144        Hash::Sha256(merkle::simple_hash_from_byte_vectors::<H>(&validator_bytes))
145    }
146}
147
148/// Validator information
149// Todo: Remove address and make it into a function that generates it on the fly from pub_key.
150#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
151pub struct Info {
152    /// Validator account address
153    pub address: account::Id,
154
155    /// Validator public key
156    pub pub_key: PublicKey,
157
158    /// Validator voting power
159    // Compatibility with genesis.json https://github.com/tendermint/tendermint/issues/5549
160    #[serde(alias = "voting_power", alias = "total_voting_power")]
161    pub power: vote::Power,
162
163    /// Validator name
164    pub name: Option<String>,
165
166    /// Validator proposer priority
167    #[serde(skip)]
168    pub proposer_priority: ProposerPriority,
169}
170
171impl Info {
172    /// Return the voting power of the validator.
173    pub fn power(&self) -> u64 {
174        self.power.value()
175    }
176
177    /// Verify the given signature against the given sign_bytes using the validators
178    /// public key.
179    pub fn verify_signature<V>(&self, sign_bytes: &[u8], signature: &Signature) -> Result<(), Error>
180    where
181        V: Verifier,
182    {
183        V::verify(self.pub_key, sign_bytes, signature)
184            .map_err(|_| Error::signature_invalid("Ed25519 signature verification failed".into()))
185    }
186
187    #[cfg(feature = "rust-crypto")]
188    /// Create a new validator.
189    pub fn new(pk: PublicKey, vp: vote::Power) -> Info {
190        Info {
191            address: account::Id::from(pk),
192            pub_key: pk,
193            power: vp,
194            name: None,
195            proposer_priority: ProposerPriority::default(),
196        }
197    }
198}
199
200/// SimpleValidator is the form of the validator used for computing the Merkle tree.
201/// It does not include the address, as that is redundant with the pubkey,
202/// nor the proposer priority, as that changes with every block even if the validator set didn't.
203/// It contains only the pubkey and the voting power.
204/// TODO: currently only works for Ed25519 pubkeys
205#[derive(Clone, PartialEq, Eq)]
206pub struct SimpleValidator {
207    /// Public key
208    pub pub_key: PublicKey,
209    /// Voting power
210    pub voting_power: vote::Power,
211}
212
213/// Info -> SimpleValidator
214impl From<&Info> for SimpleValidator {
215    fn from(info: &Info) -> SimpleValidator {
216        SimpleValidator {
217            pub_key: info.pub_key,
218            voting_power: info.power,
219        }
220    }
221}
222
223impl Info {
224    /// Returns the bytes to be hashed into the Merkle tree -
225    /// the leaves of the tree.
226    pub fn hash_bytes(&self) -> Vec<u8> {
227        Protobuf::<RawSimpleValidator>::encode_vec(SimpleValidator::from(self))
228    }
229}
230
231// Todo: Is there more knowledge/restrictions about proposerPriority?
232/// Proposer priority
233#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Default)]
234pub struct ProposerPriority(i64);
235
236impl From<i64> for ProposerPriority {
237    fn from(value: i64) -> Self {
238        ProposerPriority(value)
239    }
240}
241
242impl From<ProposerPriority> for i64 {
243    fn from(priority: ProposerPriority) -> i64 {
244        priority.value()
245    }
246}
247
248impl ProposerPriority {
249    /// Get the current proposer priority
250    pub fn value(self) -> i64 {
251        self.0
252    }
253}
254
255/// A change to the validator set.
256///
257/// Used to inform Tendermint of changes to the validator set.
258///
259/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#validatorupdate)
260#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
261pub struct Update {
262    /// Validator public key
263    #[serde(deserialize_with = "deserialize_public_key")]
264    pub pub_key: PublicKey,
265
266    /// New voting power
267    #[serde(default)]
268    pub power: vote::Power,
269}
270
271// =============================================================================
272// Protobuf conversions
273// =============================================================================
274
275tendermint_pb_modules! {
276    use pb::{
277        abci::ValidatorUpdate as RawValidatorUpdate,
278        types::{
279            SimpleValidator as RawSimpleValidator, Validator as RawValidator,
280            ValidatorSet as RawValidatorSet,
281        },
282    };
283    use super::{Info, Set, SimpleValidator, Update};
284    use crate::{prelude::*, Error, account};
285
286    impl Protobuf<RawValidatorSet> for Set {}
287
288    impl TryFrom<RawValidatorSet> for Set {
289        type Error = Error;
290
291        fn try_from(value: RawValidatorSet) -> Result<Self, Self::Error> {
292            let validators = value
293                .validators
294                .into_iter()
295                .map(TryInto::try_into)
296                .collect::<Result<Vec<_>, _>>()?;
297
298            let proposer = value.proposer.map(TryInto::try_into).transpose()?;
299
300            Self::try_from_parts(validators, proposer, value.total_voting_power)
301        }
302    }
303
304    impl From<Set> for RawValidatorSet {
305        fn from(value: Set) -> Self {
306            RawValidatorSet {
307                validators: value.validators.into_iter().map(Into::into).collect(),
308                proposer: value.proposer.map(Into::into),
309                total_voting_power: value.total_voting_power.into(),
310            }
311        }
312    }
313
314    impl TryFrom<RawValidator> for Info {
315        type Error = Error;
316
317        fn try_from(value: RawValidator) -> Result<Self, Self::Error> {
318            let raw_pub_key = value.pub_key.ok_or_else(Error::missing_public_key)?;
319            let address = value.address.try_into()?;
320            if account::Id::try_from(raw_pub_key.clone())? != address {
321                return Err(Error::invalid_validator_address());
322            }
323            let pub_key = raw_pub_key.try_into()?;
324            Ok(Info {
325                address: address,
326                pub_key: pub_key,
327                power: value.voting_power.try_into()?,
328                name: None,
329                proposer_priority: value.proposer_priority.into(),
330            })
331        }
332    }
333
334    impl From<Info> for RawValidator {
335        fn from(value: Info) -> Self {
336            RawValidator {
337                address: value.address.into(),
338                pub_key: Some(value.pub_key.into()),
339                voting_power: value.power.into(),
340                proposer_priority: value.proposer_priority.into(),
341            }
342        }
343    }
344
345    impl Protobuf<RawSimpleValidator> for SimpleValidator {}
346
347    impl TryFrom<RawSimpleValidator> for SimpleValidator {
348        type Error = Error;
349
350        fn try_from(value: RawSimpleValidator) -> Result<Self, Self::Error> {
351            Ok(SimpleValidator {
352                pub_key: value.pub_key
353                    .ok_or_else(Error::missing_public_key)?
354                    .try_into()?,
355                voting_power: value.voting_power.try_into()?,
356            })
357        }
358    }
359
360    impl From<SimpleValidator> for RawSimpleValidator {
361        fn from(value: SimpleValidator) -> Self {
362            RawSimpleValidator {
363                pub_key: Some(value.pub_key.into()),
364                voting_power: value.voting_power.into(),
365            }
366        }
367    }
368
369    impl Protobuf<RawValidatorUpdate> for Update {}
370
371    impl From<Update> for RawValidatorUpdate {
372        fn from(vu: Update) -> Self {
373            Self {
374                pub_key: Some(vu.pub_key.into()),
375                power: vu.power.into(),
376            }
377        }
378    }
379
380    impl TryFrom<RawValidatorUpdate> for Update {
381        type Error = Error;
382
383        fn try_from(vu: RawValidatorUpdate) -> Result<Self, Self::Error> {
384            Ok(Self {
385                pub_key: vu
386                    .pub_key
387                    .ok_or_else(Error::missing_public_key)?
388                    .try_into()?,
389                power: vu.power.try_into()?,
390            })
391        }
392    }
393}
394
395#[cfg(test)]
396mod tests {
397    use super::*;
398
399    #[cfg(feature = "rust-crypto")]
400    mod crypto {
401        use super::*;
402
403        // make a validator
404        fn make_validator(pk: Vec<u8>, vp: u64) -> Info {
405            let pk = PublicKey::from_raw_ed25519(&pk).unwrap();
406            Info::new(pk, vote::Power::try_from(vp).unwrap())
407        }
408
409        #[test]
410        fn test_validator_set() {
411            // test vector generated by Go code
412            // import (
413            // "fmt"
414            // "github.com/tendermint/tendermint/crypto/ed25519"
415            // "github.com/tendermint/tendermint/types"
416            // "strings"
417            // )
418            // func testValSet() {
419            // pk1 := ed25519.GenPrivKeyFromSecret([]byte{4, 211, 14, 157, 10, 0, 205, 9, 10, 116, 207,
420            // 161, 4, 211, 190, 37, 108, 88, 202, 168, 63, 135, 0, 141, 53, 55, 254, 57, 40, 184, 20,
421            // 242}) pk2 := ed25519.GenPrivKeyFromSecret([]byte{99, 231, 126, 151, 159, 236, 2,
422            // 229, 33, 44, 200, 248, 147, 176, 13, 127, 105, 76, 49, 83, 25, 101, 44, 57, 20, 215, 166,
423            // 188, 134, 94, 56, 165}) pk3 := ed25519.GenPrivKeyFromSecret([]byte{54, 253, 151,
424            // 16, 182, 114, 125, 12, 74, 101, 54, 253, 174, 153, 121, 74, 145, 180, 111, 16, 214, 48,
425            // 193, 109, 104, 134, 55, 162, 151, 16, 182, 114}) not_in_set :=
426            // ed25519.GenPrivKeyFromSecret([]byte{121, 74, 145, 180, 111, 16, 214, 48, 193, 109, 35,
427            // 68, 19, 27, 173, 69, 92, 204, 127, 218, 234, 81, 232, 75, 204, 199, 48, 163, 55, 132,
428            // 231, 147}) fmt.Println("pk1: ", strings.Join(strings.Split(fmt.Sprintf("%v",
429            // pk1.PubKey().Bytes()), " "), ", ")) fmt.Println("pk2:",
430            // strings.Join(strings.Split(fmt.Sprintf("%v", pk2.PubKey().Bytes()), " "), ", "))
431            // fmt.Println("pk3: ", strings.Join(strings.Split(fmt.Sprintf("%v", pk3.PubKey().Bytes()),
432            // " "), ", ")) fmt.Println("not_in_set: ",
433            // strings.Join(strings.Split(fmt.Sprintf("%v", not_in_set.PubKey().Bytes()), " "), ", "))
434            // v1 := types.NewValidator(pk1.PubKey(), 148151478422287875)
435            // v2 := types.NewValidator(pk2.PubKey(), 158095448483785107)
436            // v3 := types.NewValidator(pk3.PubKey(), 770561664770006272)
437            // set := types.NewValidatorSet([]*types.Validator{v1, v2, v3})
438            // fmt.Println("Hash:", strings.Join(strings.Split(fmt.Sprintf("%v", set.Hash()), " "), ",
439            // ")) }
440            let v1 = make_validator(
441                vec![
442                    48, 163, 55, 132, 231, 147, 230, 163, 56, 158, 127, 218, 179, 139, 212, 103,
443                    218, 89, 122, 126, 229, 88, 84, 48, 32, 0, 185, 174, 63, 72, 203, 52,
444                ],
445                148_151_478_422_287_875,
446            );
447            let v2 = make_validator(
448                vec![
449                    54, 253, 174, 153, 121, 74, 145, 180, 111, 16, 214, 48, 193, 109, 104, 134, 55,
450                    162, 151, 16, 182, 114, 125, 135, 32, 195, 236, 248, 64, 112, 74, 101,
451                ],
452                158_095_448_483_785_107,
453            );
454            let v3 = make_validator(
455                vec![
456                    182, 205, 13, 86, 147, 27, 65, 49, 160, 118, 11, 180, 117, 35, 206, 35, 68, 19,
457                    27, 173, 69, 92, 204, 224, 200, 51, 249, 81, 105, 128, 112, 244,
458                ],
459                770_561_664_770_006_272,
460            );
461            let hash_expect = vec![
462                11, 64, 107, 4, 234, 81, 232, 75, 204, 199, 160, 114, 229, 97, 243, 95, 118, 213,
463                17, 22, 57, 84, 71, 122, 200, 169, 192, 252, 41, 148, 223, 180,
464            ];
465
466            let val_set = Set::without_proposer(vec![v1.clone(), v2.clone(), v3.clone()]);
467            let hash = val_set.hash();
468            assert_eq!(hash_expect, hash.as_bytes().to_vec());
469
470            let not_in_set = make_validator(
471                vec![
472                    110, 147, 87, 120, 27, 218, 66, 209, 81, 4, 169, 153, 64, 163, 137, 89, 168,
473                    97, 219, 233, 42, 119, 24, 61, 47, 59, 76, 31, 182, 60, 13, 4,
474                ],
475                10_000_000_000_000_000,
476            );
477
478            assert_eq!(val_set.validator(v1.address).unwrap(), v1);
479            assert_eq!(val_set.validator(v2.address).unwrap(), v2);
480            assert_eq!(val_set.validator(v3.address).unwrap(), v3);
481            assert_eq!(val_set.validator(not_in_set.address), None);
482            assert_eq!(
483                val_set.total_voting_power().value(),
484                148_151_478_422_287_875 + 158_095_448_483_785_107 + 770_561_664_770_006_272
485            );
486        }
487    }
488
489    #[test]
490    fn deserialize_validator_updates() {
491        const FMT1: &str = r#"{
492            "pub_key": {
493                "Sum": {
494                    "type": "tendermint.crypto.PublicKey_Ed25519",
495                    "value": {
496                        "ed25519": "VqJCr3vjQdffcLIG6RMBl2MgXDFYNY6b3Joaa43gV3o="
497                    }
498                }
499            },
500            "power": "573929"
501        }"#;
502        const FMT2: &str = r#"{
503            "pub_key": {
504                "type": "tendermint/PubKeyEd25519",
505                "value": "VqJCr3vjQdffcLIG6RMBl2MgXDFYNY6b3Joaa43gV3o="
506            },
507            "power": "573929"
508        }"#;
509
510        let update1 = serde_json::from_str::<Update>(FMT1).unwrap();
511        let update2 = serde_json::from_str::<Update>(FMT2).unwrap();
512
513        assert_eq!(u64::from(update1.power), 573929);
514        assert_eq!(update1, update2);
515    }
516
517    #[test]
518    fn validator_set_deserialize_all_fields() {
519        const VSET: &str = r#"{
520            "validators": [
521                {
522                    "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
523                    "pub_key": {
524                        "type": "tendermint/PubKeyEd25519",
525                        "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
526                    },
527                    "voting_power": "50",
528                    "proposer_priority": "-150"
529                },
530                {
531                    "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
532                    "pub_key": {
533                        "type": "tendermint/PubKeyEd25519",
534                        "value": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4="
535                    },
536                    "voting_power": "42",
537                    "proposer_priority": "50"
538                }
539            ],
540            "proposer": {
541                "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
542                "pub_key": {
543                    "type": "tendermint/PubKeyEd25519",
544                    "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
545                },
546                "voting_power": "50",
547                "proposer_priority": "-150"
548            },
549            "total_voting_power": "92"
550        }"#;
551
552        let vset = serde_json::from_str::<Set>(VSET).unwrap();
553        assert_eq!(vset.total_voting_power().value(), 92);
554    }
555
556    #[test]
557    fn validator_set_deserialize_no_total_voting_power() {
558        const VSET: &str = r#"{
559            "validators": [
560                {
561                    "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
562                    "pub_key": {
563                        "type": "tendermint/PubKeyEd25519",
564                        "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
565                    },
566                    "voting_power": "50",
567                    "proposer_priority": "-150"
568                },
569                {
570                    "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
571                    "pub_key": {
572                        "type": "tendermint/PubKeyEd25519",
573                        "value": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4="
574                    },
575                    "voting_power": "42",
576                    "proposer_priority": "50"
577                }
578            ],
579            "proposer": {
580                "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
581                "pub_key": {
582                    "type": "tendermint/PubKeyEd25519",
583                    "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
584                },
585                "voting_power": "50",
586                "proposer_priority": "-150"
587            }
588        }"#;
589
590        let vset = serde_json::from_str::<Set>(VSET).unwrap();
591        assert_eq!(vset.total_voting_power().value(), 92);
592    }
593
594    #[test]
595    fn validator_set_deserialize_total_voting_power_mismatch() {
596        const VSET: &str = r#"{
597            "validators": [
598                {
599                    "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
600                    "pub_key": {
601                        "type": "tendermint/PubKeyEd25519",
602                        "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
603                    },
604                    "voting_power": "50",
605                    "proposer_priority": "-150"
606                },
607                {
608                    "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
609                    "pub_key": {
610                        "type": "tendermint/PubKeyEd25519",
611                        "value": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4="
612                    },
613                    "voting_power": "42",
614                    "proposer_priority": "50"
615                }
616            ],
617            "proposer": {
618                "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
619                "pub_key": {
620                    "type": "tendermint/PubKeyEd25519",
621                    "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
622                },
623                "voting_power": "50",
624                "proposer_priority": "-150"
625            },
626            "total_voting_power": "100"
627        }"#;
628
629        let err = serde_json::from_str::<Set>(VSET).unwrap_err();
630        assert!(
631            err.to_string()
632                .contains("total voting power in validator set does not match the sum of participants' powers"),
633            "{err}"
634        );
635    }
636
637    #[test]
638    fn validator_set_deserialize_total_voting_power_exceeds_limit() {
639        const VSET: &str = r#"{
640            "validators": [
641                {
642                    "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
643                    "pub_key": {
644                        "type": "tendermint/PubKeyEd25519",
645                        "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
646                    },
647                    "voting_power": "576460752303423488",
648                    "proposer_priority": "-150"
649                },
650                {
651                    "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
652                    "pub_key": {
653                        "type": "tendermint/PubKeyEd25519",
654                        "value": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4="
655                    },
656                    "voting_power": "576460752303423488",
657                    "proposer_priority": "50"
658                }
659            ],
660            "proposer": {
661                "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
662                "pub_key": {
663                    "type": "tendermint/PubKeyEd25519",
664                    "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
665                },
666                "voting_power": "50",
667                "proposer_priority": "-150"
668            },
669            "total_voting_power": "92"
670        }"#;
671
672        let err = serde_json::from_str::<Set>(VSET).unwrap_err();
673        assert!(
674            err.to_string()
675                .contains("total voting power in validator set exceeds the allowed maximum"),
676            "{err}"
677        );
678    }
679
680    #[test]
681    fn validator_set_deserialize_total_voting_power_overflow() {
682        const VSET: &str = r#"{
683            "validators": [
684                {
685                    "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
686                    "pub_key": {
687                        "type": "tendermint/PubKeyEd25519",
688                        "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
689                    },
690                    "voting_power": "6148914691236517205",
691                    "proposer_priority": "-150"
692                },
693                {
694                    "address": "026CC7B6F3E62F789DBECEC59766888B5464737D",
695                    "pub_key": {
696                        "type": "tendermint/PubKeyEd25519",
697                        "value": "+vlsKpn6ojn+UoTZl+w+fxeqm6xvUfBokTcKfcG3au4="
698                    },
699                    "voting_power": "6148914691236517205",
700                    "proposer_priority": "50"
701                },
702                {
703                    "address": "044EB1BB5D4C1CDB90029648439AEB10431FF295",
704                    "pub_key": {
705                        "type": "tendermint/PubKeyEd25519",
706                        "value": "Wc790fkCDAi7LvZ4UIBAIJSNI+Rp2aU80/8l+idZ/wI="
707                    },
708                    "voting_power": "6148914691236517206",
709                    "proposer_priority": "50"
710                }
711            ],
712            "proposer": {
713                "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A33",
714                "pub_key": {
715                    "type": "tendermint/PubKeyEd25519",
716                    "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
717                },
718                "voting_power": "50",
719                "proposer_priority": "-150"
720            }
721        }"#;
722
723        let err = serde_json::from_str::<Set>(VSET).unwrap_err();
724        assert!(
725            err.to_string()
726                .contains("total voting power in validator set exceeds the allowed maximum"),
727            "{err}"
728        );
729    }
730
731    #[test]
732    fn validator_set_deserialize_invalid_validator_address() {
733        const VSET: &str = r#"{
734            "validators": [
735                {
736                    "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A22",
737                    "pub_key": {
738                        "type": "tendermint/PubKeyEd25519",
739                        "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
740                    },
741                    "voting_power": "50",
742                    "proposer_priority": "-150"
743                }
744            ],
745            "proposer": {
746                "address": "01F527D77D3FFCC4FCFF2DDC2952EEA5414F2A22",
747                "pub_key": {
748                    "type": "tendermint/PubKeyEd25519",
749                    "value": "OAaNq3DX/15fGJP2MI6bujt1GRpvjwrqIevChirJsbc="
750                },
751                "voting_power": "50",
752                "proposer_priority": "-150"
753            },
754            "total_voting_power": "50"
755        }"#;
756
757        let err = serde_json::from_str::<Set>(VSET).unwrap_err();
758        assert!(
759            err.to_string().contains("invalid validator address"),
760            "{err}"
761        );
762    }
763}