Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions common/commands/src/internal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use clap::{Args, Subcommand};

pub mod ecash;
pub mod nyx;

#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
Expand All @@ -16,4 +17,6 @@ pub struct Internal {
pub enum InternalCommands {
/// Ecash related internal commands
Ecash(ecash::InternalEcash),

Nyx(nyx::InternalNyx),
}
116 changes: 116 additions & 0 deletions common/commands/src/internal/nyx/force_advance_epoch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright 2025 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: Apache-2.0

use crate::context::SigningClient;
use anyhow::bail;
use clap::Parser;
use nym_mixnet_contract_common::nym_node::Role;
use nym_mixnet_contract_common::reward_params::NodeRewardingParameters;
use nym_mixnet_contract_common::{
EpochRewardedSet, EpochState, NodeId, RewardingParams, RoleAssignment,
};
use nym_validator_client::nyxd::contract_traits::mixnet_query_client::MixnetQueryClientExt;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
use rand::prelude::*;
use rand::thread_rng;

#[derive(Debug, Parser)]
pub struct Args {}

fn choose_new_nodes(
params: &RewardingParams,
rewarded_set: &EpochRewardedSet,
role: Role,
) -> Vec<NodeId> {
let mut rng = thread_rng();

match role {
Role::EntryGateway => rewarded_set
.assignment
.entry_gateways
.choose_multiple(&mut rng, params.rewarded_set.entry_gateways as usize)
.copied()
.collect(),
Role::Layer1 => rewarded_set
.assignment
.layer1
.choose_multiple(&mut rng, params.rewarded_set.mixnodes as usize / 3)
.copied()
.collect(),
Role::Layer2 => rewarded_set
.assignment
.layer2
.choose_multiple(&mut rng, params.rewarded_set.mixnodes as usize / 3)
.copied()
.collect(),
Role::Layer3 => rewarded_set
.assignment
.layer3
.choose_multiple(&mut rng, params.rewarded_set.mixnodes as usize / 3)
.copied()
.collect(),
Role::ExitGateway => rewarded_set
.assignment
.exit_gateways
.choose_multiple(&mut rng, params.rewarded_set.exit_gateways as usize)
.copied()
.collect(),
Role::Standby => rewarded_set
.assignment
.standby
.choose_multiple(&mut rng, params.rewarded_set.standby as usize)
.copied()
.collect(),
}
}

pub async fn force_advance_epoch(_: Args, client: SigningClient) -> anyhow::Result<()> {
let current_epoch = client.get_current_interval_details().await?;
let epoch_status = client.get_current_epoch_status().await?;
if epoch_status.being_advanced_by.as_str() != client.address().to_string() {
bail!(
"this client is not authorised to perform any epoch operations. we need {}",
client.address()
)
}

let rewarding_params = client.get_rewarding_parameters().await?;
let current_rewarded_set = client.get_rewarded_set().await?;

if !current_epoch.is_current_epoch_over {
println!("the current epoch is not over yet - there's nothing to do")
}

// is this most efficient? no. but it's simple
loop {
let epoch_status = client.get_current_epoch_status().await?;

match epoch_status.state {
EpochState::InProgress => break,
EpochState::Rewarding { final_node_id, .. } => {
println!("rewarding {final_node_id} with big fat 0...");
client
.reward_node(
final_node_id,
NodeRewardingParameters::new(Default::default(), Default::default()),
None,
)
.await?;
}
EpochState::ReconcilingEvents => {
println!("trying to reconcile events...");
client.reconcile_epoch_events(None, None).await?;
}
EpochState::RoleAssignment { next } => {
let nodes = choose_new_nodes(&rewarding_params, &current_rewarded_set, next);
println!("assigning {nodes:?} as {next}");

client
.assign_roles(RoleAssignment { role: next, nodes }, None)
.await?;
}
}
}

Ok(())
}
19 changes: 19 additions & 0 deletions common/commands/src/internal/nyx/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2025 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: Apache-2.0

use clap::{Args, Subcommand};

pub mod force_advance_epoch;

#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct InternalNyx {
#[clap(subcommand)]
pub command: InternalNyxCommands,
}

#[derive(Debug, Subcommand)]
pub enum InternalNyxCommands {
/// Attempt to force advance the current epoch
ForceAdvanceEpoch(force_advance_epoch::Args),
}
2 changes: 1 addition & 1 deletion tools/nym-cli/src/internal/ecash/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use nym_network_defaults::NymNetworkDetails;

pub(super) async fn execute(
global_args: ClientArgs,
ecash: nym_cli_commands::internal::ecash::InternalEcash,
nym_network_details: &NymNetworkDetails,
ecash: nym_cli_commands::internal::ecash::InternalEcash,
) -> anyhow::Result<()> {
// I reckon those will be needed later
let _ = global_args;
Expand Down
6 changes: 5 additions & 1 deletion tools/nym-cli/src/internal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use nym_cli_commands::internal::InternalCommands;
use nym_network_defaults::NymNetworkDetails;

mod ecash;
mod nyx;

pub(super) async fn execute(
global_args: ClientArgs,
Expand All @@ -14,7 +15,10 @@ pub(super) async fn execute(
) -> anyhow::Result<()> {
match internal.command {
InternalCommands::Ecash(ecash_commands) => {
ecash::execute(global_args, ecash_commands, nym_network_details).await
ecash::execute(global_args, nym_network_details, ecash_commands).await
}
InternalCommands::Nyx(nyx_commands) => {
nyx::execute(global_args, nym_network_details, nyx_commands).await
}
}
}
22 changes: 22 additions & 0 deletions tools/nym-cli/src/internal/nyx/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2025 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: Apache-2.0

use nym_cli_commands::context::{create_signing_client, ClientArgs};
use nym_cli_commands::internal::nyx::InternalNyxCommands;
use nym_network_defaults::NymNetworkDetails;

pub(super) async fn execute(
global_args: ClientArgs,
nym_network_details: &NymNetworkDetails,
nyx: nym_cli_commands::internal::nyx::InternalNyx,
) -> anyhow::Result<()> {
match nyx.command {
InternalNyxCommands::ForceAdvanceEpoch(args) => {
nym_cli_commands::internal::nyx::force_advance_epoch::force_advance_epoch(
args,
create_signing_client(global_args, nym_network_details)?,
)
.await
}
}
}
Loading