From d0647f030d1abc07ac622e900eeffa94abddb02a Mon Sep 17 00:00:00 2001 From: nhpd Date: Wed, 4 Jun 2025 11:59:59 +0400 Subject: [PATCH 1/7] remove validator correctly; add migration to remote validator at correct height --- contracts/dao/neutron-staking-tracker/src/contract.rs | 8 +++++++- .../dao/neutron-staking-tracker/src/testing/tests.rs | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/contracts/dao/neutron-staking-tracker/src/contract.rs b/contracts/dao/neutron-staking-tracker/src/contract.rs index b8a0256a..401fb5a5 100644 --- a/contracts/dao/neutron-staking-tracker/src/contract.rs +++ b/contracts/dao/neutron-staking-tracker/src/contract.rs @@ -208,8 +208,8 @@ pub(crate) fn after_validator_created( pub(crate) fn after_validator_removed( deps: DepsMut, env: Env, - valoper_address: String, _valcons_address: String, + valoper_address: String, ) -> Result { let validator_addr = Addr::unchecked(&valoper_address); @@ -650,6 +650,12 @@ pub fn query_list_delegations( pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result { // Set contract to version to latest set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + + // Remove validator + let validator_addr = Addr::unchecked("neutronvaloper1v9xys5c4zdr89tvwq983ycnj3j4pekpjwr0raa"); + let remove_height = 26438494; + VALIDATORS.remove(deps.storage, &validator_addr, remove_height)?; + Ok(Response::default()) } diff --git a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs index f8ba8136..649004f7 100644 --- a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs +++ b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs @@ -246,8 +246,8 @@ fn test_after_validator_removed() { let res = after_validator_removed( deps.as_mut(), env.clone(), - oper_addr.to_string(), cons_addr.to_string(), + oper_addr.to_string(), ); assert!(res.is_ok(), "Error: {:?}", res.err()); From 4ccb83748d363d1004b6a0b48af9ca304be0b43d Mon Sep 17 00:00:00 2001 From: nhpd Date: Wed, 4 Jun 2025 20:30:20 +0400 Subject: [PATCH 2/7] remove cons_addr from calling funcs --- .../neutron-staking-tracker/src/contract.rs | 24 +++++++------------ .../src/testing/tests.rs | 24 +++---------------- 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/contracts/dao/neutron-staking-tracker/src/contract.rs b/contracts/dao/neutron-staking-tracker/src/contract.rs index 401fb5a5..1f024e87 100644 --- a/contracts/dao/neutron-staking-tracker/src/contract.rs +++ b/contracts/dao/neutron-staking-tracker/src/contract.rs @@ -139,18 +139,15 @@ pub fn execute_update_config( pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> Result { match msg { SudoMsg::AfterValidatorCreated { val_addr } => after_validator_created(deps, env, val_addr), - SudoMsg::AfterValidatorRemoved { - cons_addr, - val_addr, - } => after_validator_removed(deps, env, cons_addr, val_addr), - SudoMsg::AfterValidatorBonded { - cons_addr, - val_addr, - } => after_validator_bonded(deps, env, cons_addr, val_addr), - SudoMsg::AfterValidatorBeginUnbonding { - cons_addr, - val_addr, - } => after_validator_begin_unbonding(deps, env, cons_addr, val_addr), + SudoMsg::AfterValidatorRemoved { val_addr, .. } => { + after_validator_removed(deps, env, val_addr) + } + SudoMsg::AfterValidatorBonded { val_addr, .. } => { + after_validator_bonded(deps, env, val_addr) + } + SudoMsg::AfterValidatorBeginUnbonding { val_addr, .. } => { + after_validator_begin_unbonding(deps, env, val_addr) + } SudoMsg::AfterDelegationModified { del_addr, val_addr } => { after_delegation_modified(deps, env, del_addr, val_addr) } @@ -208,7 +205,6 @@ pub(crate) fn after_validator_created( pub(crate) fn after_validator_removed( deps: DepsMut, env: Env, - _valcons_address: String, valoper_address: String, ) -> Result { let validator_addr = Addr::unchecked(&valoper_address); @@ -224,7 +220,6 @@ pub(crate) fn after_validator_removed( pub(crate) fn after_validator_bonded( deps: DepsMut, env: Env, - _valcons_address: String, valoper_address: String, ) -> Result { let valoper_addr = Addr::unchecked(&valoper_address); @@ -322,7 +317,6 @@ pub fn before_validator_slashed( pub(crate) fn after_validator_begin_unbonding( deps: DepsMut, env: Env, - _valcons_address: String, valoper_address: String, ) -> Result { let mut resp = Response::new() diff --git a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs index 649004f7..a4d859d5 100644 --- a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs +++ b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs @@ -224,7 +224,6 @@ fn test_after_validator_removed() { // Define operator (valoper) and consensus (valcons) addresses let oper_addr = Addr::unchecked("neutronvaloper1xyz"); - let cons_addr = Addr::unchecked("neutronvalconsoper1xyz"); // Store some validator let validator = Validator { @@ -243,12 +242,7 @@ fn test_after_validator_removed() { .unwrap(); // Call `after_validator_removed` - let res = after_validator_removed( - deps.as_mut(), - env.clone(), - cons_addr.to_string(), - oper_addr.to_string(), - ); + let res = after_validator_removed(deps.as_mut(), env.clone(), oper_addr.to_string()); assert!(res.is_ok(), "Error: {:?}", res.err()); let validator = VALIDATORS @@ -275,7 +269,6 @@ fn test_after_validator_bonded_with_mock_query() { // Define operator (valoper) and consensus (valcons) addresses let oper_addr = Addr::unchecked("neutronvaloper1xyz"); - let cons_addr = Addr::unchecked("neutronvalcons1xyz"); BONDED_VALIDATORS_SET .save(deps.as_mut().storage, &Vec::new(), env.block.height) @@ -313,12 +306,7 @@ fn test_after_validator_bonded_with_mock_query() { deps.querier.with_validators(vec![proto_validator]); // Call `after_validator_bonded` - let res = after_validator_bonded( - deps.as_mut(), - env.clone(), - cons_addr.to_string(), - oper_addr.to_string(), - ); + let res = after_validator_bonded(deps.as_mut(), env.clone(), oper_addr.to_string()); assert!(res.is_ok(), "Error: {:?}", res.err()); // Load updated validator state @@ -1208,7 +1196,6 @@ fn test_after_validator_begin_unbonding() { let admin = deps.api.addr_make("admin"); // Define operator (valoper) and consensus (valcons) addresses let oper_addr = Addr::unchecked("neutronvaloper1xyz"); - let cons_addr = Addr::unchecked("neutronvalcons1xyz"); let config = Config { name: String::from("Test Config"), @@ -1263,12 +1250,7 @@ fn test_after_validator_begin_unbonding() { deps.querier.with_validators(vec![proto_validator]); // Call `after_validator_begin_unbonding` - let res = after_validator_begin_unbonding( - deps.as_mut(), - env.clone(), - cons_addr.to_string(), - oper_addr.to_string(), - ); + let res = after_validator_begin_unbonding(deps.as_mut(), env.clone(), oper_addr.to_string()); assert!(res.is_ok(), "Error: {:?}", res.err()); assert!( !BONDED_VALIDATORS_SET From 08f3b0df6a82dbb14ff677a0b1e144b61911d0c9 Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Thu, 5 Jun 2025 18:10:12 +0300 Subject: [PATCH 3/7] simple migration test [wip] --- .../src/testing/tests.rs | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs index a4d859d5..08ca0907 100644 --- a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs +++ b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs @@ -4,7 +4,7 @@ use crate::contract::{ before_validator_slashed, execute, instantiate, query_stake_at_height, query_total_stake_at_height, }; -use crate::contract::{after_validator_created, after_validator_removed}; +use crate::contract::{after_validator_created, after_validator_removed, migrate}; use crate::state::{BONDED_VALIDATORS_SET, CONFIG, DELEGATIONS, VALIDATORS}; use crate::testing::mock_querier::mock_dependencies as dependencies; use cosmwasm_std::testing::message_info; @@ -12,7 +12,7 @@ use cosmwasm_std::{ testing::{mock_dependencies, mock_env}, to_json_binary, Addr, Decimal256, Uint128, }; -use neutron_staking_tracker_common::msg::{ExecuteMsg, InstantiateMsg}; +use neutron_staking_tracker_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg}; use neutron_staking_tracker_common::types::{Config, Delegation, Validator}; use neutron_std::types::cosmos::staking::v1beta1::{ QueryValidatorResponse, Validator as CosmosValidator, @@ -216,6 +216,42 @@ fn test_after_validator_created_with_mock_query() { ); } +#[test] +fn test_after_validator_removed_during_migration() { + let mut deps = dependencies(); + + let env = mock_env(); + + // Define operator (valoper) and consensus (valcons) addresses + let oper_addr = Addr::unchecked("neutronvaloper1v9xys5c4zdr89tvwq983ycnj3j4pekpjwr0raa"); + + // Store some validator + let validator = Validator { + oper_address: oper_addr.clone(), + total_tokens: Uint128::new(1000), // Self-bonded tokens + total_shares: Uint128::new(1000), // No external delegators + }; + + // Validator is created some time ago + VALIDATORS + .save(deps.as_mut().storage, &oper_addr, &validator, 16438494) + .unwrap(); + + // Validator is created on some height again for some reason on a height (the one after validator should've been removed) + VALIDATORS + .save(deps.as_mut().storage, &oper_addr, &validator, 30000000) + .unwrap(); + + // Call `after_validator_removed` + let res = migrate(deps.as_mut(), env.clone(), MigrateMsg {}); + assert!(res.is_ok(), "Error: {:?}", res.err()); + + let validator = VALIDATORS + .may_load(deps.as_ref().storage, &oper_addr) + .unwrap(); + assert!(validator.is_some(), "Validator should not be removed") +} + #[test] fn test_after_validator_removed() { let mut deps = dependencies(); From a35b43266e817f6680049550309877558b867396 Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Thu, 5 Jun 2025 18:42:09 +0300 Subject: [PATCH 4/7] simple migration test [wip] --- .../neutron-staking-tracker/src/contract.rs | 9 ++++ .../src/testing/tests.rs | 41 ++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/contracts/dao/neutron-staking-tracker/src/contract.rs b/contracts/dao/neutron-staking-tracker/src/contract.rs index 1f024e87..11c48947 100644 --- a/contracts/dao/neutron-staking-tracker/src/contract.rs +++ b/contracts/dao/neutron-staking-tracker/src/contract.rs @@ -647,6 +647,15 @@ pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result Date: Thu, 5 Jun 2025 18:42:57 +0300 Subject: [PATCH 5/7] simple migration test [wip] --- contracts/dao/neutron-staking-tracker/src/testing/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs index 370b6455..f638eb9b 100644 --- a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs +++ b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs @@ -245,8 +245,8 @@ fn test_after_validator_removed_during_migration() { let proto_validator = CosmosValidator { operator_address: oper_addr.to_string(), consensus_pubkey: None, - status: 3, // Bonded status - tokens: "900".to_string(), // 10% slashed, from 1000 → 900 + status: 3, + tokens: "900".to_string(), jailed: false, delegator_shares: "1000".to_string(), description: None, From d61dd44fa3042ee392ecdc43385fd2bd040bd6bd Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Fri, 6 Jun 2025 12:58:17 +0300 Subject: [PATCH 6/7] review fixes --- Cargo.lock | 2 +- contracts/dao/neutron-staking-tracker/Cargo.toml | 2 +- contracts/dao/neutron-staking-tracker/src/testing/tests.rs | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b06d79ab..d719c918 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2666,7 +2666,7 @@ dependencies = [ [[package]] name = "neutron-staking-tracker" -version = "0.2.1" +version = "0.2.2" dependencies = [ "cosmwasm-schema 2.2.2", "cosmwasm-std 2.2.2", diff --git a/contracts/dao/neutron-staking-tracker/Cargo.toml b/contracts/dao/neutron-staking-tracker/Cargo.toml index 4455fcb8..edab3c63 100644 --- a/contracts/dao/neutron-staking-tracker/Cargo.toml +++ b/contracts/dao/neutron-staking-tracker/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" name = "neutron-staking-tracker" license = "Apache-2.0" repository = "https://github.com/neutron/neutron-dao" -version = "0.2.1" +version = "0.2.2" [lib] crate-type = ["cdylib", "rlib"] diff --git a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs index f638eb9b..906fd8ee 100644 --- a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs +++ b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs @@ -216,8 +216,10 @@ fn test_after_validator_created_with_mock_query() { ); } +// This test covers v2.0.2 migration logic +// The test should be removed in the next releases #[test] -fn test_after_validator_removed_during_migration() { +fn test_after_validator_removed_during_migration_v2_0_2() { let mut deps = dependencies(); let env = mock_env(); From 5179aeb8fa77050bf9c4781440661cbbebc7d40c Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Fri, 6 Jun 2025 12:58:43 +0300 Subject: [PATCH 7/7] review fixes --- contracts/dao/neutron-staking-tracker/src/testing/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs index 906fd8ee..677dc486 100644 --- a/contracts/dao/neutron-staking-tracker/src/testing/tests.rs +++ b/contracts/dao/neutron-staking-tracker/src/testing/tests.rs @@ -216,10 +216,10 @@ fn test_after_validator_created_with_mock_query() { ); } -// This test covers v2.0.2 migration logic +// This test covers v0.2.2 migration logic // The test should be removed in the next releases #[test] -fn test_after_validator_removed_during_migration_v2_0_2() { +fn test_after_validator_removed_during_migration_v0_2_2() { let mut deps = dependencies(); let env = mock_env();