From 8eb45c2f7af089972c683fac0c07269ac999283a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 1 May 2025 14:25:12 +0100 Subject: [PATCH] added basic key rotation information to mixnet contract --- .../contract_traits/mixnet_query_client.rs | 22 ++++-- .../mixnet-contract/Cargo.toml | 3 + .../mixnet-contract/src/key_rotation.rs | 71 +++++++++++++++++++ .../mixnet-contract/src/lib.rs | 6 +- .../mixnet-contract/src/mixnode.rs | 10 +++ .../mixnet-contract/src/msg.rs | 10 +++ .../src/rewarding/simulator/mod.rs | 3 + common/nymsphinx/anonymous-replies/Cargo.toml | 2 +- contracts/Cargo.lock | 3 - contracts/Cargo.toml | 10 +++ contracts/mixnet/Cargo.toml | 6 +- contracts/mixnet/src/constants.rs | 1 + contracts/mixnet/src/contract.rs | 21 ++++-- contracts/mixnet/src/nodes/queries.rs | 16 ++++- contracts/mixnet/src/nodes/storage/helpers.rs | 13 +++- contracts/mixnet/src/nodes/storage/mod.rs | 15 ++-- contracts/mixnet/src/queued_migrations.rs | 21 +++++- nym-node/src/node/key_rotation/key.rs | 8 --- 18 files changed, 200 insertions(+), 41 deletions(-) create mode 100644 common/cosmwasm-smart-contracts/mixnet-contract/src/key_rotation.rs diff --git a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs index 5060fe3df4..b85a78596e 100644 --- a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs +++ b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs @@ -28,12 +28,12 @@ use nym_mixnet_contract_common::{ ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse, CurrentNymNodeVersionResponse, Delegation, EpochEventId, EpochRewardedSet, EpochStatus, GatewayBond, GatewayBondResponse, GatewayOwnershipResponse, HistoricalNymNodeVersionEntry, - IdentityKey, IdentityKeyRef, IntervalEventId, MixNodeBond, MixNodeDetails, - MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse, NodeId, - NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails, NymNodeVersionHistoryResponse, - PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse, - PagedMixnodeBondsResponse, PagedNodeDelegationsResponse, PendingEpochEvent, - PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent, + IdentityKey, IdentityKeyRef, IntervalEventId, KeyRotationIdResponse, KeyRotationState, + MixNodeBond, MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse, + MixnodeDetailsResponse, NodeId, NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails, + NymNodeVersionHistoryResponse, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, + PagedGatewayResponse, PagedMixnodeBondsResponse, PagedNodeDelegationsResponse, + PendingEpochEvent, PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent, PendingIntervalEventResponse, PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg, RewardedSet, UnbondedMixnode, }; @@ -546,6 +546,16 @@ pub trait MixnetQueryClient { }) .await } + + async fn get_key_rotation_state(&self) -> Result { + self.query_mixnet_contract(MixnetQueryMsg::GetKeyRotationState {}) + .await + } + + async fn get_key_rotation_id(&self) -> Result { + self.query_mixnet_contract(MixnetQueryMsg::GetKeyRotationId {}) + .await + } } // extension trait to the query client to deal with the paged queries diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml b/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml index 8800e72b20..abe502c50e 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml +++ b/common/cosmwasm-smart-contracts/mixnet-contract/Cargo.toml @@ -40,3 +40,6 @@ contract-testing = [] utoipa = ["dep:utoipa"] schema = ["cw2"] generate-ts = ['ts-rs'] + +[lints] +workspace = true \ No newline at end of file diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/key_rotation.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/key_rotation.rs new file mode 100644 index 0000000000..a6f330d68e --- /dev/null +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/key_rotation.rs @@ -0,0 +1,71 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::EpochId; +use cosmwasm_schema::cw_serde; + +pub type KeyRotationId = u32; + +#[cw_serde] +pub struct KeyRotationState { + /// Defines how long each key rotation is valid for (in terms of epochs) + pub validity_epochs: u32, + + /// Records the initial epoch_id when the key rotation has been introduced (0 for fresh contracts). + /// It is used for determining when rotation is meant to advance. + pub initial_epoch_id: EpochId, +} + +impl KeyRotationState { + pub fn key_rotation_id(&self, current_epoch_id: EpochId) -> KeyRotationId { + let diff = current_epoch_id.saturating_sub(self.initial_epoch_id); + let full_rots = diff / self.validity_epochs; + full_rots + } +} + +#[cw_serde] +pub struct KeyRotationIdResponse { + pub rotation_id: KeyRotationId, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn key_rotation_id() { + let state = KeyRotationState { + validity_epochs: 24, + initial_epoch_id: 0, + }; + assert_eq!(0, state.key_rotation_id(0)); + assert_eq!(0, state.key_rotation_id(23)); + assert_eq!(1, state.key_rotation_id(24)); + assert_eq!(1, state.key_rotation_id(47)); + assert_eq!(2, state.key_rotation_id(48)); + + let state = KeyRotationState { + validity_epochs: 12, + initial_epoch_id: 0, + }; + assert_eq!(0, state.key_rotation_id(0)); + assert_eq!(0, state.key_rotation_id(11)); + assert_eq!(1, state.key_rotation_id(12)); + assert_eq!(1, state.key_rotation_id(23)); + assert_eq!(2, state.key_rotation_id(24)); + + let state = KeyRotationState { + validity_epochs: 24, + initial_epoch_id: 10000, + }; + assert_eq!(0, state.key_rotation_id(123)); + assert_eq!(0, state.key_rotation_id(10000)); + assert_eq!(0, state.key_rotation_id(10001)); + assert_eq!(0, state.key_rotation_id(10023)); + assert_eq!(1, state.key_rotation_id(10024)); + assert_eq!(1, state.key_rotation_id(10047)); + assert_eq!(2, state.key_rotation_id(10048)); + assert_eq!(2, state.key_rotation_id(10060)); + } +} diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/lib.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/lib.rs index 4f9d7a088f..eb1d533270 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/lib.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/lib.rs @@ -1,10 +1,6 @@ // Copyright 2021-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -#![warn(clippy::expect_used)] -#![warn(clippy::unwrap_used)] -#![warn(clippy::todo)] - mod config_score; pub mod constants; pub mod delegation; @@ -13,6 +9,7 @@ pub mod events; pub mod gateway; pub mod helpers; pub mod interval; +pub mod key_rotation; pub mod mixnode; pub mod msg; pub mod nym_node; @@ -37,6 +34,7 @@ pub use gateway::{ pub use interval::{ CurrentIntervalResponse, EpochId, EpochState, EpochStatus, Interval, IntervalId, }; +pub use key_rotation::*; pub use mixnode::{ LegacyMixLayer, MixNode, MixNodeBond, MixNodeConfigUpdate, MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse, NodeCostParams, diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/mixnode.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/mixnode.rs index 763082a1f1..64b69fe737 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/mixnode.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/mixnode.rs @@ -170,6 +170,11 @@ impl NodeRewarding { } } + // we panic here as opposed to returning an error as this is undefined behaviour, + // because the pledge amount has decreased (i.e. slashing has occurred) which + // should not be possible under any situation. at this point we don't know how many other things + // might have failed so we have to bail + #[allow(clippy::panic)] pub fn pending_detailed_operator_reward(&self, original_pledge: &Coin) -> StdResult { let initial_dec = original_pledge.amount.into_base_decimal()?; if initial_dec > self.operator { @@ -189,6 +194,11 @@ impl NodeRewarding { Ok(truncate_reward(delegator_reward, &delegation.amount.denom)) } + // we panic here as opposed to returning an error as this is undefined behaviour, + // because the pledge amount has decreased (i.e. slashing has occurred) which + // should not be possible under any situation. at this point we don't know how many other things + // might have failed so we have to bail + #[allow(clippy::panic)] pub fn withdraw_operator_reward( &mut self, original_pledge: &Coin, diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs index 1f32e71441..dcd218dd62 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs @@ -35,6 +35,7 @@ use crate::{ PreassignedGatewayIdsResponse, }, interval::{CurrentIntervalResponse, EpochStatus}, + key_rotation::{KeyRotationIdResponse, KeyRotationState}, mixnode::{ MixOwnershipResponse, MixStakeSaturationResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse, MixnodeRewardingDetailsResponse, PagedMixnodeBondsResponse, @@ -857,6 +858,15 @@ pub enum QueryMsg { /// Cosmos address used for the query of the signing nonce. address: String, }, + + // sphinx key rotation-related + #[cfg_attr(feature = "schema", returns(KeyRotationState))] + /// Gets the current state config of the key rotation (i.e. starting epoch id and validity duration) + GetKeyRotationState {}, + + /// Gets the current key rotation id + #[cfg_attr(feature = "schema", returns(KeyRotationIdResponse))] + GetKeyRotationId {}, } #[cw_serde] diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/rewarding/simulator/mod.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/rewarding/simulator/mod.rs index 9ad2a3d02a..25f588b476 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/rewarding/simulator/mod.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/rewarding/simulator/mod.rs @@ -151,6 +151,9 @@ impl Simulator { } } + // this code is not meant to be used in production systems, only in tests + // so a panic due to inconsistent arguments is fine + #[allow(clippy::panic)] pub fn simulate_epoch( &mut self, node_params: &BTreeMap, diff --git a/common/nymsphinx/anonymous-replies/Cargo.toml b/common/nymsphinx/anonymous-replies/Cargo.toml index 7d7084a7ad..ef9c74b73d 100644 --- a/common/nymsphinx/anonymous-replies/Cargo.toml +++ b/common/nymsphinx/anonymous-replies/Cargo.toml @@ -21,7 +21,7 @@ nym-sphinx-types = { path = "../types" } nym-topology = { path = "../../topology" } [target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen] -version = "0.2.95" +workspace = true [dev-dependencies] rand_chacha = { workspace = true } diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 04d4e3cb0e..20ab2abf41 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -1193,7 +1193,6 @@ version = "1.5.1" dependencies = [ "anyhow", "bs58", - "cosmwasm-derive", "cosmwasm-schema", "cosmwasm-std", "cw-controllers", @@ -1208,8 +1207,6 @@ dependencies = [ "rand_chacha", "semver", "serde", - "thiserror 2.0.12", - "time", ] [[package]] diff --git a/contracts/Cargo.toml b/contracts/Cargo.toml index 8b744af7b2..c8cee21dfa 100644 --- a/contracts/Cargo.toml +++ b/contracts/Cargo.toml @@ -55,3 +55,13 @@ sylvia = "1.3.3" schemars = "0.8.16" thiserror = "2.0.11" + +[workspace.lints.clippy] +unwrap_used = "deny" +expect_used = "deny" +todo = "deny" +dbg_macro = "deny" +exit = "deny" +panic = "deny" +unimplemented = "deny" +unreachable = "deny" \ No newline at end of file diff --git a/contracts/mixnet/Cargo.toml b/contracts/mixnet/Cargo.toml index 917ad82e88..9fa22fe0db 100644 --- a/contracts/mixnet/Cargo.toml +++ b/contracts/mixnet/Cargo.toml @@ -33,7 +33,6 @@ nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts cosmwasm-schema = { workspace = true, optional = true } cosmwasm-std = { workspace = true } -cosmwasm-derive = { workspace = true } cw-controllers = { workspace = true } cw2 = { workspace = true } cw-storage-plus = { workspace = true } @@ -41,8 +40,6 @@ cw-storage-plus = { workspace = true } bs58 = { workspace = true } serde = { workspace = true, default-features = false, features = ["derive"] } semver = { workspace = true } -thiserror = { workspace = true } -time = { version = "0.3", features = ["macros"] } [dev-dependencies] anyhow.workspace = true @@ -55,3 +52,6 @@ easy-addr = { path = "../../common/cosmwasm-smart-contracts/easy_addr" } default = [] contract-testing = ["mixnet-contract-common/contract-testing"] schema-gen = ["mixnet-contract-common/schema", "cosmwasm-schema"] + +[lints] +workspace = true \ No newline at end of file diff --git a/contracts/mixnet/src/constants.rs b/contracts/mixnet/src/constants.rs index 50cf7c2541..2bcb2ba4ea 100644 --- a/contracts/mixnet/src/constants.rs +++ b/contracts/mixnet/src/constants.rs @@ -78,6 +78,7 @@ pub const NYMNODE_ROLES_ASSIGNMENT_NAMESPACE: &str = "roles"; pub const NYMNODE_REWARDED_SET_METADATA_NAMESPACE: &str = "roles_metadata"; pub const NYMNODE_ACTIVE_ROLE_ASSIGNMENT_KEY: &str = "active_roles"; +pub const KEY_ROTATION_STATE_KEY: &str = "key_rot_state"; pub const NODE_ID_COUNTER_KEY: &str = "nic"; pub const PENDING_MIXNODE_CHANGES_NAMESPACE: &str = "pmc"; pub const MIXNODES_PK_NAMESPACE: &str = "mnn"; diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index db9e3f44f4..b856630476 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -5,6 +5,7 @@ use crate::constants::INITIAL_PLEDGE_AMOUNT; use crate::interval::storage as interval_storage; use crate::mixnet_contract_settings::storage as mixnet_params_storage; use crate::nodes::storage as nymnodes_storage; +use crate::queued_migrations::introduce_key_rotation_id; use crate::rewards::storage::RewardingStorage; use cosmwasm_std::{ entry_point, to_json_binary, Addr, Coin, Deps, DepsMut, Env, MessageInfo, QueryResponse, @@ -598,6 +599,14 @@ pub fn query( QueryMsg::GetSigningNonce { address } => to_json_binary( &crate::signing::queries::query_current_signing_nonce(deps, address)?, ), + + // sphinx key rotation-related + QueryMsg::GetKeyRotationState {} => { + to_json_binary(&crate::nodes::queries::query_key_rotation_state(deps)?) + } + QueryMsg::GetKeyRotationId {} => { + to_json_binary(&crate::nodes::queries::query_key_rotation_id(deps)?) + } }; Ok(query_res?) @@ -605,18 +614,18 @@ pub fn query( #[entry_point] pub fn migrate( - deps: DepsMut<'_>, + mut deps: DepsMut<'_>, _env: Env, msg: MigrateMsg, ) -> Result { set_build_information!(deps.storage)?; cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - // let skip_state_updates = msg.unsafe_skip_state_updates.unwrap_or(false); - // - // if !skip_state_updates { - // - // } + let skip_state_updates = msg.unsafe_skip_state_updates.unwrap_or(false); + + if !skip_state_updates { + introduce_key_rotation_id(deps.branch())?; + } // 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/nodes/queries.rs b/contracts/mixnet/src/nodes/queries.rs index 6283d21d75..02bc5276fc 100644 --- a/contracts/mixnet/src/nodes/queries.rs +++ b/contracts/mixnet/src/nodes/queries.rs @@ -6,6 +6,7 @@ use crate::constants::{ NYM_NODE_DETAILS_DEFAULT_RETRIEVAL_LIMIT, NYM_NODE_DETAILS_MAX_RETRIEVAL_LIMIT, UNBONDED_NYM_NODES_DEFAULT_RETRIEVAL_LIMIT, UNBONDED_NYM_NODES_MAX_RETRIEVAL_LIMIT, }; +use crate::interval::storage as interval_storage; use crate::nodes::helpers::{ attach_nym_node_details, get_node_details_by_id, get_node_details_by_identity, get_node_details_by_owner, @@ -21,7 +22,9 @@ use mixnet_contract_common::nym_node::{ PagedNymNodeDetailsResponse, PagedUnbondedNymNodesResponse, Role, RolesMetadataResponse, StakeSaturationResponse, UnbondedNodeResponse, }; -use mixnet_contract_common::{NodeId, NymNodeBond, NymNodeDetails}; +use mixnet_contract_common::{ + KeyRotationIdResponse, KeyRotationState, NodeId, NymNodeBond, NymNodeDetails, +}; use nym_contracts_common::IdentityKey; pub(crate) fn query_nymnode_bonds_paged( @@ -257,3 +260,14 @@ pub fn query_stake_saturation( uncapped_saturation: Some(node_rewarding.uncapped_bond_saturation(&rewarding_params)), }) } + +pub fn query_key_rotation_state(deps: Deps<'_>) -> StdResult { + storage::KEY_ROTATION_STATE.load(deps.storage) +} + +pub fn query_key_rotation_id(deps: Deps<'_>) -> StdResult { + let interval = interval_storage::current_interval(deps.storage)?; + let rotation_state = storage::KEY_ROTATION_STATE.load(deps.storage)?; + let rotation_id = rotation_state.key_rotation_id(interval.current_epoch_absolute_id()); + Ok(KeyRotationIdResponse { rotation_id }) +} diff --git a/contracts/mixnet/src/nodes/storage/helpers.rs b/contracts/mixnet/src/nodes/storage/helpers.rs index 169a0d42bc..8a2fade399 100644 --- a/contracts/mixnet/src/nodes/storage/helpers.rs +++ b/contracts/mixnet/src/nodes/storage/helpers.rs @@ -2,11 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 use crate::nodes::storage::rewarded_set::{ACTIVE_ROLES_BUCKET, ROLES, ROLES_METADATA}; -use crate::nodes::storage::{nym_nodes, NYMNODE_ID_COUNTER}; +use crate::nodes::storage::{nym_nodes, KEY_ROTATION_STATE, NYMNODE_ID_COUNTER}; use cosmwasm_std::{StdResult, Storage}; use mixnet_contract_common::error::MixnetContractError; use mixnet_contract_common::nym_node::{RewardedSetMetadata, Role}; -use mixnet_contract_common::{EpochId, NodeId, NymNodeBond, RoleAssignment}; +use mixnet_contract_common::{EpochId, KeyRotationState, NodeId, NymNodeBond, RoleAssignment}; use serde::{Deserialize, Serialize}; #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] @@ -124,6 +124,15 @@ pub(crate) fn initialise_storage(storage: &mut dyn Storage) -> Result<(), Mixnet ROLES_METADATA.save(storage, active_bucket as u8, &Default::default())?; ROLES_METADATA.save(storage, inactive_bucket as u8, &Default::default())?; + // since we're initialising fresh storage, the current epoch_id is 0 + KEY_ROTATION_STATE.save( + storage, + &KeyRotationState { + validity_epochs: 24, + initial_epoch_id: 0, + }, + )?; + Ok(()) } diff --git a/contracts/mixnet/src/nodes/storage/mod.rs b/contracts/mixnet/src/nodes/storage/mod.rs index 41e7aea033..fd45ee613a 100644 --- a/contracts/mixnet/src/nodes/storage/mod.rs +++ b/contracts/mixnet/src/nodes/storage/mod.rs @@ -2,23 +2,26 @@ // SPDX-License-Identifier: Apache-2.0 use crate::constants::{ - NODE_ID_COUNTER_KEY, NYMNODE_ACTIVE_ROLE_ASSIGNMENT_KEY, NYMNODE_IDENTITY_IDX_NAMESPACE, - NYMNODE_OWNER_IDX_NAMESPACE, NYMNODE_PK_NAMESPACE, NYMNODE_REWARDED_SET_METADATA_NAMESPACE, - NYMNODE_ROLES_ASSIGNMENT_NAMESPACE, PENDING_NYMNODE_CHANGES_NAMESPACE, - UNBONDED_NYMNODE_IDENTITY_IDX_NAMESPACE, UNBONDED_NYMNODE_OWNER_IDX_NAMESPACE, - UNBONDED_NYMNODE_PK_NAMESPACE, + KEY_ROTATION_STATE_KEY, NODE_ID_COUNTER_KEY, NYMNODE_ACTIVE_ROLE_ASSIGNMENT_KEY, + NYMNODE_IDENTITY_IDX_NAMESPACE, NYMNODE_OWNER_IDX_NAMESPACE, NYMNODE_PK_NAMESPACE, + NYMNODE_REWARDED_SET_METADATA_NAMESPACE, NYMNODE_ROLES_ASSIGNMENT_NAMESPACE, + PENDING_NYMNODE_CHANGES_NAMESPACE, UNBONDED_NYMNODE_IDENTITY_IDX_NAMESPACE, + UNBONDED_NYMNODE_OWNER_IDX_NAMESPACE, UNBONDED_NYMNODE_PK_NAMESPACE, }; use crate::nodes::storage::helpers::RoleStorageBucket; use cosmwasm_std::Addr; use cw_storage_plus::{Index, IndexList, IndexedMap, Item, Map, MultiIndex, UniqueIndex}; use mixnet_contract_common::nym_node::{NymNodeBond, RewardedSetMetadata, Role, UnbondedNymNode}; -use mixnet_contract_common::{NodeId, PendingNodeChanges}; +use mixnet_contract_common::{KeyRotationState, NodeId, PendingNodeChanges}; use nym_contracts_common::IdentityKey; pub(crate) mod helpers; pub(crate) use helpers::*; +/// Item recording the current state of the key rotation setup +pub const KEY_ROTATION_STATE: Item = Item::new(KEY_ROTATION_STATE_KEY); + // IMPORTANT NOTE: we're using the same storage key as we had for MIXNODE_ID_COUNTER, // so that we could start from the old values pub const NYMNODE_ID_COUNTER: Item = Item::new(NODE_ID_COUNTER_KEY); diff --git a/contracts/mixnet/src/queued_migrations.rs b/contracts/mixnet/src/queued_migrations.rs index a0273196be..4f9690a87e 100644 --- a/contracts/mixnet/src/queued_migrations.rs +++ b/contracts/mixnet/src/queued_migrations.rs @@ -1,2 +1,21 @@ -// Copyright 2022-2024 - Nym Technologies SA +// Copyright 2022-2025 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 + +use crate::interval::storage as interval_storage; +use crate::nodes::storage as nymnodes_storage; +use cosmwasm_std::DepsMut; +use mixnet_contract_common::error::MixnetContractError; +use mixnet_contract_common::KeyRotationState; + +pub fn introduce_key_rotation_id(deps: DepsMut) -> Result<(), MixnetContractError> { + let current_epoch_id = + interval_storage::current_interval(deps.storage)?.current_epoch_absolute_id(); + nymnodes_storage::KEY_ROTATION_STATE.save( + deps.storage, + &KeyRotationState { + validity_epochs: 24, + initial_epoch_id: current_epoch_id, + }, + )?; + Ok(()) +} diff --git a/nym-node/src/node/key_rotation/key.rs b/nym-node/src/node/key_rotation/key.rs index ebe8389e90..512b13f494 100644 --- a/nym-node/src/node/key_rotation/key.rs +++ b/nym-node/src/node/key_rotation/key.rs @@ -56,14 +56,6 @@ impl AsRef for SphinxPrivateKey { } } -// impl Deref for SphinxPrivateKey { -// type Target = x25519::PrivateKey; -// -// fn deref(&self) -> &Self::Target { -// &self.inner -// } -// } - pub(crate) struct SphinxPublicKey { pub(crate) rotation_id: u32, pub(crate) inner: x25519::PublicKey,