Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions rs/registry/admin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,9 @@ enum SubCommand {
// Submit a root proposal to the root canister to upgrade the governance canister.
SubmitRootProposalToUpgradeGovernanceCanister(SubmitRootProposalToUpgradeGovernanceCanisterCmd),

/// Swap nodes in subnet directly, without governance.
SwapNodeInSubnetDirectly(SwapNodeInSubnetDirectlyCmd),

/// Update local registry store by pulling from remote URL
UpdateRegistryLocalStore(UpdateRegistryLocalStoreCmd),

Expand Down Expand Up @@ -2593,6 +2596,18 @@ struct SubmitRootProposalToUpgradeGovernanceCanisterCmd {
wasm_module_sha256: String,
}

#[derive(Parser)]
struct SwapNodeInSubnetDirectlyCmd {
/// Represents the node principal id of a node which will be removed from a subnet.
#[clap(long)]
pub old_node_id: PrincipalId,

/// Represents the node principal id of a node which will be added to a subnet in
/// place of the `old_node_id`.
#[clap(long)]
pub new_node_id: PrincipalId,
}

/// Sub-command to vote on a root proposal to upgrade the governance canister.
#[derive(Parser)]
struct VoteOnRootProposalToUpgradeGovernanceCanisterCmd {
Expand Down Expand Up @@ -3783,6 +3798,7 @@ async fn main() {
SubCommand::ProposeToUpdateSubnetType(_) => (),
SubCommand::ProposeToUpdateXdrIcpConversionRate(_) => (),
SubCommand::SubmitRootProposalToUpgradeGovernanceCanister(_) => (),
SubCommand::SwapNodeInSubnetDirectly(_) => (),
SubCommand::VoteOnRootProposalToUpgradeGovernanceCanister(_) => (),
_ => panic!(
"Specifying a secret key or HSM is only supported for \
Expand Down Expand Up @@ -4544,6 +4560,13 @@ async fn main() {
)
.await
}
SubCommand::SwapNodeInSubnetDirectly(cmd) => {
registry_canister
.swap_node_in_subnet_directly(cmd.old_node_id, cmd.new_node_id)
.await
.unwrap();
println!("Nodes swapped.");
}
SubCommand::GetPendingRootProposalsToUpgradeGovernanceCanister => {
get_pending_root_proposals_to_upgrade_governance_canister(make_canister_client(
reachable_nns_urls,
Expand Down
1 change: 1 addition & 0 deletions rs/registry/nns_data_provider/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ DEPENDENCIES = [
"//rs/crypto/tree_hash",
"//rs/interfaces/registry",
"//rs/nns/constants",
"//rs/registry/canister",
"//rs/registry/canister/api",
"//rs/registry/transport",
"//rs/tree_deserializer",
Expand Down
1 change: 1 addition & 0 deletions rs/registry/nns_data_provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ rand = { workspace = true }
serde = { workspace = true }
tree-deserializer = { path = "../../tree_deserializer" }
url = { workspace = true }
registry-canister = { path = "../canister" }

[dev-dependencies]
futures-util = { workspace = true }
Expand Down
41 changes: 40 additions & 1 deletion rs/registry/nns_data_provider/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use async_trait::async_trait;
use candid::{Decode, Encode};
use prost::Message;
use rand::seq::SliceRandom;
use registry_canister::mutations::do_swap_node_in_subnet_directly::SwapNodeInSubnetDirectlyPayload;
use std::time::Duration;
use url::Url;

Expand All @@ -15,7 +16,9 @@ use ic_registry_transport::{
serialize_atomic_mutate_request, serialize_get_changes_since_request,
serialize_get_value_request, Error, GetChunk,
};
use ic_types::{crypto::threshold_sig::ThresholdSigPublicKey, CanisterId, RegistryVersion, Time};
use ic_types::{
crypto::threshold_sig::ThresholdSigPublicKey, CanisterId, PrincipalId, RegistryVersion, Time,
};

pub const MAX_NUM_SSH_KEYS: usize = 50;

Expand Down Expand Up @@ -312,6 +315,42 @@ impl RegistryCanister {
))]),
}
}

pub async fn swap_node_in_subnet_directly(
&self,
old_node_id: PrincipalId,
new_node_id: PrincipalId,
) -> Result<(), Error> {
let nonce = format!("{}", chrono::Utc::now().timestamp_nanos_opt().unwrap())
.as_bytes()
.to_vec();

let request = SwapNodeInSubnetDirectlyPayload {
new_node_id: Some(new_node_id),
old_node_id: Some(old_node_id),
};

let payload = Encode!(&request)
.map_err(|err| ic_registry_transport::Error::MalformedMessage(err.to_string()))?;

match self
.choose_random_agent()
.execute_update(
&self.canister_id,
&self.canister_id,
"swap_node_in_subnet_directly",
payload,
nonce,
)
.await
.map_err(ic_registry_transport::Error::UnknownError)?
{
Some(_) => Ok(()),
None => Err(ic_registry_transport::Error::UnknownError(
"No response was received from swap_node_in_subnet_directly".to_string(),
)),
}
}
}

/// Convert `Vec<RegistryDelta>` to `Vec<RegistryRecord>`.
Expand Down
Loading