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

Add borsh derive for MsgTransfer #845

Merged
merged 2 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Add borsh derive for `MsgTransfer`
([#845](https://github.com/cosmos/ibc-rs/pull/845))
67 changes: 66 additions & 1 deletion crates/ibc/src/applications/transfer/amount.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Contains the `Amount` type, which represents amounts of tokens transferred.

use crate::prelude::*;
use core::{ops::Deref, str::FromStr};
use derive_more::{Display, From, Into};

Expand Down Expand Up @@ -28,6 +29,54 @@ impl parity_scale_codec::WrapperTypeDecode for Amount {
#[cfg(feature = "parity-scale-codec")]
impl parity_scale_codec::WrapperTypeEncode for Amount {}

#[cfg(feature = "borsh")]
impl borsh::BorshSerialize for Amount {
fn serialize<W: borsh::maybestd::io::Write>(
&self,
writer: &mut W,
) -> borsh::maybestd::io::Result<()> {
// Note: a "word" is 8 bytes (i.e. a u64)
let words = self.as_slice();
let bytes: Vec<u8> = words.iter().flat_map(|word| word.to_be_bytes()).collect();

writer.write_all(&bytes)
}
}
#[cfg(feature = "borsh")]
impl borsh::BorshDeserialize for Amount {
fn deserialize_reader<R: borsh::maybestd::io::Read>(
reader: &mut R,
) -> borsh::maybestd::io::Result<Self> {
const NUM_BYTES_IN_U64: usize = 8;
const NUM_WORDS_IN_U256: usize = 4;

let mut buf = [0; 32];
let bytes_read = reader.read(&mut buf)?;
if bytes_read != 32 {
return Err(borsh::maybestd::io::Error::new(
borsh::maybestd::io::ErrorKind::InvalidInput,
format!("Expected to read 32 bytes, read {bytes_read}"),
));
}
Comment on lines +55 to +60
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the `buf`` is of fixed 32 size, would this error ever occur?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if somehow we read less than 32 bytes


let words: Vec<u64> = buf
.chunks_exact(NUM_BYTES_IN_U64)
.map(|word| {
let word: [u8; NUM_BYTES_IN_U64] = word
.try_into()
.expect("exact chunks of 8 bytes are expected to be 8 bytes");
u64::from_be_bytes(word)
})
.collect();

let four_words: [u64; NUM_WORDS_IN_U256] = words
.try_into()
.expect("U256 is always 4 four words, and we confirmed that we read 32 bytes");

Ok(four_words.into())
}
}

impl Deref for Amount {
type Target = [u64; 4];

Expand Down Expand Up @@ -83,10 +132,10 @@ where
}

#[cfg(test)]
#[cfg(feature = "serde")]
mod tests {
use super::Amount;

#[cfg(feature = "serde")]
#[test]
fn serde_amount() {
let value = Amount::from(42);
Expand All @@ -96,4 +145,20 @@ mod tests {
let de: Amount = serde_json::from_slice(binary.as_ref()).expect("can deserialize");
assert_eq!(de, value);
}

#[cfg(feature = "borsh")]
#[test]
fn borsh_amount() {
use borsh::BorshDeserialize;

let value = Amount::from(42);
let serialized = borsh::to_vec(&value).unwrap();

// Amount is supposed to be a U256 according to the spec, which is 32 bytes
assert_eq!(serialized.len(), 32);

let value_deserialized = Amount::try_from_slice(&serialized).unwrap();

assert_eq!(value, value_deserialized);
}
}
4 changes: 4 additions & 0 deletions crates/ibc/src/applications/transfer/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ pub type RawCoin = Coin<String>;
feature = "parity-scale-codec",
derive(parity_scale_codec::Encode, parity_scale_codec::Decode,)
)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Coin<D> {
/// Denomination
Expand Down
16 changes: 16 additions & 0 deletions crates/ibc/src/applications/transfer/denom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ use crate::serializers::serde_string;
scale_info::TypeInfo
)
)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Display)]
pub struct BaseDenom(String);
Expand Down Expand Up @@ -62,6 +66,10 @@ impl FromStr for BaseDenom {
scale_info::TypeInfo
)
)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
Expand Down Expand Up @@ -97,6 +105,10 @@ impl Display for TracePrefix {
scale_info::TypeInfo
)
)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord, From)]
Expand Down Expand Up @@ -198,6 +210,10 @@ impl Display for TracePath {
scale_info::TypeInfo
)
)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct PrefixedDenom {
/// A series of `{port-id}/{channel-id}`s for tracing the source of the token.
Expand Down
4 changes: 4 additions & 0 deletions crates/ibc/src/applications/transfer/msgs/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ pub(crate) const TYPE_URL: &str = "/ibc.applications.transfer.v1.MsgTransfer";
feature = "parity-scale-codec",
derive(parity_scale_codec::Encode, parity_scale_codec::Decode,)
)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct MsgTransfer {
/// the port on which the packet will be sent
pub port_id_on_a: PortId,
Expand Down
4 changes: 4 additions & 0 deletions crates/ibc/src/applications/transfer/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ use crate::signer::Signer;
feature = "parity-scale-codec",
derive(parity_scale_codec::Encode, parity_scale_codec::Decode,)
)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PacketData {
pub token: PrefixedCoin,
Expand Down