Skip to content

Commit

Permalink
feat(dre): adding api boundary nodes to registry dump command (#357)
Browse files Browse the repository at this point in the history
* adding api boundary nodes to registry dump command

* fixing compilation problems

* making small changes for easier access to arbitrary networks

* fixing tests
  • Loading branch information
NikolaMilosa committed May 7, 2024
1 parent b589268 commit 42de821
Show file tree
Hide file tree
Showing 11 changed files with 2,201 additions and 1,365 deletions.
2,585 changes: 1,613 additions & 972 deletions Cargo.Bazel.lock

Large diffs are not rendered by default.

787 changes: 463 additions & 324 deletions Cargo.lock

Large diffs are not rendered by default.

62 changes: 31 additions & 31 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,47 +93,47 @@ humantime = "2.1.0"
hyper = { version = "0.14.11", features = ["http2", "stream"] }
hyper-tls = "0.6.0"
ic-agent = "0.34.0"
ic-async-utils = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-base-types = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-canister-client = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-canister-client-sender = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-async-utils = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-base-types = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-canister-client = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-canister-client-sender = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-canisters = { path = "rs/ic-canisters" }
ic-cdk = "0.13.1"
ic-config = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-crypto-utils-threshold-sig-der = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-http-endpoints-metrics = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-config = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-crypto-utils-threshold-sig-der = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-http-endpoints-metrics = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-identity-hsm = "0.34.0"
ic-interfaces = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-interfaces-registry = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-interfaces = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-interfaces-registry = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-management-backend = { path = "rs/ic-management-backend" }
ic-management-canister-types = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-management-canister-types = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-management-types = { path = "rs/ic-management-types" }
ic-metrics = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-nns-common = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-nns-constants = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-nns-governance = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-protobuf = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-registry-client = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-registry-client-fake = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-registry-client-helpers = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-registry-common-proto = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-registry-keys = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-registry-local-registry = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-registry-local-store = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-registry-local-store-artifacts = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-registry-nns-data-provider = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-registry-subnet-type = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-registry-transport = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-sys = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-types = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
ic-metrics = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-nns-common = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-nns-constants = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-nns-governance = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-protobuf = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-registry-client = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-registry-client-fake = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-registry-client-helpers = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-registry-common-proto = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-registry-keys = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-registry-local-registry = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-registry-local-store = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-registry-local-store-artifacts = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-registry-nns-data-provider = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-registry-subnet-type = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-registry-transport = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-sys = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-types = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
ic-utils = "0.34.0"
include_dir = "0.7.3"
itertools = "0.12.0"
keyring = "2.0.2"
lazy_static = "1.4.0"
log = "0.4.21"
lru = "0.12.3"
phantom_newtype = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
phantom_newtype = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
pkcs11 = "0.5.0"
pretty_assertions = "1.4.0"
pretty_env_logger = "0.5.0"
Expand All @@ -144,7 +144,7 @@ rand = { version = "0.8.5", features = ["std_rng"] }
rand_seeder = "0.2.3"
rayon = "1.10.0"
regex = "1.10.4"
registry-canister = { git = "https://github.com/dfinity/ic.git", rev = "778d2bb870f858952ca9fbe69324f9864e3cf5e7" }
registry-canister = { git = "https://github.com/dfinity/ic.git", rev = "b531d2e0a7438d61ce14915a2d0b43684ff7d667" }
reqwest = { version = "0.12.2", features = ["json"] }
retry = "2.0.0"
reverse_geocoder = "4.1.1"
Expand All @@ -171,7 +171,7 @@ tabled = "0.15.0"
tabular = "0.2"
tempfile = "3.10.0"
thiserror = "1.0.57"
tokio = { version = "1.2.0", features = ["full"] }
tokio = { version = "1.37.0", features = ["full"] }
url = "2.5.0"
urlencoding = "2.1.0"
warp = "0.3"
Expand Down
2 changes: 1 addition & 1 deletion WORKSPACE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ aspect_bazel_lib_dependencies()

aspect_bazel_lib_register_toolchains()

IC_REPO_VERSION = "778d2bb870f858952ca9fbe69324f9864e3cf5e7"
IC_REPO_VERSION = "b531d2e0a7438d61ce14915a2d0b43684ff7d667"

http_archive(
name = "ic_repo",
Expand Down
69 changes: 62 additions & 7 deletions rs/cli/src/registry_dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ic_interfaces_registry::RegistryClient;
use ic_management_backend::registry::{local_registry_path, sync_local_store, RegistryFamilyEntries};
use ic_management_types::Network;
use ic_protobuf::registry::{
api_boundary_node::v1::ApiBoundaryNodeRecord,
dc::v1::DataCenterRecord,
node::v1::{ConnectionEndpoint, IPv4InterfaceConfig, NodeRecord},
node_operator::v1::NodeOperatorRecord,
Expand All @@ -15,6 +16,7 @@ use ic_registry_keys::NODE_REWARDS_TABLE_KEY;
use ic_registry_local_registry::LocalRegistry;
use ic_registry_subnet_type::SubnetType;
use itertools::Itertools;
use log::warn;
use registry_canister::mutations::common::decode_registry_value;
use serde::Serialize;

Expand Down Expand Up @@ -44,7 +46,9 @@ pub async fn dump_registry(path: &Option<PathBuf>, network: &Network, version: &

let nodes = get_nodes(&local_registry, version, &node_operators, &subnets)?;

let node_rewards_table = get_node_rewards_table(&local_registry, version);
let node_rewards_table = get_node_rewards_table(&local_registry, version, network);

let api_bns = get_api_boundary_nodes(&local_registry, version)?;

#[derive(Serialize)]
struct RegistryDump {
Expand All @@ -53,6 +57,7 @@ pub async fn dump_registry(path: &Option<PathBuf>, network: &Network, version: &
dcs: Vec<DataCenterRecord>,
node_operators: Vec<NodeOperator>,
node_rewards_table: NodeRewardsTableFlattened,
api_bns: Vec<ApiBoundaryNodeDetails>,
}
println!(
"{}",
Expand All @@ -61,7 +66,8 @@ pub async fn dump_registry(path: &Option<PathBuf>, network: &Network, version: &
subnets,
dcs,
node_operators: node_operators.values().cloned().collect_vec(),
node_rewards_table
node_rewards_table,
api_bns
})?
);

Expand Down Expand Up @@ -183,15 +189,64 @@ fn get_node_operators(
Ok(node_operators)
}

fn get_node_rewards_table(local_registry: &LocalRegistry, version: RegistryVersion) -> NodeRewardsTableFlattened {
let rewards_table_bytes = local_registry
.get_value(NODE_REWARDS_TABLE_KEY, version)
.expect("Failed to get Node Rewards Table")
.expect("Failed to get Node Rewards Table");
fn get_node_rewards_table(
local_registry: &LocalRegistry,
version: RegistryVersion,
network: &Network,
) -> NodeRewardsTableFlattened {
let rewards_table_bytes = local_registry.get_value(NODE_REWARDS_TABLE_KEY, version);

let rewards_table_bytes = match rewards_table_bytes {
Ok(r) => match r {
Some(r) => r,
None => {
if network.name.eq("mainnet") {
panic!("Failed to get Node Rewards Table")
} else {
warn!("Didn't find any node rewards details for network: {}", network.name);
vec![]
}
}
},
Err(_) => {
if network.name.eq("mainnet") {
panic!("Failed to get Node Rewards Table for mainnet")
} else {
warn!("Failed to get Node Rewards Table for {}", network.name);
vec![]
}
}
};

decode_registry_value::<NodeRewardsTableFlattened>(rewards_table_bytes)
}

fn get_api_boundary_nodes(
local_registry: &LocalRegistry,
version: RegistryVersion,
) -> Result<Vec<ApiBoundaryNodeDetails>, Error> {
let api_bns = local_registry
.get_family_entries_of_version::<ApiBoundaryNodeRecord>(version)
.map_err(|e| anyhow::anyhow!("Couldn't get api boundary nodes: {:?}", e))?
.into_iter()
.map(|(k, (_, record))| {
let principal = PrincipalId::from_str(&k).expect("Couldn't parse principal id");
ApiBoundaryNodeDetails {
principal,
version: record.version,
}
})
.collect();

Ok(api_bns)
}

#[derive(Serialize, Clone)]
struct ApiBoundaryNodeDetails {
principal: PrincipalId,
version: String,
}

#[derive(Serialize, Clone)]
struct NodeDetails {
node_id: PrincipalId,
Expand Down
10 changes: 5 additions & 5 deletions rs/ic-management-backend/src/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ use itertools::Itertools;
use registry_canister::mutations::do_add_nodes_to_subnet::AddNodesToSubnetPayload;
use registry_canister::mutations::do_change_subnet_membership::ChangeSubnetMembershipPayload;
use registry_canister::mutations::do_create_subnet::CreateSubnetPayload;
use registry_canister::mutations::do_deploy_guestos_to_all_subnet_nodes::DeployGuestosToAllSubnetNodesPayload;
use registry_canister::mutations::do_remove_nodes_from_subnet::RemoveNodesFromSubnetPayload;
use registry_canister::mutations::do_revise_elected_replica_versions::ReviseElectedGuestosVersionsPayload;
use registry_canister::mutations::do_update_elected_hostos_versions::UpdateElectedHostosVersionsPayload;
use registry_canister::mutations::do_update_elected_replica_versions::UpdateElectedReplicaVersionsPayload;
use registry_canister::mutations::do_update_nodes_hostos_version::UpdateNodesHostosVersionPayload;
use registry_canister::mutations::do_update_subnet_replica::UpdateSubnetReplicaVersionPayload;
use registry_canister::mutations::do_update_unassigned_nodes_config::UpdateUnassignedNodesConfigPayload;
use registry_canister::mutations::node_management::do_remove_nodes::RemoveNodesPayload;
use serde::Serialize;
Expand Down Expand Up @@ -73,7 +73,7 @@ impl From<ProposalInfo> for ProposalInfoInternal {
#[derive(Clone, Serialize)]
pub struct SubnetUpdateProposal {
pub info: ProposalInfoInternal,
pub payload: UpdateSubnetReplicaVersionPayload,
pub payload: DeployGuestosToAllSubnetNodesPayload,
}

#[derive(Clone, Serialize)]
Expand Down Expand Up @@ -135,7 +135,7 @@ impl ProposalAgent {
pub async fn list_open_elect_replica_proposals(&self) -> Result<Vec<UpdateElectedReplicaVersionsProposal>> {
let proposals = &self.list_proposals(vec![ProposalStatus::Open]).await?;
let open_elect_guest_proposals =
filter_map_nns_function_proposals::<UpdateElectedReplicaVersionsPayload>(proposals);
filter_map_nns_function_proposals::<ReviseElectedGuestosVersionsPayload>(proposals);

let result = open_elect_guest_proposals
.into_iter()
Expand Down Expand Up @@ -250,7 +250,7 @@ impl ProposalAgent {
Topic::NetworkCanisterManagement,
Topic::Kyc,
Topic::NodeProviderRewards,
Topic::SnsDecentralizationSale,
Topic::SnsAndCommunityFund,
// Topic::SubnetReplicaVersionManagement,
// Topic::ReplicaVersionManagement,
Topic::SnsAndCommunityFund,
Expand Down
18 changes: 12 additions & 6 deletions rs/ic-management-backend/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use ic_management_types::{
NodeProvidersResponse, Operator, Provider, Release, Subnet, SubnetMetadata, UpdateElectedHostosVersionsProposal,
UpdateElectedReplicaVersionsProposal,
};
use ic_protobuf::registry::api_boundary_node::v1::ApiBoundaryNodeRecord;
use ic_protobuf::registry::crypto::v1::PublicKey;
use ic_protobuf::registry::hostos_version::v1::HostosVersionRecord;
use ic_protobuf::registry::replica_version::v1::BlessedReplicaVersions;
Expand All @@ -27,14 +28,14 @@ use ic_registry_client_helpers::node::NodeRegistry;
use ic_registry_common_proto::pb::local_store::v1::{
ChangelogEntry as PbChangelogEntry, KeyMutation as PbKeyMutation, MutationType,
};
use ic_registry_keys::DATA_CENTER_KEY_PREFIX;
use ic_registry_keys::{
make_blessed_replica_versions_key, HOSTOS_VERSION_KEY_PREFIX, NODE_OPERATOR_RECORD_KEY_PREFIX,
NODE_RECORD_KEY_PREFIX, SUBNET_RECORD_KEY_PREFIX,
};
use ic_registry_keys::{make_crypto_threshold_signing_pubkey_key, ROOT_SUBNET_ID_KEY};
use ic_registry_keys::{API_BOUNDARY_NODE_RECORD_KEY_PREFIX, DATA_CENTER_KEY_PREFIX};
use ic_registry_local_registry::LocalRegistry;
use ic_registry_local_store::{Changelog, ChangelogEntry, KeyMutation, LocalStoreImpl, LocalStoreWriter};
use ic_registry_local_store::{Changelog, ChangelogEntry, KeyMutation, LocalStoreImpl};
use ic_registry_nns_data_provider::registry::RegistryCanister;
use ic_registry_subnet_type::SubnetType;
use ic_types::PrincipalId;
Expand Down Expand Up @@ -101,6 +102,10 @@ impl RegistryEntry for SubnetRecord {
const KEY_PREFIX: &'static str = SUBNET_RECORD_KEY_PREFIX;
}

impl RegistryEntry for ApiBoundaryNodeRecord {
const KEY_PREFIX: &'static str = API_BOUNDARY_NODE_RECORD_KEY_PREFIX;
}

pub trait RegistryFamilyEntries {
fn get_family_entries<T: RegistryEntry + Default>(&self) -> Result<BTreeMap<String, T>>;
fn get_family_entries_versioned<T: RegistryEntry + Default>(&self) -> Result<BTreeMap<String, (u64, T)>>;
Expand Down Expand Up @@ -325,6 +330,10 @@ impl RegistryState {
}

async fn update_releases(&mut self) -> Result<()> {
// If the network isn't mainnet we don't need to check git branches
if !self.network.eq(&Network::new("mainnet", &vec![]).await.unwrap()) {
return Ok(());
}
if self.ic_repo.is_some() {
lazy_static! {
// TODO: We don't need to distinguish release branch and name, they can be the same
Expand Down Expand Up @@ -1005,7 +1014,6 @@ pub async fn sync_local_store(target_network: &Network) -> anyhow::Result<()> {
registry_cache.update_to_latest_version();
registry_cache.get_latest_version()
};
let mut latest_certified_time = 0;
let mut updates = vec![];
let nns_public_key = nns_public_key(&registry_canister).await?;

Expand Down Expand Up @@ -1040,7 +1048,7 @@ pub async fn sync_local_store(target_network: &Network) -> anyhow::Result<()> {
error!("Failed to get latest registry version: {}", e);
}
}
if let Ok((mut initial_records, _, t)) = registry_canister
if let Ok((mut initial_records, _, _)) = registry_canister
.get_certified_changes_since(local_latest_version.get(), &nns_public_key)
.await
{
Expand Down Expand Up @@ -1111,14 +1119,12 @@ pub async fn sync_local_store(target_network: &Network) -> anyhow::Result<()> {

local_latest_version = local_latest_version.add(RegistryVersion::new(versions_count as u64));

latest_certified_time = t.as_nanos_since_unix_epoch();
debug!("Sync reached version {local_latest_version}");
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
}
}

futures::future::join_all(updates).await;
local_store.update_certified_time(latest_certified_time)?;
Ok(())
}

Expand Down
Loading

0 comments on commit 42de821

Please sign in to comment.