Skip to content

Commit

Permalink
Fix TM hash encoding
Browse files Browse the repository at this point in the history
- Add base64 `tendermint::hash::Hash` encoding/decoding support
- Add base64 `Option<tendermint::hash::Hash>` encoding/decoding support
- Add missing `FromStr` import
- Rename `hash_base64` serializer to `tx_hash_base64`

Relates informalsystems#942
Links informalsystems#832
  • Loading branch information
fmorency committed Oct 4, 2022
1 parent f5d90a0 commit d890cd6
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 4 deletions.
4 changes: 4 additions & 0 deletions .changelog/unreleased/bug-fixes/832-block-by-hash-encoding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- `[tendermint-rpc]` The encoding of the `hash` field for requests to the `/block_by_hash`
endpoint has been changed to base64 (from hex) to accommodate discrepancies in
how the Tendermint RPC encodes this field for different RPC interfaces
([#942](https://github.com/informalsystems/tendermint-rs/issues/942))
5 changes: 5 additions & 0 deletions rpc/src/endpoint/block_by_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ pub struct Request {
///
/// If no hash is provided, it will return no block (as if the hash
/// did not match any block).
///
/// Serialized internally into a base64-encoded string before sending to
/// the RPC server.
#[serde(default)]
#[serde(with = "crate::serializers::opt_tm_hash_base64")]
pub hash: Option<Hash>,
}

Expand Down
2 changes: 1 addition & 1 deletion rpc/src/endpoint/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub struct Request {
///
/// Serialized internally into a base64-encoded string before sending to
/// the RPC server.
#[serde(with = "crate::serializers::hash_base64")]
#[serde(with = "crate::serializers::tx_hash_base64")]
pub hash: abci::transaction::Hash,
/// Whether or not to include the proofs of the transaction's inclusion in
/// the block.
Expand Down
4 changes: 3 additions & 1 deletion rpc/src/serializers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@
//! risk.
pub use tendermint_proto::serializers::*;

pub mod hash_base64;
pub mod opt_tm_hash_base64;
pub mod tm_hash_base64;
pub mod tx_hash_base64;
25 changes: 25 additions & 0 deletions rpc/src/serializers/opt_tm_hash_base64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! Encoding/decoding Option Tendermint hashes to/from base64.
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use tendermint::hash::Hash;

use crate::prelude::*;

#[derive(Serialize, Deserialize)]
struct Helper(#[serde(with = "crate::serializers::tm_hash_base64")] Hash);

/// Deserialize base64-encoded string into an Option<tendermint::Hash>
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Hash>, D::Error>
where
D: Deserializer<'de>,
{
let helper: Option<Helper> = Option::deserialize(deserializer)?;
Ok(helper.map(|Helper(hash)| hash))
}

/// Serialize from an Option<tendermint::Hash> into a base64-encoded string
pub fn serialize<S>(value: &Option<Hash>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
value.map(Helper).serialize(serializer)
}
34 changes: 34 additions & 0 deletions rpc/src/serializers/tm_hash_base64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! Encoding/decoding Tendermint hashes to/from base64.

use serde::{Deserialize, Deserializer, Serializer};
use subtle_encoding::base64;
use tendermint::hash::{Algorithm::Sha256, Hash, SHA256_HASH_SIZE};

use crate::prelude::*;

/// Deserialize a base64-encoded string into an tendermint::Hash
pub fn deserialize<'de, D>(deserializer: D) -> Result<Hash, D::Error>
where
D: Deserializer<'de>,
{
let s = Option::<String>::deserialize(deserializer)?.unwrap_or_default();
let decoded = base64::decode(&s).map_err(serde::de::Error::custom)?;
if decoded.len() != SHA256_HASH_SIZE {
return Err(serde::de::Error::custom(
"unexpected transaction length for hash",
));
}
let mut decoded_bytes = [0u8; SHA256_HASH_SIZE];
decoded_bytes.copy_from_slice(decoded.as_ref());
Ok(Hash::from_bytes(Sha256, &decoded_bytes).map_err(serde::de::Error::custom)?)
}

/// Serialize from a tendermint::Hash into a base64-encoded string
pub fn serialize<S>(value: &Hash, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let base64_bytes = base64::encode(value.as_bytes());
let base64_string = String::from_utf8(base64_bytes).map_err(serde::ser::Error::custom)?;
serializer.serialize_str(&base64_string)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
prelude::*,
};

/// Deserialize a base64-encoded string into a Hash
/// Deserialize a base64-encoded string into an abci::transaction::Hash
pub fn deserialize<'de, D>(deserializer: D) -> Result<Hash, D::Error>
where
D: Deserializer<'de>,
Expand All @@ -25,7 +25,7 @@ where
Ok(Hash::new(decoded_bytes))
}

/// Serialize from a Hash into a base64-encoded string
/// Serialize from an abci::transaction::Hash into a base64-encoded string
pub fn serialize<S>(value: &Hash, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
Expand Down
1 change: 1 addition & 0 deletions tools/kvstore-test/tests/tendermint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod rpc {
use std::{
cmp::min,
convert::TryFrom,
str::FromStr,
sync::atomic::{AtomicU8, Ordering},
};

Expand Down

0 comments on commit d890cd6

Please sign in to comment.