From dea4ad6027345eb4192ef72924dffc5b7e07ac2a Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 18 Oct 2022 17:55:40 +0200 Subject: [PATCH 1/4] Implement Binary/HexBinary <-> CanonicalAddr converters --- CHANGELOG.md | 7 ++++ packages/std/src/addresses.rs | 73 ++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 804eeee6fc..33a7fa37b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ and this project adheres to ## [Unreleased] +### Added + +- cosmwasm-std: Add `From` implementations to convert between + `CanonicalAddr`/`Binary` as well as `CanonicalAddr`/`HexBinary` ([#1463]). + +[#1463]: https://github.com/CosmWasm/cosmwasm/pull/1463 + ## [1.1.5] - 2022-10-17 ### Added diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index f58730085e..29810513c2 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; use std::fmt; use std::ops::Deref; -use crate::binary::Binary; +use crate::{binary::Binary, HexBinary}; /// A human readable address. /// @@ -144,18 +144,48 @@ impl From<&[u8]> for CanonicalAddr { } } +// Owned vector -> CanonicalAddr impl From> for CanonicalAddr { fn from(source: Vec) -> Self { Self(source.into()) } } +// CanonicalAddr -> Owned vector impl From for Vec { fn from(source: CanonicalAddr) -> Vec { source.0.into() } } +// Owned Binary -> CanonicalAddr +impl From for CanonicalAddr { + fn from(source: Binary) -> Self { + Self(source) + } +} + +// CanonicalAddr -> Owned Binary +impl From for Binary { + fn from(source: CanonicalAddr) -> Binary { + source.0 + } +} + +// Owned HexBinary -> CanonicalAddr +impl From for CanonicalAddr { + fn from(source: HexBinary) -> Self { + Self(source.into()) + } +} + +// CanonicalAddr -> Owned HexBinary +impl From for HexBinary { + fn from(source: CanonicalAddr) -> HexBinary { + source.0.into() + } +} + /// Just like Vec, CanonicalAddr is a smart pointer to [u8]. /// This implements `*canonical_address` for us and allows us to /// do `&*canonical_address`, returning a `&[u8]` from a `&CanonicalAddr`. @@ -278,8 +308,9 @@ mod tests { } #[test] - fn canonical_addr_from_vec_works() { + fn canonical_addr_implements_from_and_to_vector() { // Into for Vec + // This test is a bit pointless because we get Into from the From implementation let original = vec![0u8, 187, 61, 11, 250, 0]; let original_ptr = original.as_ptr(); let addr: CanonicalAddr = original.into(); @@ -292,11 +323,9 @@ mod tests { let addr = CanonicalAddr::from(original); assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]); assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied"); - } - #[test] - fn canonical_addr_into_vec_works() { // Into> for CanonicalAddr + // This test is a bit pointless because we get Into from the From implementation let original = CanonicalAddr::from(vec![0u8, 187, 61, 11, 250, 0]); let original_ptr = (original.0).0.as_ptr(); let vec: Vec = original.into(); @@ -311,6 +340,40 @@ mod tests { assert_eq!(vec.as_ptr(), original_ptr, "must not be copied"); } + #[test] + fn canonical_addr_implements_from_and_to_binary() { + // From for CanonicalAddr + let original = Binary::from([0u8, 187, 61, 11, 250, 0]); + let original_ptr = original.as_ptr(); + let addr = CanonicalAddr::from(original); + assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]); + assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied"); + + // From for Binary + let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]); + let original_ptr = (original.0).0.as_ptr(); + let bin = Binary::from(original); + assert_eq!(bin.as_slice(), [7u8, 35, 49, 101, 0, 255]); + assert_eq!(bin.as_ptr(), original_ptr, "must not be copied"); + } + + #[test] + fn canonical_addr_implements_from_and_to_hex_binary() { + // From for CanonicalAddr + let original = HexBinary::from([0u8, 187, 61, 11, 250, 0]); + let original_ptr = original.as_ptr(); + let addr = CanonicalAddr::from(original); + assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]); + assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied"); + + // From for HexBinary + let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]); + let original_ptr = (original.0).0.as_ptr(); + let bin = HexBinary::from(original); + assert_eq!(bin.as_slice(), [7u8, 35, 49, 101, 0, 255]); + assert_eq!(bin.as_ptr(), original_ptr, "must not be copied"); + } + #[test] fn canonical_addr_len() { let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0]; From 044c0b65ced8ab17a53b1a72f1ba3da49d5f1d21 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 18 Oct 2022 18:00:58 +0200 Subject: [PATCH 2/4] Add array to CanonicalAddr converters --- CHANGELOG.md | 2 ++ packages/std/src/addresses.rs | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33a7fa37b9..e568a3e23b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to - cosmwasm-std: Add `From` implementations to convert between `CanonicalAddr`/`Binary` as well as `CanonicalAddr`/`HexBinary` ([#1463]). +- cosmwasm-std: Add `From` implementations to convert `u8` arrays to + `CanonicalAddr` ([#1463]). [#1463]: https://github.com/CosmWasm/cosmwasm/pull/1463 diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index 29810513c2..b218074a34 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -144,6 +144,20 @@ impl From<&[u8]> for CanonicalAddr { } } +// Array reference +impl From<&[u8; LENGTH]> for CanonicalAddr { + fn from(source: &[u8; LENGTH]) -> Self { + Self(source.into()) + } +} + +// Owned array +impl From<[u8; LENGTH]> for CanonicalAddr { + fn from(source: [u8; LENGTH]) -> Self { + Self(source.into()) + } +} + // Owned vector -> CanonicalAddr impl From> for CanonicalAddr { fn from(source: Vec) -> Self { @@ -307,6 +321,17 @@ mod tests { assert_eq!(canonical_addr_vec.as_slice(), &[0u8, 187, 61, 11, 250, 0]); } + #[test] + fn canonical_addr_implements_from_array() { + let array = [1, 2, 3]; + let addr = CanonicalAddr::from(array); + assert_eq!(addr.as_slice(), [1, 2, 3]); + + let array_ref = b"foo"; + let addr = CanonicalAddr::from(array_ref); + assert_eq!(addr.as_slice(), [0x66, 0x6f, 0x6f]); + } + #[test] fn canonical_addr_implements_from_and_to_vector() { // Into for Vec From 013fda5fbcc2e4463aa032fe701ded71d418d8e6 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 18 Oct 2022 16:12:16 +0200 Subject: [PATCH 3/4] Implement PartialEq between CanonicalAddr and HexBinary/Binary --- CHANGELOG.md | 2 ++ packages/std/src/addresses.rs | 52 +++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e568a3e23b..5ad7e956b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to `CanonicalAddr`/`Binary` as well as `CanonicalAddr`/`HexBinary` ([#1463]). - cosmwasm-std: Add `From` implementations to convert `u8` arrays to `CanonicalAddr` ([#1463]). +- cosmwasm-std: Implement `PartialEq` between `CanonicalAddr` and + `HexBinary`/`Binary` ([#1463]). [#1463]: https://github.com/CosmWasm/cosmwasm/pull/1463 diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index b218074a34..54ca2e1710 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -138,6 +138,34 @@ impl<'a> From<&'a Addr> for Cow<'a, Addr> { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, JsonSchema)] pub struct CanonicalAddr(pub Binary); +/// Implement `CanonicalAddr == Binary` +impl PartialEq for CanonicalAddr { + fn eq(&self, rhs: &Binary) -> bool { + &self.0 == rhs + } +} + +/// Implement `Binary == CanonicalAddr` +impl PartialEq for Binary { + fn eq(&self, rhs: &CanonicalAddr) -> bool { + self == &rhs.0 + } +} + +/// Implement `CanonicalAddr == HexBinary` +impl PartialEq for CanonicalAddr { + fn eq(&self, rhs: &HexBinary) -> bool { + self.as_slice() == rhs.as_slice() + } +} + +/// Implement `HexBinary == CanonicalAddr` +impl PartialEq for HexBinary { + fn eq(&self, rhs: &CanonicalAddr) -> bool { + self.as_slice() == rhs.0.as_slice() + } +} + impl From<&[u8]> for CanonicalAddr { fn from(source: &[u8]) -> Self { Self(source.into()) @@ -321,6 +349,30 @@ mod tests { assert_eq!(canonical_addr_vec.as_slice(), &[0u8, 187, 61, 11, 250, 0]); } + #[test] + fn canonical_addr_implements_partial_eq_with_binary() { + let addr = CanonicalAddr::from([1, 2, 3]); + let bin1 = Binary::from([1, 2, 3]); + let bin2 = Binary::from([42, 43]); + + assert_eq!(addr, bin1); + assert_eq!(bin1, addr); + assert_ne!(addr, bin2); + assert_ne!(bin2, addr); + } + + #[test] + fn canonical_addr_implements_partial_eq_with_hex_binary() { + let addr = CanonicalAddr::from([1, 2, 3]); + let bin1 = HexBinary::from([1, 2, 3]); + let bin2 = HexBinary::from([42, 43]); + + assert_eq!(addr, bin1); + assert_eq!(bin1, addr); + assert_ne!(addr, bin2); + assert_ne!(bin2, addr); + } + #[test] fn canonical_addr_implements_from_array() { let array = [1, 2, 3]; From e6033ae324f0ca1e56d016d1d858dce2fa82cdee Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 18 Oct 2022 17:01:35 +0200 Subject: [PATCH 4/4] Avoid the usage of CanonicalAddr.0 --- packages/std/src/addresses.rs | 12 ++++++------ packages/std/src/imports.rs | 3 +-- packages/std/src/testing/mock.rs | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index 54ca2e1710..0cdffe45a0 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -499,17 +499,17 @@ mod tests { #[test] fn canonical_addr_implements_hash() { - let alice1 = CanonicalAddr(Binary::from([0, 187, 61, 11, 250, 0])); + let alice1 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]); let mut hasher = DefaultHasher::new(); alice1.hash(&mut hasher); let alice1_hash = hasher.finish(); - let alice2 = CanonicalAddr(Binary::from([0, 187, 61, 11, 250, 0])); + let alice2 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]); let mut hasher = DefaultHasher::new(); alice2.hash(&mut hasher); let alice2_hash = hasher.finish(); - let bob = CanonicalAddr(Binary::from([16, 21, 33, 0, 255, 9])); + let bob = CanonicalAddr::from([16, 21, 33, 0, 255, 9]); let mut hasher = DefaultHasher::new(); bob.hash(&mut hasher); let bob_hash = hasher.finish(); @@ -521,9 +521,9 @@ mod tests { /// This requires Hash and Eq to be implemented #[test] fn canonical_addr_can_be_used_in_hash_set() { - let alice1 = CanonicalAddr(Binary::from([0, 187, 61, 11, 250, 0])); - let alice2 = CanonicalAddr(Binary::from([0, 187, 61, 11, 250, 0])); - let bob = CanonicalAddr(Binary::from([16, 21, 33, 0, 255, 9])); + let alice1 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]); + let alice2 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]); + let bob = CanonicalAddr::from([16, 21, 33, 0, 255, 9]); let mut set = HashSet::new(); set.insert(alice1.clone()); diff --git a/packages/std/src/imports.rs b/packages/std/src/imports.rs index df03d1d640..f7438a9df0 100644 --- a/packages/std/src/imports.rs +++ b/packages/std/src/imports.rs @@ -1,7 +1,6 @@ use std::vec::Vec; use crate::addresses::{Addr, CanonicalAddr}; -use crate::binary::Binary; use crate::errors::{RecoverPubkeyError, StdError, StdResult, SystemError, VerificationError}; use crate::import_helpers::{from_high_half, from_low_half}; use crate::memory::{alloc, build_region, consume_region, Region}; @@ -224,7 +223,7 @@ impl Api for ExternalApi { } let out = unsafe { consume_region(canon) }; - Ok(CanonicalAddr(Binary(out))) + Ok(CanonicalAddr::from(out)) } fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 0f74c3e3c1..f9681d1ccc 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -902,7 +902,7 @@ mod tests { #[should_panic(expected = "length not correct")] fn addr_humanize_input_length() { let api = MockApi::default(); - let input = CanonicalAddr(Binary(vec![61; 11])); + let input = CanonicalAddr::from(vec![61; 11]); api.addr_humanize(&input).unwrap(); }