From 9f91b1e66a7340f94fa4eb1af02aedb30b5fd190 Mon Sep 17 00:00:00 2001 From: CJ Cobb <46455409+cjcobb23@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:21:25 -0500 Subject: [PATCH 1/5] fix(minor-rewards): remove old migration handler (#692) --- Cargo.lock | 1 + contracts/rewards/Cargo.toml | 1 + contracts/rewards/src/contract.rs | 22 +- .../rewards/src/contract/migrations/mod.rs | 2 +- .../rewards/src/contract/migrations/v1_0_0.rs | 309 ------------------ 5 files changed, 18 insertions(+), 317 deletions(-) delete mode 100644 contracts/rewards/src/contract/migrations/v1_0_0.rs diff --git a/Cargo.lock b/Cargo.lock index a6fb746e2..cd62719cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6725,6 +6725,7 @@ dependencies = [ name = "rewards" version = "1.1.0" dependencies = [ + "assert_ok", "axelar-wasm-std", "cosmwasm-schema", "cosmwasm-std", diff --git a/contracts/rewards/Cargo.toml b/contracts/rewards/Cargo.toml index 9677eaf5d..1ef4e5591 100644 --- a/contracts/rewards/Cargo.toml +++ b/contracts/rewards/Cargo.toml @@ -46,6 +46,7 @@ serde_json = { workspace = true } thiserror = { workspace = true } [dev-dependencies] +assert_ok = { workspace = true } cw-multi-test = "0.15.1" [lints] diff --git a/contracts/rewards/src/contract.rs b/contracts/rewards/src/contract.rs index 403fee8f5..893dde175 100644 --- a/contracts/rewards/src/contract.rs +++ b/contracts/rewards/src/contract.rs @@ -18,6 +18,7 @@ mod query; const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME"); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); +const BASE_VERSION: &str = "1.1.0"; #[cfg_attr(not(feature = "library"), entry_point)] pub fn migrate( @@ -25,9 +26,7 @@ pub fn migrate( _env: Env, _msg: Empty, ) -> Result { - migrations::v1_0_0::migrate(deps.storage)?; - - // any version checks should be done before here + cw2::assert_contract_version(deps.storage, CONTRACT_NAME, BASE_VERSION)?; cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; @@ -191,7 +190,8 @@ pub fn query( #[cfg(test)] mod tests { - use cosmwasm_std::testing::{mock_dependencies, mock_env}; + use assert_ok::assert_ok; + use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; use cosmwasm_std::{coins, Addr, BlockInfo, Uint128}; use cw_multi_test::{App, ContractWrapper, Executor}; use router_api::ChainName; @@ -203,9 +203,17 @@ mod tests { #[test] fn migrate_sets_contract_version() { let mut deps = mock_dependencies(); - - #[allow(deprecated)] - migrations::v1_0_0::tests::instantiate_contract(deps.as_mut(), "denom"); + let env = mock_env(); + let info = mock_info("instantiator", &[]); + assert_ok!(instantiate( + deps.as_mut(), + env, + info, + InstantiateMsg { + governance_address: "governance".to_string(), + rewards_denom: "uaxl".to_string() + } + )); migrate(deps.as_mut(), mock_env(), Empty {}).unwrap(); diff --git a/contracts/rewards/src/contract/migrations/mod.rs b/contracts/rewards/src/contract/migrations/mod.rs index 1d185e9d7..8b1378917 100644 --- a/contracts/rewards/src/contract/migrations/mod.rs +++ b/contracts/rewards/src/contract/migrations/mod.rs @@ -1 +1 @@ -pub mod v1_0_0; + diff --git a/contracts/rewards/src/contract/migrations/v1_0_0.rs b/contracts/rewards/src/contract/migrations/v1_0_0.rs deleted file mode 100644 index 4075cc492..000000000 --- a/contracts/rewards/src/contract/migrations/v1_0_0.rs +++ /dev/null @@ -1,309 +0,0 @@ -#![allow(deprecated)] - -use std::collections::HashMap; -use std::marker::PhantomData; - -use axelar_wasm_std::error::ContractError; -use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Addr, Order, Storage, Uint128}; -use cw_storage_plus::{Item, KeyDeserialize, Map}; -use router_api::ChainName; - -use crate::contract::CONTRACT_NAME; -use crate::state::{self, EpochTally, ParamsSnapshot, PoolId, TallyId}; - -const BASE_VERSION: &str = "1.0.0"; - -pub fn migrate(storage: &mut dyn Storage) -> Result<(), ContractError> { - cw2::assert_contract_version(storage, CONTRACT_NAME, BASE_VERSION)?; - - migrate_params(storage)?; - Ok(()) -} - -fn migrate_params(storage: &mut dyn Storage) -> Result<(), ContractError> { - let params = PARAMS.load(storage)?; - let funded_pools = get_all_pools(storage)?; - - for pool in funded_pools.values() { - state::save_rewards_pool( - storage, - &state::RewardsPool { - params: params.to_owned(), - id: pool.id.to_owned(), - balance: pool.balance, - }, - )?; - } - - let tallied_pools = get_pool_ids_from_tallies(storage)?; - for pool in tallied_pools { - if funded_pools.contains_key(&pool) { - continue; - } - state::save_rewards_pool( - storage, - &state::RewardsPool { - params: params.to_owned(), - id: pool, - balance: Uint128::zero(), - }, - )?; - } - PARAMS.remove(storage); - - Ok(()) -} - -const POOLS: Map = Map::new("pools"); - -const TALLIES: Map = Map::new("tallies"); - -// This will only return pools that were funded -fn get_all_pools(storage: &mut dyn Storage) -> Result, ContractError> { - POOLS - .range(storage, None, None, Order::Ascending) - .map(|res| res.map_err(|err| err.into())) - .collect::, _>>() -} - -// Pools can have active tallies without being funded, or having an object in the POOLS map -fn get_pool_ids_from_tallies(storage: &mut dyn Storage) -> Result, ContractError> { - let mut pool_ids: Vec = vec![]; - let mut lower_bound = None; - loop { - let tallies: Vec<_> = TALLIES - .range_raw(storage, lower_bound, None, Order::Ascending) - .take(1) - .collect::, _>>()?; - match tallies.as_slice() { - [] => { - break; - } - [(tally_id, _)] => { - // cw_storage_plus v1.2.0 has a known bug where certain key types are not decoded correctly - // However, treating the key as a 3 element tuple works to decode the individual fields, and then - // we can recreate the pool id - let (chain_name, contract, _) = - <(ChainName, Addr, u64)>::from_vec(tally_id.to_owned())?; - let pool_id = PoolId { - chain_name, - contract, - }; - pool_ids.push(pool_id.clone()); - lower_bound = Some(cw_storage_plus::Bound::Exclusive(( - TallyId { - pool_id, - epoch_num: u64::MAX, - }, - PhantomData, - ))); - } - _ => panic!("take yielded more than one"), - }; - } - Ok(pool_ids) -} - -#[deprecated(since = "1.0.0", note = "only used during migration")] -const PARAMS: Item = Item::new("params"); - -#[cw_serde] -#[deprecated(since = "1.0.0", note = "only used during migration")] -struct RewardsPool { - pub id: PoolId, - pub balance: Uint128, -} - -#[cfg(test)] -pub mod tests { - use std::collections::HashMap; - - use axelar_wasm_std::permission_control; - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cosmwasm_std::{Addr, DepsMut, Env, MessageInfo, Response, Uint128}; - - use super::{RewardsPool, PARAMS, POOLS, TALLIES}; - use crate::contract::migrations::v1_0_0; - use crate::contract::CONTRACT_NAME; - use crate::msg::{InstantiateMsg, Params}; - use crate::state::{self, Config, Epoch, EpochTally, ParamsSnapshot, PoolId, TallyId, CONFIG}; - - #[test] - fn migrate_rewards_pools() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut(), "denom"); - - let test_pools = vec![ - RewardsPool { - id: PoolId { - chain_name: "mock-chain".parse().unwrap(), - contract: Addr::unchecked("contract-1"), - }, - balance: Uint128::from(250u128), - }, - RewardsPool { - id: PoolId { - chain_name: "mock-chain-2".parse().unwrap(), - contract: Addr::unchecked("contract-2"), - }, - balance: Uint128::from(100u128), - }, - ]; - - for pool in &test_pools { - POOLS - .save(deps.as_mut().storage, pool.id.to_owned(), pool) - .unwrap(); - } - - let current_epoch = Epoch { - epoch_num: 10, - block_height_started: 100, - }; - let test_tally_ids = [ - TallyId { - pool_id: PoolId { - chain_name: "mock-chain".parse().unwrap(), - contract: Addr::unchecked("contract-1"), - }, - epoch_num: current_epoch.epoch_num, - }, - TallyId { - pool_id: PoolId { - chain_name: "mock-chain-3".parse().unwrap(), - contract: Addr::unchecked("contract-3"), - }, - epoch_num: current_epoch.epoch_num, - }, - TallyId { - pool_id: PoolId { - chain_name: "mock-chain-4".parse().unwrap(), - contract: Addr::unchecked("contract-4"), - }, - epoch_num: current_epoch.epoch_num, - }, - ]; - - let params = PARAMS.load(deps.as_mut().storage).unwrap(); - let mut test_tallies: Vec<(&TallyId, EpochTally)> = test_tally_ids - .iter() - .map(|tally_id| { - ( - tally_id, - EpochTally { - pool_id: tally_id.pool_id.clone(), - event_count: 1, - participation: HashMap::new(), - epoch: current_epoch.clone(), - params: params.params.clone(), - }, - ) - }) - .collect(); - let mut test_tallies_2 = test_tallies.clone(); - test_tallies_2 - .iter_mut() - .for_each(|(_, tally)| tally.epoch.epoch_num += 1); - test_tallies.append(&mut test_tallies_2); - - for tally in &test_tallies { - TALLIES - .save(deps.as_mut().storage, tally.0.to_owned(), &tally.1) - .unwrap(); - } - - v1_0_0::migrate(deps.as_mut().storage).unwrap(); - - for pool in &test_pools { - let new_pool = - state::load_rewards_pool(deps.as_mut().storage, pool.id.to_owned()).unwrap(); - assert_eq!( - new_pool, - state::RewardsPool { - id: pool.id.to_owned(), - balance: pool.balance, - params: params.clone() - } - ); - } - - for (tally_id, _) in &test_tallies { - if test_pools.iter().any(|pool| pool.id == tally_id.pool_id) { - continue; - } - let new_pool = - state::load_rewards_pool(deps.as_mut().storage, tally_id.pool_id.to_owned()) - .unwrap(); - assert_eq!( - new_pool, - state::RewardsPool { - id: tally_id.pool_id.to_owned(), - balance: Uint128::zero(), - params: params.clone() - } - ); - } - } - - #[test] - fn migrate_checks_contract_version() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut(), "denom"); - cw2::set_contract_version(deps.as_mut().storage, CONTRACT_NAME, "something wrong").unwrap(); - - assert!(v1_0_0::migrate(deps.as_mut().storage).is_err()); - - cw2::set_contract_version(deps.as_mut().storage, CONTRACT_NAME, v1_0_0::BASE_VERSION) - .unwrap(); - - assert!(v1_0_0::migrate(deps.as_mut().storage).is_ok()); - } - - #[deprecated(since = "0.4.0", note = "only used during migration tests")] - pub fn instantiate_contract(deps: DepsMut, denom: impl Into) { - let msg = InstantiateMsg { - governance_address: "governance".to_string(), - rewards_denom: denom.into(), - }; - instantiate(deps, mock_env(), mock_info("anyone", &[]), msg).unwrap(); - } - - #[deprecated(since = "0.4.0", note = "only used during migration tests")] - fn instantiate( - deps: DepsMut, - env: Env, - _info: MessageInfo, - msg: InstantiateMsg, - ) -> Result { - cw2::set_contract_version(deps.storage, CONTRACT_NAME, v1_0_0::BASE_VERSION)?; - - let governance = deps.api.addr_validate(&msg.governance_address)?; - permission_control::set_governance(deps.storage, &governance)?; - - CONFIG.save( - deps.storage, - &Config { - rewards_denom: msg.rewards_denom, - }, - )?; - - let params = Params { - epoch_duration: 100u64.try_into().unwrap(), - rewards_per_epoch: 1000u128.try_into().unwrap(), - participation_threshold: (1, 2).try_into().unwrap(), - }; - PARAMS.save( - deps.storage, - &ParamsSnapshot { - params, - created_at: Epoch { - epoch_num: 0, - block_height_started: env.block.height, - }, - }, - )?; - - Ok(Response::new()) - } -} From f168b205c9eea79dbcfeafc969e7b78b097edfcc Mon Sep 17 00:00:00 2001 From: CJ Cobb <46455409+cjcobb23@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:28:26 -0500 Subject: [PATCH 2/5] fix(minor-voting-verifier): remove old migration handler (#693) --- contracts/voting-verifier/src/contract.rs | 6 +- .../src/contract/migrations/mod.rs | 2 +- .../src/contract/migrations/v0_5_0.rs | 266 ------------------ 3 files changed, 5 insertions(+), 269 deletions(-) delete mode 100644 contracts/voting-verifier/src/contract/migrations/v0_5_0.rs diff --git a/contracts/voting-verifier/src/contract.rs b/contracts/voting-verifier/src/contract.rs index 099f392a9..f406704ec 100644 --- a/contracts/voting-verifier/src/contract.rs +++ b/contracts/voting-verifier/src/contract.rs @@ -7,7 +7,6 @@ use cosmwasm_std::{ }; use error_stack::ResultExt; -use crate::contract::migrations::v0_5_0; use crate::error::ContractError; use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; use crate::state::{Config, CONFIG}; @@ -18,6 +17,7 @@ mod query; const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME"); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); +const BASE_VERSION: &str = "1.0.0"; #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( @@ -111,7 +111,9 @@ pub fn migrate( _env: Env, _msg: Empty, ) -> Result { - v0_5_0::migrate(deps.storage)?; + cw2::assert_contract_version(deps.storage, CONTRACT_NAME, BASE_VERSION)?; + + cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; Ok(Response::default()) } diff --git a/contracts/voting-verifier/src/contract/migrations/mod.rs b/contracts/voting-verifier/src/contract/migrations/mod.rs index 504cbdb5c..8b1378917 100644 --- a/contracts/voting-verifier/src/contract/migrations/mod.rs +++ b/contracts/voting-verifier/src/contract/migrations/mod.rs @@ -1 +1 @@ -pub mod v0_5_0; + diff --git a/contracts/voting-verifier/src/contract/migrations/v0_5_0.rs b/contracts/voting-verifier/src/contract/migrations/v0_5_0.rs deleted file mode 100644 index 90d1313ea..000000000 --- a/contracts/voting-verifier/src/contract/migrations/v0_5_0.rs +++ /dev/null @@ -1,266 +0,0 @@ -#![allow(deprecated)] - -use axelar_wasm_std::address::AddressFormat; -use axelar_wasm_std::error::ContractError; -use axelar_wasm_std::msg_id::MessageIdFormat; -use axelar_wasm_std::{nonempty, permission_control, MajorityThreshold}; -use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Addr, Attribute, StdResult, Storage}; -use cw_storage_plus::Item; -use router_api::ChainName; - -use crate::contract::{CONTRACT_NAME, CONTRACT_VERSION}; -use crate::state; - -const BASE_VERSION: &str = "0.5.0"; - -pub fn migrate(storage: &mut dyn Storage) -> Result<(), ContractError> { - cw2::assert_contract_version(storage, CONTRACT_NAME, BASE_VERSION)?; - - let config = CONFIG.load(storage)?; - migrate_permission_control(storage, &config.governance)?; - migrate_config(storage, config)?; - - delete_polls(storage); - - cw2::set_contract_version(storage, CONTRACT_NAME, CONTRACT_VERSION)?; - - Ok(()) -} - -fn migrate_config(storage: &mut dyn Storage, config: Config) -> StdResult<()> { - CONFIG.remove(storage); - - let config = state::Config { - service_registry_contract: config.service_registry_contract, - service_name: config.service_name, - source_chain: config.source_chain, - rewards_contract: config.rewards_contract, - block_expiry: config - .block_expiry - .try_into() - .unwrap_or(1.try_into().expect("1 is not zero")), - confirmation_height: config.confirmation_height, - msg_id_format: config.msg_id_format, - source_gateway_address: config.source_gateway_address, - voting_threshold: config.voting_threshold, - address_format: AddressFormat::Eip55, - }; - - state::CONFIG.save(storage, &config) -} - -fn migrate_permission_control(storage: &mut dyn Storage, governance: &Addr) -> StdResult<()> { - permission_control::set_governance(storage, governance) -} - -fn delete_polls(storage: &mut dyn Storage) { - state::POLLS.clear(storage); - state::VOTES.clear(storage); - state::poll_messages().clear(storage); - state::poll_messages().clear(storage); -} - -#[cw_serde] -#[deprecated(since = "0.5.0", note = "only used during migration")] -pub struct Config { - pub governance: Addr, - pub service_registry_contract: Addr, - pub service_name: nonempty::String, - pub source_gateway_address: nonempty::String, - pub voting_threshold: MajorityThreshold, - pub block_expiry: u64, // number of blocks after which a poll expires - pub confirmation_height: u64, - pub source_chain: ChainName, - pub rewards_contract: Addr, - pub msg_id_format: MessageIdFormat, -} -impl From for Vec { - fn from(other: Config) -> Self { - vec![ - ("service_name", other.service_name.to_string()), - ( - "service_registry_contract", - other.service_registry_contract.to_string(), - ), - ( - "source_gateway_address", - other.source_gateway_address.to_string(), - ), - ( - "voting_threshold", - serde_json::to_string(&other.voting_threshold) - .expect("failed to serialize voting_threshold"), - ), - ("block_expiry", other.block_expiry.to_string()), - ("confirmation_height", other.confirmation_height.to_string()), - ] - .into_iter() - .map(Attribute::from) - .collect() - } -} -#[deprecated(since = "0.5.0", note = "only used during migration")] -pub const CONFIG: Item = Item::new("config"); - -#[cfg(test)] -mod tests { - use axelar_wasm_std::msg_id::MessageIdFormat; - use axelar_wasm_std::permission_control::Permission; - use axelar_wasm_std::{nonempty, permission_control, MajorityThreshold, Threshold}; - use cosmwasm_schema::cw_serde; - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cosmwasm_std::{Addr, Attribute, DepsMut, Empty, Env, Event, MessageInfo, Response}; - use router_api::ChainName; - - use crate::contract::migrations::v0_5_0; - use crate::contract::{migrate, CONTRACT_NAME, CONTRACT_VERSION}; - use crate::state; - - const GOVERNANCE: &str = "governance"; - - #[test] - fn migrate_checks_contract_version() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut()); - cw2::set_contract_version(deps.as_mut().storage, CONTRACT_NAME, "something wrong").unwrap(); - - assert!(v0_5_0::migrate(deps.as_mut().storage).is_err()); - - cw2::set_contract_version(deps.as_mut().storage, CONTRACT_NAME, v0_5_0::BASE_VERSION) - .unwrap(); - - assert!(v0_5_0::migrate(deps.as_mut().storage).is_ok()); - } - - #[test] - fn migrate_sets_contract_version() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut()); - - migrate(deps.as_mut(), mock_env(), Empty {}).unwrap(); - - let contract_version = cw2::get_contract_version(deps.as_mut().storage).unwrap(); - assert_eq!(contract_version.contract, CONTRACT_NAME); - assert_eq!(contract_version.version, CONTRACT_VERSION); - } - - #[test] - fn config_gets_migrated() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut()); - - assert!(v0_5_0::CONFIG.load(deps.as_mut().storage).is_ok()); - assert!(state::CONFIG.load(deps.as_mut().storage).is_err()); - - assert!(v0_5_0::migrate(deps.as_mut().storage).is_ok()); - - assert!(v0_5_0::CONFIG.load(deps.as_mut().storage).is_err()); - assert!(state::CONFIG.load(deps.as_mut().storage).is_ok()); - } - - #[test] - fn permission_control_gets_migrated() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut()); - - assert!(v0_5_0::migrate(deps.as_mut().storage).is_ok()); - - assert!(permission_control::sender_role( - deps.as_mut().storage, - &Addr::unchecked(GOVERNANCE) - ) - .unwrap() - .contains(Permission::Governance)); - } - - #[test] - fn state_is_cleared_after_migration() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut()); - - assert!(v0_5_0::migrate(deps.as_mut().storage).is_ok()); - - assert!(state::VOTES.is_empty(deps.as_ref().storage)); - assert!(state::POLLS.is_empty(deps.as_ref().storage)); - assert!(state::poll_messages().is_empty(deps.as_ref().storage)); - assert!(state::poll_verifier_sets().is_empty(deps.as_ref().storage)); - } - - fn instantiate_contract(deps: DepsMut) { - instantiate( - deps, - mock_env(), - mock_info("admin", &[]), - InstantiateMsg { - governance_address: GOVERNANCE.parse().unwrap(), - service_registry_address: "service_registry".parse().unwrap(), - service_name: "service".parse().unwrap(), - source_gateway_address: "source_gateway".parse().unwrap(), - voting_threshold: Threshold::try_from((2u64, 3u64)) - .and_then(MajorityThreshold::try_from) - .unwrap(), - block_expiry: 1, - confirmation_height: 1, - source_chain: "source-chain".parse().unwrap(), - rewards_address: "rewards".to_string(), - msg_id_format: MessageIdFormat::HexTxHashAndEventIndex, - }, - ) - .unwrap(); - } - - #[deprecated(since = "0.5.0", note = "only used to test the migration")] - fn instantiate( - deps: DepsMut, - _env: Env, - _info: MessageInfo, - msg: InstantiateMsg, - ) -> Result { - cw2::set_contract_version(deps.storage, CONTRACT_NAME, v0_5_0::BASE_VERSION)?; - - let config = v0_5_0::Config { - governance: deps.api.addr_validate(&msg.governance_address)?, - service_name: msg.service_name, - service_registry_contract: deps.api.addr_validate(&msg.service_registry_address)?, - source_gateway_address: msg.source_gateway_address, - voting_threshold: msg.voting_threshold, - block_expiry: msg.block_expiry, - confirmation_height: msg.confirmation_height, - source_chain: msg.source_chain, - rewards_contract: deps.api.addr_validate(&msg.rewards_address)?, - msg_id_format: msg.msg_id_format, - }; - v0_5_0::CONFIG.save(deps.storage, &config)?; - - Ok(Response::new() - .add_event(Event::new("instantiated").add_attributes(>::from(config)))) - } - - #[cw_serde] - #[deprecated(since = "0.5.0", note = "only used to test the migration")] - pub struct InstantiateMsg { - /// Address that can call all messages of unrestricted governance permission level, like UpdateVotingThreshold. - /// It can execute messages that bypasses verification checks to rescue the contract if it got into an otherwise unrecoverable state due to external forces. - /// On mainnet it should match the address of the Cosmos governance module. - pub governance_address: nonempty::String, - /// Service registry contract address on axelar. - pub service_registry_address: nonempty::String, - /// Name of service in the service registry for which verifiers are registered. - pub service_name: nonempty::String, - /// Axelar's gateway contract address on the source chain - pub source_gateway_address: nonempty::String, - /// Threshold of weighted votes required for voting to be considered complete for a particular message - pub voting_threshold: MajorityThreshold, - /// The number of blocks after which a poll expires - pub block_expiry: u64, - /// The number of blocks to wait for on the source chain before considering a transaction final - pub confirmation_height: u64, - /// Name of the source chain - pub source_chain: ChainName, - /// Rewards contract address on axelar. - pub rewards_address: String, - /// Format that incoming messages should use for the id field of CrossChainId - pub msg_id_format: MessageIdFormat, - } -} From a5d3d8d1d781ecfbf37bb4123aa940ee33d4afe1 Mon Sep 17 00:00:00 2001 From: CJ Cobb <46455409+cjcobb23@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:32:42 -0500 Subject: [PATCH 3/5] fix(minor-service-registry): remove old migration handler (#695) --- contracts/service-registry/src/contract.rs | 3 +- .../src/contract/migrations/mod.rs | 2 +- .../src/contract/migrations/v0_4_1.rs | 117 ------------------ 3 files changed, 3 insertions(+), 119 deletions(-) delete mode 100644 contracts/service-registry/src/contract/migrations/v0_4_1.rs diff --git a/contracts/service-registry/src/contract.rs b/contracts/service-registry/src/contract.rs index 67cada62a..9731b2e35 100644 --- a/contracts/service-registry/src/contract.rs +++ b/contracts/service-registry/src/contract.rs @@ -18,6 +18,7 @@ mod query; const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME"); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); +const BASE_VERSION: &str = "1.0.0"; #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( @@ -191,7 +192,7 @@ pub fn migrate( _env: Env, _msg: Empty, ) -> Result { - migrations::v0_4_1::migrate(deps.storage)?; + cw2::assert_contract_version(deps.storage, CONTRACT_NAME, BASE_VERSION)?; cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; diff --git a/contracts/service-registry/src/contract/migrations/mod.rs b/contracts/service-registry/src/contract/migrations/mod.rs index 080e953e7..8b1378917 100644 --- a/contracts/service-registry/src/contract/migrations/mod.rs +++ b/contracts/service-registry/src/contract/migrations/mod.rs @@ -1 +1 @@ -pub mod v0_4_1; + diff --git a/contracts/service-registry/src/contract/migrations/v0_4_1.rs b/contracts/service-registry/src/contract/migrations/v0_4_1.rs deleted file mode 100644 index b06e781c8..000000000 --- a/contracts/service-registry/src/contract/migrations/v0_4_1.rs +++ /dev/null @@ -1,117 +0,0 @@ -#![allow(deprecated)] -use axelar_wasm_std::error::ContractError; -use axelar_wasm_std::permission_control; -use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Addr, StdResult, Storage}; -use cw_storage_plus::Item; - -use crate::contract::CONTRACT_NAME; - -const BASE_VERSION: &str = "0.4.1"; -pub fn migrate(storage: &mut dyn Storage) -> Result<(), ContractError> { - cw2::assert_contract_version(storage, CONTRACT_NAME, BASE_VERSION)?; - - let config = CONFIG.load(storage)?; - delete_config(storage); - migrate_permission_control(storage, config)?; - - Ok(()) -} - -fn migrate_permission_control(storage: &mut dyn Storage, config: Config) -> StdResult<()> { - permission_control::set_governance(storage, &config.governance) -} - -fn delete_config(storage: &mut dyn Storage) { - CONFIG.remove(storage) -} - -#[cw_serde] -#[deprecated(since = "0.4.1", note = "Only used during migrations")] -pub struct Config { - pub governance: Addr, -} - -#[deprecated(since = "0.4.1", note = "Only used during migrations")] -pub const CONFIG: Item = Item::new("config"); - -#[cfg(test)] -mod tests { - use axelar_wasm_std::permission_control; - use axelar_wasm_std::permission_control::Permission; - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cosmwasm_std::{Addr, DepsMut, Env, MessageInfo, Response}; - - use crate::contract::migrations::v0_4_1; - use crate::contract::CONTRACT_NAME; - use crate::msg::InstantiateMsg; - - const GOVERNANCE: &str = "governance"; - - #[test] - fn migrate_checks_contract_version() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut()); - - cw2::set_contract_version(deps.as_mut().storage, CONTRACT_NAME, "something wrong").unwrap(); - - assert!(v0_4_1::migrate(deps.as_mut().storage).is_err()); - - cw2::set_contract_version(deps.as_mut().storage, CONTRACT_NAME, v0_4_1::BASE_VERSION) - .unwrap(); - - assert!(v0_4_1::migrate(deps.as_mut().storage).is_ok()); - } - #[test] - fn migrate_to_permission_control() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut()); - - assert!(v0_4_1::migrate(deps.as_mut().storage).is_ok()); - - assert!( - permission_control::sender_role(&deps.storage, &Addr::unchecked(GOVERNANCE)) - .unwrap() - .contains(Permission::Governance) - ); - } - - #[test] - fn migrate_deletes_config() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut()); - - assert!(v0_4_1::migrate(deps.as_mut().storage).is_ok()); - - assert!(v0_4_1::CONFIG.load(&deps.storage).is_err()) - } - - fn instantiate_contract(deps: DepsMut) { - instantiate( - deps, - mock_env(), - mock_info("admin", &[]), - InstantiateMsg { - governance_account: GOVERNANCE.to_string(), - }, - ) - .unwrap(); - } - #[deprecated(since = "0.4.1", note = "Only used to test the migration")] - fn instantiate( - deps: DepsMut, - _env: Env, - _info: MessageInfo, - msg: InstantiateMsg, - ) -> Result { - cw2::set_contract_version(deps.storage, CONTRACT_NAME, v0_4_1::BASE_VERSION)?; - - v0_4_1::CONFIG.save( - deps.storage, - &v0_4_1::Config { - governance: deps.api.addr_validate(&msg.governance_account)?, - }, - )?; - Ok(Response::default()) - } -} From 6eb0ed950cc9fb30f11359e8cf6b2853e27c3b1b Mon Sep 17 00:00:00 2001 From: CJ Cobb <46455409+cjcobb23@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:37:15 -0500 Subject: [PATCH 4/5] chore: update changelog with migration notes (#691) --- CHANGELOG.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dc58dc07..3c40a1e9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,25 @@ - Change event index in message ids from u32 to u64. Emit message id from voting verifier [#666](https://github.com/axelarnetwork/axelar-amplifier/pull/666) -#### Migration Notes +#### v1.3.0 Migration Notes + +Components that need upgrading: +ampd + +Contracts that need migration: +coordinator +voting-verifier +service-registry +rewards +router +multisig-prover + +Contracts that should be redeployed (deploy fresh instance): +interchain-token-service +axelarnet-gateway (deploy with chain name "axelar") + +Contracts no longer used (no longer part of the active system): +nexus-gateway + +The voting verifier contracts must be migrated before ampd is upgraded. Existing ampd instances will continue to work even after the contract migration, but we recommend upgrading ampd. -The voting verifier contracts must be migrated before ampd is upgraded. Existing ampd instances will continue to work even after the contract migration, but we recommend upgrading ampd. \ No newline at end of file From 2561ddb5bf388cf542c57647de86b8915976dd31 Mon Sep 17 00:00:00 2001 From: Sammy Date: Thu, 14 Nov 2024 13:31:20 -0500 Subject: [PATCH 5/5] fix(minor-multisig-prover): remove old migration (#696) --- contracts/multisig-prover/src/contract.rs | 16 +- .../src/contract/migrations/mod.rs | 2 +- .../src/contract/migrations/v1_0_0.rs | 239 ------------------ 3 files changed, 15 insertions(+), 242 deletions(-) delete mode 100644 contracts/multisig-prover/src/contract/migrations/v1_0_0.rs diff --git a/contracts/multisig-prover/src/contract.rs b/contracts/multisig-prover/src/contract.rs index caa7d25b4..31f2750a7 100644 --- a/contracts/multisig-prover/src/contract.rs +++ b/contracts/multisig-prover/src/contract.rs @@ -19,6 +19,7 @@ pub const START_MULTISIG_REPLY_ID: u64 = 1; const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME"); const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); +const BASE_VERSION: &str = "1.0.0"; #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( @@ -122,9 +123,9 @@ pub fn migrate( _env: Env, _msg: Empty, ) -> Result { - migrations::v1_0_0::migrate(deps.storage)?; - + cw2::assert_contract_version(deps.storage, CONTRACT_NAME, BASE_VERSION)?; cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Response::default()) } @@ -290,6 +291,17 @@ mod tests { query(deps, mock_env(), QueryMsg::CurrentVerifierSet {}).map(|res| from_json(res).unwrap()) } + #[test] + fn migrate_sets_contract_version() { + let mut deps = setup_test_case(); + + migrate(deps.as_mut(), mock_env(), Empty {}).unwrap(); + + let contract_version = cw2::get_contract_version(deps.as_mut().storage).unwrap(); + assert_eq!(contract_version.contract, CONTRACT_NAME); + assert_eq!(contract_version.version, CONTRACT_VERSION); + } + #[test] #[allow(clippy::arithmetic_side_effects)] fn test_instantiation() { diff --git a/contracts/multisig-prover/src/contract/migrations/mod.rs b/contracts/multisig-prover/src/contract/migrations/mod.rs index 1d185e9d7..8b1378917 100644 --- a/contracts/multisig-prover/src/contract/migrations/mod.rs +++ b/contracts/multisig-prover/src/contract/migrations/mod.rs @@ -1 +1 @@ -pub mod v1_0_0; + diff --git a/contracts/multisig-prover/src/contract/migrations/v1_0_0.rs b/contracts/multisig-prover/src/contract/migrations/v1_0_0.rs deleted file mode 100644 index e8dad3daa..000000000 --- a/contracts/multisig-prover/src/contract/migrations/v1_0_0.rs +++ /dev/null @@ -1,239 +0,0 @@ -#![allow(deprecated)] - -use axelar_wasm_std::error::ContractError; -use cosmwasm_std::{wasm_execute, Response, Storage}; - -use crate::contract::execute::all_active_verifiers; -use crate::contract::CONTRACT_NAME; -use crate::state::CONFIG; - -const BASE_VERSION: &str = "1.0.0"; - -pub fn migrate(storage: &mut dyn Storage) -> Result { - cw2::assert_contract_version(storage, CONTRACT_NAME, BASE_VERSION)?; - let config = CONFIG.load(storage)?; - - let verifiers = all_active_verifiers(storage)?; - - Ok(Response::new().add_message( - wasm_execute( - config.coordinator, - &coordinator::msg::ExecuteMsg::SetActiveVerifiers { verifiers }, - vec![], - ) - .map_err(ContractError::from)?, - )) -} - -#[cfg(test)] -mod tests { - use std::collections::HashSet; - - use axelar_wasm_std::{MajorityThreshold, Threshold}; - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cosmwasm_std::{ - from_json, CosmosMsg, DepsMut, Env, MessageInfo, Response, SubMsg, WasmMsg, - }; - use multisig::key::KeyType; - - use crate::contract::migrations::v1_0_0; - use crate::contract::{CONTRACT_NAME, CONTRACT_VERSION}; - use crate::encoding::Encoder; - use crate::error::ContractError; - use crate::msg::InstantiateMsg; - use crate::state::{Config, CURRENT_VERIFIER_SET, NEXT_VERIFIER_SET}; - use crate::test::test_data; - use crate::test::test_utils::COORDINATOR_ADDRESS; - - #[test] - fn migrate_checks_contract_version() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut()); - cw2::set_contract_version(deps.as_mut().storage, CONTRACT_NAME, "something wrong").unwrap(); - - assert!(v1_0_0::migrate(deps.as_mut().storage).is_err()); - - cw2::set_contract_version(deps.as_mut().storage, CONTRACT_NAME, v1_0_0::BASE_VERSION) - .unwrap(); - - assert!(v1_0_0::migrate(deps.as_mut().storage).is_ok()); - } - - #[test] - fn migrate_sets_contract_version() { - let mut deps = mock_dependencies(); - instantiate_contract(deps.as_mut()); - - v1_0_0::migrate(deps.as_mut().storage).unwrap(); - - let contract_version = cw2::get_contract_version(deps.as_mut().storage).unwrap(); - assert_eq!(contract_version.contract, CONTRACT_NAME); - assert_eq!(contract_version.version, CONTRACT_VERSION); - } - - // returns None if the msg is not the expected type (coordinator::msg::ExecuteMsg::SetActiveVerifiers) - fn extract_verifiers_from_set_active_verifiers_msg(msg: SubMsg) -> Option> { - match msg.msg { - CosmosMsg::Wasm(WasmMsg::Execute { msg, .. }) => { - let msg: coordinator::msg::ExecuteMsg = from_json(msg).unwrap(); - match msg { - coordinator::msg::ExecuteMsg::SetActiveVerifiers { verifiers } => { - Some(verifiers) - } - _ => None, - } - } - _ => None, - } - } - - // returns None if the msg is not the expected type (WasmMsg::Execute) - fn extract_contract_address_from_wasm_msg(msg: SubMsg) -> Option { - match msg.msg { - CosmosMsg::Wasm(WasmMsg::Execute { contract_addr, .. }) => Some(contract_addr), - _ => None, - } - } - - #[test] - fn migrate_sets_active_verifiers() { - let mut deps = mock_dependencies(); - - instantiate_contract(deps.as_mut()); - CURRENT_VERIFIER_SET - .save(deps.as_mut().storage, &test_data::curr_verifier_set()) - .unwrap(); - - let res = v1_0_0::migrate(deps.as_mut().storage); - assert!(res.is_ok()); - - let msgs = res.unwrap().messages; - assert_eq!(msgs.len(), 1); - let msg = msgs[0].clone(); - - let contract_address = extract_contract_address_from_wasm_msg(msg.clone()); - assert!(contract_address.is_some()); - assert_eq!(COORDINATOR_ADDRESS, contract_address.unwrap()); - - let verifiers = extract_verifiers_from_set_active_verifiers_msg(msg); - assert!(verifiers.is_some()); - - assert_eq!( - verifiers.unwrap(), - test_data::curr_verifier_set() - .signers - .values() - .map(|signer| signer.address.to_string()) - .collect::>() - ); - } - - #[test] - fn migrate_sets_active_verifiers_when_rotation_in_progress() { - let mut deps = mock_dependencies(); - - instantiate_contract(deps.as_mut()); - CURRENT_VERIFIER_SET - .save(deps.as_mut().storage, &test_data::curr_verifier_set()) - .unwrap(); - - NEXT_VERIFIER_SET - .save(deps.as_mut().storage, &test_data::new_verifier_set()) - .unwrap(); - - let res = v1_0_0::migrate(deps.as_mut().storage); - assert!(res.is_ok()); - - let msgs = res.unwrap().messages; - assert_eq!(msgs.len(), 1); - let msg = msgs[0].clone(); - - let contract_address = extract_contract_address_from_wasm_msg(msg.clone()); - assert!(contract_address.is_some()); - assert_eq!(COORDINATOR_ADDRESS, contract_address.unwrap()); - - let verifiers = extract_verifiers_from_set_active_verifiers_msg(msg); - assert!(verifiers.is_some()); - - assert_eq!( - verifiers.unwrap(), - test_data::curr_verifier_set() - .signers - .values() - .chain(test_data::new_verifier_set().signers.values()) - .map(|signer| signer.address.to_string()) - .collect::>() - ); - } - - fn instantiate_contract(deps: DepsMut) { - instantiate( - deps, - mock_env(), - mock_info("admin", &[]), - InstantiateMsg { - admin_address: "admin".to_string(), - governance_address: "governance".to_string(), - gateway_address: "gateway".to_string(), - multisig_address: "multisig".to_string(), - coordinator_address: "coordinator".to_string(), - service_registry_address: "service_registry".to_string(), - voting_verifier_address: "voting_verifier".to_string(), - signing_threshold: Threshold::try_from((2u64, 3u64)) - .and_then(MajorityThreshold::try_from) - .unwrap(), - service_name: "service".to_string(), - chain_name: "chain".to_string(), - verifier_set_diff_threshold: 1, - encoder: Encoder::Abi, - key_type: KeyType::Ecdsa, - domain_separator: [0; 32], - }, - ) - .unwrap(); - } - - #[deprecated(since = "0.6.0", note = "only used to test the migration")] - pub fn instantiate( - deps: DepsMut, - _env: Env, - _info: MessageInfo, - msg: InstantiateMsg, - ) -> Result { - cw2::set_contract_version(deps.storage, CONTRACT_NAME, v1_0_0::BASE_VERSION)?; - - let config = make_config(&deps, msg)?; - v1_0_0::CONFIG.save(deps.storage, &config)?; - - Ok(Response::default()) - } - - fn make_config( - deps: &DepsMut, - msg: InstantiateMsg, - ) -> Result { - let gateway = deps.api.addr_validate(&msg.gateway_address)?; - let multisig = deps.api.addr_validate(&msg.multisig_address)?; - let coordinator = deps.api.addr_validate(&msg.coordinator_address)?; - let service_registry = deps.api.addr_validate(&msg.service_registry_address)?; - let voting_verifier = deps.api.addr_validate(&msg.voting_verifier_address)?; - - Ok(Config { - gateway, - multisig, - coordinator, - service_registry, - voting_verifier, - signing_threshold: msg.signing_threshold, - service_name: msg.service_name, - chain_name: msg - .chain_name - .parse() - .map_err(|_| ContractError::InvalidChainName)?, - verifier_set_diff_threshold: msg.verifier_set_diff_threshold, - encoder: msg.encoder, - key_type: msg.key_type, - domain_separator: msg.domain_separator, - }) - } -}