1mod canonical_vote;
4mod power;
5mod sign_vote;
6mod validator_index;
7
8use core::{fmt, str::FromStr};
9
10use bytes::BufMut;
11use serde::{Deserialize, Serialize};
12use tendermint_proto::v0_38::types::{CanonicalVote as RawCanonicalVote, Vote as RawVote};
13use tendermint_proto::{Error as ProtobufError, Protobuf};
14
15pub use self::{
16 canonical_vote::CanonicalVote, power::Power, sign_vote::*, validator_index::ValidatorIndex,
17};
18use crate::{
19 account, block, chain::Id as ChainId, consensus::State, error::Error, hash, prelude::*,
20 Signature, Time,
21};
22
23#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
28#[serde(try_from = "RawVote", into = "RawVote")]
29pub struct Vote {
30 pub vote_type: Type,
32
33 pub height: block::Height,
35
36 pub round: block::Round,
38
39 pub block_id: Option<block::Id>,
41
42 pub timestamp: Option<Time>,
44
45 pub validator_address: account::Id,
47
48 pub validator_index: ValidatorIndex,
50
51 pub signature: Option<Signature>,
53
54 pub extension: Vec<u8>,
60
61 pub extension_signature: Option<Signature>,
67}
68
69mod v0_34 {
74 use super::Vote;
75 use crate::{block, prelude::*, Error, Signature};
76 use tendermint_proto::v0_34::types::Vote as RawVote;
77 use tendermint_proto::Protobuf;
78
79 impl Protobuf<RawVote> for Vote {}
80
81 impl TryFrom<RawVote> for Vote {
82 type Error = Error;
83
84 fn try_from(value: RawVote) -> Result<Self, Self::Error> {
85 if value.timestamp.is_none() {
86 return Err(Error::missing_timestamp());
87 }
88 Ok(Vote {
89 vote_type: value.r#type.try_into()?,
90 height: value.height.try_into()?,
91 round: value.round.try_into()?,
92 block_id: value
94 .block_id
95 .map(TryInto::try_into)
96 .transpose()?
97 .filter(|i| i != &block::Id::default()),
98 timestamp: value.timestamp.map(|t| t.try_into()).transpose()?,
99 validator_address: value.validator_address.try_into()?,
100 validator_index: value.validator_index.try_into()?,
101 signature: Signature::new(value.signature)?,
102 extension: Default::default(),
103 extension_signature: None,
104 })
105 }
106 }
107
108 impl From<Vote> for RawVote {
109 fn from(value: Vote) -> Self {
110 RawVote {
111 r#type: value.vote_type.into(),
112 height: value.height.into(),
113 round: value.round.into(),
114 block_id: value.block_id.map(Into::into),
115 timestamp: value.timestamp.map(Into::into),
116 validator_address: value.validator_address.into(),
117 validator_index: value.validator_index.into(),
118 signature: value.signature.map(|s| s.into_bytes()).unwrap_or_default(),
119 }
120 }
121 }
122}
123
124mod v0_37 {
125 use super::Vote;
126 use crate::{block, prelude::*, Error, Signature};
127 use tendermint_proto::v0_37::types::Vote as RawVote;
128 use tendermint_proto::Protobuf;
129
130 impl Protobuf<RawVote> for Vote {}
131
132 impl TryFrom<RawVote> for Vote {
133 type Error = Error;
134
135 fn try_from(value: RawVote) -> Result<Self, Self::Error> {
136 if value.timestamp.is_none() {
137 return Err(Error::missing_timestamp());
138 }
139 Ok(Vote {
140 vote_type: value.r#type.try_into()?,
141 height: value.height.try_into()?,
142 round: value.round.try_into()?,
143 block_id: value
145 .block_id
146 .map(TryInto::try_into)
147 .transpose()?
148 .filter(|i| i != &block::Id::default()),
149 timestamp: value.timestamp.map(|t| t.try_into()).transpose()?,
150 validator_address: value.validator_address.try_into()?,
151 validator_index: value.validator_index.try_into()?,
152 signature: Signature::new(value.signature)?,
153 extension: Default::default(),
154 extension_signature: None,
155 })
156 }
157 }
158
159 impl From<Vote> for RawVote {
160 fn from(value: Vote) -> Self {
161 RawVote {
162 r#type: value.vote_type.into(),
163 height: value.height.into(),
164 round: value.round.into(),
165 block_id: value.block_id.map(Into::into),
166 timestamp: value.timestamp.map(Into::into),
167 validator_address: value.validator_address.into(),
168 validator_index: value.validator_index.into(),
169 signature: value.signature.map(|s| s.into_bytes()).unwrap_or_default(),
170 }
171 }
172 }
173}
174
175mod v0_38 {
176 use super::Vote;
177 use crate::{block, prelude::*, Error, Signature};
178 use tendermint_proto::v0_38::types::Vote as RawVote;
179 use tendermint_proto::Protobuf;
180
181 impl Protobuf<RawVote> for Vote {}
182
183 impl TryFrom<RawVote> for Vote {
184 type Error = Error;
185
186 fn try_from(value: RawVote) -> Result<Self, Self::Error> {
187 if value.timestamp.is_none() {
188 return Err(Error::missing_timestamp());
189 }
190 Ok(Vote {
191 vote_type: value.r#type.try_into()?,
192 height: value.height.try_into()?,
193 round: value.round.try_into()?,
194 block_id: value
196 .block_id
197 .map(TryInto::try_into)
198 .transpose()?
199 .filter(|i| i != &block::Id::default()),
200 timestamp: value.timestamp.map(|t| t.try_into()).transpose()?,
201 validator_address: value.validator_address.try_into()?,
202 validator_index: value.validator_index.try_into()?,
203 signature: Signature::new(value.signature)?,
204 extension: value.extension,
205 extension_signature: Signature::new(value.extension_signature)?,
206 })
207 }
208 }
209
210 impl From<Vote> for RawVote {
211 fn from(value: Vote) -> Self {
212 RawVote {
213 r#type: value.vote_type.into(),
214 height: value.height.into(),
215 round: value.round.into(),
216 block_id: value.block_id.map(Into::into),
217 timestamp: value.timestamp.map(Into::into),
218 validator_address: value.validator_address.into(),
219 validator_index: value.validator_index.into(),
220 signature: value.signature.map(|s| s.into_bytes()).unwrap_or_default(),
221 extension: value.extension,
222 extension_signature: value
223 .extension_signature
224 .map(|s| s.into_bytes())
225 .unwrap_or_default(),
226 }
227 }
228 }
229}
230
231impl Vote {
232 pub fn is_prevote(&self) -> bool {
234 match self.vote_type {
235 Type::Prevote => true,
236 Type::Precommit => false,
237 }
238 }
239
240 pub fn is_precommit(&self) -> bool {
242 match self.vote_type {
243 Type::Precommit => true,
244 Type::Prevote => false,
245 }
246 }
247
248 pub fn header_hash(&self) -> Option<hash::Hash> {
250 self.block_id.map(|b| b.hash)
251 }
252
253 pub fn to_signable_bytes<B>(
255 &self,
256 chain_id: ChainId,
257 sign_bytes: &mut B,
258 ) -> Result<bool, ProtobufError>
259 where
260 B: BufMut,
261 {
262 let canonical = CanonicalVote::new(self.clone(), chain_id);
263 Protobuf::<RawCanonicalVote>::encode_length_delimited(canonical, sign_bytes)?;
264 Ok(true)
265 }
266
267 pub fn into_signable_vec(self, chain_id: ChainId) -> Vec<u8> {
269 let canonical = CanonicalVote::new(self, chain_id);
270 Protobuf::<RawCanonicalVote>::encode_length_delimited_vec(canonical)
271 }
272
273 #[deprecated(
275 since = "0.17.0",
276 note = "This seems unnecessary, please raise it to the team, if you need it."
277 )]
278 pub fn consensus_state(&self) -> State {
279 State {
280 height: self.height,
281 round: self.round,
282 step: 6,
283 block_id: self.block_id,
284 }
285 }
286}
287
288pub struct SignedVote {
291 vote: CanonicalVote,
292 validator_address: account::Id,
293 signature: Signature,
294}
295
296impl SignedVote {
297 pub fn new(
300 vote: Vote,
301 chain_id: ChainId,
302 validator_address: account::Id,
303 signature: Signature,
304 ) -> SignedVote {
305 let canonical_vote = CanonicalVote::new(vote, chain_id);
306 SignedVote {
307 vote: canonical_vote,
308 signature,
309 validator_address,
310 }
311 }
312
313 pub fn from_vote(vote: Vote, chain_id: ChainId) -> Option<Self> {
316 let validator_address = vote.validator_address;
317 vote.signature
318 .clone()
319 .map(|signature| Self::new(vote, chain_id, validator_address, signature))
320 }
321
322 pub fn validator_id(&self) -> account::Id {
324 self.validator_address
325 }
326
327 pub fn sign_bytes(&self) -> Vec<u8> {
329 Protobuf::<RawCanonicalVote>::encode_length_delimited_vec(self.vote.clone())
330 }
331
332 pub fn sign_bytes_into(&self, buf: &mut impl BufMut) -> Result<(), ProtobufError> {
333 Protobuf::<RawCanonicalVote>::encode_length_delimited(self.vote.clone(), buf)
334 }
335
336 pub fn signature(&self) -> &Signature {
338 &self.signature
339 }
340}
341
342#[repr(u8)]
344#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
345pub enum Type {
346 Prevote = 1,
348
349 Precommit = 2,
351}
352
353impl Protobuf<i32> for Type {}
354
355impl TryFrom<i32> for Type {
356 type Error = Error;
357
358 fn try_from(value: i32) -> Result<Self, Self::Error> {
359 match value {
360 1 => Ok(Type::Prevote),
361 2 => Ok(Type::Precommit),
362 _ => Err(Error::invalid_message_type()),
363 }
364 }
365}
366
367impl From<Type> for i32 {
368 fn from(value: Type) -> Self {
369 value as i32
370 }
371}
372
373impl fmt::Display for Type {
374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375 let id = match self {
376 Type::Prevote => "Prevote",
377 Type::Precommit => "Precommit",
378 };
379 write!(f, "{id}")
380 }
381}
382
383impl FromStr for Type {
384 type Err = Error;
385
386 fn from_str(s: &str) -> Result<Self, Self::Err> {
387 match s {
388 "Prevote" => Ok(Self::Prevote),
389 "Precommit" => Ok(Self::Precommit),
390 _ => Err(Error::invalid_message_type()),
391 }
392 }
393}