Skip to content

Commit 6974885

Browse files
refactor: Use Principal in RemoveNodeOperatorsPayload, instead of Vec<u8> (dfinity#3386)
The objective in this PR is to make the ic-admin (and potentially other) output prettier by showing the list of operators in `RemoveNodeOperatorsPayload` as principals (strings) instead of Vec[u8]. In result: before: ```bash ic-admin propose-to-remove-node-operators --nns-urls https://ic0.app xla4b-4vmw4-db4cm-qg63h-6jvj6-zm2nj-von5y-7dx2k-calku-e6hke-wae --dry-run --summary "Remove obsolete node operator" [...] Title: Remove node operators with principal ids: ["xla4b"] Summary: Remove obsolete node operator Payload: RemoveNodeOperatorsPayload { node_operators_to_remove: [ [ 172, 183, 6, 30, 9, 144, 55, 182, 127, 38, 169, 246, 89, 166, 166, 174, 111, 113, 241, 223, 74, 16, 22, 170, 19, 199, 81, 44, 2, ], ], } ``` With this change: ``` ic-admin propose-to-remove-node-operators --nns-urls https://ic0.app xla4b-4vmw4-db4cm-qg63h-6jvj6-zm2nj-von5y-7dx2k-calku-e6hke-wae --dry-run --summary "Remove obsolete node operator" [...] Title: Remove node operators with principal ids: ["xla4b"] Summary: Remove obsolete node operator Payload: RemoveNodeOperatorsPayload { node_operators_to_remove: [], node_operator_principals_to_remove: Some( NodeOperatorPrincipals { principals: [ xla4b-4vmw4-db4cm-qg63h-6jvj6-zm2nj-von5y-7dx2k-calku-e6hke-wae, ], }, ), } ``` ### Changes - Removed `RemoveNodeOperatorsPayload` from `node_operator.proto`. - Moved `RemoveNodeOperatorsPayload` definition into `do_remove_node_operators.rs`. --------- Co-authored-by: Max Summe <[email protected]>
1 parent cf52a50 commit 6974885

File tree

8 files changed

+84
-63
lines changed

8 files changed

+84
-63
lines changed

rs/nns/integration_tests/src/node_operator_handler.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@ use ic_nns_test_utils::{
2020
itest_helpers::{state_machine_test_on_nns_subnet, NnsCanisters},
2121
registry::{get_value_or_panic, prepare_add_node_payload},
2222
};
23-
use ic_protobuf::registry::node_operator::v1::{NodeOperatorRecord, RemoveNodeOperatorsPayload};
23+
use ic_protobuf::registry::node_operator::v1::NodeOperatorRecord;
2424
use ic_registry_keys::make_node_operator_record_key;
2525
use ic_registry_transport::{
2626
deserialize_get_value_response, serialize_get_value_request, Error::KeyNotPresent,
2727
};
2828
use ic_types::PrincipalId;
2929
use maplit::btreemap;
30-
use registry_canister::mutations::do_add_node_operator::AddNodeOperatorPayload;
30+
use registry_canister::mutations::{
31+
do_add_node_operator::AddNodeOperatorPayload,
32+
do_remove_node_operators::RemoveNodeOperatorsPayload,
33+
};
3134
use std::time::Duration;
3235

3336
/// Test that new Node Operator records can be added and removed to/from the
@@ -123,11 +126,10 @@ fn test_node_operator_records_can_be_added_and_removed() {
123126
.await
124127
.unwrap();
125128

126-
let node_operator_id_1: Vec<u8> = (*TEST_NEURON_1_OWNER_PRINCIPAL.into_vec()).to_vec();
127-
let node_operator_id_2: Vec<u8> = (*TEST_NEURON_2_OWNER_PRINCIPAL.into_vec()).to_vec();
128-
let proposal_payload = RemoveNodeOperatorsPayload {
129-
node_operators_to_remove: vec![node_operator_id_1, node_operator_id_2],
130-
};
129+
let proposal_payload = RemoveNodeOperatorsPayload::new(vec![
130+
*TEST_NEURON_1_OWNER_PRINCIPAL,
131+
*TEST_NEURON_2_OWNER_PRINCIPAL,
132+
]);
131133

132134
let node_operator_record_key_1 =
133135
make_node_operator_record_key(*TEST_NEURON_1_OWNER_PRINCIPAL).into_bytes();

rs/protobuf/def/registry/node_operator/v1/node_operator.proto

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,3 @@ message NodeOperatorRecord {
2929

3030
optional string ipv6 = 6;
3131
}
32-
33-
// The payload of a request to remove Node Operator records from the Registry
34-
message RemoveNodeOperatorsPayload {
35-
repeated bytes node_operators_to_remove = 1;
36-
}

rs/protobuf/src/gen/registry/registry.node_operator.v1.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,3 @@ pub struct NodeOperatorRecord {
3939
#[prost(string, optional, tag = "6")]
4040
pub ipv6: ::core::option::Option<::prost::alloc::string::String>,
4141
}
42-
/// The payload of a request to remove Node Operator records from the Registry
43-
#[derive(
44-
candid::CandidType,
45-
serde::Serialize,
46-
candid::Deserialize,
47-
Eq,
48-
Hash,
49-
Clone,
50-
PartialEq,
51-
::prost::Message,
52-
)]
53-
pub struct RemoveNodeOperatorsPayload {
54-
#[prost(bytes = "vec", repeated, tag = "1")]
55-
pub node_operators_to_remove: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
56-
}

rs/registry/admin/src/main.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ use ic_protobuf::registry::{
7777
dc::v1::{AddOrRemoveDataCentersProposalPayload, DataCenterRecord},
7878
firewall::v1::{FirewallConfig, FirewallRule, FirewallRuleSet},
7979
node::v1::{NodeRecord, NodeRewardType},
80-
node_operator::v1::{NodeOperatorRecord, RemoveNodeOperatorsPayload},
80+
node_operator::v1::NodeOperatorRecord,
8181
node_rewards::v2::{NodeRewardRate, UpdateNodeRewardsTableProposalPayload},
8282
provisional_whitelist::v1::ProvisionalWhitelist as ProvisionalWhitelistProto,
8383
replica_version::v1::{BlessedReplicaVersions, ReplicaVersionRecord},
@@ -134,6 +134,7 @@ use registry_canister::mutations::{
134134
do_deploy_guestos_to_all_subnet_nodes::DeployGuestosToAllSubnetNodesPayload,
135135
do_deploy_guestos_to_all_unassigned_nodes::DeployGuestosToAllUnassignedNodesPayload,
136136
do_remove_api_boundary_nodes::RemoveApiBoundaryNodesPayload,
137+
do_remove_node_operators::RemoveNodeOperatorsPayload,
137138
do_revise_elected_replica_versions::ReviseElectedGuestosVersionsPayload,
138139
do_set_firewall_config::SetFirewallConfigPayload,
139140
do_update_api_boundary_nodes_version::DeployGuestosToSomeApiBoundaryNodes,
@@ -701,14 +702,7 @@ impl ProposalTitle for ProposeToRemoveNodeOperatorsCmd {
701702
#[async_trait]
702703
impl ProposalPayload<RemoveNodeOperatorsPayload> for ProposeToRemoveNodeOperatorsCmd {
703704
async fn payload(&self, _: &Agent) -> RemoveNodeOperatorsPayload {
704-
RemoveNodeOperatorsPayload {
705-
node_operators_to_remove: self
706-
.node_operators_to_remove
707-
.clone()
708-
.iter()
709-
.map(|x| x.to_vec())
710-
.collect(),
711-
}
705+
RemoveNodeOperatorsPayload::new(self.node_operators_to_remove.clone())
712706
}
713707
}
714708

rs/registry/canister/canister/canister.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use ic_nervous_system_string::clamp_debug_len;
1010
use ic_nns_constants::{GOVERNANCE_CANISTER_ID, ROOT_CANISTER_ID};
1111
use ic_protobuf::registry::{
1212
dc::v1::{AddOrRemoveDataCentersProposalPayload, DataCenterRecord},
13-
node_operator::v1::{NodeOperatorRecord, RemoveNodeOperatorsPayload},
13+
node_operator::v1::NodeOperatorRecord,
1414
node_rewards::v2::UpdateNodeRewardsTableProposalPayload,
1515
};
1616
use ic_registry_canister_api::{
@@ -43,6 +43,7 @@ use registry_canister::{
4343
do_deploy_guestos_to_all_unassigned_nodes::DeployGuestosToAllUnassignedNodesPayload,
4444
do_recover_subnet::RecoverSubnetPayload,
4545
do_remove_api_boundary_nodes::RemoveApiBoundaryNodesPayload,
46+
do_remove_node_operators::RemoveNodeOperatorsPayload,
4647
do_remove_nodes_from_subnet::RemoveNodesFromSubnetPayload,
4748
do_revise_elected_replica_versions::ReviseElectedGuestosVersionsPayload,
4849
do_set_firewall_config::SetFirewallConfigPayload,

rs/registry/canister/canister/registry.did

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,11 @@ type RemoveNodeDirectlyPayload = record { node_id : principal };
273273

274274
type RemoveNodeOperatorsPayload = record {
275275
node_operators_to_remove : vec blob;
276+
node_operator_principals_to_remove : opt NodeOperatorPrincipals;
277+
};
278+
279+
type NodeOperatorPrincipals = record {
280+
principals : vec principal;
276281
};
277282

278283
type RemoveNodesPayload = record { node_ids : vec principal };

rs/registry/canister/src/mutations/do_remove_node_operators.rs

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ use crate::{common::LOG_PREFIX, registry::Registry};
33
#[cfg(target_arch = "wasm32")]
44
use dfn_core::println;
55

6+
use candid::CandidType;
67
use ic_base_types::PrincipalId;
7-
use ic_protobuf::registry::node_operator::v1::RemoveNodeOperatorsPayload;
88
use ic_registry_keys::{make_node_operator_record_key, NODE_RECORD_KEY_PREFIX};
99
use ic_registry_transport::pb::v1::{registry_mutation, RegistryMutation};
10-
11-
use std::convert::TryFrom;
10+
use serde::{Deserialize, Serialize};
1211

1312
use ic_protobuf::registry::node::v1::NodeRecord;
1413
use prost::Message;
@@ -20,26 +19,21 @@ impl Registry {
2019

2120
let mut mutations = vec![];
2221

23-
// Node Operator IDs that are parsable as PrincipalIds and have an associated
24-
// NodeOperatorRecord in the Registry
25-
let mut valid_node_operator_ids = payload
26-
.node_operators_to_remove
22+
// Filter Node Operator IDs that have a NodeOperatorRecord in the Registry
23+
let mut valid_node_operator_ids_to_remove: Vec<PrincipalId> = payload
24+
.principal_ids_to_remove()
2725
.into_iter()
28-
.filter_map(|bytes| {
29-
PrincipalId::try_from(bytes)
30-
.ok()
31-
.filter(|node_operator_id| {
32-
let node_operator_record_key =
33-
make_node_operator_record_key(*node_operator_id).into_bytes();
34-
self.get(&node_operator_record_key, self.latest_version())
35-
.is_some()
36-
})
26+
.filter(|node_operator_id| {
27+
let node_operator_record_key =
28+
make_node_operator_record_key(*node_operator_id).into_bytes();
29+
self.get(&node_operator_record_key, self.latest_version())
30+
.is_some()
3731
})
3832
.collect();
3933

40-
self.filter_node_operators_that_have_nodes(&mut valid_node_operator_ids);
34+
self.filter_node_operators_that_have_nodes(&mut valid_node_operator_ids_to_remove);
4135

42-
for node_operator_id in valid_node_operator_ids {
36+
for node_operator_id in valid_node_operator_ids_to_remove {
4337
let node_operator_record_key =
4438
make_node_operator_record_key(node_operator_id).into_bytes();
4539
mutations.push(RegistryMutation {
@@ -73,3 +67,50 @@ impl Registry {
7367
}
7468
}
7569
}
70+
71+
/// The payload of a request to remove Node Operator records from the Registry
72+
#[derive(Clone, Debug, Eq, PartialEq, CandidType, Deserialize, Serialize, Hash)]
73+
pub struct RemoveNodeOperatorsPayload {
74+
// Old compatibility field, required for Candid, to be removed in the future
75+
pub node_operators_to_remove: Vec<Vec<u8>>,
76+
77+
// New field, where the Node Operator IDs are passed as PrincipalIds instead of Vec<u8>
78+
pub node_operator_principals_to_remove: Option<NodeOperatorPrincipals>,
79+
}
80+
81+
/// Wrapper message for the optional repeated field
82+
#[derive(Clone, Debug, Eq, PartialEq, CandidType, Deserialize, Serialize, Hash)]
83+
pub struct NodeOperatorPrincipals {
84+
pub principals: Vec<PrincipalId>,
85+
}
86+
87+
impl RemoveNodeOperatorsPayload {
88+
pub fn new(node_operators_to_remove: Vec<PrincipalId>) -> Self {
89+
Self {
90+
node_operators_to_remove: vec![],
91+
node_operator_principals_to_remove: Some(NodeOperatorPrincipals {
92+
principals: node_operators_to_remove,
93+
}),
94+
}
95+
}
96+
97+
pub fn principal_ids_to_remove(&self) -> Vec<PrincipalId> {
98+
// Ensure only one of the fields is set to avoid confusing semantics.
99+
// If the new field is present, panic if the old field is also set.
100+
// This approach encourages clients to use the new field and allows for
101+
// eventual deprecation of the old field.
102+
match &self.node_operator_principals_to_remove {
103+
Some(principals) if self.node_operators_to_remove.is_empty() => {
104+
principals.principals.clone()
105+
}
106+
Some(_) => {
107+
panic!("Cannot specify both node_operators_to_remove and node_operator_principals_to_remove");
108+
}
109+
None => self
110+
.node_operators_to_remove
111+
.iter()
112+
.filter_map(|bytes| PrincipalId::try_from(bytes.clone()).ok())
113+
.collect(),
114+
}
115+
}
116+
}

rs/registry/canister/tests/remove_node_operators.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ use ic_nns_test_utils::{
88
},
99
registry::invariant_compliant_mutation_as_atomic_req,
1010
};
11-
use ic_protobuf::registry::node_operator::v1::RemoveNodeOperatorsPayload;
12-
use registry_canister::init::RegistryCanisterInitPayloadBuilder;
11+
use registry_canister::{
12+
init::RegistryCanisterInitPayloadBuilder,
13+
mutations::do_remove_node_operators::RemoveNodeOperatorsPayload,
14+
};
1315

1416
#[test]
1517
fn test_the_anonymous_user_cannot_remove_node_operators() {
@@ -22,9 +24,7 @@ fn test_the_anonymous_user_cannot_remove_node_operators() {
2224
)
2325
.await;
2426

25-
let payload = RemoveNodeOperatorsPayload {
26-
node_operators_to_remove: vec![],
27-
};
27+
let payload = RemoveNodeOperatorsPayload::new(vec![]);
2828

2929
// The anonymous end-user tries to remove node operators, bypassing
3030
// the Governance canister. This should be rejected.
@@ -72,9 +72,7 @@ fn test_a_canister_other_than_the_governance_canister_cannot_remove_node_operato
7272
)
7373
.await;
7474

75-
let payload = RemoveNodeOperatorsPayload {
76-
node_operators_to_remove: vec![],
77-
};
75+
let payload = RemoveNodeOperatorsPayload::new(vec![]);
7876

7977
// The attacker canister tries to remove node operators, pretending
8078
// to be the Governance canister. This should have no effect.

0 commit comments

Comments
 (0)