From cb8a2ea7e9875370aa68769a5b2a50f4ead0917a Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Thu, 22 Feb 2024 11:15:08 -0300 Subject: [PATCH 1/5] change inner type, add convetion and tests --- packages/neutron-sdk/src/errors/error.rs | 5 +- .../src/interchain_queries/v045/testing.rs | 97 ++++++++++++++++++- .../src/interchain_queries/v045/types.rs | 33 +++++-- 3 files changed, 123 insertions(+), 12 deletions(-) diff --git a/packages/neutron-sdk/src/errors/error.rs b/packages/neutron-sdk/src/errors/error.rs index bb05d320..566a7a3a 100644 --- a/packages/neutron-sdk/src/errors/error.rs +++ b/packages/neutron-sdk/src/errors/error.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{DecimalRangeExceeded, OverflowError, StdError}; +use cosmwasm_std::{Decimal256RangeExceeded, DecimalRangeExceeded, OverflowError, StdError}; use serde_json_wasm; use thiserror::Error; @@ -33,6 +33,9 @@ pub enum NeutronError { #[error("Decimal range exceeded")] DecimalRangeExceeded(#[from] DecimalRangeExceeded), + #[error("Decimal256 range exceeded")] + Decimal256RangeExceeded(#[from] Decimal256RangeExceeded), + #[error("Overflow error")] OverflowError(#[from] OverflowError), diff --git a/packages/neutron-sdk/src/interchain_queries/v045/testing.rs b/packages/neutron-sdk/src/interchain_queries/v045/testing.rs index 10648784..85376c00 100644 --- a/packages/neutron-sdk/src/interchain_queries/v045/testing.rs +++ b/packages/neutron-sdk/src/interchain_queries/v045/testing.rs @@ -26,10 +26,11 @@ use cosmos_sdk_proto::cosmos::staking::v1beta1::{ }; use cosmos_sdk_proto::traits::Message; use cosmwasm_std::{ - to_json_binary, Addr, Binary, Coin as StdCoin, Decimal, Delegation as StdDelegation, Timestamp, - Uint128, + to_json_binary, Addr, Binary, Coin as StdCoin, Decimal, Decimal256, + Delegation as StdDelegation, Timestamp, Uint128, }; use hex; +use std::ops::Div; use std::ops::Mul; use std::str::FromStr; @@ -1150,3 +1151,95 @@ fn test_unbonding_delegations_reconstruct_from_hex() { } ); } + +#[test] +fn overflov_test() { + let delegation_shares = Decimal256::from_str("960000020000").unwrap(); + let validator_tokens = Decimal256::from_str("967000020000").unwrap(); + let delegator_shares = Decimal256::from_str("967000020000").unwrap(); + + println!("validator.tokens {:?}", validator_tokens); + println!("delegation_shares {:?}", delegation_shares); + println!("delegator_shares {:?}", delegator_shares); + let delegated_tokens = delegation_shares + .checked_mul(validator_tokens) + .unwrap() + .div(delegator_shares); + println!("{:?}", delegated_tokens); +} + +#[test] +fn test_delegations_reconstruct_overflow() { + struct TestCase { + stake_denom: String, + delegations: Vec, + validators: Vec, + expected_result: NeutronResult, + } + let test_cases: Vec = vec![TestCase { + stake_denom: "stake".to_string(), + delegations: vec![Delegation { + delegator_address: "osmo1yz54ncxj9csp7un3xled03q6thrrhy9cztkfzs".to_string(), + validator_address: "osmovaloper1r2u5q6t6w0wssrk6l66n3t2q3dw2uqny4gj2e3".to_string(), + shares: "960000020000".to_string(), + }], + validators: vec![Validator { + operator_address: "osmovaloper1r2u5q6t6w0wssrk6l66n3t2q3dw2uqny4gj2e3".to_string(), + consensus_pubkey: None, + jailed: false, + status: 0, + tokens: "967000020000".to_string(), + delegator_shares: "967000020000".to_string(), + description: None, + unbonding_height: 0, + unbonding_time: None, + commission: None, + min_self_delegation: "".to_string(), + }], + expected_result: Ok(Delegations { + delegations: vec![StdDelegation { + delegator: Addr::unchecked("osmo1yz54ncxj9csp7un3xled03q6thrrhy9cztkfzs"), + validator: "osmovaloper1r2u5q6t6w0wssrk6l66n3t2q3dw2uqny4gj2e3".to_string(), + amount: StdCoin::new(960000020000u128, "stake"), + }], + }), + }]; + + for ts in &test_cases { + // prepare storage values + let mut st_values: Vec = vec![StorageValue { + storage_prefix: STAKING_STORE_KEY.to_string(), + key: Binary(create_params_store_key(STAKING_STORE_KEY, KEY_BOND_DENOM)), + value: { + if ts.stake_denom.is_empty() { + return Default::default(); + } + to_json_binary(&ts.stake_denom).unwrap() + }, + }]; + + for (i, d) in ts.delegations.iter().enumerate() { + let delegator_addr = decode_and_convert(&d.delegator_address).unwrap(); + let val_addr = decode_and_convert(&d.validator_address).unwrap(); + + st_values.push(StorageValue { + storage_prefix: STAKING_STORE_KEY.to_string(), + key: Binary(create_delegation_key(&delegator_addr, &val_addr).unwrap()), + value: Binary::from(d.encode_to_vec()), + }); + + if let Some(v) = ts.validators.get(i) { + st_values.push(StorageValue { + storage_prefix: STAKING_STORE_KEY.to_string(), + key: Binary(create_validator_key(&val_addr).unwrap()), + value: Binary::from(v.encode_to_vec()), + }); + } + } + + // test reconstruction + let delegations = Delegations::reconstruct(&st_values); + + assert_eq!(delegations, ts.expected_result) + } +} diff --git a/packages/neutron-sdk/src/interchain_queries/v045/types.rs b/packages/neutron-sdk/src/interchain_queries/v045/types.rs index 74113236..da6ba1c9 100644 --- a/packages/neutron-sdk/src/interchain_queries/v045/types.rs +++ b/packages/neutron-sdk/src/interchain_queries/v045/types.rs @@ -11,7 +11,9 @@ use cosmos_sdk_proto::cosmos::{ staking::v1beta1::{Delegation, UnbondingDelegation, Validator as CosmosValidator}, }; use cosmos_sdk_proto::traits::Message; -use cosmwasm_std::{from_json, Addr, Coin, Decimal, StdError, Timestamp, Uint128}; +use cosmwasm_std::{ + from_json, Addr, Coin, Decimal, Decimal256, StdError, Timestamp, Uint128, Uint256, +}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{ops::Div, str::FromStr}; @@ -443,15 +445,18 @@ impl KVReconstruct for Delegations { } let validator: CosmosValidator = CosmosValidator::decode(chunk[1].value.as_slice())?; - let delegation_shares = - Decimal::from_atomics(Uint128::from_str(&delegation_sdk.shares)?, DECIMAL_PLACES)?; + let delegation_shares = Decimal256::from_atomics( + Uint256::from_str(&delegation_sdk.shares)?, + DECIMAL_PLACES, + )?; - let delegator_shares = Decimal::from_atomics( - Uint128::from_str(&validator.delegator_shares)?, + let delegator_shares = Decimal256::from_atomics( + Uint256::from_str(&validator.delegator_shares)?, DECIMAL_PLACES, )?; - let validator_tokens = Decimal::from_atomics(Uint128::from_str(&validator.tokens)?, 0)?; + let validator_tokens = + Decimal256::from_atomics(Uint128::from_str(&validator.tokens)?, 0)?; // https://github.com/cosmos/cosmos-sdk/blob/35ae2c4c72d4aeb33447d5a7af23ca47f786606e/x/staking/keeper/querier.go#L463 // delegated_tokens = quotient(delegation.shares * validator.tokens / validator.total_shares); @@ -459,10 +464,9 @@ impl KVReconstruct for Delegations { .checked_mul(validator_tokens)? .div(delegator_shares) .atomics() - .u128() - .div(DECIMAL_FRACTIONAL); + .div(Uint256::from_u128(DECIMAL_FRACTIONAL)); - delegation_std.amount = Coin::new(delegated_tokens, &denom); + delegation_std.amount = Coin::new(uint256_to_u128(delegated_tokens)?, &denom); delegations.push(delegation_std); } @@ -471,6 +475,17 @@ impl KVReconstruct for Delegations { } } +fn uint256_to_u128(value: Uint256) -> Result { + // Convert Uint256 to string + let value_str = value.to_string(); + + // Attempt to parse the string as u128 + match value_str.parse::() { + Ok(parsed_value) => Ok(parsed_value), + Err(_) => Err(StdError::generic_err("Uint256 value exceeds u128 limits")), + } +} + /// Represents a single unbonding delegation from some validator to some delegator on remote chain #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct UnbondingEntry { From b97f90c6292ee153661dde48c7619c5395b2a978 Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Thu, 22 Feb 2024 15:34:46 -0300 Subject: [PATCH 2/5] use the max possible numbers to cover corner case --- .../neutron-sdk/src/interchain_queries/v045/testing.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/neutron-sdk/src/interchain_queries/v045/testing.rs b/packages/neutron-sdk/src/interchain_queries/v045/testing.rs index 85376c00..896ed109 100644 --- a/packages/neutron-sdk/src/interchain_queries/v045/testing.rs +++ b/packages/neutron-sdk/src/interchain_queries/v045/testing.rs @@ -1181,15 +1181,15 @@ fn test_delegations_reconstruct_overflow() { delegations: vec![Delegation { delegator_address: "osmo1yz54ncxj9csp7un3xled03q6thrrhy9cztkfzs".to_string(), validator_address: "osmovaloper1r2u5q6t6w0wssrk6l66n3t2q3dw2uqny4gj2e3".to_string(), - shares: "960000020000".to_string(), + shares: "340282366920938463463".to_string(), }], validators: vec![Validator { operator_address: "osmovaloper1r2u5q6t6w0wssrk6l66n3t2q3dw2uqny4gj2e3".to_string(), consensus_pubkey: None, jailed: false, status: 0, - tokens: "967000020000".to_string(), - delegator_shares: "967000020000".to_string(), + tokens: "340282366920938463463".to_string(), + delegator_shares: "340282366920938463463".to_string(), description: None, unbonding_height: 0, unbonding_time: None, @@ -1200,7 +1200,7 @@ fn test_delegations_reconstruct_overflow() { delegations: vec![StdDelegation { delegator: Addr::unchecked("osmo1yz54ncxj9csp7un3xled03q6thrrhy9cztkfzs"), validator: "osmovaloper1r2u5q6t6w0wssrk6l66n3t2q3dw2uqny4gj2e3".to_string(), - amount: StdCoin::new(960000020000u128, "stake"), + amount: StdCoin::new(340282366920938463463u128, "stake"), }], }), }]; From 8d21eecc80a010378051f19a3fb0f0bd697ca4e4 Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Fri, 23 Feb 2024 09:39:06 -0300 Subject: [PATCH 3/5] rm useless test --- .../src/interchain_queries/v045/testing.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/neutron-sdk/src/interchain_queries/v045/testing.rs b/packages/neutron-sdk/src/interchain_queries/v045/testing.rs index 896ed109..4dc8982a 100644 --- a/packages/neutron-sdk/src/interchain_queries/v045/testing.rs +++ b/packages/neutron-sdk/src/interchain_queries/v045/testing.rs @@ -1152,22 +1152,6 @@ fn test_unbonding_delegations_reconstruct_from_hex() { ); } -#[test] -fn overflov_test() { - let delegation_shares = Decimal256::from_str("960000020000").unwrap(); - let validator_tokens = Decimal256::from_str("967000020000").unwrap(); - let delegator_shares = Decimal256::from_str("967000020000").unwrap(); - - println!("validator.tokens {:?}", validator_tokens); - println!("delegation_shares {:?}", delegation_shares); - println!("delegator_shares {:?}", delegator_shares); - let delegated_tokens = delegation_shares - .checked_mul(validator_tokens) - .unwrap() - .div(delegator_shares); - println!("{:?}", delegated_tokens); -} - #[test] fn test_delegations_reconstruct_overflow() { struct TestCase { From 33739fbc2b419d88460c7b9a712e0d6a043e697d Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Fri, 23 Feb 2024 10:00:50 -0300 Subject: [PATCH 4/5] clippy --- packages/neutron-sdk/src/interchain_queries/v045/testing.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/neutron-sdk/src/interchain_queries/v045/testing.rs b/packages/neutron-sdk/src/interchain_queries/v045/testing.rs index 4dc8982a..f8ae1bd6 100644 --- a/packages/neutron-sdk/src/interchain_queries/v045/testing.rs +++ b/packages/neutron-sdk/src/interchain_queries/v045/testing.rs @@ -26,11 +26,10 @@ use cosmos_sdk_proto::cosmos::staking::v1beta1::{ }; use cosmos_sdk_proto::traits::Message; use cosmwasm_std::{ - to_json_binary, Addr, Binary, Coin as StdCoin, Decimal, Decimal256, - Delegation as StdDelegation, Timestamp, Uint128, + to_json_binary, Addr, Binary, Coin as StdCoin, Decimal, Delegation as StdDelegation, Timestamp, + Uint128, }; use hex; -use std::ops::Div; use std::ops::Mul; use std::str::FromStr; From 75b7f3965db2b74614ab742834c2fbbee7c7305b Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Wed, 28 Feb 2024 11:02:38 -0300 Subject: [PATCH 5/5] convertation using try into --- .../neutron-sdk/src/interchain_queries/v045/types.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/neutron-sdk/src/interchain_queries/v045/types.rs b/packages/neutron-sdk/src/interchain_queries/v045/types.rs index da6ba1c9..4a0f6ea4 100644 --- a/packages/neutron-sdk/src/interchain_queries/v045/types.rs +++ b/packages/neutron-sdk/src/interchain_queries/v045/types.rs @@ -476,14 +476,10 @@ impl KVReconstruct for Delegations { } fn uint256_to_u128(value: Uint256) -> Result { - // Convert Uint256 to string - let value_str = value.to_string(); - - // Attempt to parse the string as u128 - match value_str.parse::() { - Ok(parsed_value) => Ok(parsed_value), - Err(_) => Err(StdError::generic_err("Uint256 value exceeds u128 limits")), - } + let converted: Uint128 = value + .try_into() + .map_err(|_| StdError::generic_err("Uint256 value exceeds u128 limits"))?; + Ok(converted.u128()) } /// Represents a single unbonding delegation from some validator to some delegator on remote chain