tendermint_testgen/
validator.rs

1use gumdrop::Options;
2use serde::{Deserialize, Serialize};
3use simple_error::*;
4use tendermint::{
5    account, consensus::state::Ordering, private_key, public_key, public_key::PublicKey, validator,
6    vote,
7};
8
9use crate::{helpers::*, Generator};
10
11#[derive(Debug, Options, Serialize, Deserialize, Clone)]
12pub struct Validator {
13    #[options(help = "validator id (required; can be passed via STDIN)")]
14    pub id: Option<String>,
15    #[options(help = "voting power of this validator (default: 0)", meta = "POWER")]
16    pub voting_power: Option<u64>,
17    #[options(
18        help = "proposer priority of this validator (default: 0)",
19        meta = "PRIORITY"
20    )]
21    pub proposer_priority: Option<i64>,
22}
23
24impl Validator {
25    pub fn new(id: &str) -> Self {
26        Validator {
27            id: Some(id.to_string()),
28            voting_power: None,
29            proposer_priority: None,
30        }
31    }
32    // Question: Why do we need this option since we're already initializing id with fn new()??
33    set_option!(id, &str, Some(id.to_string()));
34    set_option!(voting_power, u64);
35    set_option!(proposer_priority, i64);
36
37    /// Get private key for this validator companion.
38    pub fn get_private_key(&self) -> Result<private_key::Ed25519, SimpleError> {
39        let id = match &self.id {
40            None => bail!("validator identifier is missing"),
41            Some(id) => id,
42        };
43        if id.is_empty() {
44            bail!("empty validator identifier")
45        }
46        let mut bytes = id.clone().into_bytes();
47        if bytes.len() > 32 {
48            bail!("validator identifier is too long")
49        }
50        bytes.extend(vec![0u8; 32 - bytes.len()].iter());
51        let signing_key = require_with!(
52            private_key::Ed25519::try_from(&bytes[..]).ok(),
53            "failed to construct a seed from validator identifier"
54        );
55        Ok(signing_key)
56    }
57
58    /// Get public key for this validator companion.
59    pub fn get_public_key(&self) -> Result<public_key::Ed25519, SimpleError> {
60        self.get_private_key()
61            .map(|secret_key| secret_key.verification_key())
62    }
63}
64
65impl std::str::FromStr for Validator {
66    type Err = SimpleError;
67    fn from_str(s: &str) -> Result<Self, Self::Err> {
68        let validator = match parse_as::<Validator>(s) {
69            Ok(input) => input,
70            Err(_) => Validator::new(s),
71        };
72        Ok(validator)
73    }
74}
75
76impl std::cmp::PartialEq for Validator {
77    fn eq(&self, other: &Self) -> bool {
78        self.id == other.id
79    }
80}
81impl std::cmp::Eq for Validator {}
82
83impl std::cmp::Ord for Validator {
84    fn cmp(&self, other: &Self) -> Ordering {
85        self.generate()
86            .unwrap()
87            .address
88            .cmp(&other.generate().unwrap().address)
89    }
90}
91
92impl std::cmp::PartialOrd for Validator {
93    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
94        Some(self.cmp(other))
95    }
96}
97
98impl Generator<validator::Info> for Validator {
99    fn merge_with_default(self, default: Self) -> Self {
100        Validator {
101            id: self.id.or(default.id),
102            voting_power: self.voting_power.or(default.voting_power),
103            proposer_priority: self.proposer_priority.or(default.proposer_priority),
104        }
105    }
106
107    fn generate(&self) -> Result<validator::Info, SimpleError> {
108        let verification_key = self.get_private_key()?.verification_key();
109        let info = validator::Info {
110            address: account::Id::from(verification_key),
111            pub_key: PublicKey::from(verification_key),
112            power: vote::Power::try_from(self.voting_power.unwrap_or(0)).unwrap(),
113            name: None,
114            proposer_priority: validator::ProposerPriority::from(
115                self.proposer_priority.unwrap_or_default(),
116            ),
117        };
118        Ok(info)
119    }
120}
121
122/// A helper function to generate multiple validators at once.
123pub fn generate_validators(vals: &[Validator]) -> Result<Vec<validator::Info>, SimpleError> {
124    sort_validators(vals)
125        .iter()
126        .map(|v| v.generate())
127        .collect::<Result<Vec<validator::Info>, SimpleError>>()
128}
129
130/// A helper function to sort validators according to the Tendermint specs.
131pub fn sort_validators(vals: &[Validator]) -> Vec<Validator> {
132    let mut sorted = vals.to_owned();
133    sorted.sort_by_key(|v| {
134        let v = v.generate().unwrap();
135        (std::cmp::Reverse(v.power), v.address)
136    });
137    sorted
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143
144    fn make_publickey(pk_string: &str) -> PublicKey {
145        serde_json::from_str(pk_string).unwrap()
146    }
147
148    // make a validator from a pubkey, a voting power, and a proposer priority
149    fn make_validator(pk: PublicKey, vp: u64, pp: Option<i64>) -> validator::Info {
150        let mut info = validator::Info::new(pk, vote::Power::try_from(vp).unwrap());
151        info.proposer_priority = validator::ProposerPriority::from(pp.unwrap_or_default());
152        info
153    }
154
155    #[test]
156    fn test_validator() {
157        let pk_a = make_publickey("{\"type\":\"tendermint/PubKeyEd25519\",\"value\":\"YnT69eNDaRaNU7teDTcyBedSD0B/Ziqx+sejm0wQba0=\"}");
158        let pk_b = make_publickey("{\"type\":\"tendermint/PubKeyEd25519\",\"value\":\"hYkrBnbzZQd3r/bjZgyxXfcxfNrYg8PCVsB4JLUB9eU=\"}");
159
160        let val = Validator::new("a").voting_power(10);
161        assert_eq!(val.generate().unwrap(), make_validator(pk_a, 10, None));
162
163        let val = val.voting_power(20);
164        assert_eq!(val.generate().unwrap(), make_validator(pk_a, 20, None));
165
166        let val = val.proposer_priority(100);
167        assert_eq!(val.generate().unwrap(), make_validator(pk_a, 20, Some(100)));
168
169        let val_b = val.id("b").proposer_priority(-100);
170        assert_eq!(
171            val_b.generate().unwrap(),
172            make_validator(pk_b, 20, Some(-100))
173        );
174
175        let val_a = Validator::new("a").voting_power(20).proposer_priority(-100);
176        assert_eq!(
177            val_a.generate().unwrap(),
178            make_validator(pk_a, 20, Some(-100))
179        );
180
181        let val_b_a = val_b.id("a");
182        assert_eq!(val_b_a, val_a);
183        assert_eq!(val_b_a.generate().unwrap(), val_a.generate().unwrap());
184
185        let mut val = val_a;
186        val.proposer_priority = None;
187        assert_eq!(val.generate().unwrap(), make_validator(pk_a, 20, None));
188
189        let mut block_val = val.generate().unwrap();
190
191        block_val.power = vote::Power::from(30_u32);
192        assert_ne!(val.generate().unwrap(), block_val);
193
194        let val = val.voting_power(30);
195        assert_eq!(val.generate().unwrap(), block_val);
196
197        block_val.proposer_priority = validator::ProposerPriority::from(1000);
198        assert_ne!(val.generate().unwrap(), block_val);
199
200        let val = val.proposer_priority(1000);
201        assert_eq!(val.generate().unwrap(), block_val);
202    }
203}