diff --git a/Cargo.lock b/Cargo.lock index 88adc80814..9974f92fa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4337,10 +4337,12 @@ dependencies = [ "bs58 0.5.1", "cosmwasm-schema", "cosmwasm-std", + "cw-storage-plus", "schemars", "serde", "serde_json", "thiserror", + "vergen", ] [[package]] @@ -9213,11 +9215,14 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "8.2.6" +version = "8.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1290fd64cc4e7d3c9b07d7f333ce0ce0007253e32870e632624835cc80b83939" +checksum = "e27d6bdd219887a9eadd19e1c34f32e47fa332301184935c6d9bca26f3cca525" dependencies = [ "anyhow", + "cargo_metadata", + "cfg-if", + "regex", "rustc_version 0.4.0", "rustversion", "time", diff --git a/Cargo.toml b/Cargo.toml index bdce9b228e..e329b82511 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -289,7 +289,7 @@ tungstenite = { version = "0.20.1", default-features = false } url = "2.4" utoipa = "4.2.0" utoipa-swagger-ui = "6.0.0" -vergen = { version = "=8.2.6", default-features = false } +vergen = { version = "=8.3.1", default-features = false } walkdir = "2" wasm-bindgen-test = "0.3.36" zeroize = "1.6.0" diff --git a/common/client-libs/validator-client/src/nyxd/mod.rs b/common/client-libs/validator-client/src/nyxd/mod.rs index 2fd0f23e76..ec77c2ecad 100644 --- a/common/client-libs/validator-client/src/nyxd/mod.rs +++ b/common/client-libs/validator-client/src/nyxd/mod.rs @@ -70,6 +70,8 @@ use crate::http_client; use crate::{DirectSigningHttpRpcNyxdClient, QueryHttpRpcNyxdClient}; #[cfg(feature = "http-client")] use cosmrs::rpc::{HttpClient, HttpClientUrl}; +use nym_contracts_common::build_information::CONTRACT_BUILD_INFO_STORAGE_KEY; +use nym_contracts_common::ContractBuildInformation; pub mod coin; pub mod contract_traits; @@ -328,6 +330,31 @@ where .await .map(|block| block.block_id.hash) } + + pub async fn get_cw2_contract_version( + &self, + contract_address: &AccountId, + ) -> Result, NyxdError> { + let raw_info = self + .query_contract_raw(contract_address, b"contract_info".to_vec()) + .await?; + + Ok(serde_json::from_slice(&raw_info).ok()) + } + + pub async fn get_contract_build_information( + &self, + contract_address: &AccountId, + ) -> Result, NyxdError> { + let raw_info = self + .query_contract_raw( + contract_address, + CONTRACT_BUILD_INFO_STORAGE_KEY.as_bytes().to_vec(), + ) + .await?; + + Ok(serde_json::from_slice(&raw_info).ok()) + } } // signing diff --git a/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml b/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml index 93acef267d..8a299c1c2a 100644 --- a/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml +++ b/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml @@ -11,9 +11,13 @@ repository = { workspace = true } bs58 = { workspace = true } cosmwasm-std = { workspace = true } cosmwasm-schema = { workspace = true } +cw-storage-plus = { workspace = true } schemars = { workspace = true } serde = { workspace = true, features = ["derive"] } thiserror = { workspace = true } [dev-dependencies] serde_json = { workspace = true } + +[build-dependencies] +vergen = { version = "=8.3.1", features = ["build", "git", "gitcl", "rustc", "cargo"] } diff --git a/common/cosmwasm-smart-contracts/contracts-common/build.rs b/common/cosmwasm-smart-contracts/contracts-common/build.rs new file mode 100644 index 0000000000..951fa6094a --- /dev/null +++ b/common/cosmwasm-smart-contracts/contracts-common/build.rs @@ -0,0 +1,17 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use vergen::EmitBuilder; + +fn main() { + EmitBuilder::builder() + .all_build() + .rustc_semver() + .git_branch() + .git_commit_timestamp() + .git_sha(false) + .cargo_debug() + .cargo_opt_level() + .emit() + .expect("failed to extract build metadata"); +} diff --git a/common/cosmwasm-smart-contracts/contracts-common/src/build_information.rs b/common/cosmwasm-smart-contracts/contracts-common/src/build_information.rs new file mode 100644 index 0000000000..7d1ea82623 --- /dev/null +++ b/common/cosmwasm-smart-contracts/contracts-common/src/build_information.rs @@ -0,0 +1,85 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::ContractBuildInformation; +use cosmwasm_std::{StdResult, Storage}; +use cw_storage_plus::Item; + +pub const CONTRACT_BUILD_INFO_STORAGE_KEY: &str = "contract_build_info"; +pub const CONTRACT_BUILD_INFO: Item = + Item::new(CONTRACT_BUILD_INFO_STORAGE_KEY); + +// important note. this MUST BE called inside the contract code itself and not any intermediate crate +// otherwise macro expansions will resolve to incorrect data +#[macro_export] +macro_rules! get_build_information { + () => { + $crate::types::ContractBuildInformation::new( + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION"), + ) + }; +} + +pub fn set_state_build_information( + store: &mut dyn Storage, + build_info: ContractBuildInformation, +) -> StdResult<()> { + CONTRACT_BUILD_INFO.save(store, &build_info) +} + +pub fn get_contract_build_information(store: &dyn Storage) -> StdResult { + CONTRACT_BUILD_INFO.load(store) +} + +#[macro_export] +macro_rules! set_build_information { + ( $store:expr ) => { + $crate::build_information::set_state_build_information( + $store, + $crate::get_build_information!(), + ) + }; +} + +#[cfg(test)] +mod tests { + use super::*; + use cosmwasm_std::testing::MockStorage; + + #[test] + fn get_and_set_work() { + let mut store = MockStorage::new(); + + // error if not set + assert!(get_contract_build_information(&store).is_err()); + + // set and get + let contract_name = "nym-mixnet-contract"; + let contract_version = "1.2.3"; + let build_info = ContractBuildInformation::new(contract_name, contract_version); + + set_state_build_information(&mut store, build_info).unwrap(); + + let loaded = get_contract_build_information(&store).unwrap(); + + let expected = ContractBuildInformation { + contract_name: contract_name.into(), + build_version: contract_version.into(), + build_timestamp: env!("VERGEN_BUILD_TIMESTAMP").to_string(), + commit_sha: option_env!("VERGEN_GIT_SHA") + .unwrap_or("UNKNOWN") + .to_string(), + commit_timestamp: option_env!("VERGEN_GIT_COMMIT_TIMESTAMP") + .unwrap_or("UNKNOWN") + .to_string(), + commit_branch: option_env!("VERGEN_GIT_BRANCH") + .unwrap_or("UNKNOWN") + .to_string(), + rustc_version: env!("VERGEN_RUSTC_SEMVER").to_string(), + cargo_debug: env!("VERGEN_CARGO_DEBUG").to_string(), + cargo_opt_level: env!("VERGEN_CARGO_OPT_LEVEL").to_string(), + }; + assert_eq!(expected, loaded); + } +} diff --git a/common/cosmwasm-smart-contracts/contracts-common/src/lib.rs b/common/cosmwasm-smart-contracts/contracts-common/src/lib.rs index 9f6cd8098f..301e109d80 100644 --- a/common/cosmwasm-smart-contracts/contracts-common/src/lib.rs +++ b/common/cosmwasm-smart-contracts/contracts-common/src/lib.rs @@ -4,6 +4,7 @@ #![warn(clippy::expect_used)] #![warn(clippy::unwrap_used)] +pub mod build_information; pub mod dealings; pub mod events; pub mod signing; diff --git a/common/cosmwasm-smart-contracts/contracts-common/src/types.rs b/common/cosmwasm-smart-contracts/contracts-common/src/types.rs index 218bd6ca50..e14cb3501a 100644 --- a/common/cosmwasm-smart-contracts/contracts-common/src/types.rs +++ b/common/cosmwasm-smart-contracts/contracts-common/src/types.rs @@ -132,10 +132,18 @@ where } } +fn default_unknown() -> String { + "unknown".to_string() +} + // TODO: there's no reason this couldn't be used for proper binaries, but in that case // perhaps the struct should get renamed and moved to a "more" common crate #[cw_serde] pub struct ContractBuildInformation { + /// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable. + #[serde(default = "default_unknown")] + pub contract_name: String, + // VERGEN_BUILD_TIMESTAMP /// Provides the build timestamp, for example `2021-02-23T20:14:46.558472672+00:00`. pub build_timestamp: String, @@ -159,6 +167,38 @@ pub struct ContractBuildInformation { // VERGEN_RUSTC_SEMVER /// Provides the rustc version that was used for the build, for example `1.52.0-nightly`. pub rustc_version: String, + + // VERGEN_CARGO_DEBUG + /// Provides the cargo debug mode that was used for the build. + #[serde(default = "default_unknown")] + pub cargo_debug: String, + + // VERGEN_CARGO_OPT_LEVEL + /// Provides the opt value set by cargo during the build + #[serde(default = "default_unknown")] + pub cargo_opt_level: String, +} + +impl ContractBuildInformation { + pub fn new(name: impl Into, version: impl Into) -> Self { + ContractBuildInformation { + contract_name: name.into(), + build_version: version.into(), + build_timestamp: env!("VERGEN_BUILD_TIMESTAMP").to_string(), + commit_sha: option_env!("VERGEN_GIT_SHA") + .unwrap_or("UNKNOWN") + .to_string(), + commit_timestamp: option_env!("VERGEN_GIT_COMMIT_TIMESTAMP") + .unwrap_or("UNKNOWN") + .to_string(), + commit_branch: option_env!("VERGEN_GIT_BRANCH") + .unwrap_or("UNKNOWN") + .to_string(), + rustc_version: env!("VERGEN_RUSTC_SEMVER").to_string(), + cargo_debug: env!("VERGEN_CARGO_DEBUG").to_string(), + cargo_opt_level: env!("VERGEN_CARGO_OPT_LEVEL").to_string(), + } + } } #[cfg(test)] diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/error.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/error.rs index 6007884cc8..ec6e79c65f 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/error.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/error.rs @@ -234,12 +234,6 @@ pub enum MixnetContractError { #[error("the epoch is currently not in the 'epoch advancement' state. (the state is {current_state})")] EpochNotInAdvancementState { current_state: EpochState }, - #[error("failed to parse {value} into a valid SemVer version: {error_message}")] - SemVerFailure { - value: String, - error_message: String, - }, - #[error("failed to verify message signature: {source}")] SignatureVerificationFailure { #[from] diff --git a/contracts/coconut-dkg/Cargo.toml b/contracts/coconut-dkg/Cargo.toml index 7d81b122fe..836c58104a 100644 --- a/contracts/coconut-dkg/Cargo.toml +++ b/contracts/coconut-dkg/Cargo.toml @@ -14,6 +14,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] nym-coconut-dkg-common = { path = "../../common/cosmwasm-smart-contracts/coconut-dkg" } +nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common" } cosmwasm-schema = { workspace = true, optional = true } cosmwasm-std = { workspace = true } @@ -23,7 +24,6 @@ cw-controllers = { workspace = true } cw2 = { workspace = true } cw4 = { workspace = true } serde = { version = "1.0.103", default-features = false, features = ["derive"] } -semver = { workspace = true, default-features = false } thiserror = { workspace = true } [dev-dependencies] diff --git a/contracts/coconut-dkg/src/contract.rs b/contracts/coconut-dkg/src/contract.rs index 2d1e25d5e9..a1d84337af 100644 --- a/contracts/coconut-dkg/src/contract.rs +++ b/contracts/coconut-dkg/src/contract.rs @@ -30,7 +30,7 @@ use cosmwasm_std::{ use cw4::Cw4Contract; use nym_coconut_dkg_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; use nym_coconut_dkg_common::types::{Epoch, EpochState, State}; -use semver::Version; +use nym_contracts_common::set_build_information; const CONTRACT_NAME: &str = "crate:nym-coconut-dkg"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -77,6 +77,7 @@ pub fn instantiate( )?; cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + set_build_information!(deps.storage)?; Ok(Response::default()) } @@ -213,25 +214,8 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result, _env: Env, _msg: MigrateMsg) -> Result { - fn parse_semver(raw: &str) -> Result { - raw.parse() - .map_err(|error: semver::Error| ContractError::SemVerFailure { - value: CONTRACT_VERSION.to_string(), - error_message: error.to_string(), - }) - } - - // Note: don't remove this particular bit of code as we have to ALWAYS check whether we have to - // update the stored version - let build_version: Version = parse_semver(CONTRACT_VERSION)?; - let stored_version: Version = parse_semver(&cw2::get_contract_version(deps.storage)?.version)?; - - if stored_version < build_version { - cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - - // If state structure changed in any contract version in the way migration is needed, it - // should occur here, for example anything from `crate::queued_migrations::` - } + set_build_information!(deps.storage)?; + cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; Ok(Response::new()) } diff --git a/contracts/coconut-dkg/src/error.rs b/contracts/coconut-dkg/src/error.rs index bde8738951..c867fec2be 100644 --- a/contracts/coconut-dkg/src/error.rs +++ b/contracts/coconut-dkg/src/error.rs @@ -128,12 +128,6 @@ pub enum ContractError { #[error("No verification key committed for owner {owner}")] NoCommitForOwner { owner: String }, - #[error("failed to parse {value} into a valid SemVer version: {error_message}")] - SemVerFailure { - value: String, - error_message: String, - }, - #[error("cannot perform DKG reset during an ongoing exchange")] CantResetDuringExchange, diff --git a/contracts/mixnet/Cargo.toml b/contracts/mixnet/Cargo.toml index 2b854def9f..94133686d5 100644 --- a/contracts/mixnet/Cargo.toml +++ b/contracts/mixnet/Cargo.toml @@ -9,10 +9,10 @@ repository = { workspace = true } readme = "README.md" exclude = [ - # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. - "contract.wasm", - "hash.txt", - "artifacts", + # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. + "contract.wasm", + "hash.txt", + "artifacts", ] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -41,15 +41,11 @@ bs58 = { workspace = true } serde = { workspace = true, default-features = false, features = ["derive"] } thiserror = { workspace = true } time = { version = "0.3", features = ["macros"] } -semver = { workspace = true, default-features = false } [dev-dependencies] rand_chacha = "0.3" nym-crypto = { path = "../../common/crypto", features = ["asymmetric", "rand"] } -[build-dependencies] -vergen = { version = "=7.4.3", default-features = false, features = ["build", "git", "rustc"] } - [features] default = [] contract-testing = ["mixnet-contract-common/contract-testing"] diff --git a/contracts/mixnet/build.rs b/contracts/mixnet/build.rs deleted file mode 100644 index 93402c2fbd..0000000000 --- a/contracts/mixnet/build.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2021 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use vergen::{vergen, Config}; - -fn main() { - let mut config = Config::default(); - if std::env::var("DOCS_RS").is_ok() { - // If we don't have access to git information, such as in a docs.rs build, don't error - *config.git_mut().skip_if_error_mut() = true; - } - vergen(config).expect("failed to extract build metadata"); -} diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index 0e8a75df39..e6c755d05d 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -13,7 +13,7 @@ use mixnet_contract_common::error::MixnetContractError; use mixnet_contract_common::{ ContractState, ContractStateParams, ExecuteMsg, InstantiateMsg, Interval, MigrateMsg, QueryMsg, }; -use semver::Version; +use nym_contracts_common::set_build_information; // version info for migration info const CONTRACT_NAME: &str = "crate:nym-mixnet-contract"; @@ -87,6 +87,7 @@ pub fn instantiate( mixnode_storage::initialise_storage(deps.storage)?; rewards_storage::initialise_storage(deps.storage, reward_params)?; cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + set_build_information!(deps.storage)?; Ok(Response::default()) } @@ -610,29 +611,8 @@ pub fn migrate( _env: Env, msg: MigrateMsg, ) -> Result { - // note: don't remove this particular bit of code as we have to ALWAYS check whether we have to update the stored version - let version: Version = CONTRACT_VERSION.parse().map_err(|error: semver::Error| { - MixnetContractError::SemVerFailure { - value: CONTRACT_VERSION.to_string(), - error_message: error.to_string(), - } - })?; - - let storage_version_raw = cw2::get_contract_version(deps.storage)?.version; - let storage_version: Version = - storage_version_raw - .parse() - .map_err(|error: semver::Error| MixnetContractError::SemVerFailure { - value: storage_version_raw, - error_message: error.to_string(), - })?; - - if storage_version < version { - cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - - // If state structure changed in any contract version in the way migration is needed, it - // should occur here, for example anything from `crate::queued_migrations::` - } + set_build_information!(deps.storage)?; + cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; // due to circular dependency on contract addresses (i.e. mixnet contract requiring vesting contract address // and vesting contract requiring the mixnet contract address), if we ever want to deploy any new fresh diff --git a/contracts/mixnet/src/mixnet_contract_settings/queries.rs b/contracts/mixnet/src/mixnet_contract_settings/queries.rs index d479017508..1fbedf4d62 100644 --- a/contracts/mixnet/src/mixnet_contract_settings/queries.rs +++ b/contracts/mixnet/src/mixnet_contract_settings/queries.rs @@ -4,6 +4,7 @@ use super::storage; use cosmwasm_std::{Deps, StdResult}; use mixnet_contract_common::{ContractBuildInformation, ContractState, ContractStateParams}; +use nym_contracts_common::get_build_information; pub(crate) fn query_contract_state(deps: Deps<'_>) -> StdResult { storage::CONTRACT_STATE.load(deps.storage) @@ -22,21 +23,7 @@ pub(crate) fn query_rewarding_validator_address(deps: Deps<'_>) -> StdResult ContractBuildInformation { - // as per docs - // env! macro will expand to the value of the named environment variable at - // compile time, yielding an expression of type `&'static str` - ContractBuildInformation { - build_timestamp: env!("VERGEN_BUILD_TIMESTAMP").to_string(), - build_version: env!("VERGEN_BUILD_SEMVER").to_string(), - commit_sha: option_env!("VERGEN_GIT_SHA").unwrap_or("NONE").to_string(), - commit_timestamp: option_env!("VERGEN_GIT_COMMIT_TIMESTAMP") - .unwrap_or("NONE") - .to_string(), - commit_branch: option_env!("VERGEN_GIT_BRANCH") - .unwrap_or("NONE") - .to_string(), - rustc_version: env!("VERGEN_RUSTC_SEMVER").to_string(), - } + get_build_information!() } #[cfg(test)] diff --git a/contracts/multisig/cw3-flex-multisig/Cargo.toml b/contracts/multisig/cw3-flex-multisig/Cargo.toml index bd0e980bde..f923697b77 100644 --- a/contracts/multisig/cw3-flex-multisig/Cargo.toml +++ b/contracts/multisig/cw3-flex-multisig/Cargo.toml @@ -34,7 +34,8 @@ cosmwasm-schema = { workspace = true, optional = true } cosmwasm-std = { workspace = true } nym-group-contract-common = { path = "../../../common/cosmwasm-smart-contracts/group-contract" } -nym-multisig-contract-common = { path= "../../../common/cosmwasm-smart-contracts/multisig-contract" } +nym-multisig-contract-common = { path = "../../../common/cosmwasm-smart-contracts/multisig-contract" } +nym-contracts-common = { path = "../../../common/cosmwasm-smart-contracts/contracts-common" } [dev-dependencies] cw4-group = { path = "../cw4-group", version = "1.0.0" } diff --git a/contracts/multisig/cw3-flex-multisig/src/contract.rs b/contracts/multisig/cw3-flex-multisig/src/contract.rs index 9a0c8eacad..555eb02f39 100644 --- a/contracts/multisig/cw3-flex-multisig/src/contract.rs +++ b/contracts/multisig/cw3-flex-multisig/src/contract.rs @@ -17,6 +17,7 @@ use cw3_fixed_multisig::state::{next_id, BALLOTS, PROPOSALS}; use cw4::{Cw4Contract, MemberChangedHookMsg, MemberDiff}; use cw_storage_plus::Bound; use cw_utils::{maybe_addr, Expiration, ThresholdResponse}; +use nym_contracts_common::set_build_information; use nym_multisig_contract_common::error::ContractError; use nym_multisig_contract_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; @@ -53,6 +54,7 @@ pub fn instantiate( .transpose()?; set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + set_build_information!(deps.storage)?; let cfg = Config { threshold: msg.threshold, @@ -488,6 +490,9 @@ fn list_voters( #[cfg_attr(not(feature = "library"), entry_point)] pub fn migrate(deps: DepsMut<'_>, _env: Env, msg: MigrateMsg) -> Result { + set_build_information!(deps.storage)?; + cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + let mut cfg = CONFIG.load(deps.storage)?; cfg.coconut_bandwidth_addr = deps.api.addr_validate(&msg.coconut_bandwidth_address)?; cfg.coconut_dkg_addr = deps.api.addr_validate(&msg.coconut_dkg_address)?; diff --git a/contracts/multisig/cw4-group/Cargo.toml b/contracts/multisig/cw4-group/Cargo.toml index 6c63d707ef..9798ab626f 100644 --- a/contracts/multisig/cw4-group/Cargo.toml +++ b/contracts/multisig/cw4-group/Cargo.toml @@ -10,8 +10,8 @@ homepage = "https://cosmwasm.com" documentation = "https://docs.cosmwasm.com" exclude = [ - # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. - "artifacts/*", + # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. + "artifacts/*", ] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -31,6 +31,7 @@ library = [] [dependencies] nym-group-contract-common = { path = "../../../common/cosmwasm-smart-contracts/group-contract" } +nym-contracts-common = { path = "../../../common/cosmwasm-smart-contracts/contracts-common" } cw-utils = { workspace = true } cw2 = { workspace = true } diff --git a/contracts/multisig/cw4-group/src/contract.rs b/contracts/multisig/cw4-group/src/contract.rs index c5c039658c..46d853e022 100644 --- a/contracts/multisig/cw4-group/src/contract.rs +++ b/contracts/multisig/cw4-group/src/contract.rs @@ -11,6 +11,7 @@ use cw4::{ }; use cw_storage_plus::Bound; use cw_utils::maybe_addr; +use nym_contracts_common::set_build_information; use crate::error::ContractError; use crate::helpers::validate_unique_members; @@ -31,6 +32,8 @@ pub fn instantiate( msg: InstantiateMsg, ) -> Result { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + set_build_information!(deps.storage)?; + create(deps, msg.admin, msg.members, env.block.height)?; Ok(Response::default()) } @@ -221,6 +224,9 @@ pub fn query_list_members( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result { +pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result { + set_build_information!(deps.storage)?; + cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + Ok(Default::default()) } diff --git a/contracts/name-service/Cargo.toml b/contracts/name-service/Cargo.toml index e3ec82c685..5e60860761 100644 --- a/contracts/name-service/Cargo.toml +++ b/contracts/name-service/Cargo.toml @@ -20,13 +20,9 @@ cw-utils = { workspace = true } cw2 = { workspace = true } nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", version = "0.5.0" } nym-name-service-common = { path = "../../common/cosmwasm-smart-contracts/name-service" } -semver = { workspace = true, default-features = false } serde = { version = "1.0.155", default-features = false, features = ["derive"] } thiserror = { workspace = true } -[build-dependencies] -vergen = { version = "=7.4.3", default-features = false, features = ["build", "git", "rustc"] } - [dev-dependencies] anyhow = "1.0.40" cw-multi-test = { workspace = true } diff --git a/contracts/service-provider-directory/Cargo.toml b/contracts/service-provider-directory/Cargo.toml index 570b50e8aa..95c001f85b 100644 --- a/contracts/service-provider-directory/Cargo.toml +++ b/contracts/service-provider-directory/Cargo.toml @@ -20,13 +20,9 @@ cw-utils = { workspace = true } cw2 = { workspace = true } nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", version = "0.5.0" } nym-service-provider-directory-common = { path = "../../common/cosmwasm-smart-contracts/service-provider-directory" } -semver = { workspace = true, default-features = false } serde = { version = "1.0.155", default-features = false, features = ["derive"] } thiserror = { workspace = true } -[build-dependencies] -vergen = { version = "=7.4.3", default-features = false, features = ["build", "git", "rustc"] } - [dev-dependencies] anyhow = "1.0.40" cw-multi-test = { workspace = true } diff --git a/contracts/vesting/Cargo.toml b/contracts/vesting/Cargo.toml index 28f3120c17..2845ee15a1 100644 --- a/contracts/vesting/Cargo.toml +++ b/contracts/vesting/Cargo.toml @@ -9,10 +9,10 @@ repository = { workspace = true } readme = "README.md" exclude = [ - # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. - "contract.wasm", - "hash.txt", - "artifacts", + # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. + "contract.wasm", + "hash.txt", + "artifacts", ] [[bin]] @@ -35,8 +35,7 @@ cw2 = { workspace = true } cw-storage-plus = { workspace = true, features = ["iterator"] } serde = { version = "1.0", default-features = false, features = ["derive"] } -thiserror ={ workspace = true } -semver = { workspace = true, default-features = false } +thiserror = { workspace = true } [dev-dependencies] rand_chacha = "0.3.1" @@ -45,8 +44,6 @@ hex = "0.4.3" serde_json = "1.0.66" cosmwasm-crypto = { workspace = true } -[build-dependencies] -vergen = { version = "=7.4.3", default-features = false, features = ["build", "git", "rustc"] } [features] schema-gen = ["vesting-contract-common/schema", "cosmwasm-schema"] diff --git a/contracts/vesting/build.rs b/contracts/vesting/build.rs deleted file mode 100644 index dfffaafd59..0000000000 --- a/contracts/vesting/build.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2021 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use vergen::{vergen, Config}; - -fn main() { - let mut config = Config::default(); - if std::env::var("DOCS_RS").is_ok() { - // If we don't have access to git information, such as in a docs.rs build, don't error - *config.git_mut().skip_if_error_mut() = true; - } - vergen(config).expect("failed to extract build metadata") -} diff --git a/contracts/vesting/src/contract.rs b/contracts/vesting/src/contract.rs index 31d3c21b06..a9689e3390 100644 --- a/contracts/vesting/src/contract.rs +++ b/contracts/vesting/src/contract.rs @@ -1,11 +1,11 @@ pub use crate::queries::*; use crate::storage::{ADMIN, MIXNET_CONTRACT_ADDRESS, MIX_DENOM}; pub use crate::transactions::*; +use contracts_common::set_build_information; use cosmwasm_std::{ entry_point, to_binary, Addr, Coin, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, Uint128, }; -use semver::Version; use vesting_contract_common::messages::{ExecuteMsg, InitMsg, MigrateMsg, QueryMsg}; use vesting_contract_common::{Account, VestingContractError}; @@ -45,6 +45,7 @@ pub fn instantiate( MIX_DENOM.save(deps.storage, &msg.mix_denom)?; cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + set_build_information!(deps.storage)?; Ok(Response::default()) } @@ -55,29 +56,8 @@ pub fn migrate( _env: Env, _msg: MigrateMsg, ) -> Result { - // note: don't remove this particular bit of code as we have to ALWAYS check whether we have to update the stored version - let version: Version = CONTRACT_VERSION.parse().map_err(|error: semver::Error| { - VestingContractError::SemVerFailure { - value: CONTRACT_VERSION.to_string(), - error_message: error.to_string(), - } - })?; - - let storage_version_raw = cw2::get_contract_version(deps.storage)?.version; - let storage_version: Version = - storage_version_raw - .parse() - .map_err(|error: semver::Error| VestingContractError::SemVerFailure { - value: storage_version_raw, - error_message: error.to_string(), - })?; - - if storage_version < version { - cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - - // If state structure changed in any contract version in the way migration is needed, it - // should occur here, for example anything from `crate::queued_migrations::` - } + set_build_information!(deps.storage)?; + cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; Ok(Response::new()) } diff --git a/contracts/vesting/src/queries.rs b/contracts/vesting/src/queries.rs index c3c9c0d99d..17330c6dbe 100644 --- a/contracts/vesting/src/queries.rs +++ b/contracts/vesting/src/queries.rs @@ -5,7 +5,7 @@ use crate::storage; use crate::storage::{account_from_address, BlockTimestampSecs, ACCOUNTS, DELEGATIONS, MIX_DENOM}; use crate::traits::VestingAccount; use crate::vesting::StorableVestingAccountExt; -use contracts_common::ContractBuildInformation; +use contracts_common::{get_build_information, ContractBuildInformation}; use cosmwasm_std::{Coin, Deps, Env, Order, StdResult, Timestamp, Uint128}; use cw_storage_plus::Bound; use mixnet_contract_common::MixId; @@ -49,21 +49,7 @@ pub fn try_get_account(address: &str, deps: Deps<'_>) -> Result ContractBuildInformation { - // as per docs - // env! macro will expand to the value of the named environment variable at - // compile time, yielding an expression of type `&'static str` - ContractBuildInformation { - build_timestamp: env!("VERGEN_BUILD_TIMESTAMP").to_string(), - build_version: env!("VERGEN_BUILD_SEMVER").to_string(), - commit_sha: option_env!("VERGEN_GIT_SHA").unwrap_or("NONE").to_string(), - commit_timestamp: option_env!("VERGEN_GIT_COMMIT_TIMESTAMP") - .unwrap_or("NONE") - .to_string(), - commit_branch: option_env!("VERGEN_GIT_BRANCH") - .unwrap_or("NONE") - .to_string(), - rustc_version: env!("VERGEN_RUSTC_SEMVER").to_string(), - } + get_build_information!() } pub fn try_get_all_accounts( diff --git a/nym-api/src/nym_contract_cache/cache/refresher.rs b/nym-api/src/nym_contract_cache/cache/refresher.rs index b855e48f83..5a9970008e 100644 --- a/nym-api/src/nym_contract_cache/cache/refresher.rs +++ b/nym-api/src/nym_contract_cache/cache/refresher.rs @@ -6,13 +6,11 @@ use crate::nym_contract_cache::cache::data::{CachedContractInfo, CachedContracts use crate::nyxd::Client; use crate::support::caching::CacheNotification; use anyhow::Result; -use futures::future::join_all; use nym_mixnet_contract_common::{MixId, MixNodeDetails, RewardedSetNodeStatus}; use nym_task::TaskClient; use nym_validator_client::nyxd::contract_traits::{ MixnetQueryClient, NymContractsProvider, VestingQueryClient, }; -use nym_validator_client::nyxd::CosmWasmClient; use std::{collections::HashMap, sync::atomic::Ordering, time::Duration}; use tokio::sync::watch; use tokio::time; @@ -59,81 +57,48 @@ impl NymContractCacheRefresher { let group = query_guard!(client_guard, group_contract_address()); let multisig = query_guard!(client_guard, multisig_contract_address()); - // get cw2 versions - let mixnet_cw2_future = query_guard!(client_guard, get_mixnet_contract_cw2_version()); - let vesting_cw2_future = query_guard!(client_guard, get_vesting_contract_cw2_version()); + for (address, name) in [ + (mixnet, "nym-mixnet-contract"), + (vesting, "nym-vesting-contract"), + (coconut_bandwidth, "nym-coconut-bandwidth-contract"), + (coconut_dkg, "nym-coconut-dkg-contract"), + (group, "nym-cw4-group-contract"), + (multisig, "nym-cw3-multisig-contract"), + ] { + let (cw2, build_info) = if let Some(address) = address { + let cw2 = query_guard!(client_guard, get_cw2_contract_version(address).await)?; + let mut build_info = + query_guard!(client_guard, get_contract_build_information(address).await)?; - // group and multisig contract save that information in their storage but don't expose it via queries - // so a temporary workaround... - let multisig_cw2 = if let Some(multisig_contract) = multisig { - query_guard!( - client_guard, - query_contract_raw(multisig_contract, b"contract_info".to_vec()) - .await - .map(|r| serde_json::from_slice(&r).ok()) - .ok() - .flatten() - ) - } else { - None - }; - let group_cw2 = if let Some(group_contract) = group { - query_guard!( - client_guard, - query_contract_raw(group_contract, b"contract_info".to_vec()) - .await - .map(|r| serde_json::from_slice(&r).ok()) - .ok() - .flatten() - ) - } else { - None - }; + // for backwards compatibility until we migrate the contracts + if build_info.is_none() { + match name { + "nym-mixnet-contract" => { + build_info = Some(query_guard!( + client_guard, + get_mixnet_contract_version().await + )?) + } + "nym-vesting-contract" => { + build_info = Some(query_guard!( + client_guard, + get_vesting_contract_version().await + )?) + } + _ => (), + } + } - let mut cw2_info = join_all(vec![mixnet_cw2_future, vesting_cw2_future]).await; + (cw2, build_info) + } else { + (None, None) + }; - // get detailed build info - let mixnet_detailed_future = query_guard!(client_guard, get_mixnet_contract_version()); - let vesting_detailed_future = query_guard!(client_guard, get_vesting_contract_version()); - - let mut build_info = join_all(vec![mixnet_detailed_future, vesting_detailed_future]).await; - - // the below unwraps are fine as we definitely have the specified number of entries - // Note to whoever updates this code in the future: `pop` removes **LAST** element, - // so make sure you call them in correct order, depending on what's specified in the `join_all` - updated.insert( - "nym-vesting-contract".to_string(), - CachedContractInfo::new( - vesting, - cw2_info.pop().unwrap().ok(), - build_info.pop().unwrap().ok(), - ), - ); - updated.insert( - "nym-mixnet-contract".to_string(), - CachedContractInfo::new( - mixnet, - cw2_info.pop().unwrap().ok(), - build_info.pop().unwrap().ok(), - ), - ); - - updated.insert( - "nym-coconut-bandwidth-contract".to_string(), - CachedContractInfo::new(coconut_bandwidth, None, None), - ); - updated.insert( - "nym-coconut-dkg-contract".to_string(), - CachedContractInfo::new(coconut_dkg, None, None), - ); - updated.insert( - "nym-cw3-multisig-contract".to_string(), - CachedContractInfo::new(multisig, multisig_cw2, None), - ); - updated.insert( - "nym-cw4-group-contract".to_string(), - CachedContractInfo::new(group, group_cw2, None), - ); + updated.insert( + name.to_string(), + CachedContractInfo::new(address, cw2, build_info), + ); + } Ok(updated) } diff --git a/nym-api/src/support/nyxd/mod.rs b/nym-api/src/support/nyxd/mod.rs index 99a6afa21e..833d891473 100644 --- a/nym-api/src/support/nyxd/mod.rs +++ b/nym-api/src/support/nyxd/mod.rs @@ -9,6 +9,7 @@ use async_trait::async_trait; use cw3::{ProposalResponse, VoteResponse}; use cw4::MemberResponse; use nym_coconut_bandwidth_contract_common::spend_credential::SpendCredentialResponse; +use nym_coconut_dkg_common::dealer::RegisteredDealerDetails; use nym_coconut_dkg_common::dealing::{ DealerDealingsStatusResponse, DealingChunkInfo, DealingMetadata, DealingStatusResponse, PartialContractDealing, @@ -21,8 +22,6 @@ use nym_coconut_dkg_common::{ verification_key::{ContractVKShare, VerificationKeyShare}, }; use nym_config::defaults::{ChainDetails, NymNetworkDetails}; - -use nym_coconut_dkg_common::dealer::RegisteredDealerDetails; use nym_mixnet_contract_common::families::FamilyHead; use nym_mixnet_contract_common::mixnode::MixNodeDetails; use nym_mixnet_contract_common::reward_params::RewardingParams;