celestia_tendermint/
validator.rs

1//! Tendermint validators
2
3use celestia_tendermint_proto::v0_37::types::SimpleValidator as RawSimpleValidator;
4use celestia_tendermint_proto::Protobuf;
5use serde::{Deserialize, Serialize};
6
7use crate::{
8    account,
9    crypto::signature::Verifier,
10    crypto::Sha256,
11    hash::Hash,
12    merkle::{self, MerkleHash},
13    prelude::*,
14    public_key::deserialize_public_key,
15    vote, Error, PublicKey, Signature,
16};
17
18/// Validator set contains a vector of validators
19#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
20pub struct Set {
21    validators: Vec<Info>,
22    proposer: Option<Info>,
23    total_voting_power: vote::Power,
24}
25
26impl Set {
27    /// Constructor
28    pub fn new(mut validators: Vec<Info>, proposer: Option<Info>) -> Set {
29        Self::sort_validators(&mut validators);
30
31        // Compute the total voting power
32        let total_voting_power = validators
33            .iter()
34            .map(|v| v.power.value())
35            .sum::<u64>()
36            .try_into()
37            .unwrap();
38
39        Set {
40            validators,
41            proposer,
42            total_voting_power,
43        }
44    }
45
46    /// Convenience constructor for cases where there is no proposer
47    pub fn without_proposer(validators: Vec<Info>) -> Set {
48        Self::new(validators, None)
49    }
50
51    /// Convenience constructor for cases where there is a proposer
52    pub fn with_proposer(
53        validators: Vec<Info>,
54        proposer_address: account::Id,
55    ) -> Result<Self, Error> {
56        // Get the proposer.
57        let proposer = validators
58            .iter()
59            .find(|v| v.address == proposer_address)
60            .cloned()
61            .ok_or_else(|| Error::proposer_not_found(proposer_address))?;
62
63        // Create the validator set with the given proposer.
64        // This is required by IBC on-chain validation.
65        Ok(Self::new(validators, Some(proposer)))
66    }
67
68    /// Get Info of the underlying validators.
69    pub fn validators(&self) -> &Vec<Info> {
70        &self.validators
71    }
72
73    /// Get proposer
74    pub fn proposer(&self) -> &Option<Info> {
75        &self.proposer
76    }
77
78    /// Get total voting power
79    pub fn total_voting_power(&self) -> vote::Power {
80        self.total_voting_power
81    }
82
83    /// Sort the validators according to the current Tendermint requirements
84    /// (v. 0.34 -> first by validator power, descending, then by address, ascending)
85    fn sort_validators(vals: &mut [Info]) {
86        vals.sort_by_key(|v| (core::cmp::Reverse(v.power), v.address));
87    }
88
89    /// Returns the validator with the given Id if its in the Set.
90    pub fn validator(&self, val_id: account::Id) -> Option<Info> {
91        self.validators
92            .iter()
93            .find(|val| val.address == val_id)
94            .cloned()
95    }
96
97    /// Compute the hash of this validator set.
98    #[cfg(feature = "rust-crypto")]
99    pub fn hash(&self) -> Hash {
100        self.hash_with::<crate::crypto::default::Sha256>()
101    }
102
103    /// Hash this header with a SHA256 hasher provided by a crypto provider.
104    pub fn hash_with<H>(&self) -> Hash
105    where
106        H: MerkleHash + Sha256 + Default,
107    {
108        let validator_bytes: Vec<Vec<u8>> = self
109            .validators()
110            .iter()
111            .map(|validator| validator.hash_bytes())
112            .collect();
113
114        Hash::Sha256(merkle::simple_hash_from_byte_vectors::<H>(&validator_bytes))
115    }
116}
117
118/// Validator information
119// Todo: Remove address and make it into a function that generates it on the fly from pub_key.
120#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
121pub struct Info {
122    /// Validator account address
123    pub address: account::Id,
124
125    /// Validator public key
126    pub pub_key: PublicKey,
127
128    /// Validator voting power
129    // Compatibility with genesis.json https://github.com/tendermint/tendermint/issues/5549
130    #[serde(alias = "voting_power", alias = "total_voting_power")]
131    pub power: vote::Power,
132
133    /// Validator name
134    pub name: Option<String>,
135
136    /// Validator proposer priority
137    #[serde(skip)]
138    pub proposer_priority: ProposerPriority,
139}
140
141impl Info {
142    /// Return the voting power of the validator.
143    pub fn power(&self) -> u64 {
144        self.power.value()
145    }
146
147    /// Verify the given signature against the given sign_bytes using the validators
148    /// public key.
149    pub fn verify_signature<V>(&self, sign_bytes: &[u8], signature: &Signature) -> Result<(), Error>
150    where
151        V: Verifier,
152    {
153        V::verify(self.pub_key, sign_bytes, signature)
154            .map_err(|_| Error::signature_invalid("Ed25519 signature verification failed".into()))
155    }
156
157    #[cfg(feature = "rust-crypto")]
158    /// Create a new validator.
159    pub fn new(pk: PublicKey, vp: vote::Power) -> Info {
160        Info {
161            address: account::Id::from(pk),
162            pub_key: pk,
163            power: vp,
164            name: None,
165            proposer_priority: ProposerPriority::default(),
166        }
167    }
168}
169
170/// SimpleValidator is the form of the validator used for computing the Merkle tree.
171/// It does not include the address, as that is redundant with the pubkey,
172/// nor the proposer priority, as that changes with every block even if the validator set didn't.
173/// It contains only the pubkey and the voting power.
174/// TODO: currently only works for Ed25519 pubkeys
175#[derive(Clone, PartialEq, Eq)]
176pub struct SimpleValidator {
177    /// Public key
178    pub pub_key: PublicKey,
179    /// Voting power
180    pub voting_power: vote::Power,
181}
182
183/// Info -> SimpleValidator
184impl From<&Info> for SimpleValidator {
185    fn from(info: &Info) -> SimpleValidator {
186        SimpleValidator {
187            pub_key: info.pub_key,
188            voting_power: info.power,
189        }
190    }
191}
192
193impl Info {
194    /// Returns the bytes to be hashed into the Merkle tree -
195    /// the leaves of the tree.
196    pub fn hash_bytes(&self) -> Vec<u8> {
197        Protobuf::<RawSimpleValidator>::encode_vec(&SimpleValidator::from(self)).unwrap()
198    }
199}
200
201// Todo: Is there more knowledge/restrictions about proposerPriority?
202/// Proposer priority
203#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Default)]
204pub struct ProposerPriority(i64);
205
206impl From<i64> for ProposerPriority {
207    fn from(value: i64) -> Self {
208        ProposerPriority(value)
209    }
210}
211
212impl From<ProposerPriority> for i64 {
213    fn from(priority: ProposerPriority) -> i64 {
214        priority.value()
215    }
216}
217
218impl ProposerPriority {
219    /// Get the current proposer priority
220    pub fn value(self) -> i64 {
221        self.0
222    }
223}
224
225/// A change to the validator set.
226///
227/// Used to inform Tendermint of changes to the validator set.
228///
229/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#validatorupdate)
230#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
231pub struct Update {
232    /// Validator public key
233    #[serde(deserialize_with = "deserialize_public_key")]
234    pub pub_key: PublicKey,
235
236    /// New voting power
237    #[serde(default)]
238    pub power: vote::Power,
239}
240
241// =============================================================================
242// Protobuf conversions
243// =============================================================================
244
245tendermint_pb_modules! {
246    use pb::{
247        abci::ValidatorUpdate as RawValidatorUpdate,
248        types::{
249            SimpleValidator as RawSimpleValidator, Validator as RawValidator,
250            ValidatorSet as RawValidatorSet,
251        },
252    };
253    use super::{Info, Set, SimpleValidator, Update};
254    use crate::{prelude::*, Error};
255
256    impl Protobuf<RawValidatorSet> for Set {}
257
258    impl TryFrom<RawValidatorSet> for Set {
259        type Error = Error;
260
261        fn try_from(value: RawValidatorSet) -> Result<Self, Self::Error> {
262            let validators = value
263                .validators
264                .into_iter()
265                .map(TryInto::try_into)
266                .collect::<Result<Vec<_>, _>>()?;
267
268            let proposer = value.proposer.map(TryInto::try_into).transpose()?;
269            let validator_set = Self::new(validators, proposer);
270
271            Ok(validator_set)
272        }
273    }
274
275    impl From<Set> for RawValidatorSet {
276        fn from(value: Set) -> Self {
277            RawValidatorSet {
278                validators: value.validators.into_iter().map(Into::into).collect(),
279                proposer: value.proposer.map(Into::into),
280                total_voting_power: value.total_voting_power.into(),
281            }
282        }
283    }
284
285    impl TryFrom<RawValidator> for Info {
286        type Error = Error;
287
288        fn try_from(value: RawValidator) -> Result<Self, Self::Error> {
289            Ok(Info {
290                address: value.address.try_into()?,
291                pub_key: value
292                    .pub_key
293                    .ok_or_else(Error::missing_public_key)?
294                    .try_into()?,
295                power: value.voting_power.try_into()?,
296                name: None,
297                proposer_priority: value.proposer_priority.into(),
298            })
299        }
300    }
301
302    impl From<Info> for RawValidator {
303        fn from(value: Info) -> Self {
304            RawValidator {
305                address: value.address.into(),
306                pub_key: Some(value.pub_key.into()),
307                voting_power: value.power.into(),
308                proposer_priority: value.proposer_priority.into(),
309            }
310        }
311    }
312
313    impl Protobuf<RawSimpleValidator> for SimpleValidator {}
314
315    impl TryFrom<RawSimpleValidator> for SimpleValidator {
316        type Error = Error;
317
318        fn try_from(value: RawSimpleValidator) -> Result<Self, Self::Error> {
319            Ok(SimpleValidator {
320                pub_key: value.pub_key
321                    .ok_or_else(Error::missing_public_key)?
322                    .try_into()?,
323                voting_power: value.voting_power.try_into()?,
324            })
325        }
326    }
327
328    impl From<SimpleValidator> for RawSimpleValidator {
329        fn from(value: SimpleValidator) -> Self {
330            RawSimpleValidator {
331                pub_key: Some(value.pub_key.into()),
332                voting_power: value.voting_power.into(),
333            }
334        }
335    }
336
337    impl Protobuf<RawValidatorUpdate> for Update {}
338
339    impl From<Update> for RawValidatorUpdate {
340        fn from(vu: Update) -> Self {
341            Self {
342                pub_key: Some(vu.pub_key.into()),
343                power: vu.power.into(),
344            }
345        }
346    }
347
348    impl TryFrom<RawValidatorUpdate> for Update {
349        type Error = Error;
350
351        fn try_from(vu: RawValidatorUpdate) -> Result<Self, Self::Error> {
352            Ok(Self {
353                pub_key: vu
354                    .pub_key
355                    .ok_or_else(Error::missing_public_key)?
356                    .try_into()?,
357                power: vu.power.try_into()?,
358            })
359        }
360    }
361}
362
363#[cfg(test)]
364mod tests {
365    use super::*;
366
367    #[cfg(feature = "rust-crypto")]
368    mod crypto {
369        use super::*;
370
371        // make a validator
372        fn make_validator(pk: Vec<u8>, vp: u64) -> Info {
373            let pk = PublicKey::from_raw_ed25519(&pk).unwrap();
374            Info::new(pk, vote::Power::try_from(vp).unwrap())
375        }
376
377        #[test]
378        fn test_validator_set() {
379            // test vector generated by Go code
380            // import (
381            // "fmt"
382            // "github.com/tendermint/tendermint/crypto/ed25519"
383            // "github.com/tendermint/tendermint/types"
384            // "strings"
385            // )
386            // func testValSet() {
387            // pk1 := ed25519.GenPrivKeyFromSecret([]byte{4, 211, 14, 157, 10, 0, 205, 9, 10, 116, 207,
388            // 161, 4, 211, 190, 37, 108, 88, 202, 168, 63, 135, 0, 141, 53, 55, 254, 57, 40, 184, 20,
389            // 242}) pk2 := ed25519.GenPrivKeyFromSecret([]byte{99, 231, 126, 151, 159, 236, 2,
390            // 229, 33, 44, 200, 248, 147, 176, 13, 127, 105, 76, 49, 83, 25, 101, 44, 57, 20, 215, 166,
391            // 188, 134, 94, 56, 165}) pk3 := ed25519.GenPrivKeyFromSecret([]byte{54, 253, 151,
392            // 16, 182, 114, 125, 12, 74, 101, 54, 253, 174, 153, 121, 74, 145, 180, 111, 16, 214, 48,
393            // 193, 109, 104, 134, 55, 162, 151, 16, 182, 114}) not_in_set :=
394            // ed25519.GenPrivKeyFromSecret([]byte{121, 74, 145, 180, 111, 16, 214, 48, 193, 109, 35,
395            // 68, 19, 27, 173, 69, 92, 204, 127, 218, 234, 81, 232, 75, 204, 199, 48, 163, 55, 132,
396            // 231, 147}) fmt.Println("pk1: ", strings.Join(strings.Split(fmt.Sprintf("%v",
397            // pk1.PubKey().Bytes()), " "), ", ")) fmt.Println("pk2:",
398            // strings.Join(strings.Split(fmt.Sprintf("%v", pk2.PubKey().Bytes()), " "), ", "))
399            // fmt.Println("pk3: ", strings.Join(strings.Split(fmt.Sprintf("%v", pk3.PubKey().Bytes()),
400            // " "), ", ")) fmt.Println("not_in_set: ",
401            // strings.Join(strings.Split(fmt.Sprintf("%v", not_in_set.PubKey().Bytes()), " "), ", "))
402            // v1 := types.NewValidator(pk1.PubKey(), 148151478422287875)
403            // v2 := types.NewValidator(pk2.PubKey(), 158095448483785107)
404            // v3 := types.NewValidator(pk3.PubKey(), 770561664770006272)
405            // set := types.NewValidatorSet([]*types.Validator{v1, v2, v3})
406            // fmt.Println("Hash:", strings.Join(strings.Split(fmt.Sprintf("%v", set.Hash()), " "), ",
407            // ")) }
408            let v1 = make_validator(
409                vec![
410                    48, 163, 55, 132, 231, 147, 230, 163, 56, 158, 127, 218, 179, 139, 212, 103,
411                    218, 89, 122, 126, 229, 88, 84, 48, 32, 0, 185, 174, 63, 72, 203, 52,
412                ],
413                148_151_478_422_287_875,
414            );
415            let v2 = make_validator(
416                vec![
417                    54, 253, 174, 153, 121, 74, 145, 180, 111, 16, 214, 48, 193, 109, 104, 134, 55,
418                    162, 151, 16, 182, 114, 125, 135, 32, 195, 236, 248, 64, 112, 74, 101,
419                ],
420                158_095_448_483_785_107,
421            );
422            let v3 = make_validator(
423                vec![
424                    182, 205, 13, 86, 147, 27, 65, 49, 160, 118, 11, 180, 117, 35, 206, 35, 68, 19,
425                    27, 173, 69, 92, 204, 224, 200, 51, 249, 81, 105, 128, 112, 244,
426                ],
427                770_561_664_770_006_272,
428            );
429            let hash_expect = vec![
430                11, 64, 107, 4, 234, 81, 232, 75, 204, 199, 160, 114, 229, 97, 243, 95, 118, 213,
431                17, 22, 57, 84, 71, 122, 200, 169, 192, 252, 41, 148, 223, 180,
432            ];
433
434            let val_set = Set::without_proposer(vec![v1.clone(), v2.clone(), v3.clone()]);
435            let hash = val_set.hash();
436            assert_eq!(hash_expect, hash.as_bytes().to_vec());
437
438            let not_in_set = make_validator(
439                vec![
440                    110, 147, 87, 120, 27, 218, 66, 209, 81, 4, 169, 153, 64, 163, 137, 89, 168,
441                    97, 219, 233, 42, 119, 24, 61, 47, 59, 76, 31, 182, 60, 13, 4,
442                ],
443                10_000_000_000_000_000,
444            );
445
446            assert_eq!(val_set.validator(v1.address).unwrap(), v1);
447            assert_eq!(val_set.validator(v2.address).unwrap(), v2);
448            assert_eq!(val_set.validator(v3.address).unwrap(), v3);
449            assert_eq!(val_set.validator(not_in_set.address), None);
450            assert_eq!(
451                val_set.total_voting_power().value(),
452                148_151_478_422_287_875 + 158_095_448_483_785_107 + 770_561_664_770_006_272
453            );
454        }
455    }
456
457    #[test]
458    fn deserialize_validator_updates() {
459        const FMT1: &str = r#"{
460            "pub_key": {
461                "Sum": {
462                    "type": "tendermint.crypto.PublicKey_Ed25519",
463                    "value": {
464                        "ed25519": "VqJCr3vjQdffcLIG6RMBl2MgXDFYNY6b3Joaa43gV3o="
465                    }
466                }
467            },
468            "power": "573929"
469        }"#;
470        const FMT2: &str = r#"{
471            "pub_key": {
472                "type": "tendermint/PubKeyEd25519",
473                "value": "VqJCr3vjQdffcLIG6RMBl2MgXDFYNY6b3Joaa43gV3o="
474            },
475            "power": "573929"
476        }"#;
477
478        let update1 = serde_json::from_str::<Update>(FMT1).unwrap();
479        let update2 = serde_json::from_str::<Update>(FMT2).unwrap();
480
481        assert_eq!(u64::from(update1.power), 573929);
482        assert_eq!(update1, update2);
483    }
484}