diff --git a/rs/cli/src/cli.rs b/rs/cli/src/cli.rs index 226395bb..537ee504 100644 --- a/rs/cli/src/cli.rs +++ b/rs/cli/src/cli.rs @@ -115,10 +115,15 @@ pub(crate) mod subnet { verbose: bool, }, - /// Extends the size of the subnet - Extend { + /// Resize the subnet + Resize { // Number of nodes to be added - size: usize, + #[clap(long)] + add: usize, + + // Number of nodes to be removed + #[clap(long)] + remove: usize, /// Features or Node IDs to exclude from the available nodes pool #[clap(long, num_args(1..))] @@ -129,7 +134,7 @@ pub(crate) mod subnet { #[clap(long, num_args(1..))] include: Vec, - /// Motivation for extending the subnet + /// Motivation for resing the subnet #[clap(short, long)] motivation: Option, diff --git a/rs/cli/src/clients.rs b/rs/cli/src/clients.rs index a5d5f165..08444d86 100644 --- a/rs/cli/src/clients.rs +++ b/rs/cli/src/clients.rs @@ -2,7 +2,7 @@ use async_trait::async_trait; use decentralization::SubnetChangeResponse; use ic_base_types::PrincipalId; use ic_management_types::{ - requests::{MembershipReplaceRequest, NodesRemoveRequest, NodesRemoveResponse, SubnetExtendRequest}, + requests::{MembershipReplaceRequest, NodesRemoveRequest, NodesRemoveResponse, SubnetResizeRequest}, Network, NetworkError, ReplicaRelease, SubnetMembershipChangeProposal, }; use log::error; @@ -61,11 +61,11 @@ impl DashboardBackendClient { .await } - pub async fn subnet_extend(&self, request: SubnetExtendRequest) -> anyhow::Result { + pub async fn subnet_resize(&self, request: SubnetResizeRequest) -> anyhow::Result { reqwest::Client::new() .post( self.url - .join("subnet/membership/extend") + .join("subnet/membership/resize") .map_err(|e| anyhow::anyhow!(e))?, ) .json(&request) @@ -101,7 +101,7 @@ impl RESTRequestBuilder for reqwest::RequestBuilder { if let Err(e) = response_result.error_for_status_ref() { let response = response_result.text().await?; match serde_json::from_str(&response) { - Ok(NetworkError::ExtensionFailed(s)) => { + Ok(NetworkError::ResizeFailed(s)) => { error!("{}", s); Err(anyhow::anyhow!("failed request (error: {})", e)) } diff --git a/rs/cli/src/main.rs b/rs/cli/src/main.rs index d2f74743..17f084b5 100644 --- a/rs/cli/src/main.rs +++ b/rs/cli/src/main.rs @@ -56,7 +56,7 @@ async fn main() -> Result<(), anyhow::Error> { cli::Commands::Subnet(subnet) => { let runner = runner::Runner::from_opts(&cli_opts).await?; match &subnet.subcommand { - cli::subnet::Commands::Deploy { .. } | cli::subnet::Commands::Extend { .. } => { + cli::subnet::Commands::Deploy { .. } | cli::subnet::Commands::Resize { .. } => { if subnet.id.is_none() { cmd.error(ErrorKind::MissingRequiredArgument, "Required argument `id` not found") .exit(); @@ -125,11 +125,12 @@ async fn main() -> Result<(), anyhow::Error> { }, *verbose) .await } - cli::subnet::Commands::Extend { size, include, exclude, motivation, verbose, } => { + cli::subnet::Commands::Resize { add, remove, include, exclude, motivation, verbose, } => { if let Some(motivation) = motivation.clone() { - runner.subnet_extend(ic_management_types::requests::SubnetExtendRequest { + runner.subnet_resize(ic_management_types::requests::SubnetResizeRequest { subnet: subnet.id.unwrap(), - size: *size, + add: *add, + remove: *remove, exclude: exclude.clone().into(), include: include.clone().into(), }, motivation, *verbose).await diff --git a/rs/cli/src/runner.rs b/rs/cli/src/runner.rs index 59163d77..18c30e14 100644 --- a/rs/cli/src/runner.rs +++ b/rs/cli/src/runner.rs @@ -36,14 +36,14 @@ impl Runner { Ok(()) } - pub async fn subnet_extend( + pub async fn subnet_resize( &self, - request: ic_management_types::requests::SubnetExtendRequest, + request: ic_management_types::requests::SubnetResizeRequest, motivation: String, verbose: bool, ) -> anyhow::Result<()> { let subnet = request.subnet; - let change = self.dashboard_backend_client.subnet_extend(request).await?; + let change = self.dashboard_backend_client.subnet_resize(request).await?; if verbose { if let Some(run_log) = &change.run_log { println!("{}\n", run_log.join("\n")); @@ -51,16 +51,32 @@ impl Runner { } println!("{}", change); - self.run_membership_change( - change, - ProposeOptions { - title: format!("Extend subnet {subnet}").into(), - summary: format!("Extend subnet {subnet}").into(), - motivation: motivation.clone().into(), - simulate: false, - }, - ) - .await + if change.added.is_empty() && change.removed.is_empty() { + return Ok(()); + } + if change.added.len() == change.removed.len() { + self.run_membership_change( + change.clone(), + ops_subnet_node_replace::replace_proposal_options(&change)?, + ) + .await + } else { + let action = if change.added.len() < change.removed.len() { + "Removing nodes from" + } else { + "Adding nodes to" + }; + self.run_membership_change( + change, + ProposeOptions { + title: format!("{action} subnet {subnet}").into(), + summary: format!("{action} subnet {subnet}").into(), + motivation: motivation.clone().into(), + simulate: false, + }, + ) + .await + } } pub async fn membership_replace( @@ -76,6 +92,9 @@ impl Runner { } println!("{}", change); + if change.added.is_empty() && change.removed.is_empty() { + return Ok(()); + } self.run_membership_change( change.clone(), ops_subnet_node_replace::replace_proposal_options(&change)?, diff --git a/rs/decentralization/src/nakamoto/mod.rs b/rs/decentralization/src/nakamoto/mod.rs index 241e6655..a6160151 100644 --- a/rs/decentralization/src/nakamoto/mod.rs +++ b/rs/decentralization/src/nakamoto/mod.rs @@ -451,6 +451,7 @@ mod tests { DecentralizedSubnet { id: PrincipalId::new_subnet_test_id(subnet_num), nodes: new_test_nodes("feat", num_nodes, num_dfinity_nodes), + removed_nodes: Vec::new(), min_nakamoto_coefficients: None, comment: None, run_log: Vec::new(), @@ -474,6 +475,7 @@ mod tests { num_dfinity_nodes, feature_to_override, ), + removed_nodes: Vec::new(), min_nakamoto_coefficients: None, comment: None, run_log: Vec::new(), @@ -713,6 +715,7 @@ mod tests { .cloned() .filter(|n| !re_unhealthy_nodes.is_match(&n.id.to_string())) .collect(), + removed_nodes: Vec::new(), min_nakamoto_coefficients: None, comment: None, run_log: Vec::new(), diff --git a/rs/decentralization/src/network.rs b/rs/decentralization/src/network.rs index 9c383ffd..7fb57dec 100644 --- a/rs/decentralization/src/network.rs +++ b/rs/decentralization/src/network.rs @@ -122,13 +122,16 @@ impl From<&ic_management_types::Node> for Node { pub struct DecentralizedSubnet { pub id: PrincipalId, pub nodes: Vec, + pub removed_nodes: Vec, pub min_nakamoto_coefficients: Option, pub comment: Option, pub run_log: Vec, } impl DecentralizedSubnet { - pub fn remove_nodes(&self, nodes: &[PrincipalId]) -> Result<(Self, Vec), NetworkError> { + /// Return a new instance of a DecentralizedSubnet that does not contain the + /// provided nodes. + pub fn without_nodes(&self, nodes: &[PrincipalId]) -> Result { let mut new_subnet_nodes = self.nodes.clone(); let mut removed = Vec::new(); for node in nodes { @@ -138,31 +141,32 @@ impl DecentralizedSubnet { return Err(NetworkError::NodeNotFound(*node)); } } - Ok(( - Self { - id: self.id, - nodes: new_subnet_nodes, - min_nakamoto_coefficients: self.min_nakamoto_coefficients.clone(), - comment: self.comment.clone(), - run_log: { - let mut run_log = self.run_log.clone(); - run_log.push(format!("Remove nodes {:?}", removed.iter().map(|n| n.id))); - run_log - }, + Ok(Self { + id: self.id, + nodes: new_subnet_nodes, + removed_nodes: removed.clone(), + min_nakamoto_coefficients: self.min_nakamoto_coefficients.clone(), + comment: self.comment.clone(), + run_log: { + let mut run_log = self.run_log.clone(); + run_log.push(format!("Without nodes {:?}", removed.iter().map(|n| n.id))); + run_log }, - removed, - )) + }) } - pub fn add_nodes(&self, nodes: Vec) -> Self { + /// Return a new instance of a DecentralizedSubnet that contains the + /// provided nodes. + pub fn with_nodes(&self, nodes: Vec) -> Self { Self { id: self.id, nodes: self.nodes.clone().into_iter().chain(nodes.clone()).collect(), + removed_nodes: self.removed_nodes.clone(), min_nakamoto_coefficients: self.min_nakamoto_coefficients.clone(), comment: self.comment.clone(), run_log: { let mut run_log = self.run_log.clone(); - run_log.push(format!("Remove nodes {:?}", nodes.iter().map(|n| n.id))); + run_log.push(format!("With nodes {:?}", nodes.iter().map(|n| n.id))); run_log }, } @@ -334,7 +338,7 @@ impl DecentralizedSubnet { num_nodes_to_add: usize, available_nodes: &[Node], ) -> anyhow::Result { - let mut run_log = Vec::new(); + let mut run_log = self.run_log.clone(); let mut nodes_initial = self.nodes.clone(); let mut available_nodes = available_nodes.to_vec(); @@ -507,6 +511,9 @@ impl DecentralizedSubnet { match best_result { Some(best_result) => { + let line = format!("Nakamoto score after extension {}", best_result.score); + info!("{}", &line); + run_log.push(line); available_nodes.swap_remove(best_result.index); nodes_after_extension.push(best_result.node.clone()); nodes_initial.push(best_result.node.clone()); @@ -548,6 +555,7 @@ impl DecentralizedSubnet { Ok(Self { id: self.id, nodes: nodes_after_extension, + removed_nodes: self.removed_nodes.clone(), min_nakamoto_coefficients: self.min_nakamoto_coefficients.clone(), comment, run_log, @@ -578,6 +586,7 @@ impl From<&ic_management_types::Subnet> for DecentralizedSubnet { Self { id: s.principal, nodes: s.nodes.iter().map(Node::from).collect(), + removed_nodes: Vec::new(), min_nakamoto_coefficients: None, comment: None, run_log: Vec::new(), @@ -651,7 +660,7 @@ pub trait TopologyManager: SubnetQuerier + AvailableNodesQuerier { min_nakamoto_coefficients, ..Default::default() } - .extend(size) + .resize(size, 0) } } @@ -720,7 +729,62 @@ impl SubnetChangeRequest { } } - pub fn extend(&self, extension_size: usize) -> Result { + /// Remove nodes from the subnet such that we keep nodes with the best + /// Nakamoto coefficient. + pub fn remove_nodes_and_keep_best_nakamoto( + &self, + how_many_nodes: usize, + ) -> Result { + let mut subnet = self.subnet.clone(); + + subnet.run_log.push(format!( + "Nakamoto score before removing nodes {}", + NakamotoScore::new_from_nodes(subnet.nodes.as_slice()) + )); + for i in 0..how_many_nodes { + // Find the node that gives the best score when removed. + let (j, score_max) = subnet + .clone() + .nodes + .iter() + .enumerate() + .map(|(j, _node)| { + let mut subnet = subnet.clone(); + subnet.nodes.swap_remove(j); + (j, NakamotoScore::new_from_nodes(subnet.nodes.as_slice())) + }) + .max_by_key(|(_, score)| score.clone()) + .ok_or_else(|| { + NetworkError::ResizeFailed(format!( + "Cannot remove {} nodes from subnet with {} nodes", + how_many_nodes, + self.subnet.nodes.len() + )) + })?; + + // Remove the node from the subnet. + let node_removed = subnet.nodes.swap_remove(j); + subnet.run_log.push(format!( + "Removed {}/{} node {} with score {}", + i + 1, + how_many_nodes, + node_removed.id, + score_max + )); + } + subnet.run_log.push(format!( + "Nakamoto score after removing nodes {}", + NakamotoScore::new_from_nodes(subnet.nodes.as_slice()) + )); + Ok(subnet) + } + + /// Add or remove nodes to the subnet. + pub fn resize( + &self, + how_many_nodes_to_add: usize, + how_many_nodes_to_remove: usize, + ) -> Result { let included_nodes = self .available_nodes .iter() @@ -735,12 +799,17 @@ impl SubnetChangeRequest { .filter(|n| !included_nodes.contains(n)) .collect::>(); - let extended_subnet = self - .subnet - .add_nodes(included_nodes) + let resized_subnet = if how_many_nodes_to_remove > 0 { + self.remove_nodes_and_keep_best_nakamoto(how_many_nodes_to_remove) + .map_err(|e| NetworkError::ResizeFailed(e.to_string()))? + } else { + self.subnet.clone() + }; + let resized_subnet = resized_subnet + .with_nodes(included_nodes) .with_min_nakamoto_coefficients(&self.min_nakamoto_coefficients) - .new_extended_subnet(extension_size, &available_nodes) - .map_err(|e| NetworkError::ExtensionFailed(e.to_string()))?; + .new_extended_subnet(how_many_nodes_to_add, &available_nodes) + .map_err(|e| NetworkError::ResizeFailed(e.to_string()))?; let subnet_change = SubnetChange { id: self.subnet.id, @@ -751,20 +820,29 @@ impl SubnetChangeRequest { .into_iter() .chain(self.removed_nodes.clone()) .collect(), - new_nodes: extended_subnet.nodes, + new_nodes: resized_subnet.nodes, min_nakamoto_coefficients: self.min_nakamoto_coefficients.clone(), - comment: extended_subnet.comment, - run_log: extended_subnet.run_log, + comment: resized_subnet.comment, + run_log: resized_subnet.run_log, }; - info!("Subnet {} extend {}", self.subnet.id, subnet_change); + info!( + "Subnet {} resized, {} nodes added, {} nodes removed", + self.subnet.id, how_many_nodes_to_add, how_many_nodes_to_remove + ); Ok(subnet_change) } pub fn replace(self, nodes: &[PrincipalId]) -> Result { - let (subnet, mut removed_nodes) = self.subnet.remove_nodes(nodes)?; + let subnet = self.subnet.without_nodes(nodes)?; + let num_removed_nodes = subnet.removed_nodes.len(); - Self { subnet, ..self }.extend(removed_nodes.len()).map(|mut sc| { - sc.old_nodes.append(&mut removed_nodes); + Self { + subnet: subnet.clone(), + ..self + } + .resize(num_removed_nodes, 0) + .map(|mut sc| { + sc.old_nodes.append(&mut subnet.removed_nodes.clone()); sc }) } @@ -836,7 +914,7 @@ impl SubnetChangeRequest { score1.cmp(&score2) }) { Some(best_result) => Ok(best_result.clone()), - None => Err(NetworkError::ExtensionFailed(format!( + None => Err(NetworkError::ResizeFailed(format!( "Optimize failed, could not find any suitable solution for the request\n{}", errs.join("\n") ))), @@ -844,10 +922,10 @@ impl SubnetChangeRequest { } pub fn remove(self, nodes: &[PrincipalId]) -> Result { - let (subnet, removed_nodes) = self.subnet.remove_nodes(nodes)?; + let subnet = self.subnet.without_nodes(nodes)?; Ok(SubnetChangeRequest { - subnet, - removed_nodes: self.removed_nodes.into_iter().chain(removed_nodes).collect(), + subnet: subnet.clone(), + removed_nodes: self.removed_nodes.into_iter().chain(subnet.removed_nodes).collect(), ..self }) } @@ -890,7 +968,7 @@ impl SubnetChangeRequest { match (request_change, result_optimize) { (request_change, Some(result_optimize)) => { let result_extend = - request_change.extend(request_change.removed_nodes.len() - result_optimize.added().len())?; + request_change.resize(request_change.removed_nodes.len() - result_optimize.added().len(), 0)?; Ok(SubnetChange { comment: if result_optimize.comment == result_extend.comment { result_extend.comment @@ -909,9 +987,10 @@ impl SubnetChangeRequest { ..result_extend }) } - (request_change, _) => { - request_change.extend(request_change.removed_nodes.len() - request_change.include_nodes.len()) - } + (request_change, _) => request_change.resize( + request_change.removed_nodes.len() - request_change.include_nodes.len(), + 0, + ), } } } @@ -947,6 +1026,7 @@ impl SubnetChange { DecentralizedSubnet { id: self.id, nodes: self.old_nodes.clone(), + removed_nodes: Vec::new(), min_nakamoto_coefficients: self.min_nakamoto_coefficients.clone(), comment: self.comment.clone(), run_log: Vec::new(), @@ -957,6 +1037,12 @@ impl SubnetChange { DecentralizedSubnet { id: self.id, nodes: self.new_nodes.clone(), + removed_nodes: self + .old_nodes + .clone() + .into_iter() + .filter(|n| !self.new_nodes.contains(n)) + .collect(), min_nakamoto_coefficients: self.min_nakamoto_coefficients.clone(), comment: self.comment.clone(), run_log: self.run_log.clone(), diff --git a/rs/ic-management-backend/src/endpoints/query_decentralization.rs b/rs/ic-management-backend/src/endpoints/query_decentralization.rs index ccfa6285..b7b693de 100644 --- a/rs/ic-management-backend/src/endpoints/query_decentralization.rs +++ b/rs/ic-management-backend/src/endpoints/query_decentralization.rs @@ -1,10 +1,9 @@ use super::*; -use decentralization::SubnetChangeResponse; use decentralization::network::{DecentralizedSubnet, SubnetChange}; +use decentralization::SubnetChangeResponse; use ic_base_types::PrincipalId; use ic_management_types::MinNakamotoCoefficients; -use serde::{Serialize, Deserialize}; - +use serde::{Deserialize, Serialize}; #[derive(Deserialize)] struct SubnetRequest { @@ -16,7 +15,7 @@ struct DecentralizedSubnetResponse { id: PrincipalId, message: String, run_log: String, - nakamoto: decentralization::nakamoto::NakamotoScore + nakamoto: decentralization::nakamoto::NakamotoScore, } /// Get the decentralization coefficients for a subnet @@ -42,7 +41,14 @@ async fn decentralization_whatif_query( request: web::Json, registry: web::Data>>, ) -> Result { - get_decentralization_analysis(registry, request.subnet, request.nodes_to_add.clone(), request.nodes_to_remove.clone(), request.min_nakamoto_coefficients.clone()).await + get_decentralization_analysis( + registry, + request.subnet, + request.nodes_to_add.clone(), + request.nodes_to_remove.clone(), + request.min_nakamoto_coefficients.clone(), + ) + .await } async fn get_decentralization_analysis( @@ -50,52 +56,53 @@ async fn get_decentralization_analysis( subnet: Option, nodes_to_add: Option>, nodes_to_remove: Option>, - min_nakamoto_coefficients: Option + min_nakamoto_coefficients: Option, ) -> Result { let subnets = registry.read().await.subnets(); let nodes = registry.read().await.nodes(); - let original_subnet = subnet.map(|subnet_id| { - match subnets.get(&subnet_id) { - Some(subnet) => { - DecentralizedSubnet { - id: subnet_id, - nodes: subnet.nodes.iter().map(decentralization::network::Node::from).collect(), - min_nakamoto_coefficients: min_nakamoto_coefficients.clone(), - comment: None, - run_log: Vec::new(), - } - }, - None => DecentralizedSubnet { - id: PrincipalId::new_subnet_test_id(0), - nodes: Vec::new(), + let original_subnet = subnet + .map(|subnet_id| match subnets.get(&subnet_id) { + Some(subnet) => DecentralizedSubnet { + id: subnet_id, + nodes: subnet.nodes.iter().map(decentralization::network::Node::from).collect(), + removed_nodes: Vec::new(), min_nakamoto_coefficients: min_nakamoto_coefficients.clone(), comment: None, run_log: Vec::new(), - } - } - }).unwrap_or_else(|| DecentralizedSubnet { + }, + None => DecentralizedSubnet { id: PrincipalId::new_subnet_test_id(0), nodes: Vec::new(), + removed_nodes: Vec::new(), min_nakamoto_coefficients: min_nakamoto_coefficients.clone(), comment: None, run_log: Vec::new(), - }); + }, + }) + .unwrap_or_else(|| DecentralizedSubnet { + id: PrincipalId::new_subnet_test_id(0), + nodes: Vec::new(), + removed_nodes: Vec::new(), + min_nakamoto_coefficients: min_nakamoto_coefficients.clone(), + comment: None, + run_log: Vec::new(), + }); let updated_subnet = match &nodes_to_remove { - Some(nodes_to_remove) => { - let (updated_subnet, _removed_nodes) = original_subnet.remove_nodes(nodes_to_remove)?; - updated_subnet - }, - None => original_subnet.clone() + Some(nodes_to_remove) => original_subnet.without_nodes(nodes_to_remove)?, + None => original_subnet.clone(), }; let updated_subnet = match &nodes_to_add { Some(nodes_to_add) => { - let nodes_to_add = nodes_to_add.iter().map(|n| decentralization::network::Node::from(&nodes[n])).collect(); - updated_subnet.add_nodes(nodes_to_add) - }, - None => updated_subnet + let nodes_to_add = nodes_to_add + .iter() + .map(|n| decentralization::network::Node::from(&nodes[n])) + .collect(); + updated_subnet.with_nodes(nodes_to_add) + } + None => updated_subnet, }; let subnet_change = SubnetChange { @@ -109,9 +116,9 @@ async fn get_decentralization_analysis( let response = DecentralizedSubnetResponse { id: subnet.unwrap_or_else(|| PrincipalId::new_subnet_test_id(0)), - message: format!("{}", SubnetChangeResponse::from(&subnet_change)), + message: format!("{}", SubnetChangeResponse::from(&subnet_change)), nakamoto: updated_subnet.nakamoto_score(), run_log: subnet_change.run_log.join("\n"), }; Ok(HttpResponse::Ok().json(&response)) -} \ No newline at end of file +} diff --git a/rs/ic-management-backend/src/endpoints/subnet.rs b/rs/ic-management-backend/src/endpoints/subnet.rs index bbbd3551..86690662 100644 --- a/rs/ic-management-backend/src/endpoints/subnet.rs +++ b/rs/ic-management-backend/src/endpoints/subnet.rs @@ -3,7 +3,7 @@ use crate::health; use decentralization::{network::TopologyManager, SubnetChangeResponse}; use ic_base_types::PrincipalId; use ic_management_types::requests::{ - MembershipReplaceRequest, ReplaceTarget, SubnetCreateRequest, SubnetExtendRequest, + MembershipReplaceRequest, ReplaceTarget, SubnetCreateRequest, SubnetResizeRequest, }; use serde::Deserialize; @@ -186,10 +186,10 @@ async fn create_subnet( ))) } -/// Simulates extending subnet size, i.e. adding nodes to a subnet. -#[post("/subnet/membership/extend")] -async fn extend( - request: web::Json, +/// Simulates resizing the subnet, i.e. adding or removing nodes to a subnet. +#[post("/subnet/membership/resize")] +async fn resize( + request: web::Json, registry: web::Data>>, ) -> Result { let registry = registry.read().await; @@ -199,7 +199,7 @@ async fn extend( .await? .exclude_nodes(request.exclude.clone().unwrap_or_default()) .include_nodes(request.include.clone().unwrap_or_default()) - .extend(request.size)?; + .resize(request.add, request.remove)?; Ok(HttpResponse::Ok().json(decentralization::SubnetChangeResponse::from(&change))) } diff --git a/rs/ic-management-backend/src/main.rs b/rs/ic-management-backend/src/main.rs index 26799711..0aa6eb26 100644 --- a/rs/ic-management-backend/src/main.rs +++ b/rs/ic-management-backend/src/main.rs @@ -122,7 +122,7 @@ async fn main() -> std::io::Result<()> { .service(endpoints::subnet::pending_action) .service(endpoints::subnet::replace) .service(endpoints::subnet::create_subnet) - .service(endpoints::subnet::extend) + .service(endpoints::subnet::resize) .service(endpoints::subnet::change_preview) .service(endpoints::nodes::remove) .service(endpoints::query_decentralization::decentralization_subnet_query) diff --git a/rs/ic-management-backend/src/registry.rs b/rs/ic-management-backend/src/registry.rs index feafddae..7ccfead4 100644 --- a/rs/ic-management-backend/src/registry.rs +++ b/rs/ic-management-backend/src/registry.rs @@ -8,7 +8,8 @@ use ic_management_types::{ ReplicaRelease, Subnet, SubnetMetadata, }; use ic_registry_keys::{ - make_blessed_replica_versions_key, NODE_OPERATOR_RECORD_KEY_PREFIX, NODE_RECORD_KEY_PREFIX, SUBNET_RECORD_KEY_PREFIX, + make_blessed_replica_versions_key, NODE_OPERATOR_RECORD_KEY_PREFIX, NODE_RECORD_KEY_PREFIX, + SUBNET_RECORD_KEY_PREFIX, }; use ic_registry_local_registry::LocalRegistry; use ic_registry_subnet_type::SubnetType; @@ -605,6 +606,7 @@ impl SubnetQuerier for RegistryState { .map(|s| decentralization::network::DecentralizedSubnet { id: s.principal, nodes: s.nodes.iter().map(decentralization::network::Node::from).collect(), + removed_nodes: Vec::new(), min_nakamoto_coefficients: None, comment: None, run_log: Vec::new(), @@ -637,6 +639,7 @@ impl SubnetQuerier for RegistryState { .iter() .map(decentralization::network::Node::from) .collect(), + removed_nodes: Vec::new(), min_nakamoto_coefficients: None, comment: None, run_log: Vec::new(), diff --git a/rs/ic-management-types/src/errors.rs b/rs/ic-management-types/src/errors.rs index 14c8aa94..081880b0 100644 --- a/rs/ic-management-types/src/errors.rs +++ b/rs/ic-management-types/src/errors.rs @@ -8,7 +8,7 @@ use std::fmt::Debug; pub enum NetworkError { NodeNotFound(PrincipalId), SubnetNotFound(PrincipalId), - ExtensionFailed(String), + ResizeFailed(String), DataRequestError, IllegalRequest(String), } @@ -17,7 +17,7 @@ impl ResponseError for NetworkError { fn error_response(&self) -> HttpResponse { match self { NetworkError::IllegalRequest(_input) => HttpResponse::build(StatusCode::BAD_REQUEST).json(self), - NetworkError::ExtensionFailed(_) => HttpResponse::InternalServerError().json(self), + NetworkError::ResizeFailed(_) => HttpResponse::InternalServerError().json(self), NetworkError::DataRequestError => HttpResponse::build(StatusCode::FAILED_DEPENDENCY).json(self), NetworkError::SubnetNotFound(_) | NetworkError::NodeNotFound(_) => HttpResponse::NotFound().json(self), } @@ -27,7 +27,7 @@ impl ResponseError for NetworkError { match self { Self::NodeNotFound(_) | Self::SubnetNotFound(_) => StatusCode::NOT_FOUND, Self::IllegalRequest(_) => StatusCode::BAD_REQUEST, - Self::ExtensionFailed(_) => StatusCode::INTERNAL_SERVER_ERROR, + Self::ResizeFailed(_) => StatusCode::INTERNAL_SERVER_ERROR, Self::DataRequestError => StatusCode::INTERNAL_SERVER_ERROR, } } diff --git a/rs/ic-management-types/src/requests.rs b/rs/ic-management-types/src/requests.rs index e57e7732..95f5439a 100644 --- a/rs/ic-management-types/src/requests.rs +++ b/rs/ic-management-types/src/requests.rs @@ -31,9 +31,10 @@ pub struct SubnetCreateRequest { } #[derive(Serialize, Deserialize)] -pub struct SubnetExtendRequest { +pub struct SubnetResizeRequest { pub subnet: PrincipalId, - pub size: usize, + pub add: usize, + pub remove: usize, pub exclude: Option>, pub include: Option>, }