diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a79762d68..9c888a8eb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,86 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// ## [Unreleased] +## [2025.1-reeses] (2025-01-15) + +- Feture/legacy alert ([#5346]) +- chore: readjusted --mode behaviour to fix the regression ([#5331]) +- chore: apply 1.84 linter suggestions ([#5330]) +- bugfix: make sure refresh data key matches bond info ([#5329]) +- reduce log severity for number of packets being delayed ([#5321]) +- feat: warn users if node is run in exit mode only ([#5320]) +- Bugfix/contract version assignment ([#5318]) +- fixed client session histogram buckets ([#5316]) +- amend 250gb limit ([#5313]) +- feature: expand nym-node prometheus metrics ([#5298]) +- Cherry picked #5286 ([#5287]) +- Add close to credential storage ([#5283]) +- feature: wireguard metrics ([#5278]) +- Add PATCH support to nym-http-api-client ([#5260]) +- chore: removed legacy socks5 listener ([#5259]) +- bugfix: make sure to apply gateway score filtering when choosing initial node ([#5256]) +- Update TS bindings ([#5255]) +- Add conversion unit tests for auth msg ([#5251]) +- Add control messages to GatewayTransciver ([#5247]) +- Remove unneeded async function annotation ([#5246]) +- bugfix: make sure to update timestamp of last batch verification to prevent double redemption ([#5239]) +- Add FromStr impl for UserAgent ([#5236]) +- Extend swagger docs ([#5235]) +- TicketType derive Hash and Eq ([#5233]) +- Add fd callback to client core ([#5230]) +- Extend raw ws fd for gateway client ([#5218]) +- Shipping raw metrics to PG ([#5216]) +- Change sqlite journal mode to WAL ([#5213]) +- Derive serialize for UserAgent ([#5210]) +- Restore Location fields ([#5208]) +- better date serialization ([#5207]) +- Fix overflow ([#5204]) +- feature: hopefully final steps of the smoosh™️ ([#5201]) +- Fix overflow ([#5184]) +- NS API - Gateway stats scraping ([#5180]) +- introduced initial internal commands for nym-cli: ecash key and request generation ([#5174]) +- Move NS client to separate package under NS API ([#5171]) +- build(deps): bump micromatch from 4.0.4 to 4.0.8 in /testnet-faucet ([#4813]) + +[#5346]: https://github.com/nymtech/nym/pull/5346 +[#5331]: https://github.com/nymtech/nym/pull/5331 +[#5330]: https://github.com/nymtech/nym/pull/5330 +[#5329]: https://github.com/nymtech/nym/pull/5329 +[#5321]: https://github.com/nymtech/nym/pull/5321 +[#5320]: https://github.com/nymtech/nym/pull/5320 +[#5318]: https://github.com/nymtech/nym/pull/5318 +[#5316]: https://github.com/nymtech/nym/pull/5316 +[#5313]: https://github.com/nymtech/nym/pull/5313 +[#5298]: https://github.com/nymtech/nym/pull/5298 +[#5287]: https://github.com/nymtech/nym/pull/5287 +[#5283]: https://github.com/nymtech/nym/pull/5283 +[#5278]: https://github.com/nymtech/nym/pull/5278 +[#5260]: https://github.com/nymtech/nym/pull/5260 +[#5259]: https://github.com/nymtech/nym/pull/5259 +[#5256]: https://github.com/nymtech/nym/pull/5256 +[#5255]: https://github.com/nymtech/nym/pull/5255 +[#5251]: https://github.com/nymtech/nym/pull/5251 +[#5247]: https://github.com/nymtech/nym/pull/5247 +[#5246]: https://github.com/nymtech/nym/pull/5246 +[#5239]: https://github.com/nymtech/nym/pull/5239 +[#5236]: https://github.com/nymtech/nym/pull/5236 +[#5235]: https://github.com/nymtech/nym/pull/5235 +[#5233]: https://github.com/nymtech/nym/pull/5233 +[#5230]: https://github.com/nymtech/nym/pull/5230 +[#5218]: https://github.com/nymtech/nym/pull/5218 +[#5216]: https://github.com/nymtech/nym/pull/5216 +[#5213]: https://github.com/nymtech/nym/pull/5213 +[#5210]: https://github.com/nymtech/nym/pull/5210 +[#5208]: https://github.com/nymtech/nym/pull/5208 +[#5207]: https://github.com/nymtech/nym/pull/5207 +[#5204]: https://github.com/nymtech/nym/pull/5204 +[#5201]: https://github.com/nymtech/nym/pull/5201 +[#5184]: https://github.com/nymtech/nym/pull/5184 +[#5180]: https://github.com/nymtech/nym/pull/5180 +[#5174]: https://github.com/nymtech/nym/pull/5174 +[#5171]: https://github.com/nymtech/nym/pull/5171 +[#4813]: https://github.com/nymtech/nym/pull/4813 + ## [2024.14-crunch-patched] (2024-12-17) - Fixes an issue to allow previously registred clients to connect to latest nym-nodes diff --git a/Cargo.lock b/Cargo.lock index fcb00c05c0..6b3403c9b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2369,7 +2369,7 @@ dependencies = [ [[package]] name = "explorer-api" -version = "1.1.43" +version = "1.1.44" dependencies = [ "chrono", "clap", @@ -2436,9 +2436,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fancy_constructor" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71f317e4af73b2f8f608fac190c52eac4b1879d2145df1db2fe48881ca69435" +checksum = "07b19d0e43eae2bfbafe4931b5e79c73fb1a849ca15cd41a761a7b8587f9a1a2" dependencies = [ "macroific", "proc-macro2", @@ -2812,15 +2812,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "gloo-net" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173" +checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580" dependencies = [ "futures-channel", "futures-core", "futures-sink", "gloo-utils 0.2.0", - "http 0.2.12", + "http 1.1.0", "js-sys", "pin-project", "serde", @@ -3533,7 +3533,8 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexed_db_futures" version = "0.4.2" -source = "git+https://github.com/TiemenSch/rust-indexed-db?branch=update-uuid#9745d015707008b0c410115d787014a6d1af2efb" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0704b71f13f81b5933d791abf2de26b33c40935143985220299a357721166706" dependencies = [ "accessory", "cfg-if", @@ -4497,7 +4498,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "nym-api" -version = "1.1.47" +version = "1.1.48" dependencies = [ "anyhow", "async-trait", @@ -4746,7 +4747,7 @@ dependencies = [ [[package]] name = "nym-cli" -version = "1.1.45" +version = "1.1.46" dependencies = [ "anyhow", "base64 0.22.1", @@ -4829,7 +4830,7 @@ dependencies = [ [[package]] name = "nym-client" -version = "1.1.45" +version = "1.1.46" dependencies = [ "bs58", "clap", @@ -5893,7 +5894,7 @@ dependencies = [ [[package]] name = "nym-network-requester" -version = "1.1.46" +version = "1.1.47" dependencies = [ "addr", "anyhow", @@ -5944,7 +5945,7 @@ dependencies = [ [[package]] name = "nym-node" -version = "1.2.1" +version = "1.3.1" dependencies = [ "anyhow", "async-trait", @@ -6316,7 +6317,7 @@ dependencies = [ [[package]] name = "nym-socks5-client" -version = "1.1.45" +version = "1.1.46" dependencies = [ "bs58", "clap", @@ -6920,7 +6921,7 @@ dependencies = [ [[package]] name = "nymvisor" -version = "0.1.10" +version = "0.1.11" dependencies = [ "anyhow", "bytes", @@ -11032,9 +11033,9 @@ dependencies = [ [[package]] name = "wasmtimer" -version = "0.2.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f656cd8858a5164932d8a90f936700860976ec21eb00e0fe2aa8cab13f6b4cf" +checksum = "0048ad49a55b9deb3953841fa1fc5858f0efbcb7a18868c899a360269fac1b23" dependencies = [ "futures", "js-sys", diff --git a/Cargo.toml b/Cargo.toml index 355ccc9159..9dc3d4bdf7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -396,19 +396,17 @@ prost = { version = "0.12", default-features = false } # wasm-related dependencies gloo-utils = "0.2.0" -gloo-net = "0.5.0" +gloo-net = "0.6.0" -# use a separate branch due to feature unification failures -# this is blocked until the upstream removes outdates `wasm_bindgen` feature usage -# indexed_db_futures = "0.4.1" -indexed_db_futures = { git = "https://github.com/TiemenSch/rust-indexed-db", branch = "update-uuid" } +# TODO: migrate to 0.6+ +indexed_db_futures = "0.4.2" js-sys = "0.3.76" serde-wasm-bindgen = "0.6.5" tsify = "0.4.5" wasm-bindgen = "0.2.99" wasm-bindgen-futures = "0.4.49" -wasmtimer = "0.2.0" -web-sys = "0.3.72" +wasmtimer = "0.4.1" +web-sys = "0.3.76" # Profile settings for individual crates diff --git a/clients/native/Cargo.toml b/clients/native/Cargo.toml index 03eb55186e..5f95bbb088 100644 --- a/clients/native/Cargo.toml +++ b/clients/native/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-client" -version = "1.1.45" +version = "1.1.46" authors = ["Dave Hrycyszyn ", "Jędrzej Stuczyński "] description = "Implementation of the Nym Client" edition = "2021" diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index 4363c56387..d538cd5b75 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-socks5-client" -version = "1.1.45" +version = "1.1.46" authors = ["Dave Hrycyszyn "] description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" edition = "2021" diff --git a/common/authenticator-requests/src/v4/registration.rs b/common/authenticator-requests/src/v4/registration.rs index 2595922f00..d6e2ee9682 100644 --- a/common/authenticator-requests/src/v4/registration.rs +++ b/common/authenticator-requests/src/v4/registration.rs @@ -28,7 +28,7 @@ pub type HmacSha256 = Hmac; pub type Nonce = u64; pub type Taken = Option; -pub const BANDWIDTH_CAP_PER_DAY: u64 = 1024 * 1024 * 1024; // 1 GB +pub const BANDWIDTH_CAP_PER_DAY: u64 = 250 * 1024 * 1024 * 1024; // 250 GB #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct IpPair { diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs index 214e7e95df..1f32e71441 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs @@ -863,11 +863,4 @@ pub enum QueryMsg { pub struct MigrateMsg { pub unsafe_skip_state_updates: Option, pub vesting_contract_address: Option, - pub current_nym_node_semver: String, - - #[serde(default)] - pub version_score_weights: OutdatedVersionWeights, - - #[serde(default)] - pub version_score_params: VersionScoreFormulaParams, } diff --git a/contracts/mixnet-vesting-integration-tests/src/support/setup.rs b/contracts/mixnet-vesting-integration-tests/src/support/setup.rs index 7193097aa4..f1d0328f69 100644 --- a/contracts/mixnet-vesting-integration-tests/src/support/setup.rs +++ b/contracts/mixnet-vesting-integration-tests/src/support/setup.rs @@ -464,10 +464,7 @@ pub fn instantiate_contracts( mixnet_contract_address.clone(), &nym_mixnet_contract_common::MigrateMsg { vesting_contract_address: Some(vesting_contract_address.to_string()), - current_nym_node_semver: "1.1.10".to_string(), - version_score_weights: Default::default(), unsafe_skip_state_updates: Some(true), - version_score_params: Default::default(), }, mixnet_code_id, ) diff --git a/contracts/mixnet/schema/nym-mixnet-contract.json b/contracts/mixnet/schema/nym-mixnet-contract.json index 3549011058..2cf7b7675f 100644 --- a/contracts/mixnet/schema/nym-mixnet-contract.json +++ b/contracts/mixnet/schema/nym-mixnet-contract.json @@ -3470,43 +3470,13 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "MigrateMsg", "type": "object", - "required": [ - "current_nym_node_semver" - ], "properties": { - "current_nym_node_semver": { - "type": "string" - }, "unsafe_skip_state_updates": { "type": [ "boolean", "null" ] }, - "version_score_params": { - "default": { - "penalty": "0.995", - "penalty_scaling": "1.65" - }, - "allOf": [ - { - "$ref": "#/definitions/VersionScoreFormulaParams" - } - ] - }, - "version_score_weights": { - "default": { - "major": 100, - "minor": 10, - "patch": 1, - "prerelease": 1 - }, - "allOf": [ - { - "$ref": "#/definitions/OutdatedVersionWeights" - } - ] - }, "vesting_contract_address": { "type": [ "string", @@ -3514,63 +3484,7 @@ ] } }, - "additionalProperties": false, - "definitions": { - "Decimal": { - "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", - "type": "string" - }, - "OutdatedVersionWeights": { - "description": "Defines weights for calculating numbers of versions behind the current release.", - "type": "object", - "required": [ - "major", - "minor", - "patch", - "prerelease" - ], - "properties": { - "major": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "minor": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "patch": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "prerelease": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - "VersionScoreFormulaParams": { - "description": "Given the formula of version_score = penalty ^ (versions_behind_factor ^ penalty_scaling) define the relevant parameters", - "type": "object", - "required": [ - "penalty", - "penalty_scaling" - ], - "properties": { - "penalty": { - "$ref": "#/definitions/Decimal" - }, - "penalty_scaling": { - "$ref": "#/definitions/Decimal" - } - }, - "additionalProperties": false - } - } + "additionalProperties": false }, "sudo": null, "responses": { diff --git a/contracts/mixnet/schema/raw/migrate.json b/contracts/mixnet/schema/raw/migrate.json index 3844bce308..57f0d2acdb 100644 --- a/contracts/mixnet/schema/raw/migrate.json +++ b/contracts/mixnet/schema/raw/migrate.json @@ -2,43 +2,13 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "MigrateMsg", "type": "object", - "required": [ - "current_nym_node_semver" - ], "properties": { - "current_nym_node_semver": { - "type": "string" - }, "unsafe_skip_state_updates": { "type": [ "boolean", "null" ] }, - "version_score_params": { - "default": { - "penalty": "0.995", - "penalty_scaling": "1.65" - }, - "allOf": [ - { - "$ref": "#/definitions/VersionScoreFormulaParams" - } - ] - }, - "version_score_weights": { - "default": { - "major": 100, - "minor": 10, - "patch": 1, - "prerelease": 1 - }, - "allOf": [ - { - "$ref": "#/definitions/OutdatedVersionWeights" - } - ] - }, "vesting_contract_address": { "type": [ "string", @@ -46,61 +16,5 @@ ] } }, - "additionalProperties": false, - "definitions": { - "Decimal": { - "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", - "type": "string" - }, - "OutdatedVersionWeights": { - "description": "Defines weights for calculating numbers of versions behind the current release.", - "type": "object", - "required": [ - "major", - "minor", - "patch", - "prerelease" - ], - "properties": { - "major": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "minor": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "patch": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "prerelease": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - "VersionScoreFormulaParams": { - "description": "Given the formula of version_score = penalty ^ (versions_behind_factor ^ penalty_scaling) define the relevant parameters", - "type": "object", - "required": [ - "penalty", - "penalty_scaling" - ], - "properties": { - "penalty": { - "$ref": "#/definitions/Decimal" - }, - "penalty_scaling": { - "$ref": "#/definitions/Decimal" - } - }, - "additionalProperties": false - } - } + "additionalProperties": false } diff --git a/contracts/mixnet/src/mixnet_contract_settings/storage.rs b/contracts/mixnet/src/mixnet_contract_settings/storage.rs index 6201972e51..992d15ab8a 100644 --- a/contracts/mixnet/src/mixnet_contract_settings/storage.rs +++ b/contracts/mixnet/src/mixnet_contract_settings/storage.rs @@ -34,9 +34,13 @@ impl NymNodeVersionHistory<'_> { } fn next_id(&self, storage: &mut dyn Storage) -> Result { - let next = self.id_counter.may_load(storage)?.unwrap_or_default(); - self.id_counter.save(storage, &next)?; - Ok(next) + let id = self + .id_counter + .may_load(storage)? + .map(|current| current + 1) + .unwrap_or_default(); + self.id_counter.save(storage, &id)?; + Ok(id) } pub fn current_version( @@ -56,10 +60,10 @@ impl NymNodeVersionHistory<'_> { pub fn insert_new( &self, storage: &mut dyn Storage, - entry: HistoricalNymNodeVersion, + entry: &HistoricalNymNodeVersion, ) -> Result { let next_id = self.next_id(storage)?; - self.version_history.save(storage, next_id, &entry)?; + self.version_history.save(storage, next_id, entry)?; Ok(next_id) } @@ -79,7 +83,7 @@ impl NymNodeVersionHistory<'_> { // treat this as genesis let genesis = HistoricalNymNodeVersion::genesis(raw_semver.to_string(), env.block.height); - return self.insert_new(storage, genesis); + return self.insert_new(storage, &genesis); }; let current_semver = current.version_information.semver_unchecked(); @@ -99,7 +103,7 @@ impl NymNodeVersionHistory<'_> { introduced_at_height: env.block.height, difference_since_genesis: diff, }; - self.insert_new(storage, entry) + self.insert_new(storage, &entry) } } @@ -170,3 +174,218 @@ pub(crate) fn initialise_storage( ADMIN.set(deps, Some(initial_admin))?; Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(test)] + mod nym_node_version_history { + use super::*; + use crate::support::tests::test_helpers::TestSetup; + use cosmwasm_std::testing::{mock_dependencies, mock_env}; + + #[test] + fn getting_current() -> anyhow::Result<()> { + // empty storage + let deps = mock_dependencies(); + let storage = NymNodeVersionHistory::new(); + assert!(storage.current_version(&deps.storage)?.is_none()); + + let mut test = TestSetup::new(); + + let zeroth = storage.current_version(test.storage())?.unwrap(); + let manual_zeroth = storage.version_history.load(test.storage(), 0)?; + assert_eq!(zeroth.version_information, manual_zeroth); + + // manually update the counter to make sure data is still read correctly + let dummy = HistoricalNymNodeVersion { + semver: "1.2.3".to_string(), + introduced_at_height: 1234, + difference_since_genesis: Default::default(), + }; + storage.id_counter.save(test.storage_mut(), &123)?; + storage + .version_history + .save(test.storage_mut(), 123, &dummy)?; + + let updated = storage.current_version(test.storage())?.unwrap(); + assert_eq!(updated.version_information, dummy); + + Ok(()) + } + + #[test] + fn inserting_new_entry() -> anyhow::Result<()> { + let mut test = TestSetup::new(); + let storage = NymNodeVersionHistory::new(); + + let first = HistoricalNymNodeVersion { + semver: "1.1.1".to_string(), + introduced_at_height: 12, + difference_since_genesis: Default::default(), + }; + let second = HistoricalNymNodeVersion { + semver: "1.1.2".to_string(), + introduced_at_height: 123, + difference_since_genesis: Default::default(), + }; + let third = HistoricalNymNodeVersion { + semver: "1.1.3".to_string(), + introduced_at_height: 1234, + difference_since_genesis: Default::default(), + }; + + assert_eq!(storage.id_counter.load(test.storage())?, 0); + + // id is correctly incremented for each case and no entry is overwritten + storage.insert_new(test.storage_mut(), &first)?; + assert_eq!(storage.id_counter.load(test.storage())?, 1); + + storage.insert_new(test.storage_mut(), &second)?; + assert_eq!(storage.id_counter.load(test.storage())?, 2); + + storage.insert_new(test.storage_mut(), &third)?; + assert_eq!(storage.id_counter.load(test.storage())?, 3); + + assert_eq!(storage.version_history.load(test.storage(), 1)?, first); + assert_eq!(storage.version_history.load(test.storage(), 2)?, second); + assert_eq!(storage.version_history.load(test.storage(), 3)?, third); + + Ok(()) + } + + #[test] + fn inserting_initial_semver() -> anyhow::Result<()> { + // empty storage + let mut deps = mock_dependencies(); + let env = mock_env(); + let storage = NymNodeVersionHistory::new(); + + assert!(storage + .id_counter + .may_load(deps.as_mut().storage)? + .is_none()); + + storage.try_insert_new(deps.as_mut().storage, &env, "1.1.1")?; + assert_eq!(storage.id_counter.load(deps.as_mut().storage)?, 0); + + assert_eq!( + storage + .version_history + .load(deps.as_ref().storage, 0)? + .semver, + "1.1.1" + ); + assert_eq!( + storage + .current_version(deps.as_ref().storage)? + .unwrap() + .version_information + .semver, + "1.1.1" + ); + + Ok(()) + } + + #[test] + fn inserting_second_semver() -> anyhow::Result<()> { + let mut test = TestSetup::new(); + let env = test.env(); + let storage = NymNodeVersionHistory::new(); + + // lower version + assert!(storage + .try_insert_new(test.storage_mut(), &env, "1.1.9") + .is_err()); + assert!(storage + .try_insert_new(test.storage_mut(), &env, "1.0.1") + .is_err()); + + // malformed + assert!(storage + .try_insert_new(test.storage_mut(), &env, "1.0") + .is_err()); + assert!(storage + .try_insert_new(test.storage_mut(), &env, "1.0bad") + .is_err()); + assert!(storage + .try_insert_new(test.storage_mut(), &env, "foomp") + .is_err()); + + // patch + let mut test = TestSetup::new(); + storage.try_insert_new(test.storage_mut(), &env, "1.1.11")?; + let current = storage + .current_version(test.storage_mut())? + .unwrap() + .version_information; + assert_eq!(current.semver, "1.1.11"); + assert_eq!(current.difference_since_genesis.major, 0); + assert_eq!(current.difference_since_genesis.minor, 0); + assert_eq!(current.difference_since_genesis.patch, 1); + assert_eq!(current.difference_since_genesis.prerelease, 0); + + // minor + let mut test = TestSetup::new(); + storage.try_insert_new(test.storage_mut(), &env, "1.2.0")?; + let current = storage + .current_version(test.storage_mut())? + .unwrap() + .version_information; + assert_eq!(current.semver, "1.2.0"); + assert_eq!(current.difference_since_genesis.major, 0); + assert_eq!(current.difference_since_genesis.minor, 1); + assert_eq!(current.difference_since_genesis.patch, 0); + assert_eq!(current.difference_since_genesis.prerelease, 0); + + // minor alt. + let mut test = TestSetup::new(); + storage.try_insert_new(test.storage_mut(), &env, "1.2.3")?; + let current = storage + .current_version(test.storage_mut())? + .unwrap() + .version_information; + assert_eq!(current.semver, "1.2.3"); + assert_eq!(current.difference_since_genesis.major, 0); + assert_eq!(current.difference_since_genesis.minor, 1); + assert_eq!(current.difference_since_genesis.patch, 0); + assert_eq!(current.difference_since_genesis.prerelease, 0); + + Ok(()) + } + + #[test] + fn inserting_subsequent_semver() -> anyhow::Result<()> { + let mut test = TestSetup::new(); + let env = test.env(); + let storage = NymNodeVersionHistory::new(); + + storage.try_insert_new(test.storage_mut(), &env, "1.2.0")?; + storage.try_insert_new(test.storage_mut(), &env, "1.2.1")?; + storage.try_insert_new(test.storage_mut(), &env, "1.2.3")?; + let current = storage + .current_version(test.storage_mut())? + .unwrap() + .version_information; + assert_eq!(current.semver, "1.2.3"); + assert_eq!(current.difference_since_genesis.major, 0); + assert_eq!(current.difference_since_genesis.minor, 1); + assert_eq!(current.difference_since_genesis.patch, 3); + assert_eq!(current.difference_since_genesis.prerelease, 0); + + storage.try_insert_new(test.storage_mut(), &env, "1.3.0")?; + let current = storage + .current_version(test.storage_mut())? + .unwrap() + .version_information; + assert_eq!(current.semver, "1.3.0"); + assert_eq!(current.difference_since_genesis.major, 0); + assert_eq!(current.difference_since_genesis.minor, 2); + assert_eq!(current.difference_since_genesis.patch, 3); + assert_eq!(current.difference_since_genesis.prerelease, 0); + Ok(()) + } + } +} diff --git a/contracts/mixnet/src/mixnet_contract_settings/transactions.rs b/contracts/mixnet/src/mixnet_contract_settings/transactions.rs index d3c3a211f1..f48f7b401a 100644 --- a/contracts/mixnet/src/mixnet_contract_settings/transactions.rs +++ b/contracts/mixnet/src/mixnet_contract_settings/transactions.rs @@ -238,4 +238,446 @@ pub mod tests { // let res = try_update_contract_settings(deps.as_mut(), info, new_params); // assert_eq!(Err(MixnetContractError::ZeroActiveSet), res); } + + #[cfg(test)] + mod updating_current_nym_node_semver { + use super::*; + use crate::mixnet_contract_settings::queries::query_current_nym_node_version; + use crate::support::tests::test_helpers::TestSetup; + + #[test] + fn is_restricted_to_the_admin() -> anyhow::Result<()> { + let mut test = TestSetup::new(); + + let not_admin = mock_info("not-admin", &[]); + let admin = mock_info(test.admin().as_ref(), &[]); + + let env = test.env(); + let res = try_update_current_nym_node_semver( + test.deps_mut(), + env, + not_admin, + "1.2.1".to_string(), + ); + assert!(res.is_err()); + + let env = test.env(); + let res = try_update_current_nym_node_semver( + test.deps_mut(), + env, + admin, + "1.2.1".to_string(), + ); + assert!(res.is_ok()); + Ok(()) + } + + #[test] + fn updates_current_semver_value() -> anyhow::Result<()> { + let mut test = TestSetup::new(); + + let res = query_current_nym_node_version(test.deps())?; + + let initial = res.version.unwrap().version_information.semver; + // sanity check to make sure our contract init hasn't changed + assert_eq!(initial, "1.1.10"); + + let update = "1.2.0".to_string(); + + let env = test.env(); + let sender = test.admin_sender(); + try_update_current_nym_node_semver(test.deps_mut(), env, sender, update.clone())?; + + let updated = query_current_nym_node_version(test.deps())?; + let version = updated.version.unwrap().version_information.semver; + assert_eq!(version, update); + + Ok(()) + } + + #[cfg(test)] + mod semver_chain_updates { + use super::*; + use crate::mixnet_contract_settings::queries::query_nym_node_version_history_paged; + use mixnet_contract_common::{ + HistoricalNymNodeVersion, HistoricalNymNodeVersionEntry, TotalVersionDifference, + }; + + fn test_setup_with_initial_checks() -> anyhow::Result { + let test = TestSetup::new(); + + let res = query_current_nym_node_version(test.deps())?; + let initial = res.version.unwrap().version_information.semver; + + // sanity check to make sure our contract init hasn't changed + assert_eq!(initial, "1.1.10"); + + let history = query_nym_node_version_history_paged(test.deps(), None, None)?; + assert_eq!(history.history.len(), 1); + + Ok(test) + } + + #[test] + fn single_patch() -> anyhow::Result<()> { + let mut test = test_setup_with_initial_checks()?; + let initial = query_current_nym_node_version(test.deps())? + .version + .unwrap(); + + let env = test.env(); + let sender = test.admin_sender(); + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender, + "1.1.11".to_string(), + )?; + + let history = + query_nym_node_version_history_paged(test.deps(), None, None)?.history; + assert_eq!(history.len(), 2); + assert_eq!(history[0], initial); + assert_eq!( + history[1], + HistoricalNymNodeVersionEntry { + id: 1, + version_information: HistoricalNymNodeVersion { + semver: "1.1.11".to_string(), + introduced_at_height: env.block.height, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 0, + patch: 1, + prerelease: 0, + }, + }, + } + ); + + Ok(()) + } + + #[test] + fn single_minor() -> anyhow::Result<()> { + let mut test = test_setup_with_initial_checks()?; + let initial = query_current_nym_node_version(test.deps())? + .version + .unwrap(); + + let env = test.env(); + let sender = test.admin_sender(); + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender, + "1.2.0".to_string(), + )?; + + let history = + query_nym_node_version_history_paged(test.deps(), None, None)?.history; + assert_eq!(history.len(), 2); + assert_eq!(history[0], initial); + assert_eq!( + history[1], + HistoricalNymNodeVersionEntry { + id: 1, + version_information: HistoricalNymNodeVersion { + semver: "1.2.0".to_string(), + introduced_at_height: env.block.height, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 1, + patch: 0, + prerelease: 0, + }, + }, + } + ); + + Ok(()) + } + + #[test] + fn multiple_patches() -> anyhow::Result<()> { + let mut test = test_setup_with_initial_checks()?; + let initial = query_current_nym_node_version(test.deps())? + .version + .unwrap(); + + let mut env = test.env(); + let sender = test.admin_sender(); + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender.clone(), + "1.1.11".to_string(), + )?; + env.block.height += 1; + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender.clone(), + "1.1.12".to_string(), + )?; + env.block.height += 1; + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender, + "1.1.13".to_string(), + )?; + + let history = + query_nym_node_version_history_paged(test.deps(), None, None)?.history; + assert_eq!(history.len(), 4); + assert_eq!(history[0], initial); + assert_eq!( + history[1], + HistoricalNymNodeVersionEntry { + id: 1, + version_information: HistoricalNymNodeVersion { + semver: "1.1.11".to_string(), + introduced_at_height: env.block.height - 2, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 0, + patch: 1, + prerelease: 0, + }, + }, + } + ); + assert_eq!( + history[2], + HistoricalNymNodeVersionEntry { + id: 2, + version_information: HistoricalNymNodeVersion { + semver: "1.1.12".to_string(), + introduced_at_height: env.block.height - 1, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 0, + patch: 2, + prerelease: 0, + }, + }, + } + ); + assert_eq!( + history[3], + HistoricalNymNodeVersionEntry { + id: 3, + version_information: HistoricalNymNodeVersion { + semver: "1.1.13".to_string(), + introduced_at_height: env.block.height, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 0, + patch: 3, + prerelease: 0, + }, + }, + } + ); + + Ok(()) + } + + #[test] + fn multiple_minors() -> anyhow::Result<()> { + let mut test = test_setup_with_initial_checks()?; + let initial = query_current_nym_node_version(test.deps())? + .version + .unwrap(); + + let mut env = test.env(); + let sender = test.admin_sender(); + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender.clone(), + "1.2.0".to_string(), + )?; + env.block.height += 1; + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender.clone(), + "1.3.0".to_string(), + )?; + env.block.height += 1; + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender, + "1.4.0".to_string(), + )?; + + let history = + query_nym_node_version_history_paged(test.deps(), None, None)?.history; + assert_eq!(history.len(), 4); + assert_eq!(history[0], initial); + assert_eq!( + history[1], + HistoricalNymNodeVersionEntry { + id: 1, + version_information: HistoricalNymNodeVersion { + semver: "1.2.0".to_string(), + introduced_at_height: env.block.height - 2, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 1, + patch: 0, + prerelease: 0, + }, + }, + } + ); + assert_eq!( + history[2], + HistoricalNymNodeVersionEntry { + id: 2, + version_information: HistoricalNymNodeVersion { + semver: "1.3.0".to_string(), + introduced_at_height: env.block.height - 1, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 2, + patch: 0, + prerelease: 0, + }, + }, + } + ); + assert_eq!( + history[3], + HistoricalNymNodeVersionEntry { + id: 3, + version_information: HistoricalNymNodeVersion { + semver: "1.4.0".to_string(), + introduced_at_height: env.block.height, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 3, + patch: 0, + prerelease: 0, + }, + }, + } + ); + + Ok(()) + } + + #[test] + fn mixed_multiple_updates() -> anyhow::Result<()> { + let mut test = test_setup_with_initial_checks()?; + let initial = query_current_nym_node_version(test.deps())? + .version + .unwrap(); + + let mut env = test.env(); + let sender = test.admin_sender(); + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender.clone(), + "1.2.0".to_string(), + )?; + env.block.height += 1; + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender.clone(), + "1.2.1".to_string(), + )?; + env.block.height += 1; + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender.clone(), + "1.2.3".to_string(), + )?; + env.block.height += 1; + try_update_current_nym_node_semver( + test.deps_mut(), + env.clone(), + sender, + "1.3.0".to_string(), + )?; + + let history = + query_nym_node_version_history_paged(test.deps(), None, None)?.history; + assert_eq!(history.len(), 5); + assert_eq!(history[0], initial); + assert_eq!( + history[1], + HistoricalNymNodeVersionEntry { + id: 1, + version_information: HistoricalNymNodeVersion { + semver: "1.2.0".to_string(), + introduced_at_height: env.block.height - 3, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 1, + patch: 0, + prerelease: 0, + }, + }, + } + ); + assert_eq!( + history[2], + HistoricalNymNodeVersionEntry { + id: 2, + version_information: HistoricalNymNodeVersion { + semver: "1.2.1".to_string(), + introduced_at_height: env.block.height - 2, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 1, + patch: 1, + prerelease: 0, + }, + }, + } + ); + assert_eq!( + history[3], + HistoricalNymNodeVersionEntry { + id: 3, + version_information: HistoricalNymNodeVersion { + semver: "1.2.3".to_string(), + introduced_at_height: env.block.height - 1, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 1, + patch: 3, + prerelease: 0, + }, + }, + } + ); + assert_eq!( + history[4], + HistoricalNymNodeVersionEntry { + id: 4, + version_information: HistoricalNymNodeVersion { + semver: "1.3.0".to_string(), + introduced_at_height: env.block.height, + difference_since_genesis: TotalVersionDifference { + major: 0, + minor: 2, + patch: 3, + prerelease: 0, + }, + }, + } + ); + + Ok(()) + } + } + } } diff --git a/contracts/mixnet/src/support/tests/mod.rs b/contracts/mixnet/src/support/tests/mod.rs index cd40ef7ca4..4c0f2d85a3 100644 --- a/contracts/mixnet/src/support/tests/mod.rs +++ b/contracts/mixnet/src/support/tests/mod.rs @@ -18,7 +18,7 @@ pub mod test_helpers { }; use crate::interval::{pending_events, storage as interval_storage}; use crate::mixnet_contract_settings::storage::{ - self as mixnet_params_storage, minimum_node_pledge, + self as mixnet_params_storage, minimum_node_pledge, ADMIN, }; use crate::mixnet_contract_settings::storage::{rewarding_denom, rewarding_validator_address}; use crate::mixnodes::helpers::get_mixnode_details_by_id; @@ -318,6 +318,10 @@ pub mod test_helpers { compare_decimals(mix_info.delegates, subtotal, Some(epsilon)) } + pub fn admin(&self) -> Addr { + ADMIN.get(self.deps()).unwrap().unwrap() + } + pub fn random_address(&mut self) -> String { format!("n1foomp{}", self.rng.next_u64()) } @@ -330,6 +334,14 @@ pub mod test_helpers { self.deps.as_mut() } + pub fn storage(&self) -> &dyn Storage { + self.deps().storage + } + + pub fn storage_mut(&mut self) -> &mut dyn Storage { + self.deps_mut().storage + } + pub fn env(&self) -> Env { self.env.clone() } @@ -470,6 +482,10 @@ pub mod test_helpers { .unwrap() } + pub fn admin_sender(&self) -> MessageInfo { + mock_info(self.admin().as_ref(), &[]) + } + pub fn owner(&self) -> MessageInfo { self.owner.clone() } diff --git a/explorer-api/Cargo.toml b/explorer-api/Cargo.toml index 6fe9830dae..fd2880c4fd 100644 --- a/explorer-api/Cargo.toml +++ b/explorer-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "explorer-api" -version = "1.1.43" +version = "1.1.44" edition = "2021" license.workspace = true diff --git a/explorer-nextjs/app/components/Nav/DesktopNav.tsx b/explorer-nextjs/app/components/Nav/DesktopNav.tsx index 618037ea04..e1faab46f1 100644 --- a/explorer-nextjs/app/components/Nav/DesktopNav.tsx +++ b/explorer-nextjs/app/components/Nav/DesktopNav.tsx @@ -20,6 +20,7 @@ import { NYM_WEBSITE } from '@/app/api/constants' import { useMainContext } from '@/app/context/main' import { MobileDrawerClose } from '@/app/icons/MobileDrawerClose' import { NavOptionType, originalNavOptions } from '@/app/context/nav' +import { ReleaseAlert } from '@/app/components/ReleaseAlert' import { DarkLightSwitchDesktop } from '@/app/components/Switch' import { Footer } from '@/app/components/Footer' import { ConnectKeplrWallet } from '@/app/components/Wallet/ConnectKeplrWallet' @@ -369,6 +370,7 @@ export const Nav: FCWithChildren = ({ children }) => { style={{ width: `calc(100% - ${drawerWidth}px` }} sx={{ py: 5, px: 6, mt: 7 }} > + {children}