Skip to content

New error type #2500

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

Merged
merged 25 commits into from
Jun 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4c53801
New error type. Now with 99% less enum cases
aumetra Jun 16, 2025
f5c7fdb
Fix errors in contracts, fix scripts
aumetra Jun 16, 2025
4c9d104
Fix all contract tests
aumetra Jun 16, 2025
e49fc0e
Fix integration tests
aumetra Jun 17, 2025
20ddb4f
Update contracts/ibc-reflect-send/src/state.rs
aumetra Jun 17, 2025
8a52942
Update contracts/ibc-reflect/src/state.rs
aumetra Jun 17, 2025
f440516
Update contracts/ibc-reflect-send/src/state.rs
aumetra Jun 17, 2025
9100b07
Update contracts/ibc-reflect/src/state.rs
aumetra Jun 17, 2025
2ff4638
Change back sed command
aumetra Jun 17, 2025
a243529
Also check for ConversionOverflowError
aumetra Jun 17, 2025
327d14a
Check for overflow
aumetra Jun 17, 2025
7e15a85
Fix test errors
aumetra Jun 17, 2025
2e7f8b8
Update packages/crypto/testdata/extract_sig_gen.sh
aumetra Jun 17, 2025
ebb6e57
Update contracts/staking/src/state.rs
aumetra Jun 17, 2025
c68a5ce
Update contracts/staking/src/state.rs
aumetra Jun 17, 2025
21368f3
Update contracts/hackatom/src/contract.rs
aumetra Jun 17, 2025
d10b4bc
Update contracts/hackatom/src/contract.rs
aumetra Jun 17, 2025
fb99869
Update contracts/hackatom/src/contract.rs
aumetra Jun 17, 2025
e2c33a9
Update contracts/ibc-callbacks/src/state.rs
aumetra Jun 18, 2025
079bbf1
Update contracts/reflect/src/state.rs
aumetra Jun 18, 2025
050445d
Update contracts/reflect/src/state.rs
aumetra Jun 18, 2025
34eacf2
Format
aumetra Jun 18, 2025
0d3a2a0
thiserror compatibility
aumetra Jun 18, 2025
8a0548f
Merge branch 'main' into aw/new-error
aumetra Jun 20, 2025
3bba20c
Add Changelog entry
aumetra Jun 20, 2025
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ and this project adheres to
- cosmwasm-std: Split up `Validator` type into `Validator` and
`ValidatorMetadata` to allow adding more fields to `ValidatorResponse` in the
future. ([#2501])
- cosmwasm-std: Redesigned `StdError` to be more flexible and less immutable
([#2500])

## Fixed

Expand Down Expand Up @@ -149,6 +151,7 @@ and this project adheres to
[#2480]: https://github.com/CosmWasm/cosmwasm/pull/2480
[#2484]: https://github.com/CosmWasm/cosmwasm/pull/2484
[#2495]: https://github.com/CosmWasm/cosmwasm/pull/2495
[#2500]: https://github.com/CosmWasm/cosmwasm/pull/2500
[#2501]: https://github.com/CosmWasm/cosmwasm/pull/2501

## [2.2.0] - 2024-12-17
Expand Down
21 changes: 8 additions & 13 deletions contracts/burner/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub fn instantiate(
_info: MessageInfo,
_msg: InstantiateMsg,
) -> StdResult<Response> {
Err(StdError::generic_err(
Err(StdError::msg(
"You can only use this contract for migrations",
))
}
Expand All @@ -23,7 +23,7 @@ pub fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> StdResult<Response>
let denom_len = msg.denoms.len();
let denoms = BTreeSet::<String>::from_iter(msg.denoms); // Ensure uniqueness
if denoms.len() != denom_len {
return Err(StdError::generic_err("Denoms not unique"));
return Err(StdError::msg("Denoms not unique"));
}

// get balance and send to recipient
Expand Down Expand Up @@ -98,7 +98,7 @@ mod tests {
use cosmwasm_std::testing::{
message_info, mock_dependencies, mock_dependencies_with_balance, mock_env,
};
use cosmwasm_std::{coin, coins, Attribute, StdError, Storage, SubMsg};
use cosmwasm_std::{coin, coins, Attribute, Storage, SubMsg};

/// Gets the value of the first attribute with the given key
fn first_attr(data: impl AsRef<[Attribute]>, search_key: &str) -> Option<String> {
Expand All @@ -121,12 +121,10 @@ mod tests {
let info = message_info(&creator, &coins(1000, "earth"));
// we can just call .unwrap() to assert this was a success
let res = instantiate(deps.as_mut(), mock_env(), info, msg);
match res.unwrap_err() {
StdError::GenericErr { msg, .. } => {
assert_eq!(msg, "You can only use this contract for migrations")
}
_ => panic!("expected migrate error message"),
}
assert!(res
.unwrap_err()
.to_string()
.ends_with("You can only use this contract for migrations"));
}

#[test]
Expand All @@ -142,10 +140,7 @@ mod tests {
delete: 0,
};
let err = migrate(deps.as_mut(), mock_env(), msg).unwrap_err();
match err {
StdError::GenericErr { msg, .. } => assert_eq!(msg, "Denoms not unique"),
err => panic!("Unexpected error: {err:?}"),
}
assert!(err.to_string().ends_with("Denoms not unique"));

// One denom
let msg = MigrateMsg {
Expand Down
2 changes: 1 addition & 1 deletion contracts/burner/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn instantiate_fails() {
let msg = res.unwrap_err();
assert_eq!(
msg,
"Generic error: You can only use this contract for migrations"
"kind: Other, error: You can only use this contract for migrations"
);
}

Expand Down
32 changes: 10 additions & 22 deletions contracts/crypto-verify/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ pub fn query_verify_ethereum_text(
// Decompose signature
let (v, rs) = match signature.split_last() {
Some(pair) => pair,
None => return Err(StdError::generic_err("Signature must not be empty")),
None => return Err(StdError::msg("Signature must not be empty")),
};
let recovery = get_recovery_param(*v)?;

Expand Down Expand Up @@ -326,7 +326,7 @@ mod tests {
use cosmwasm_std::testing::{
message_info, mock_dependencies, mock_env, MockApi, MockQuerier, MockStorage,
};
use cosmwasm_std::{from_json, OwnedDeps, RecoverPubkeyError, VerificationError};
use cosmwasm_std::{from_json, OwnedDeps, StdErrorKind};
use hex_literal::hex;

const CREATOR: &str = "creator";
Expand Down Expand Up @@ -426,11 +426,8 @@ mod tests {
let res = query(deps.as_ref(), mock_env(), verify_msg);
assert!(res.is_err());
assert!(matches!(
res.unwrap_err(),
StdError::VerificationErr {
source: VerificationError::InvalidPubkeyFormat,
..
}
res.unwrap_err().kind(),
StdErrorKind::Cryptography,
))
}

Expand Down Expand Up @@ -500,11 +497,8 @@ mod tests {
signer_address: signer_address.into(),
};
let result = query(deps.as_ref(), mock_env(), verify_msg);
match result.unwrap_err() {
StdError::RecoverPubkeyErr {
source: RecoverPubkeyError::UnknownErr { .. },
..
} => {}
match result.unwrap_err().kind() {
StdErrorKind::Cryptography => {}
err => panic!("Unexpected error: {err:?}"),
}
}
Expand Down Expand Up @@ -715,11 +709,8 @@ mod tests {
let res = query(deps.as_ref(), mock_env(), verify_msg);
assert!(res.is_err());
assert!(matches!(
res.unwrap_err(),
StdError::VerificationErr {
source: VerificationError::InvalidPubkeyFormat,
..
}
res.unwrap_err().kind(),
StdErrorKind::Cryptography
))
}

Expand Down Expand Up @@ -781,11 +772,8 @@ mod tests {
let res = query(deps.as_ref(), mock_env(), verify_msg);
assert!(res.is_err());
assert!(matches!(
res.unwrap_err(),
StdError::VerificationErr {
source: VerificationError::InvalidPubkeyFormat,
..
}
res.unwrap_err().kind(),
StdErrorKind::Cryptography,
))
}

Expand Down
18 changes: 8 additions & 10 deletions contracts/crypto-verify/src/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ pub fn get_recovery_param(v: u8) -> StdResult<u8> {
match v {
27 => Ok(0),
28 => Ok(1),
_ => Err(StdError::generic_err("Values of v other than 27 and 28 not supported. Replay protection (EIP-155) cannot be used here."))
_ => Err(StdError::msg("Values of v other than 27 and 28 not supported. Replay protection (EIP-155) cannot be used here."))
}
}

Expand All @@ -87,7 +87,7 @@ pub fn get_recovery_param_with_chain_id(v: u64, chain_id: u64) -> StdResult<u8>
let recovery = v - chain_id * 2 - 35;
match recovery {
0 | 1 => Ok(recovery as u8),
_ => Err(StdError::generic_err(format!(
_ => Err(StdError::msg(format_args!(
"Calculated recovery parameter must be 0 or 1 but is {recovery}."
))),
}
Expand All @@ -97,13 +97,13 @@ pub fn get_recovery_param_with_chain_id(v: u64, chain_id: u64) -> StdResult<u8>
pub fn ethereum_address_raw(pubkey: &[u8]) -> StdResult<[u8; 20]> {
let (tag, data) = match pubkey.split_first() {
Some(pair) => pair,
None => return Err(StdError::generic_err("Public key must not be empty")),
None => return Err(StdError::msg("Public key must not be empty")),
};
if *tag != 0x04 {
return Err(StdError::generic_err("Public key must start with 0x04"));
return Err(StdError::msg("Public key must start with 0x04"));
}
if data.len() != 64 {
return Err(StdError::generic_err("Public key must be 65 bytes long"));
return Err(StdError::msg("Public key must be 65 bytes long"));
}

let hash = Keccak256::digest(data);
Expand All @@ -112,14 +112,12 @@ pub fn ethereum_address_raw(pubkey: &[u8]) -> StdResult<[u8; 20]> {

pub fn decode_address(input: &str) -> StdResult<[u8; 20]> {
if input.len() != 42 {
return Err(StdError::generic_err(
"Ethereum address must be 42 characters long",
));
return Err(StdError::msg("Ethereum address must be 42 characters long"));
}
if !input.starts_with("0x") {
return Err(StdError::generic_err("Ethereum address must start with 0x"));
return Err(StdError::msg("Ethereum address must start with 0x"));
}
let data = hex::decode(&input[2..]).map_err(|_| StdError::generic_err("hex decoding error"))?;
let data = hex::decode(&input[2..])?;
Ok(data.try_into().unwrap())
}

Expand Down
10 changes: 5 additions & 5 deletions contracts/crypto-verify/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ fn cosmos_signature_verify_errors() {
let res = query(&mut deps, mock_env(), verify_msg);
assert_eq!(
res.unwrap_err(),
"Verification error: Invalid public key format"
"kind: Cryptography, error: Invalid public key format"
)
}

Expand Down Expand Up @@ -283,7 +283,7 @@ fn secp256r1_signature_verify_errors() {
let res = query(&mut deps, mock_env(), verify_msg);
assert_eq!(
res.unwrap_err(),
"Verification error: Invalid public key format"
"kind: Cryptography, error: Invalid public key format"
)
}

Expand Down Expand Up @@ -354,7 +354,7 @@ fn ethereum_signature_verify_fails_for_corrupted_signature() {
};
let result = query(&mut deps, mock_env(), verify_msg);
let msg = result.unwrap_err();
assert_eq!(msg, "Recover pubkey error: Unknown error: 10");
assert_eq!(msg, "kind: Cryptography, error: Unknown error: 10");
}

#[test]
Expand Down Expand Up @@ -466,7 +466,7 @@ fn tendermint_signature_verify_errors() {
let res = query(&mut deps, mock_env(), verify_msg);
assert_eq!(
res.unwrap_err(),
"Verification error: Invalid public key format"
"kind: Cryptography, error: Invalid public key format"
)
}

Expand Down Expand Up @@ -625,7 +625,7 @@ fn tendermint_signatures_batch_verify_errors() {
let res = query(&mut deps, mock_env(), verify_msg);
assert_eq!(
res.unwrap_err(),
"Verification error: Invalid public key format"
"kind: Cryptography, error: Invalid public key format"
)
}

Expand Down
9 changes: 4 additions & 5 deletions contracts/cyberpunk/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ fn execute_argon2(mem_cost: u32, time_cost: u32) -> Result<Response, ContractErr
ad: &[],
hash_length: 32,
};
let hash = argon2::hash_encoded(password, salt, &config)
.map_err(|e| StdError::generic_err(format!("hash_encoded errored: {e}")))?;
let hash = argon2::hash_encoded(password, salt, &config).map_err(StdError::from)?;
// let matches = argon2::verify_encoded(&hash, password).unwrap();
// assert!(matches);
Ok(Response::new().set_data(hash.into_bytes()))
Expand Down Expand Up @@ -106,13 +105,13 @@ fn execute_allocate_large_memory(pages: u32) -> Result<Response, ContractError>
use core::arch::wasm32;
let old_size = wasm32::memory_grow(0, pages as usize);
if old_size == usize::max_value() {
return Err(StdError::generic_err("memory.grow failed").into());
return Err(StdError::msg("memory.grow failed").into());
}
Ok(Response::new().set_data((old_size as u32).to_be_bytes()))
}

#[cfg(not(target_arch = "wasm32"))]
Err(StdError::generic_err("Unsupported architecture").into())
Err(StdError::msg("Unsupported architecture").into())
}

fn execute_panic() -> Result<Response, ContractError> {
Expand All @@ -139,7 +138,7 @@ fn execute_unreachable() -> Result<Response, ContractError> {
core::arch::wasm32::unreachable();

#[cfg(not(target_arch = "wasm32"))]
Err(StdError::generic_err("Unsupported architecture").into())
Err(StdError::msg("Unsupported architecture").into())
}

fn execute_mirror_env(env: Env) -> Result<Response, ContractError> {
Expand Down
2 changes: 1 addition & 1 deletion contracts/cyberpunk/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use cosmwasm_std::StdError;
use thiserror::Error;

#[derive(Error, Debug, PartialEq)]
#[derive(Error, Debug)]
pub enum ContractError {
#[error("{0}")]
/// this is needed so we can use `bucket.load(...)?` and have it auto-converted to the custom error
Expand Down
Loading
Loading