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

Signed int keys order #582

Merged
merged 19 commits into from
Dec 17, 2021
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
12 changes: 1 addition & 11 deletions contracts/cw3-fixed-multisig/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::convert::TryInto;

use cosmwasm_std::{Addr, BlockInfo, CosmosMsg, Empty, StdError, StdResult, Storage};
use cosmwasm_std::{Addr, BlockInfo, CosmosMsg, Empty, StdResult, Storage};

use cw3::{Status, Vote};
use cw_storage_plus::{Item, Map};
Expand Down Expand Up @@ -66,12 +65,3 @@ pub fn next_id(store: &mut dyn Storage) -> StdResult<u64> {
PROPOSAL_COUNT.save(store, &id)?;
Ok(id)
}

pub fn parse_id(data: &[u8]) -> StdResult<u64> {
match data[0..8].try_into() {
Ok(bytes) => Ok(u64::from_be_bytes(bytes)),
Err(_) => Err(StdError::generic_err(
"Corrupted data found. 8 byte expected.",
)),
}
}
14 changes: 1 addition & 13 deletions contracts/cw3-flex-multisig/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::convert::TryInto;

use cosmwasm_std::{
Addr, BlockInfo, CosmosMsg, Decimal, Empty, StdError, StdResult, Storage, Uint128,
};
use cosmwasm_std::{Addr, BlockInfo, CosmosMsg, Decimal, Empty, StdResult, Storage, Uint128};

use cw3::{Status, Vote};
use cw4::Cw4Contract;
Expand Down Expand Up @@ -162,15 +159,6 @@ pub fn next_id(store: &mut dyn Storage) -> StdResult<u64> {
Ok(id)
}

pub fn parse_id(data: &[u8]) -> StdResult<u64> {
match data[0..8].try_into() {
Ok(bytes) => Ok(u64::from_be_bytes(bytes)),
Err(_) => Err(StdError::generic_err(
"Corrupted data found. 8 byte expected.",
)),
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
101 changes: 85 additions & 16 deletions packages/storage-plus/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::convert::TryInto;

use cosmwasm_std::{Addr, StdError, StdResult};

use crate::int_key::CwIntKey;
use crate::keys::{IntKey, TimestampKey};

pub trait KeyDeserialize {
Expand Down Expand Up @@ -106,7 +107,7 @@ macro_rules! integer_de {

#[inline(always)]
fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
Ok(<$t>::from_be_bytes(value.as_slice().try_into()
Ok(<$t>::from_cw_bytes(value.as_slice().try_into()
maurolacy marked this conversation as resolved.
Show resolved Hide resolved
.map_err(|err: TryFromSliceError| StdError::generic_err(err.to_string()))?))
}
})*
Expand All @@ -122,7 +123,7 @@ macro_rules! intkey_de {

#[inline(always)]
fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
Ok(<$t>::from_be_bytes(value.as_slice().try_into()
Ok(<$t>::from_cw_bytes(value.as_slice().try_into()
.map_err(|err: TryFromSliceError| StdError::generic_err(err.to_string()))?))
}
})*
Expand Down Expand Up @@ -230,41 +231,109 @@ mod test {
}

#[test]
fn deserialize_integer_works() {
assert_eq!(<IntKey<u8>>::from_slice(&[1]).unwrap(), 1u8);
assert_eq!(<IntKey<i8>>::from_slice(&[128]).unwrap(), -1i8 << 7);
assert_eq!(<IntKey<u16>>::from_slice(&[1, 0]).unwrap(), 1u16 << 8);
fn deserialize_naked_integer_works() {
assert_eq!(u8::from_slice(&[1]).unwrap(), 1u8);
assert_eq!(i8::from_slice(&[127]).unwrap(), -1i8);
assert_eq!(i8::from_slice(&[128]).unwrap(), 0i8);

assert_eq!(u16::from_slice(&[1, 0]).unwrap(), 256u16);
assert_eq!(i16::from_slice(&[128, 0]).unwrap(), 0i16);
assert_eq!(i16::from_slice(&[127, 255]).unwrap(), -1i16);

assert_eq!(u32::from_slice(&[1, 0, 0, 0]).unwrap(), 16777216u32);
assert_eq!(i32::from_slice(&[128, 0, 0, 0]).unwrap(), 0i32);
assert_eq!(i32::from_slice(&[127, 255, 255, 255]).unwrap(), -1i32);

assert_eq!(
<IntKey<i16>>::from_slice(&[128, 0]).unwrap(),
-1i16 << (8 + 7)
u64::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
72057594037927936u64
);
assert_eq!(i64::from_slice(&[128, 0, 0, 0, 0, 0, 0, 0]).unwrap(), 0i64);
assert_eq!(
maurolacy marked this conversation as resolved.
Show resolved Hide resolved
i64::from_slice(&[127, 255, 255, 255, 255, 255, 255, 255]).unwrap(),
-1i64
);

assert_eq!(
u128::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
1329227995784915872903807060280344576u128
);
assert_eq!(
i128::from_slice(&[128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
0i128
);
assert_eq!(
i128::from_slice(&[
127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
])
.unwrap(),
-1i128
);
assert_eq!(
i128::from_slice(&[
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
])
.unwrap(),
170141183460469231731687303715884105727i128,
);
}

#[test]
fn deserialize_integer_works() {
assert_eq!(<IntKey<u8>>::from_slice(&[1]).unwrap(), 1u8);
assert_eq!(<IntKey<i8>>::from_slice(&[127]).unwrap(), -1i8);
assert_eq!(<IntKey<i8>>::from_slice(&[128]).unwrap(), 0i8);

assert_eq!(<IntKey<u16>>::from_slice(&[1, 0]).unwrap(), 256u16);
assert_eq!(<IntKey<i16>>::from_slice(&[128, 0]).unwrap(), 0i16);
assert_eq!(<IntKey<i16>>::from_slice(&[127, 255]).unwrap(), -1i16);

assert_eq!(
<IntKey<u32>>::from_slice(&[1, 0, 0, 0]).unwrap(),
1u32 << (3 * 8)
16777216u32
);
assert_eq!(<IntKey<i32>>::from_slice(&[128, 0, 0, 0]).unwrap(), 0i32);
assert_eq!(
<IntKey<i32>>::from_slice(&[128, 0, 0, 0]).unwrap(),
-1i32 << (3 * 8 + 7)
<IntKey<i32>>::from_slice(&[127, 255, 255, 255]).unwrap(),
-1i32
);

assert_eq!(
<IntKey<u64>>::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
1u64 << (7 * 8)
72057594037927936u64
);
assert_eq!(
<IntKey<i64>>::from_slice(&[128, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
-1i64 << (7 * 8 + 7)
0i64
);
assert_eq!(
<IntKey<i64>>::from_slice(&[127, 255, 255, 255, 255, 255, 255, 255]).unwrap(),
-1i64
);

assert_eq!(
<IntKey<u128>>::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
1u128 << (15 * 8)
1329227995784915872903807060280344576u128
);
assert_eq!(
<IntKey<i128>>::from_slice(&[128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
.unwrap(),
0i128
);
assert_eq!(
<IntKey<i128>>::from_slice(&[
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
])
.unwrap(),
-1i128
);
assert_eq!(
<IntKey<i128>>::from_slice(&[
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
])
.unwrap(),
170141183460469231731687303715884105727i128,
);
}

#[test]
Expand All @@ -286,7 +355,7 @@ mod test {
fn deserialize_timestamp_works() {
assert_eq!(
<TimestampKey>::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
1u64 << (7 * 8)
72057594037927936
);
}

Expand Down
131 changes: 131 additions & 0 deletions packages/storage-plus/src/int_key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use std::mem;

/// Our int keys are simply the big-endian representation bytes for unsigned ints,
/// but "sign-flipped" (xored msb) big-endian bytes for signed ints.
///
/// So that the representation of signed integers is in the right lexicographical order.
// TODO: Rename to `IntKey` after deprecating current `IntKey` (https://github.com/CosmWasm/cw-plus/issues/570)
pub trait CwIntKey: Sized + Copy {
type Buf: AsRef<[u8]> + AsMut<[u8]> + Into<Vec<u8>> + Default;

fn to_cw_bytes(&self) -> Self::Buf;
fn from_cw_bytes(bytes: Self::Buf) -> Self;
}

macro_rules! cw_uint_keys {
(for $($t:ty),+) => {
$(impl CwIntKey for $t {
type Buf = [u8; mem::size_of::<$t>()];

#[inline]
fn to_cw_bytes(&self) -> Self::Buf {
self.to_be_bytes()
}

#[inline]
fn from_cw_bytes(bytes: Self::Buf) -> Self {
Self::from_be_bytes(bytes)
}
})*
}
}

cw_uint_keys!(for u8, u16, u32, u64, u128);

macro_rules! cw_int_keys {
(for $($t:ty, $ut:ty),+) => {
$(impl CwIntKey for $t {
type Buf = [u8; mem::size_of::<$t>()];

#[inline]
fn to_cw_bytes(&self) -> Self::Buf {
(*self as $ut ^ <$t>::MIN as $ut).to_be_bytes()
}

#[inline]
fn from_cw_bytes(bytes: Self::Buf) -> Self {
(Self::from_be_bytes(bytes) as $ut ^ <$t>::MIN as $ut) as _
}
})*
}
}

cw_int_keys!(for i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);

#[cfg(test)]
mod test {
use super::*;

#[test]
fn x8_int_key_works() {
assert_eq!(0x42u8.to_cw_bytes(), [0x42]);
assert_eq!(0x42i8.to_cw_bytes(), [0xc2]);
assert_eq!((-0x3ei8).to_cw_bytes(), [0x42]);
}

#[test]
fn x16_int_key_works() {
assert_eq!(0x4243u16.to_cw_bytes(), [0x42, 0x43]);
assert_eq!(0x4243i16.to_cw_bytes(), [0xc2, 0x43]);
assert_eq!((-0x3dbdi16).to_cw_bytes(), [0x42, 0x43]);
}

#[test]
fn x32_int_key_works() {
assert_eq!(0x424344u32.to_cw_bytes(), [0x00, 0x42, 0x43, 0x44]);
assert_eq!(0x424344i32.to_cw_bytes(), [0x80, 0x42, 0x43, 0x44]);
assert_eq!((-0x7fbdbcbci32).to_cw_bytes(), [0x00, 0x42, 0x43, 0x44]);
}

#[test]
fn x64_int_key_works() {
assert_eq!(
0x42434445u64.to_cw_bytes(),
[0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45]
);
assert_eq!(
0x42434445i64.to_cw_bytes(),
[0x80, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45]
);
assert_eq!(
(-0x7fffffffbdbcbbbbi64).to_cw_bytes(),
[0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x45]
);
}

#[test]
fn x128_int_key_works() {
assert_eq!(
0x4243444546u128.to_cw_bytes(),
[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44,
0x45, 0x46
]
);
assert_eq!(
0x4243444546i128.to_cw_bytes(),
[
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44,
0x45, 0x46
]
);
assert_eq!(
(-0x7fffffffffffffffffffffbdbcbbbabai128).to_cw_bytes(),
[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44,
0x45, 0x46
]
);
}

#[test]
fn unsigned_int_key_order() {
assert!(0u32.to_cw_bytes() < 652u32.to_cw_bytes());
}

#[test]
fn signed_int_key_order() {
assert!((-321i32).to_cw_bytes() < 0i32.to_cw_bytes());
assert!(0i32.to_cw_bytes() < 652i32.to_cw_bytes());
}
}
Loading