tendermint_testgen/
validator.rs1use 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 set_option!(id, &str, Some(id.to_string()));
34 set_option!(voting_power, u64);
35 set_option!(proposer_priority, i64);
36
37 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 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
122pub 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
130pub 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 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}