Skip to main content

iq_cometbft/
validator.rs

1//! CometBFT validators
2
3use 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/// Validator set contains a vector of validators
23#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(try_from = "RawValidatorSet")]
25pub struct Set {
26    /// Validators
27    pub validators: Vec<Info>,
28    // Proposer
29    pub proposer: Option<Info>,
30    // Total voting power
31    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    /// Constructor
38    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        // Compute the total voting power
48        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        // The conversion cannot fail as we have validated against a smaller limit.
58        let total_voting_power: vote::Power = total_voting_power.try_into().unwrap();
59
60        // If the given total voting power is not the default value,
61        // validate it against the sum of voting powers of the participants.
62        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    /// Convenience constructor for cases where there is no proposer
79    pub fn without_proposer(validators: Vec<Info>) -> Set {
80        Self::new(validators, None)
81    }
82
83    /// Convenience constructor for cases where there is a proposer
84    pub fn with_proposer(
85        validators: Vec<Info>,
86        proposer_address: account::Id,
87    ) -> Result<Self, Error> {
88        // Get the proposer.
89        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        // Create the validator set with the given proposer.
96        // This is required by IBC on-chain validation.
97        Ok(Self::new(validators, Some(proposer)))
98    }
99
100    /// Get Info of the underlying validators.
101    pub fn validators(&self) -> &Vec<Info> {
102        &self.validators
103    }
104
105    /// Get proposer
106    pub fn proposer(&self) -> &Option<Info> {
107        &self.proposer
108    }
109
110    /// Get total voting power
111    pub fn total_voting_power(&self) -> vote::Power {
112        self.total_voting_power
113    }
114
115    /// Sort the validators according to the current CometBFT requirements
116    /// (v. 0.34 -> first by validator power, descending, then by address, ascending)
117    fn sort_validators(vals: &mut [Info]) {
118        vals.sort_by_key(|v| (core::cmp::Reverse(v.power), v.address));
119    }
120
121    /// Returns the validator with the given Id if its in the Set.
122    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    /// Compute the hash of this validator set.
130    #[cfg(feature = "rust-crypto")]
131    pub fn hash(&self) -> Hash {
132        self.hash_with::<crate::crypto::default::Sha256>()
133    }
134
135    /// Hash this header with a SHA256 hasher provided by a crypto provider.
136    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/// Validator information
151#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
152#[serde(into = "RawValidator")]
153pub struct Info {
154    /// Validator account address
155    pub address: account::Id,
156
157    /// Validator public key
158    pub pub_key: PublicKey,
159
160    /// Validator voting power
161    // Compatibility with genesis.json https://github.com/tendermint/tendermint/issues/5549
162    #[serde(alias = "voting_power", alias = "total_voting_power")]
163    pub power: vote::Power,
164
165    /// Validator name
166    pub name: Option<String>,
167
168    /// Validator proposer priority
169    #[serde(skip)]
170    pub proposer_priority: ProposerPriority,
171}
172
173impl Info {
174    /// Return the voting power of the validator.
175    pub fn power(&self) -> u64 {
176        self.power.value()
177    }
178
179    /// Verify the given signature against the given sign_bytes using the validators
180    /// public key.
181    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    /// Create a new validator.
191    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/// SimpleValidator is the form of the validator used for computing the Merkle tree.
203/// It does not include the address, as that is redundant with the pubkey,
204/// nor the proposer priority, as that changes with every block even if the validator set didn't.
205/// It contains only the pubkey and the voting power.
206/// TODO: currently only works for Ed25519 pubkeys
207#[derive(Clone, PartialEq, Eq)]
208pub struct SimpleValidator {
209    /// Public key
210    pub pub_key: PublicKey,
211    /// Voting power
212    pub voting_power: vote::Power,
213}
214
215/// Info -> SimpleValidator
216impl 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    /// Returns the bytes to be hashed into the Merkle tree -
227    /// the leaves of the tree.
228    pub fn hash_bytes(&self) -> Vec<u8> {
229        Protobuf::<RawSimpleValidator>::encode_vec(SimpleValidator::from(self))
230    }
231}
232
233// Todo: Is there more knowledge/restrictions about proposerPriority?
234/// Proposer priority
235#[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    /// Get the current proposer priority
252    pub fn value(self) -> i64 {
253        self.0
254    }
255}
256
257/// A change to the validator set.
258///
259/// Used to inform CometBFT of changes to the validator set.
260///
261/// [ABCI documentation](https://docs.cometbft.com/v1/spec/abci/abci.html#validatorupdate)
262#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
263#[serde(into = "RawValidatorUpdate")]
264pub struct Update {
265    /// Validator public key
266    #[serde(deserialize_with = "deserialize_public_key")]
267    pub pub_key: PublicKey,
268
269    /// New voting power
270    #[serde(default)]
271    pub power: vote::Power,
272}
273
274// =============================================================================
275// Protobuf conversions
276// =============================================================================
277
278cometbft_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, // pub_key is deprecated in v1
470                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        // make a validator
656        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            // test vector generated by Go code
664            // import (
665            // "fmt"
666            // "github.com/cometbft/cometbft/crypto/ed25519"
667            // "github.com/cometbft/cometbft/types"
668            // "strings"
669            // )
670            // func testValSet() {
671            // pk1 := ed25519.GenPrivKeyFromSecret([]byte{4, 211, 14, 157, 10, 0, 205, 9, 10, 116, 207,
672            // 161, 4, 211, 190, 37, 108, 88, 202, 168, 63, 135, 0, 141, 53, 55, 254, 57, 40, 184, 20,
673            // 242}) pk2 := ed25519.GenPrivKeyFromSecret([]byte{99, 231, 126, 151, 159, 236, 2,
674            // 229, 33, 44, 200, 248, 147, 176, 13, 127, 105, 76, 49, 83, 25, 101, 44, 57, 20, 215, 166,
675            // 188, 134, 94, 56, 165}) pk3 := ed25519.GenPrivKeyFromSecret([]byte{54, 253, 151,
676            // 16, 182, 114, 125, 12, 74, 101, 54, 253, 174, 153, 121, 74, 145, 180, 111, 16, 214, 48,
677            // 193, 109, 104, 134, 55, 162, 151, 16, 182, 114}) not_in_set :=
678            // ed25519.GenPrivKeyFromSecret([]byte{121, 74, 145, 180, 111, 16, 214, 48, 193, 109, 35,
679            // 68, 19, 27, 173, 69, 92, 204, 127, 218, 234, 81, 232, 75, 204, 199, 48, 163, 55, 132,
680            // 231, 147}) fmt.Println("pk1: ", strings.Join(strings.Split(fmt.Sprintf("%v",
681            // pk1.PubKey().Bytes()), " "), ", ")) fmt.Println("pk2:",
682            // strings.Join(strings.Split(fmt.Sprintf("%v", pk2.PubKey().Bytes()), " "), ", "))
683            // fmt.Println("pk3: ", strings.Join(strings.Split(fmt.Sprintf("%v", pk3.PubKey().Bytes()),
684            // " "), ", ")) fmt.Println("not_in_set: ",
685            // strings.Join(strings.Split(fmt.Sprintf("%v", not_in_set.PubKey().Bytes()), " "), ", "))
686            // v1 := types.NewValidator(pk1.PubKey(), 148151478422287875)
687            // v2 := types.NewValidator(pk2.PubKey(), 158095448483785107)
688            // v3 := types.NewValidator(pk3.PubKey(), 770561664770006272)
689            // set := types.NewValidatorSet([]*types.Validator{v1, v2, v3})
690            // fmt.Println("Hash:", strings.Join(strings.Split(fmt.Sprintf("%v", set.Hash()), " "), ",
691            // ")) }
692            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}