Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix panic in evidence serialization #798

Merged
merged 11 commits into from
Feb 9, 2021
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## Unreleased

### BUG FIXES

* `[tendermint-proto]` Fix panic in evidence serialization in the case where we
receive an empty evidence Protobuf structure ([#782])

[#782]: https://github.com/informalsystems/tendermint-rs/issues/782

## v0.18.0

*Jan 29, 2021*
Expand Down
50 changes: 37 additions & 13 deletions proto/src/serializers/evidence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use crate::tendermint::types::Evidence;
#[derive(Clone, PartialEq, ::serde::Deserialize, ::serde::Serialize)]
#[serde(tag = "type", content = "value")]
pub enum EvidenceVariant {
/// Provided for when the evidence struct's optional `sum` field is `None`.
None,
#[serde(rename = "tendermint/DuplicateVoteEvidence")]
DuplicateVoteEvidence(crate::tendermint::types::DuplicateVoteEvidence),
#[serde(rename = "tendermint/LightClientAttackEvidence")]
Expand All @@ -17,34 +19,56 @@ pub enum EvidenceVariant {
impl From<EvidenceVariant> for Evidence {
fn from(value: EvidenceVariant) -> Self {
match value {
EvidenceVariant::DuplicateVoteEvidence(d) => Evidence {
sum: Some(Sum::DuplicateVoteEvidence(d)),
},
EvidenceVariant::LightClientAttackEvidence(l) => Evidence {
sum: Some(Sum::LightClientAttackEvidence(l)),
EvidenceVariant::None => Evidence { sum: None },
_ => Evidence {
sum: Some(value.into()),
},
}
}
}

impl From<Evidence> for EvidenceVariant {
fn from(value: Evidence) -> Self {
let sum = value.sum.unwrap(); // Todo: Error handling
match sum {
Sum::DuplicateVoteEvidence(d) => Self::DuplicateVoteEvidence(d),
Sum::LightClientAttackEvidence(l) => Self::LightClientAttackEvidence(l),
match value.sum {
Some(sum) => sum.into(),
None => Self::None,
}
}
}

impl From<Sum> for EvidenceVariant {
fn from(_: Sum) -> Self {
unimplemented!() // Prost adds extra annotations on top of Sum that are not used.
fn from(value: Sum) -> Self {
match value {
Sum::DuplicateVoteEvidence(d) => Self::DuplicateVoteEvidence(d),
Sum::LightClientAttackEvidence(l) => Self::LightClientAttackEvidence(l),
}
}
}

impl From<EvidenceVariant> for Sum {
fn from(_: EvidenceVariant) -> Self {
unimplemented!() // Prost adds extra annotations on top of Sum that are not used.
fn from(value: EvidenceVariant) -> Self {
match value {
// This should never be called - should be handled instead in the
// `impl From<EvidenceVariant> for Evidence` above.
EvidenceVariant::None => {
panic!("non-existent evidence cannot be converted into its protobuf representation")
}
EvidenceVariant::DuplicateVoteEvidence(d) => Self::DuplicateVoteEvidence(d),
EvidenceVariant::LightClientAttackEvidence(l) => Self::LightClientAttackEvidence(l),
}
}
}

#[cfg(test)]
mod test {
use super::*;

// Minimally reproduce https://github.com/informalsystems/tendermint-rs/issues/782
#[test]
fn empty_evidence() {
let ev = Evidence { sum: None };
let ev_json = serde_json::to_string(&ev).unwrap();
let ev_deserialized = serde_json::from_str::<Evidence>(&ev_json).unwrap();
assert_eq!(ev, ev_deserialized);
}
}