Skip to content

Commit

Permalink
add optional arbitrary impls (#1390)
Browse files Browse the repository at this point in the history
* add optional arbitrary impls

* arbitrary for timestamp

* fix individual crates arbitrary feature deps

* changelog: add #1390

* fix aribtrary feature not to rely on transitivity

* simpler timestamp arbitrary impl

* fix lint

* add more missing arbitrary transitive features

* add one more missing transitive arbitrary feature

* ci: try to force install cargo-msrv

---------

Co-authored-by: yito88 <[email protected]>
  • Loading branch information
tzemanovic and yito88 authored Jan 16, 2025
1 parent edb36f7 commit eb7e079
Show file tree
Hide file tree
Showing 77 changed files with 234 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .changelog/unreleased/features/1390-derive-arbitrary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Added arbitrary trait implementation behind "arbitrary" feature flag.
([\#1390](https://github.com/cosmos/ibc-rs/pull/1390))
2 changes: 1 addition & 1 deletion .github/workflows/rust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ jobs:
- name: Install cargo-msrv
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: cargo binstall --no-confirm cargo-msrv
run: cargo binstall --no-confirm cargo-msrv --force

- name: Verify and Test Rust version
run: |
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ authors = [ "Informal Systems <[email protected]>" ]

[workspace.dependencies]
# external dependencies
arbitrary = { version = "1.4", features = [ "derive" ] }
base64 = { version = "0.22", default-features = false }
borsh = { version = "1", default-features = false, features = [ "derive" ] }
displaydoc = { version = "0.2.5", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions ibc-apps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ parity-scale-codec = [
nft-transfer = [
"ibc-app-nft-transfer",
]
arbitrary = [ "ibc-app-transfer/arbitrary", "ibc-app-nft-transfer/arbitrary" ]
1 change: 1 addition & 0 deletions ibc-apps/ics20-transfer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@ parity-scale-codec = [
"ibc-app-transfer-types/parity-scale-codec",
"ibc-core/parity-scale-codec",
]
arbitrary = [ "ibc-app-transfer-types/arbitrary", "ibc-core/arbitrary" ]
2 changes: 2 additions & 0 deletions ibc-apps/ics20-transfer/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ all-features = true

[dependencies]
# external dependencies
arbitrary = { workspace = true, optional = true }
borsh = { workspace = true, optional = true }
derive_more = { workspace = true }
displaydoc = { workspace = true }
Expand Down Expand Up @@ -74,3 +75,4 @@ parity-scale-codec = [
"ibc-core/parity-scale-codec",
"ibc-proto/parity-scale-codec",
]
arbitrary = [ "dep:arbitrary", "ibc-core/arbitrary", "std" ]
8 changes: 8 additions & 0 deletions ibc-apps/ics20-transfer/types/src/amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ use ibc_core::primitives::serializers;
use primitive_types::U256;

/// A type for representing token transfer amounts.
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Display, From, Into)]
pub struct Amount(
#[cfg_attr(feature = "arbitrary", arbitrary(with = arb_u256))]
#[cfg_attr(feature = "schema", schemars(with = "String"))]
#[cfg_attr(feature = "serde", serde(serialize_with = "serializers::serialize"))]
#[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize"))]
Expand Down Expand Up @@ -129,6 +131,12 @@ where
.map_err(serde::de::Error::custom)
}

#[cfg(feature = "arbitrary")]
fn arb_u256(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<U256> {
let parts: [u8; 32] = arbitrary::Arbitrary::arbitrary(u)?;
Ok(U256::from_big_endian(&parts))
}

#[cfg(test)]
mod tests {
use super::Amount;
Expand Down
5 changes: 3 additions & 2 deletions ibc-apps/ics20-transfer/types/src/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub type RawCoin = Coin<String>;
const VALID_DENOM_CHARACTERS: &str = "/:._-";

/// Coin defines a token with a denomination and an amount.
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(
Expand Down Expand Up @@ -165,12 +166,12 @@ mod tests {
"115792089237316195423570985008687907853269984665640564039457584007913129639936stake"
)]
#[case::invalid_char_in_denom("0x!")]
#[case::blackslash_in_denom("0x1/:.\\_-")]
#[case::backslash_in_denom("0x1/:.\\_-")]
#[should_panic]
fn test_failed_parse_raw_coin(#[case] _raw: RawCoin) {}

#[rstest]
#[case::nomal("123stake,1a1,999den0m", &[(123, "stake"), (1, "a1"), (999, "den0m")])]
#[case::normal("123stake,1a1,999den0m", &[(123, "stake"), (1, "a1"), (999, "den0m")])]
#[case::tricky("123stake,1a1-999den0m", &[(123, "stake"), (1, "a1-999den0m")])]
#[case::colon_delimiter("123stake:1a1:999den0m", &[(123, "stake:1a1:999den0m")])]
#[case::dash_delimiter("123stake-1a1-999den0m", &[(123, "stake-1a1-999den0m")])]
Expand Down
4 changes: 4 additions & 0 deletions ibc-apps/ics20-transfer/types/src/denom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use ibc_proto::ibc::applications::transfer::v1::DenomTrace as RawDenomTrace;
///
/// For example, given the token `my_port-1/my_channel-1/my_port-2/my_channel-2/base_denom`,
/// `base_denom` is the "base" of the denomination
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[cfg_attr(
Expand Down Expand Up @@ -55,6 +56,7 @@ impl FromStr for BaseDenom {
/// For example, given the token `my_port-1/my_channel-1/my_port-2/my_channel-2/base_denom`,
/// `my_port-1/my_channel-1` is a trace prefix, and `my_port-2/my_channel-2` is another one.
/// See [TracePath] which stitches trace prefixes together.
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "parity-scale-codec",
derive(
Expand Down Expand Up @@ -122,6 +124,7 @@ impl Display for TracePrefix {
/// Internally, the `TracePath` is modelled as a `Vec<TracePrefix>` but with the order reversed, i.e.
/// "transfer/channel-0/transfer/channel-1/uatom" => `["transfer/channel-1", "transfer/channel-0"]`
/// This is done for ease of addition/removal of prefixes.
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "parity-scale-codec",
derive(
Expand Down Expand Up @@ -236,6 +239,7 @@ impl Display for TracePath {
}

/// A type that contains the base denomination for ICS20 and the source tracing information path.
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(
Expand Down
1 change: 1 addition & 0 deletions ibc-apps/ics20-transfer/types/src/memo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use core::str::FromStr;
use ibc_core::primitives::prelude::*;

/// Represents the token transfer memo
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "parity-scale-codec",
derive(
Expand Down
1 change: 1 addition & 0 deletions ibc-apps/ics20-transfer/types/src/msgs/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub(crate) const TYPE_URL: &str = "/ibc.applications.transfer.v1.MsgTransfer";
/// have to specify the information related to the transfer of the token, and
/// let the library figure out how to build the packet properly.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "parity-scale-codec",
Expand Down
1 change: 1 addition & 0 deletions ibc-apps/ics20-transfer/types/src/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use ibc_proto::ibc::applications::transfer::v2::FungibleTokenPacketData as RawPa
use super::{Amount, Memo, PrefixedCoin, PrefixedDenom};

/// Defines the structure of token transfers' packet bytes
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serde",
Expand Down
1 change: 1 addition & 0 deletions ibc-apps/ics721-nft-transfer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ parity-scale-codec = [
"ibc-app-nft-transfer-types/parity-scale-codec",
"ibc-core/parity-scale-codec",
]
arbitrary = [ "ibc-app-nft-transfer-types/arbitrary", "ibc-core/arbitrary" ]
7 changes: 7 additions & 0 deletions ibc-apps/ics721-nft-transfer/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ all-features = true

[dependencies]
# external dependencies
arbitrary = { workspace = true, optional = true }
borsh = { workspace = true, optional = true }
base64 = { workspace = true, features = [ "alloc" ] }
derive_more = { workspace = true }
Expand Down Expand Up @@ -81,3 +82,9 @@ parity-scale-codec = [
"ibc-proto/parity-scale-codec",
"ibc-app-transfer-types/parity-scale-codec",
]
arbitrary = [
"dep:arbitrary",
"ibc-core/arbitrary",
"ibc-app-transfer-types/arbitrary",
"std",
]
5 changes: 5 additions & 0 deletions ibc-apps/ics721-nft-transfer/types/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use ibc_proto::ibc::applications::nft_transfer::v1::ClassTrace as RawClassTrace;
use crate::data::Data;

/// Class ID for an NFT
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "parity-scale-codec",
derive(
Expand Down Expand Up @@ -56,6 +57,7 @@ impl FromStr for ClassId {
}

/// Prefixed class to trace sources like ICS-20 PrefixedDenom
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(
Expand Down Expand Up @@ -180,10 +182,12 @@ impl Display for PrefixedClassId {
}

/// Class URI for an NFT
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClassUri(
#[cfg_attr(feature = "arbitrary", arbitrary(with = crate::arb_uri))]
#[cfg_attr(feature = "serde", serde(with = "serializers"))]
#[cfg_attr(feature = "schema", schemars(with = "String"))]
Uri,
Expand Down Expand Up @@ -253,6 +257,7 @@ impl FromStr for ClassUri {
}

/// Class data for an NFT
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "parity-scale-codec",
derive(
Expand Down
1 change: 1 addition & 0 deletions ibc-apps/ics721-nft-transfer/types/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use ibc_core::host::types::error::DecodingError;
use ibc_core::primitives::prelude::*;
use mime::Mime;

#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "parity-scale-codec",
derive(
Expand Down
6 changes: 6 additions & 0 deletions ibc-apps/ics721-nft-transfer/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,9 @@ use ibc_core::channel::types::acknowledgement::StatusValue;
pub fn ack_success_b64() -> StatusValue {
StatusValue::new(ACK_SUCCESS_B64).expect("ack status value is never supposed to be empty")
}

#[cfg(feature = "arbitrary")]
fn arb_uri(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<http::Uri> {
let raw: std::string::String = arbitrary::Arbitrary::arbitrary(u)?;
http::Uri::try_from(&raw).map_err(|_| arbitrary::Error::IncorrectFormat)
}
1 change: 1 addition & 0 deletions ibc-apps/ics721-nft-transfer/types/src/memo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use core::str::FromStr;
use ibc_core::primitives::prelude::*;

/// Represents the token transfer memo
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "parity-scale-codec",
derive(
Expand Down
1 change: 1 addition & 0 deletions ibc-apps/ics721-nft-transfer/types/src/msgs/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub(crate) const TYPE_URL: &str = "/ibc.applications.nft_transfer.v1.MsgTransfer
/// have to specify the information related to the transfer of the token, and
/// let the library figure out how to build the packet properly.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "parity-scale-codec",
Expand Down
1 change: 1 addition & 0 deletions ibc-apps/ics721-nft-transfer/types/src/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::memo::Memo;
use crate::token::{TokenData, TokenIds, TokenUri};

/// Defines the structure of token transfers' packet bytes
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
Expand Down
5 changes: 5 additions & 0 deletions ibc-apps/ics721-nft-transfer/types/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use ibc_core::primitives::serializers;
use crate::data::Data;

/// Token ID for an NFT
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "parity-scale-codec",
derive(
Expand Down Expand Up @@ -52,6 +53,7 @@ impl FromStr for TokenId {
}
}

#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "parity-scale-codec",
derive(
Expand Down Expand Up @@ -116,10 +118,12 @@ impl TryFrom<Vec<String>> for TokenIds {
}

/// Token URI for an NFT
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TokenUri(
#[cfg_attr(feature = "arbitrary", arbitrary(with = crate::arb_uri))]
#[cfg_attr(feature = "serde", serde(with = "serializers"))]
#[cfg_attr(feature = "schema", schemars(with = "String"))]
Uri,
Expand Down Expand Up @@ -187,6 +191,7 @@ impl FromStr for TokenUri {
}

/// Token data for an NFT
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "parity-scale-codec",
derive(
Expand Down
10 changes: 10 additions & 0 deletions ibc-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,13 @@ parity-scale-codec = [
"ibc-core-handler/parity-scale-codec",
"ibc-primitives/parity-scale-codec",
]
arbitrary = [
"ibc-core-client/arbitrary",
"ibc-core-connection/arbitrary",
"ibc-core-channel/arbitrary",
"ibc-core-commitment-types/arbitrary",
"ibc-core-host/arbitrary",
"ibc-core-handler/arbitrary",
"ibc-primitives/arbitrary",
"std",
]
7 changes: 7 additions & 0 deletions ibc-core/ics02-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,10 @@ parity-scale-codec = [
"ibc-core-handler-types/parity-scale-codec",
"ibc-primitives/parity-scale-codec",
]
arbitrary = [
"ibc-core-client-types/arbitrary",
"ibc-core-commitment-types/arbitrary",
"ibc-core-host/arbitrary",
"ibc-core-handler-types/arbitrary",
"ibc-primitives/arbitrary",
]
8 changes: 8 additions & 0 deletions ibc-core/ics02-client/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ all-features = true

[dependencies]
# external dependencies
arbitrary = { workspace = true, optional = true }
borsh = { workspace = true, optional = true }
derive_more = { workspace = true }
displaydoc = { workspace = true }
Expand Down Expand Up @@ -86,3 +87,10 @@ parity-scale-codec = [
"ibc-primitives/parity-scale-codec",
"ibc-proto/parity-scale-codec",
]
arbitrary = [
"dep:arbitrary",
"ibc-primitives/arbitrary",
"ibc-core-commitment-types/arbitrary",
"ibc-core-host-types/arbitrary",
"std",
]
1 change: 1 addition & 0 deletions ibc-core/ics02-client/types/src/height.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::error::ClientError;
/// The core IBC height type, which represents the height of a chain,
/// which typically is the number of blocks since genesis
/// (or more generally, since the last revision/hard upgrade).
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "parity-scale-codec",
derive(
Expand Down
3 changes: 3 additions & 0 deletions ibc-core/ics02-client/types/src/msgs/create_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ use ibc_proto::Protobuf;
pub const CREATE_CLIENT_TYPE_URL: &str = "/ibc.core.client.v1.MsgCreateClient";

/// A type of message that triggers the creation of a new on-chain (IBC) client.
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MsgCreateClient {
#[cfg_attr(feature = "arbitrary", arbitrary(with = ibc_primitives::arb_protobuf_any))]
pub client_state: Any,
#[cfg_attr(feature = "arbitrary", arbitrary(with = ibc_primitives::arb_protobuf_any))]
pub consensus_state: Any,
pub signer: Signer,
}
Expand Down
2 changes: 2 additions & 0 deletions ibc-core/ics02-client/types/src/msgs/misbehaviour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub const SUBMIT_MISBEHAVIOUR_TYPE_URL: &str = "/ibc.core.client.v1.MsgSubmitMis
///
/// Deprecated since v0.51.0. Misbehaviour reports should be submitted via the `MsgUpdateClient`
/// type through its `client_message` field.
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[deprecated(
since = "0.51.0",
note = "Misbehaviour reports should be submitted via `MsgUpdateClient` through its `client_message` field"
Expand All @@ -28,6 +29,7 @@ pub struct MsgSubmitMisbehaviour {
/// client unique identifier
pub client_id: ClientId,
/// misbehaviour, used for freezing the light client
#[cfg_attr(feature = "arbitrary", arbitrary(with = ibc_primitives::arb_protobuf_any))]
pub misbehaviour: ProtoAny,
/// signer address
pub signer: Signer,
Expand Down
1 change: 1 addition & 0 deletions ibc-core/ics02-client/types/src/msgs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub use upgrade_client::*;

/// Encodes all the different client messages
#[allow(dead_code)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
Expand Down
1 change: 1 addition & 0 deletions ibc-core/ics02-client/types/src/msgs/recover_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub const RECOVER_CLIENT_TYPE_URL: &str = "/ibc.core.client.v1.MsgRecoverClient"
/// client recovery functionality is not part of ibc-rs's public API. The
/// intended usage of this message type is to be integrated with hosts'
/// governance modules, not to be called directly via `dispatch`.
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
Expand Down
Loading

0 comments on commit eb7e079

Please sign in to comment.