1use serde::{Deserialize, Serialize};
4use tendermint_proto::v0_38::types::{
5 SimpleValidator as RawSimpleValidator, ValidatorSet as RawValidatorSet,
6};
7use tendermint_proto::Protobuf;
8
9use crate::{
10 account,
11 crypto::signature::Verifier,
12 crypto::Sha256,
13 hash::Hash,
14 merkle::{self, MerkleHash},
15 prelude::*,
16 public_key::deserialize_public_key,
17 vote, Error, PublicKey, Signature,
18};
19
20#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
22#[serde(try_from = "RawValidatorSet")]
23pub struct Set {
24 pub validators: Vec<Info>,
26 pub proposer: Option<Info>,
28 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 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 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 let total_voting_power: vote::Power = total_voting_power.try_into().unwrap();
57
58 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 pub fn without_proposer(validators: Vec<Info>) -> Set {
78 Self::new(validators, None)
79 }
80
81 pub fn with_proposer(
83 validators: Vec<Info>,
84 proposer_address: account::Id,
85 ) -> Result<Self, Error> {
86 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 Ok(Self::new(validators, Some(proposer)))
96 }
97
98 pub fn validators(&self) -> &Vec<Info> {
100 &self.validators
101 }
102
103 pub fn proposer(&self) -> &Option<Info> {
105 &self.proposer
106 }
107
108 pub fn total_voting_power(&self) -> vote::Power {
110 self.total_voting_power
111 }
112
113 fn sort_validators(vals: &mut [Info]) {
116 vals.sort_by_key(|v| (core::cmp::Reverse(v.power), v.address));
117 }
118
119 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 #[cfg(feature = "rust-crypto")]
129 pub fn hash(&self) -> Hash {
130 self.hash_with::<crate::crypto::default::Sha256>()
131 }
132
133 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#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
151pub struct Info {
152 pub address: account::Id,
154
155 pub pub_key: PublicKey,
157
158 #[serde(alias = "voting_power", alias = "total_voting_power")]
161 pub power: vote::Power,
162
163 pub name: Option<String>,
165
166 #[serde(skip)]
168 pub proposer_priority: ProposerPriority,
169}
170
171impl Info {
172 pub fn power(&self) -> u64 {
174 self.power.value()
175 }
176
177 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 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#[derive(Clone, PartialEq, Eq)]
206pub struct SimpleValidator {
207 pub pub_key: PublicKey,
209 pub voting_power: vote::Power,
211}
212
213impl 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 pub fn hash_bytes(&self) -> Vec<u8> {
227 Protobuf::<RawSimpleValidator>::encode_vec(SimpleValidator::from(self))
228 }
229}
230
231#[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 pub fn value(self) -> i64 {
251 self.0
252 }
253}
254
255#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
261pub struct Update {
262 #[serde(deserialize_with = "deserialize_public_key")]
264 pub pub_key: PublicKey,
265
266 #[serde(default)]
268 pub power: vote::Power,
269}
270
271tendermint_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 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 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}