diff --git a/CHANGELOG.md b/CHANGELOG.md index 74b63962a..d43f60c03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,16 @@ - `[rpc]` The `WebSocketClient` now adds support for all remaining RPC requests by way of implementing the `Client` trait ([#646]) - `[rpc]` Support for the `tx_search` RPC endpoint has been added ([#701]) +- `[rpc]` Responses that include events now automatically have their tag + key/value pairs decoded from base64, where previously tag key/value pairs + were Base64-encoded ([#717]) - `[tendermint]` (Since v0.17.0-rc3) Bech32 encoding fix ([#690]) [#425]: https://github.com/informalsystems/tendermint-rs/issues/425 [#646]: https://github.com/informalsystems/tendermint-rs/pull/646 [#690]: https://github.com/informalsystems/tendermint-rs/issues/690 [#701]: https://github.com/informalsystems/tendermint-rs/pull/701 +[#717]: https://github.com/informalsystems/tendermint-rs/issues/717 ## v0.17.0-rc3 diff --git a/proto/src/serializers/bytes.rs b/proto/src/serializers/bytes.rs index 3561cf99f..7cffcfb64 100644 --- a/proto/src/serializers/bytes.rs +++ b/proto/src/serializers/bytes.rs @@ -42,6 +42,16 @@ pub mod base64string { base64::decode(&string).map_err(serde::de::Error::custom) } + /// Deserialize base64string into String + pub fn deserialize_to_string<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = Option::::deserialize(deserializer)?.unwrap_or_default(); + String::from_utf8(base64::decode(&s).map_err(serde::de::Error::custom)?) + .map_err(serde::de::Error::custom) + } + /// Serialize from T into base64string pub fn serialize(value: &T, serializer: S) -> Result where diff --git a/rpc/src/endpoint/broadcast/tx_commit.rs b/rpc/src/endpoint/broadcast/tx_commit.rs index 3a8fe1c1c..b4d09208e 100644 --- a/rpc/src/endpoint/broadcast/tx_commit.rs +++ b/rpc/src/endpoint/broadcast/tx_commit.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; +use tendermint::abci::responses::Codespace; +use tendermint::abci::{Event, Gas, Info}; use tendermint::{ abci::{transaction, Code, Data, Log, Transaction}, block, @@ -65,5 +67,26 @@ pub struct TxResult { pub data: Option, /// Log + #[serde(default)] pub log: Log, + + /// ABCI info (nondeterministic) + #[serde(default)] + pub info: Info, + + /// Amount of gas wanted + #[serde(default, rename = "gasWanted")] + pub gas_wanted: Gas, + + /// Amount of gas used + #[serde(default, rename = "gasUsed")] + pub gas_used: Gas, + + /// Events + #[serde(default)] + pub events: Vec, + + /// Codespace + #[serde(default)] + pub codespace: Codespace, } diff --git a/rpc/tests/parse_response.rs b/rpc/tests/parse_response.rs index 7fc468c60..4a818007f 100644 --- a/rpc/tests/parse_response.rs +++ b/rpc/tests/parse_response.rs @@ -119,6 +119,13 @@ fn block_results() { assert_eq!(deliver_tx[0].gas_wanted.value(), 200_000); assert_eq!(deliver_tx[0].gas_used.value(), 105_662); + assert_eq!(deliver_tx[0].events.len(), 1); + assert_eq!(deliver_tx[0].events[0].attributes.len(), 3); + assert_eq!(deliver_tx[0].events[0].attributes[0].key.as_ref(), "action"); + assert_eq!( + deliver_tx[0].events[0].attributes[0].value.as_ref(), + "delegate" + ); assert_eq!(validator_updates[0].power.value(), 1_233_243); } @@ -194,6 +201,7 @@ fn broadcast_tx_commit() { &response.hash.to_string(), "EFA00D85332A8197CF290E4724BAC877EA93DDFE547A561828BAE45A29BF1DAD" ); + assert_eq!(5, response.deliver_tx.events.len()); } #[test] @@ -337,4 +345,10 @@ fn tx_search_with_prove() { ], proof.root_hash ); + + let events = &response.txs[0].tx_result.events; + assert_eq!(events.len(), 1); + assert_eq!(events[0].attributes.len(), 4); + assert_eq!(events[0].attributes[0].key.as_ref(), "creator"); + assert_eq!(events[0].attributes[0].value.as_ref(), "Cosmoshi Netowoko"); } diff --git a/tendermint/src/abci/info.rs b/tendermint/src/abci/info.rs index 48c700fc2..684d79dc4 100644 --- a/tendermint/src/abci/info.rs +++ b/tendermint/src/abci/info.rs @@ -16,3 +16,9 @@ impl Display for Info { write!(f, "{}", self.0) } } + +impl Default for Info { + fn default() -> Self { + Self(String::new()) + } +} diff --git a/tendermint/src/abci/responses.rs b/tendermint/src/abci/responses.rs index 70764d578..70afa997e 100644 --- a/tendermint/src/abci/responses.rs +++ b/tendermint/src/abci/responses.rs @@ -143,3 +143,9 @@ impl Display for Codespace { write!(f, "{}", self.0) } } + +impl Default for Codespace { + fn default() -> Self { + Self(String::new()) + } +} diff --git a/tendermint/src/abci/tag.rs b/tendermint/src/abci/tag.rs index 347c53e3e..657a19eec 100644 --- a/tendermint/src/abci/tag.rs +++ b/tendermint/src/abci/tag.rs @@ -3,6 +3,7 @@ use crate::error::Error; use serde::{Deserialize, Serialize}; use std::{fmt, str::FromStr}; +use tendermint_proto::serializers::bytes::base64string; /// Tags #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] @@ -16,7 +17,13 @@ pub struct Tag { /// Tag keys #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)] -pub struct Key(String); +pub struct Key( + #[serde( + serialize_with = "base64string::serialize", + deserialize_with = "base64string::deserialize_to_string" + )] + String, +); impl AsRef for Key { fn as_ref(&self) -> &str { @@ -40,7 +47,13 @@ impl fmt::Display for Key { /// Tag values #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub struct Value(String); +pub struct Value( + #[serde( + serialize_with = "base64string::serialize", + deserialize_with = "base64string::deserialize_to_string" + )] + String, +); impl AsRef for Value { fn as_ref(&self) -> &str { @@ -61,3 +74,16 @@ impl fmt::Display for Value { write!(f, "{}", &self.0) } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn tag_serde() { + let json = r#"{"key": "cGFja2V0X3RpbWVvdXRfaGVpZ2h0", "value": "MC00ODQw"}"#; + let tag: Tag = serde_json::from_str(&json).unwrap(); + assert_eq!("packet_timeout_height", tag.key.0); + assert_eq!("0-4840", tag.value.0); + } +}