1use core::slice;
4
5use serde::{Deserialize, Serialize};
6use tendermint_proto::google::protobuf::Duration as RawDuration;
7use tendermint_proto::Protobuf;
8
9use crate::{
10 block::{signed_header::SignedHeader, Height},
11 error::Error,
12 prelude::*,
13 serializers, validator,
14 vote::Power,
15 Time, Vote,
16};
17
18#[derive(Clone, Debug, PartialEq, Eq)]
20pub enum Evidence {
21 DuplicateVote(Box<DuplicateVoteEvidence>),
23
24 LightClientAttack(Box<LightClientAttackEvidence>),
26}
27
28impl From<LightClientAttackEvidence> for Evidence {
29 fn from(ev: LightClientAttackEvidence) -> Self {
30 Self::LightClientAttack(Box::new(ev))
31 }
32}
33
34impl From<DuplicateVoteEvidence> for Evidence {
35 fn from(ev: DuplicateVoteEvidence) -> Self {
36 Self::DuplicateVote(Box::new(ev))
37 }
38}
39
40#[derive(Clone, Debug, PartialEq, Eq)]
42pub struct DuplicateVoteEvidence {
43 pub vote_a: Vote,
44 pub vote_b: Vote,
45 pub total_voting_power: Power,
46 pub validator_power: Power,
47 pub timestamp: Time,
48}
49
50impl DuplicateVoteEvidence {
51 pub fn new(vote_a: Vote, vote_b: Vote) -> Result<Self, Error> {
53 if vote_a.height != vote_b.height {
54 return Err(Error::invalid_evidence());
55 }
56
57 Ok(Self {
59 vote_a,
60 vote_b,
61 total_voting_power: Default::default(),
62 validator_power: Default::default(),
63 timestamp: Time::unix_epoch(),
64 })
65 }
66
67 pub fn votes(&self) -> (&Vote, &Vote) {
69 (&self.vote_a, &self.vote_b)
70 }
71}
72
73#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
75pub struct ConflictingBlock {
76 pub signed_header: SignedHeader,
77 pub validator_set: validator::Set,
78}
79
80#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
82pub struct LightClientAttackEvidence {
83 pub conflicting_block: ConflictingBlock,
84 pub common_height: Height,
85 pub byzantine_validators: Vec<validator::Info>,
86 pub total_voting_power: Power,
87 pub timestamp: Time,
88}
89
90#[derive(Clone, Debug, Default, PartialEq, Eq)]
94pub struct List(Vec<Evidence>);
95
96impl List {
97 pub fn new<I>(into_evidence: I) -> List
99 where
100 I: Into<Vec<Evidence>>,
101 {
102 List(into_evidence.into())
103 }
104
105 pub fn into_vec(self) -> Vec<Evidence> {
107 self.0
108 }
109
110 pub fn iter(&self) -> slice::Iter<'_, Evidence> {
112 self.0.iter()
113 }
114}
115
116impl AsRef<[Evidence]> for List {
117 fn as_ref(&self) -> &[Evidence] {
118 &self.0
119 }
120}
121
122#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
126pub struct Params {
127 #[serde(with = "serializers::from_str")]
129 pub max_age_num_blocks: u64,
130
131 pub max_age_duration: Duration,
138
139 #[serde(with = "serializers::from_str", default)]
143 pub max_bytes: i64,
144}
145
146tendermint_pb_modules! {
151 use pb::types as raw;
152
153 use super::{List, LightClientAttackEvidence, DuplicateVoteEvidence, ConflictingBlock, Evidence, Params};
154 use crate::{error::Error, prelude::*};
155
156 impl Protobuf<raw::Evidence> for Evidence {}
157
158 impl TryFrom<raw::Evidence> for Evidence {
159 type Error = Error;
160
161 fn try_from(value: raw::Evidence) -> Result<Self, Self::Error> {
162 match value.sum.ok_or_else(Error::invalid_evidence)? {
163 raw::evidence::Sum::DuplicateVoteEvidence(ev) => {
164 Ok(Evidence::DuplicateVote(Box::new(ev.try_into()?)))
165 },
166 raw::evidence::Sum::LightClientAttackEvidence(ev) => {
167 Ok(Evidence::LightClientAttack(Box::new(ev.try_into()?)))
168 },
169 }
170 }
171 }
172
173 impl From<Evidence> for raw::Evidence {
174 fn from(value: Evidence) -> Self {
175 match value {
176 Evidence::DuplicateVote(ev) => raw::Evidence {
177 sum: Some(raw::evidence::Sum::DuplicateVoteEvidence((*ev).into())),
178 },
179 Evidence::LightClientAttack(ev) => raw::Evidence {
180 sum: Some(raw::evidence::Sum::LightClientAttackEvidence((*ev).into())),
181 },
182 }
183 }
184 }
185
186 impl Protobuf<raw::DuplicateVoteEvidence> for DuplicateVoteEvidence {}
187
188 impl TryFrom<raw::DuplicateVoteEvidence> for DuplicateVoteEvidence {
189 type Error = Error;
190
191 fn try_from(value: raw::DuplicateVoteEvidence) -> Result<Self, Self::Error> {
192 Ok(Self {
193 vote_a: value
194 .vote_a
195 .ok_or_else(Error::missing_evidence)?
196 .try_into()?,
197 vote_b: value
198 .vote_b
199 .ok_or_else(Error::missing_evidence)?
200 .try_into()?,
201 total_voting_power: value.total_voting_power.try_into()?,
202 validator_power: value.validator_power.try_into()?,
203 timestamp: value
204 .timestamp
205 .ok_or_else(Error::missing_timestamp)?
206 .try_into()?,
207 })
208 }
209 }
210
211 impl From<DuplicateVoteEvidence> for raw::DuplicateVoteEvidence {
212 fn from(value: DuplicateVoteEvidence) -> Self {
213 raw::DuplicateVoteEvidence {
214 vote_a: Some(value.vote_a.into()),
215 vote_b: Some(value.vote_b.into()),
216 total_voting_power: value.total_voting_power.into(),
217 validator_power: value.total_voting_power.into(),
218 timestamp: Some(value.timestamp.into()),
219 }
220 }
221 }
222
223 impl Protobuf<raw::LightBlock> for ConflictingBlock {}
224
225 impl TryFrom<raw::LightBlock> for ConflictingBlock {
226 type Error = Error;
227
228 fn try_from(value: raw::LightBlock) -> Result<Self, Self::Error> {
229 Ok(ConflictingBlock {
230 signed_header: value
231 .signed_header
232 .ok_or_else(Error::missing_evidence)?
233 .try_into()?,
234 validator_set: value
235 .validator_set
236 .ok_or_else(Error::missing_evidence)?
237 .try_into()?,
238 })
239 }
240 }
241
242 impl From<ConflictingBlock> for raw::LightBlock {
243 fn from(value: ConflictingBlock) -> Self {
244 raw::LightBlock {
245 signed_header: Some(value.signed_header.into()),
246 validator_set: Some(value.validator_set.into()),
247 }
248 }
249 }
250
251 impl Protobuf<raw::LightClientAttackEvidence> for LightClientAttackEvidence {}
252
253 impl TryFrom<raw::LightClientAttackEvidence> for LightClientAttackEvidence {
254 type Error = Error;
255
256 fn try_from(ev: raw::LightClientAttackEvidence) -> Result<Self, Self::Error> {
257 Ok(LightClientAttackEvidence {
258 conflicting_block: ev
259 .conflicting_block
260 .ok_or_else(Error::missing_evidence)?
261 .try_into()?,
262 common_height: ev.common_height.try_into()?,
263 byzantine_validators: ev
264 .byzantine_validators
265 .into_iter()
266 .map(TryInto::try_into)
267 .collect::<Result<Vec<_>, _>>()?,
268 total_voting_power: ev.total_voting_power.try_into()?,
269 timestamp: ev
270 .timestamp
271 .ok_or_else(Error::missing_timestamp)?
272 .try_into()?,
273 })
274 }
275 }
276
277 impl From<LightClientAttackEvidence> for raw::LightClientAttackEvidence {
278 fn from(ev: LightClientAttackEvidence) -> Self {
279 raw::LightClientAttackEvidence {
280 conflicting_block: Some(ev.conflicting_block.into()),
281 common_height: ev.common_height.into(),
282 byzantine_validators: ev
283 .byzantine_validators
284 .into_iter()
285 .map(Into::into)
286 .collect(),
287 total_voting_power: ev.total_voting_power.into(),
288 timestamp: Some(ev.timestamp.into()),
289 }
290 }
291 }
292
293 impl Protobuf<raw::EvidenceList> for List {}
294
295 impl TryFrom<raw::EvidenceList> for List {
296 type Error = Error;
297 fn try_from(value: raw::EvidenceList) -> Result<Self, Self::Error> {
298 let evidence = value
299 .evidence
300 .into_iter()
301 .map(TryInto::try_into)
302 .collect::<Result<Vec<_>, _>>()?;
303 Ok(Self(evidence))
304 }
305 }
306
307 impl From<List> for raw::EvidenceList {
308 fn from(value: List) -> Self {
309 raw::EvidenceList {
310 evidence: value.0.into_iter().map(Into::into).collect(),
311 }
312 }
313 }
314
315 impl Protobuf<raw::EvidenceParams> for Params {}
316
317 impl TryFrom<raw::EvidenceParams> for Params {
318 type Error = Error;
319
320 fn try_from(value: raw::EvidenceParams) -> Result<Self, Self::Error> {
321 Ok(Self {
322 max_age_num_blocks: value
323 .max_age_num_blocks
324 .try_into()
325 .map_err(Error::negative_max_age_num)?,
326 max_age_duration: value
327 .max_age_duration
328 .ok_or_else(Error::missing_max_age_duration)?
329 .try_into()?,
330 max_bytes: value.max_bytes,
331 })
332 }
333 }
334
335 impl From<Params> for raw::EvidenceParams {
336 fn from(value: Params) -> Self {
337 Self {
338 max_age_num_blocks: value.max_age_num_blocks.try_into().unwrap(),
340 max_age_duration: Some(value.max_age_duration.into()),
341 max_bytes: value.max_bytes,
342 }
343 }
344 }
345}
346
347#[derive(Copy, Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
353pub struct Duration(#[serde(with = "serializers::time_duration")] pub core::time::Duration);
354
355impl From<Duration> for core::time::Duration {
356 fn from(d: Duration) -> core::time::Duration {
357 d.0
358 }
359}
360
361impl Protobuf<RawDuration> for Duration {}
362
363impl TryFrom<RawDuration> for Duration {
364 type Error = Error;
365
366 fn try_from(value: RawDuration) -> Result<Self, Self::Error> {
367 Ok(Self(core::time::Duration::new(
368 value.seconds.try_into().map_err(Error::integer_overflow)?,
369 value.nanos.try_into().map_err(Error::integer_overflow)?,
370 )))
371 }
372}
373
374impl From<Duration> for RawDuration {
375 fn from(value: Duration) -> Self {
376 Self {
378 seconds: value.0.as_secs() as i64,
379 nanos: value.0.subsec_nanos() as i32,
380 }
381 }
382}