From e77938f40f7eff2c5175100480d1978f6bb91eae Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 11 Sep 2024 11:17:49 +0200 Subject: [PATCH 1/6] AccountId uses Etherem 0x encoding --- Cargo.lock | 128 +++++++++++++++++++++++++++++++++ packages/std/Cargo.toml | 3 + packages/std/src/account_id.rs | 66 +++++++---------- packages/std/src/lib.rs | 2 +- 4 files changed, 157 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd8175cc..72f3491c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -304,6 +304,22 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloy-primitives" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411aff151f2a73124ee473708e82ed51b2535f68928b6a1caa8bc1246ae6f7cd" +dependencies = [ + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "ruint", + "tiny-keccak", +] + [[package]] name = "anstream" version = "0.6.15" @@ -795,6 +811,19 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -1118,6 +1147,12 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -1488,6 +1523,27 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "unicode-xid", +] + [[package]] name = "digest" version = "0.9.0" @@ -2499,6 +2555,7 @@ dependencies = [ name = "layer-std" version = "0.4.0" dependencies = [ + "alloy-primitives", "bech32 0.9.1", "bytes", "chrono", @@ -2567,6 +2624,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libredox" version = "0.1.3" @@ -2779,6 +2842,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3179,6 +3243,20 @@ dependencies = [ "yansi", ] +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bitflags 2.6.0", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "unarray", +] + [[package]] name = "prost" version = "0.11.9" @@ -3346,6 +3424,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "rayon" version = "1.10.0" @@ -3578,6 +3665,26 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "proptest", + "rand", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -4395,6 +4502,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -4676,6 +4792,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "uncased" version = "0.9.10" @@ -4712,6 +4834,12 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "unicode-xid" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" + [[package]] name = "untrusted" version = "0.9.0" diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index cf3b4667..a788d8dc 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -24,3 +24,6 @@ hex = { workspace = true } bech32 = { version = "0.9.1", default-features = false } chrono = { version = "0.4.19", default-features = false, features = ["std"] } derivative = "2.2.0" + +# TODO: move this up to top level Cargo if it works out +alloy-primitives = { version = "0.8.2", default-features = false } \ No newline at end of file diff --git a/packages/std/src/account_id.rs b/packages/std/src/account_id.rs index a9362961..1b2e7ae8 100644 --- a/packages/std/src/account_id.rs +++ b/packages/std/src/account_id.rs @@ -2,20 +2,23 @@ use std::fmt::{Debug, Display, Formatter}; use std::ops::Deref; use ::cosmwasm_schema::serde; -use bech32::{self, Error as Bech32Error, FromBase32, ToBase32, Variant}; +// use bech32::{self, Error as Bech32Error, FromBase32, ToBase32, Variant}; +use alloy_primitives::{Address, AddressError}; + use cosmwasm_std::{Addr, StdResult}; use cw_storage_plus::{Key, KeyDeserialize, Prefixer, PrimaryKey}; use thiserror::Error; -pub const ENV_BECH32_PREFIX: Option<&'static str> = std::option_env!("SLAY_BECH32"); -pub const DEFAULT_BECH32_PREFIX: &str = "slay3r"; +// pub const ENV_BECH32_PREFIX: Option<&'static str> = std::option_env!("SLAY_BECH32"); +// pub const DEFAULT_BECH32_PREFIX: &str = "slay3r"; /// Valid lengths of decoded addresses -pub const VALID_ADDR_LENGTH: [usize; 2] = [20usize, 32usize]; +pub const VALID_ADDR_LENGTH: [usize; 1] = [20usize]; +// pub const VALID_ADDR_LENGTH: [usize; 2] = [20usize, 32usize]; -fn bech32_prefix() -> &'static str { - ENV_BECH32_PREFIX.unwrap_or(DEFAULT_BECH32_PREFIX) -} +// fn bech32_prefix() -> &'static str { +// ENV_BECH32_PREFIX.unwrap_or(DEFAULT_BECH32_PREFIX) +// } // Note: this is expanded cw_serde macro minus the Debug implementation, as we want to use Display there #[derive(::std::clone::Clone, ::std::cmp::PartialEq, ::cosmwasm_schema::schemars::JsonSchema)] @@ -36,8 +39,8 @@ impl Deref for AccountId { #[derive(Error, Debug, PartialEq, Eq)] pub enum AccountIdError { /// FIXME: normalize this, so we don't have possibly non-deterministic errors from different crate versions - #[error("Bech32: {0}")] - Bech32(String), + #[error("Address: {0}")] + Address(String), #[error("Invalid variant: bech32m")] InvalidVariant, @@ -49,15 +52,16 @@ pub enum AccountIdError { InvalidLength(usize), } -impl From for AccountIdError { - fn from(value: Bech32Error) -> Self { - AccountIdError::Bech32(value.to_string()) +impl From for AccountIdError { + fn from(value: AddressError) -> Self { + AccountIdError::Address(value.to_string()) } } impl Display for AccountId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - bech32::encode_to_fmt(f, bech32_prefix(), self.0.to_base32(), Variant::Bech32).unwrap() + let addr = Address(self.0.as_slice().try_into().unwrap()); + write!(f, "{:?}", addr) } } @@ -135,23 +139,10 @@ impl AccountId { } } + // This requires checksumed.... pub fn parse_string(encoded: &str) -> Result { - let (hrp, data, variant) = bech32::decode(encoded)?; - // no bech32m - if variant != Variant::Bech32 { - return Err(AccountIdError::InvalidVariant); - } - // make sure the proper chain prefix - let prefix = bech32_prefix(); - if hrp != prefix { - return Err(AccountIdError::InvalidPrefix(hrp, prefix)); - } - let addr = Vec::::from_base32(&data).unwrap(); - // we only support 20 and 32 bytes for the binary version, enforce this for sanity check - if !VALID_ADDR_LENGTH.contains(&addr.len()) { - return Err(AccountIdError::InvalidLength(addr.len())); - } - Ok(AccountId(addr)) + let addr = Address::parse_checksummed(encoded, None)?; + Ok(AccountId(addr.0.to_vec())) } // only for use in test @@ -212,24 +203,17 @@ mod tests { #[test] fn test_creation() { - // properly parses and encoded proper size + // we can encode and decode valid addresses let id = AccountId::new(&[42u8; 20]).unwrap(); - assert!(id.to_string().starts_with("slay3r1")); + assert!(id.to_string().starts_with("0x")); let reparse = AccountId::parse_string(&id.to_string()).unwrap(); assert_eq!(id, reparse); - // we can encode and decode valid addresses - let id = AccountId::new(&[69u8; 32]).unwrap(); - assert!(id.to_string().starts_with("slay3r1")); - let reparse = AccountId::parse_string(&id.to_string()).unwrap(); - assert_eq!(id, reparse); + // enforces valid size (we reject 32 bytes) + let _ = AccountId::new(&[69u8; 32]).unwrap_err(); // incorrect raw input fails let _ = AccountId::new(&[69u8; 15]).unwrap_err(); - - // incorrect bedh32 input fails - let bad_addr = id.to_string().replace("q", "k"); - let _ = AccountId::parse_string(&bad_addr).unwrap_err(); } #[test] @@ -238,7 +222,7 @@ mod tests { let id = AccountId::new(&raw).unwrap(); let as_string = to_json_binary(&id.to_string()).unwrap(); - assert!(as_string.starts_with(br#""slay3r1"#)); + assert!(as_string.starts_with(br#""0x"#)); let as_raw = to_json_binary(&raw).unwrap(); assert!(as_raw.starts_with(b"[42,42,")); diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 955beb5c..79251340 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -10,7 +10,7 @@ mod time; mod tx; mod utils; -pub use account_id::{must_id, AccountId, AccountIdError, DEFAULT_BECH32_PREFIX}; +pub use account_id::{must_id, AccountId, AccountIdError}; use cosmwasm_std::Binary; pub use encode::{CoinEncode, HexEncode}; pub use gas::{GasError, GasMeter, GasResult}; From e43e7cbfca243192d359d3bb3cbe836b7ae37357 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 11 Sep 2024 11:22:13 +0200 Subject: [PATCH 2/6] Fix tests, checksummed address is canonical format --- packages/std/src/account_id.rs | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/packages/std/src/account_id.rs b/packages/std/src/account_id.rs index 1b2e7ae8..b18ebd02 100644 --- a/packages/std/src/account_id.rs +++ b/packages/std/src/account_id.rs @@ -61,7 +61,7 @@ impl From for AccountIdError { impl Display for AccountId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let addr = Address(self.0.as_slice().try_into().unwrap()); - write!(f, "{:?}", addr) + write!(f, "{}", addr) } } @@ -80,28 +80,13 @@ impl serde::Serialize for AccountId { } } -// Helper to parse both formats - we need this for backwards state compatibility chains <= 0.3.2 -// TODO: This can be removed in the future with a new devnet -#[derive(Debug, serde::Serialize, serde::Deserialize)] -#[serde(untagged, crate = "::cosmwasm_schema::serde")] -enum StringOrBytes { - String(String), - Vec(Vec), -} - impl<'de> serde::Deserialize<'de> for AccountId { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { - match StringOrBytes::deserialize(deserializer)? { - StringOrBytes::String(s) => { - AccountId::parse_string(&s).map_err(|e| serde::de::Error::custom(e.to_string())) - } - StringOrBytes::Vec(raw) => { - AccountId::new(&raw).map_err(|e| serde::de::Error::custom(e.to_string())) - } - } + let s = String::deserialize(deserializer)?; + AccountId::parse_string(&s).map_err(|e| serde::de::Error::custom(e.to_string())) } } @@ -224,13 +209,6 @@ mod tests { let as_string = to_json_binary(&id.to_string()).unwrap(); assert!(as_string.starts_with(br#""0x"#)); - let as_raw = to_json_binary(&raw).unwrap(); - assert!(as_raw.starts_with(b"[42,42,")); - - // ensure we can decode back to the same value from raw - let parsed: AccountId = from_json(&as_raw).unwrap(); - assert_eq!(parsed, id); - // ensure we can decode back to the same value from string let parsed: AccountId = from_json(&as_string).unwrap(); assert_eq!(parsed, id); @@ -238,5 +216,10 @@ mod tests { // ensure we encode as string let encoded = to_json_binary(&id).unwrap(); assert_eq!(encoded, as_string); + + // we no longer accept raw + let as_raw = to_json_binary(&raw).unwrap(); + assert!(as_raw.starts_with(b"[42,42,")); + let _ = from_json::(&as_raw).unwrap_err(); } } From 6aaddd44ff6aa8597afc1a2afaa678f2f142c0ca Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 11 Sep 2024 11:36:00 +0200 Subject: [PATCH 3/6] Fixed many tests - fails on app, cosmos, golem --- Cargo.lock | 1 - packages/app/src/app.rs | 1 + packages/app/src/wasm/utils.rs | 28 +++++++++------------------- packages/app/src/wasm/vm/cache.rs | 4 ++-- packages/cosmos/src/tx.rs | 4 +++- packages/std/Cargo.toml | 1 - packages/std/src/account_id.rs | 15 +++------------ packages/std/src/lib.rs | 2 +- 8 files changed, 19 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72f3491c..17a06ebf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2556,7 +2556,6 @@ name = "layer-std" version = "0.4.0" dependencies = [ "alloy-primitives", - "bech32 0.9.1", "bytes", "chrono", "cosmwasm-crypto", diff --git a/packages/app/src/app.rs b/packages/app/src/app.rs index 2b62d85c..440bd0af 100644 --- a/packages/app/src/app.rs +++ b/packages/app/src/app.rs @@ -516,6 +516,7 @@ mod tests { // run finalize_block // query account + balances for update fn transaction_workflow(storage: T) { + // TODO: convert bech32 to 0x checksummed (make script) let sender = must_id("slay3r1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmvk3r3j"); let recipient = must_id("slay3r1y5hl7x8hxl72dc9gu920eaz6l7vhl0luu6s70h"); let denom: &str = "uslay"; diff --git a/packages/app/src/wasm/utils.rs b/packages/app/src/wasm/utils.rs index 2116704d..e62db91e 100644 --- a/packages/app/src/wasm/utils.rs +++ b/packages/app/src/wasm/utils.rs @@ -4,7 +4,7 @@ use sha2::{ }; use thiserror::Error; -use layer_std::AccountId; +use layer_std::{AccountId, VALID_ADDR_LENGTH}; use crate::PulsarError; @@ -23,7 +23,7 @@ pub fn build_instantiate_address( prehash.extend(code_id.to_be_bytes()); prehash.extend(counter.to_be_bytes()); let raw = Sha256::digest(prehash); - Ok(AccountId::new(&raw)?) + Ok(AccountId::new(&raw[..VALID_ADDR_LENGTH])?) } /// We should match the reference wasmd/Go implementation for compatibility with cosmos-sdk: @@ -58,7 +58,7 @@ pub fn build_instantiate_2_address( key.extend_from_slice(&(msg.len() as u64).to_be_bytes()); key.extend_from_slice(msg); let address_data = hash("module", &key); - Ok(AccountId::new(&address_data)?) + Ok(AccountId::new(&address_data[..VALID_ADDR_LENGTH])?) } /// This must be compatible with the wasmd calls, and thus map to address.Module in Cosmos SDK. @@ -108,41 +108,31 @@ mod tests { let msg2: &[u8] = b"{}"; let msg3: &[u8] = b"{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"; + // TODO: reduce all expected to 40 chars, not 64 chars + // No msg - let expected = AccountId::new(&hex!( - "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847" - )) - .unwrap(); + let expected = AccountId::new(&hex!("5e865d3e45ad3e961f77fd77d46543417ced44d9")).unwrap(); assert_eq!( build_instantiate_2_address(&checksum1, &creator1, &salt1, msg1).unwrap(), expected ); // With msg - let expected = AccountId::new(&hex!( - "0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835" - )) - .unwrap(); + let expected = AccountId::new(&hex!("0995499608947a5281e2c7ebd71bdb26a1ad9819")).unwrap(); assert_eq!( build_instantiate_2_address(&checksum1, &creator1, &salt1, msg2).unwrap(), expected ); // Long msg - let expected = AccountId::new(&hex!( - "83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167" - )) - .unwrap(); + let expected = AccountId::new(&hex!("83326e554723b15bac664ceabc8a5887e27003ab")).unwrap(); assert_eq!( build_instantiate_2_address(&checksum1, &creator1, &salt1, msg3).unwrap(), expected ); // Long salt - let expected = AccountId::new(&hex!( - "9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564" - )) - .unwrap(); + let expected = AccountId::new(&hex!("9384c6248c0bb171e306fd7da0993ec1e20eba00")).unwrap(); assert_eq!( build_instantiate_2_address(&checksum1, &creator1, &salt2, b"").unwrap(), expected diff --git a/packages/app/src/wasm/vm/cache.rs b/packages/app/src/wasm/vm/cache.rs index 4a4e6bca..55959a0f 100644 --- a/packages/app/src/wasm/vm/cache.rs +++ b/packages/app/src/wasm/vm/cache.rs @@ -479,7 +479,7 @@ mod tests { assert_eq!(res.messages.len(), 0); assert_eq!(res.events.len(), 0); assert_eq!(res.attributes.len(), 0); - assert_eq!(gas_used, 57); + assert_eq!(gas_used, 56); // query the state was written - token_info and total supply let num = writer @@ -677,7 +677,7 @@ mod tests { let cw20::AllAccountsResponse { accounts } = from_json(res).unwrap(); assert_eq!( accounts, - vec![two.to_string(), one.to_string(), three.to_string()] + vec![one.to_string(), two.to_string(), three.to_string()] ); } diff --git a/packages/cosmos/src/tx.rs b/packages/cosmos/src/tx.rs index 48d71525..5fa79197 100644 --- a/packages/cosmos/src/tx.rs +++ b/packages/cosmos/src/tx.rs @@ -185,7 +185,9 @@ mod test { Coin, }; - use layer_std::{AccountId, BankMsg, PubKey, DEFAULT_BECH32_PREFIX}; + use layer_std::{AccountId, BankMsg, PubKey}; + + const DEFAULT_BECH32_PREFIX: &str = "slay3r"; #[test] fn happy_path_tx_parsing() { diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index a788d8dc..512a7d82 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -21,7 +21,6 @@ ripemd = { workspace = true } tracing = { workspace = true } bytes = { workspace = true } hex = { workspace = true } -bech32 = { version = "0.9.1", default-features = false } chrono = { version = "0.4.19", default-features = false, features = ["std"] } derivative = "2.2.0" diff --git a/packages/std/src/account_id.rs b/packages/std/src/account_id.rs index b18ebd02..368fcade 100644 --- a/packages/std/src/account_id.rs +++ b/packages/std/src/account_id.rs @@ -2,23 +2,14 @@ use std::fmt::{Debug, Display, Formatter}; use std::ops::Deref; use ::cosmwasm_schema::serde; -// use bech32::{self, Error as Bech32Error, FromBase32, ToBase32, Variant}; use alloy_primitives::{Address, AddressError}; use cosmwasm_std::{Addr, StdResult}; use cw_storage_plus::{Key, KeyDeserialize, Prefixer, PrimaryKey}; use thiserror::Error; -// pub const ENV_BECH32_PREFIX: Option<&'static str> = std::option_env!("SLAY_BECH32"); -// pub const DEFAULT_BECH32_PREFIX: &str = "slay3r"; - /// Valid lengths of decoded addresses -pub const VALID_ADDR_LENGTH: [usize; 1] = [20usize]; -// pub const VALID_ADDR_LENGTH: [usize; 2] = [20usize, 32usize]; - -// fn bech32_prefix() -> &'static str { -// ENV_BECH32_PREFIX.unwrap_or(DEFAULT_BECH32_PREFIX) -// } +pub const VALID_ADDR_LENGTH: usize = 20; // Note: this is expanded cw_serde macro minus the Debug implementation, as we want to use Display there #[derive(::std::clone::Clone, ::std::cmp::PartialEq, ::cosmwasm_schema::schemars::JsonSchema)] @@ -117,7 +108,7 @@ pub fn must_id(str: &str) -> AccountId { impl AccountId { /// This takes pub fn new(raw: &[u8]) -> Result { - if !VALID_ADDR_LENGTH.contains(&raw.len()) { + if raw.len() != VALID_ADDR_LENGTH { Err(AccountIdError::InvalidLength(raw.len())) } else { Ok(AccountId(raw.to_vec())) @@ -134,7 +125,7 @@ impl AccountId { pub fn unchecked(name: &str) -> Self { // pad to valid length let mut v = name.as_bytes().to_vec(); - v.resize(VALID_ADDR_LENGTH[0], 0u8); + v.resize(VALID_ADDR_LENGTH, 0u8); AccountId(v) } diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 79251340..fb9e087c 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -10,7 +10,7 @@ mod time; mod tx; mod utils; -pub use account_id::{must_id, AccountId, AccountIdError}; +pub use account_id::{must_id, AccountId, AccountIdError, VALID_ADDR_LENGTH}; use cosmwasm_std::Binary; pub use encode::{CoinEncode, HexEncode}; pub use gas::{GasError, GasMeter, GasResult}; From 114327db77cded5072fdc211c4271a6852af4fb6 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 11 Sep 2024 11:54:00 +0200 Subject: [PATCH 4/6] Added address-converter tool --- Cargo.lock | 8 ++++++++ Cargo.toml | 4 +++- packages/std/Cargo.toml | 4 +--- tools/address-converter/Cargo.toml | 10 ++++++++++ tools/address-converter/src/main.rs | 21 +++++++++++++++++++++ 5 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 tools/address-converter/Cargo.toml create mode 100644 tools/address-converter/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 17a06ebf..2ea992f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -278,6 +278,14 @@ dependencies = [ "gimli 0.29.0", ] +[[package]] +name = "address-converter" +version = "0.4.0" +dependencies = [ + "alloy-primitives", + "bech32 0.11.0", +] + [[package]] name = "adler" version = "1.0.2" diff --git a/Cargo.toml b/Cargo.toml index 8b1e1e0e..e596c352 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["app/*", "contracts/*", "packages/*"] +members = ["app/*", "contracts/*", "packages/*", "tools/address-converter"] exclude = ["tools/proto-compiler"] resolver = "2" @@ -72,6 +72,8 @@ cosmos-sdk-proto = { version = "0.18.0", default-features = false, features = [" cw-orch-core = { version = "1"} abstract-cw-multi-test = { version = "1", default-features = false } +alloy-primitives = { version = "0.8.2", default-features = false } + [profile.release] # temporary to speed up testing # lto = true diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 512a7d82..e83691ce 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -23,6 +23,4 @@ bytes = { workspace = true } hex = { workspace = true } chrono = { version = "0.4.19", default-features = false, features = ["std"] } derivative = "2.2.0" - -# TODO: move this up to top level Cargo if it works out -alloy-primitives = { version = "0.8.2", default-features = false } \ No newline at end of file +alloy-primitives = { workspace = true } \ No newline at end of file diff --git a/tools/address-converter/Cargo.toml b/tools/address-converter/Cargo.toml new file mode 100644 index 00000000..d9e5214b --- /dev/null +++ b/tools/address-converter/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "address-converter" +edition.workspace = true +version.workspace = true +license.workspace = true +exclude.workspace = true + +[dependencies] +bech32 = { version = "0.11" } +alloy-primitives = { workspace = true } \ No newline at end of file diff --git a/tools/address-converter/src/main.rs b/tools/address-converter/src/main.rs new file mode 100644 index 00000000..a22447ef --- /dev/null +++ b/tools/address-converter/src/main.rs @@ -0,0 +1,21 @@ +use std::env; + +use alloy_primitives::Address; + +// Usage: cargo run slay3r1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmvk3r3j + +fn main() { + let args: Vec<_> = env::args().collect(); + if args.len() < 2 { + println!("Usage: address-converter ..."); + return; + } + for addr in &args[1..] { + let (_, data) = bech32::decode(addr).unwrap(); + if data.len() != 20 { + println!("{} isn't 20 bytes long", addr); + } + let addr = Address(data.as_slice().try_into().unwrap()); + println!("{}", addr); + } +} From 23bb91d4af72620dc8270912768b4a3bf93968c8 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 11 Sep 2024 12:05:43 +0200 Subject: [PATCH 5/6] All tests pass except one with cosmrs signing --- packages/app/src/app.rs | 8 +++++--- packages/app/src/testing/hackatom.rs | 4 +++- packages/cosmos/src/legacy.rs | 22 +++++++++++----------- packages/cosmos/src/query.rs | 1 + packages/cosmos/src/tx.rs | 2 ++ packages/golem/src/signer.rs | 4 ++-- 6 files changed, 24 insertions(+), 17 deletions(-) diff --git a/packages/app/src/app.rs b/packages/app/src/app.rs index 440bd0af..a42b7708 100644 --- a/packages/app/src/app.rs +++ b/packages/app/src/app.rs @@ -517,8 +517,10 @@ mod tests { // query account + balances for update fn transaction_workflow(storage: T) { // TODO: convert bech32 to 0x checksummed (make script) - let sender = must_id("slay3r1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmvk3r3j"); - let recipient = must_id("slay3r1y5hl7x8hxl72dc9gu920eaz6l7vhl0luu6s70h"); + let sender = must_id("0x0d82b1E7c96dbfA42462fE612932e6bfF111D51B"); + let recipient = must_id("0x252fFf18f737fcA6E0A8E154FCf45aFf997fBFFc"); + // let sender = must_id("slay3r1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmvk3r3j"); + // let recipient = must_id("slay3r1y5hl7x8hxl72dc9gu920eaz6l7vhl0luu6s70h"); let denom: &str = "uslay"; let expected_gas = 16_000u64; @@ -578,7 +580,7 @@ mod tests { recipient: recipient.clone(), amount: coins(2_000_000, denom), })], - signer: must_id("slay3r1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmvk3r3j"), + signer: must_id("0x0d82b1E7c96dbfA42462fE612932e6bfF111D51B"), signing_info: SigningInfo { message_hash: Binary::from( hex!("6d368a4b8436e0b19a2d06069e0b70086ba7c40e91a9d04d31946c10346d79a9") diff --git a/packages/app/src/testing/hackatom.rs b/packages/app/src/testing/hackatom.rs index b6f85240..73d0ef6d 100644 --- a/packages/app/src/testing/hackatom.rs +++ b/packages/app/src/testing/hackatom.rs @@ -310,7 +310,9 @@ fn error_handling_from_api_call() { match err { PulsarError::Wasm(WasmError::Contract(msg)) => { assert!( - msg.starts_with("Generic error: addr_validate errored: Bech32:"), + msg.starts_with( + "Generic error: addr_validate errored: Address: invalid string length" + ), "Unexpected error message: {}", msg ); diff --git a/packages/cosmos/src/legacy.rs b/packages/cosmos/src/legacy.rs index 1b99e8c6..d6a5490d 100644 --- a/packages/cosmos/src/legacy.rs +++ b/packages/cosmos/src/legacy.rs @@ -271,10 +271,12 @@ mod tests { age: 32, height: Some(187), }; + // cargo run slay3r1ve6ku6mevd5xjcmtv4hqqqqqqqqqqqqqc5nacv slay3r1vfkxzcmtdphkcetndahqqqqqqqqqqqqqyet8zv + // + // let exec_msg = Msg::Wasm(WasmMsg::Execute { - sender: AccountId::parse_string("slay3r1ve6ku6mevd5xjcmtv4hqqqqqqqqqqqqqc5nacv") - .unwrap(), - contract_addr: AccountId::parse_string("slay3r1vfkxzcmtdphkcetndahqqqqqqqqqqqqqyet8zv") + sender: AccountId::parse_string("0x66756e6b79636869636b656E0000000000000000").unwrap(), + contract_addr: AccountId::parse_string("0x626C61636b686F6c65736f6E0000000000000000") .unwrap(), msg: serde_json::to_vec(&orig_msg).unwrap().into(), funds: vec![], @@ -282,7 +284,7 @@ mod tests { let amino_msg = AminoMsg::build(&exec_msg); let output = serde_json::to_string(&amino_msg).unwrap(); - let expected = r#"{"type":"wasm/MsgExecuteContract","value":{"contract":"slay3r1vfkxzcmtdphkcetndahqqqqqqqqqqqqqyet8zv","funds":[],"msg":{"age":32,"height":187,"name":"John Smith"},"sender":"slay3r1ve6ku6mevd5xjcmtv4hqqqqqqqqqqqqqc5nacv"}}"#; + let expected = r#"{"type":"wasm/MsgExecuteContract","value":{"contract":"0x626C61636b686F6c65736f6E0000000000000000","funds":[],"msg":{"age":32,"height":187,"name":"John Smith"},"sender":"0x66756e6b79636869636b656E0000000000000000"}}"#; assert_eq!(output, expected); } @@ -294,10 +296,9 @@ mod tests { height: Some(165), }; let init_msg = Msg::Wasm(WasmMsg::Instantiate { - sender: AccountId::parse_string("slay3r1ve6ku6mevd5xjcmtv4hqqqqqqqqqqqqqc5nacv") - .unwrap(), + sender: AccountId::parse_string("0x66756e6b79636869636b656E0000000000000000").unwrap(), admin: Some( - AccountId::parse_string("slay3r1vfkxzcmtdphkcetndahqqqqqqqqqqqqqyet8zv").unwrap(), + AccountId::parse_string("0x626C61636b686F6c65736f6E0000000000000000").unwrap(), ), code_id: 12345, label: "sticky".into(), @@ -307,7 +308,7 @@ mod tests { let amino_msg = AminoMsg::build(&init_msg); let output = serde_json::to_string(&amino_msg).unwrap(); - let expected = r#"{"type":"wasm/MsgInstantiateContract","value":{"admin":"slay3r1vfkxzcmtdphkcetndahqqqqqqqqqqqqqyet8zv","code_id":"12345","funds":[{"amount":"1234","denom":"uslay"}],"label":"sticky","msg":{"age":18,"height":165,"name":"n00b"},"sender":"slay3r1ve6ku6mevd5xjcmtv4hqqqqqqqqqqqqqc5nacv"}}"#; + let expected = r#"{"type":"wasm/MsgInstantiateContract","value":{"admin":"0x626C61636b686F6c65736f6E0000000000000000","code_id":"12345","funds":[{"amount":"1234","denom":"uslay"}],"label":"sticky","msg":{"age":18,"height":165,"name":"n00b"},"sender":"0x66756e6b79636869636b656E0000000000000000"}}"#; assert_eq!(output, expected); } @@ -320,8 +321,7 @@ mod tests { height: Some(165), }; let init_msg = Msg::Wasm(WasmMsg::Instantiate { - sender: AccountId::parse_string("slay3r1ve6ku6mevd5xjcmtv4hqqqqqqqqqqqqqc5nacv") - .unwrap(), + sender: AccountId::parse_string("0x66756e6b79636869636b656E0000000000000000").unwrap(), admin: None, code_id: 12345, label: "sticky".into(), @@ -331,7 +331,7 @@ mod tests { let amino_msg = AminoMsg::build(&init_msg); let output = serde_json::to_string(&amino_msg).unwrap(); - let expected = r#"{"type":"wasm/MsgInstantiateContract","value":{"code_id":"12345","funds":[],"label":"sticky","msg":{"age":18,"height":165,"name":"n00b"},"sender":"slay3r1ve6ku6mevd5xjcmtv4hqqqqqqqqqqqqqc5nacv"}}"#; + let expected = r#"{"type":"wasm/MsgInstantiateContract","value":{"code_id":"12345","funds":[],"label":"sticky","msg":{"age":18,"height":165,"name":"n00b"},"sender":"0x66756e6b79636869636b656E0000000000000000"}}"#; assert_eq!(output, expected); } } diff --git a/packages/cosmos/src/query.rs b/packages/cosmos/src/query.rs index 12951dc4..e55b93bf 100644 --- a/packages/cosmos/src/query.rs +++ b/packages/cosmos/src/query.rs @@ -406,6 +406,7 @@ mod tests { use hex_literal::hex; #[test] + #[ignore = "need to get new data with 0x address"] fn parse_simulate() { let path = "/cosmos.tx.v1beta1.Service/Simulate"; let data = hex!("1282020AAB010A91010A1C2F636F736D6F732E62616E6B2E763162657461312E4D736753656E6412710A2D736C6179337231706B707472653766646B6C366766727A6C65736A6A766878686C63337234676D766B3372336A122D736C6179337231757A3479303579387366736D75657A61616B70706D68326470636667797A72716439723063611A110A067570756C7365120732303030303030121555736520796F757220706F77657220776973656C7912500A4C0A460A1F2F636F736D6F732E63727970746F2E736563703235366B312E5075624B657912230A21034F04181EEBA35391B858633A765C4A0C189697B40D216354D50890D350C7029012020A0012001A00"); diff --git a/packages/cosmos/src/tx.rs b/packages/cosmos/src/tx.rs index 5fa79197..5ba0159e 100644 --- a/packages/cosmos/src/tx.rs +++ b/packages/cosmos/src/tx.rs @@ -189,6 +189,8 @@ mod test { const DEFAULT_BECH32_PREFIX: &str = "slay3r"; + // TODO: this is broken as cosmrs seems to require bech32 - we can otherwise encode the id, but the MsgSend creation below + // requires the bech32 objects from cosmrs. Anyway around this? Or alternatives to cosmrs? #[test] fn happy_path_tx_parsing() { let sender_private_key = secp256k1::SigningKey::random(); diff --git a/packages/golem/src/signer.rs b/packages/golem/src/signer.rs index ca2295b9..e1a0fc67 100644 --- a/packages/golem/src/signer.rs +++ b/packages/golem/src/signer.rs @@ -95,14 +95,14 @@ mod tests { assert_eq!( key.account(), - AccountId::parse_string("slay3r1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmvk3r3j").unwrap() + AccountId::parse_string("0x0d82b1E7c96dbfA42462fE612932e6bfF111D51B").unwrap() // AccountId::parse_string("slay3r1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmvk3r3j").unwrap() ); assert_eq!(key.index(), 0); let key2 = key.with_index(1); assert_eq!( key2.account(), - AccountId::parse_string("slay3r10dyr9899g6t0pelew4nvf4j5c3jcgv0rf3kguu").unwrap() + AccountId::parse_string("0x7b48329ca54696F0e7F97566C4d654C4658431e3").unwrap() // AccountId::parse_string("slay3r10dyr9899g6t0pelew4nvf4j5c3jcgv0rf3kguu").unwrap() ); assert_eq!(key2.index(), 1); } From dae786186bfc2c59755e2ae72845628ca9d963b1 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 11 Sep 2024 17:01:12 +0200 Subject: [PATCH 6/6] Improve dockerfile for building localnode --- docker/Dockerfile.slay3rd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker/Dockerfile.slay3rd b/docker/Dockerfile.slay3rd index 33f56790..fdcb676c 100644 --- a/docker/Dockerfile.slay3rd +++ b/docker/Dockerfile.slay3rd @@ -33,6 +33,10 @@ COPY packages/std/Cargo.toml /myapp/packages/std/Cargo.toml COPY dummy.rs /myapp/packages/std/src/lib.rs COPY packages/storage/Cargo.toml /myapp/packages/storage/Cargo.toml COPY dummy.rs /myapp/packages/storage/src/lib.rs +COPY tools/proto-compiler/Cargo.toml /myapp/tools/proto-compiler/Cargo.toml +COPY dummy.rs /myapp/tools/proto-compiler/src/lib.rs +COPY tools/address-converter/Cargo.toml /myapp/tools/address-converter/Cargo.toml +COPY dummy.rs /myapp/tools/address-converter/src/lib.rs RUN cargo build --release --bin slay3rd # clean up these fake local deps so we compile for real later