diff --git a/Cargo.lock b/Cargo.lock index 5b88c045f4b..a9cd32fed4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2542,6 +2542,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "consensus-vetkd-system-tests" +version = "0.9.0" +dependencies = [ + "anyhow", + "canister-test", + "ic-management-canister-types", + "ic-nns-constants", + "ic-registry-subnet-type", + "ic-system-test-driver", + "ic-types", + "ic_consensus_system_test_utils", + "ic_consensus_threshold_sig_system_test_utils", + "slog", + "tokio", +] + [[package]] name = "console" version = "0.11.3" diff --git a/Cargo.toml b/Cargo.toml index e5ce89c1e91..2a2cc45c379 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -378,6 +378,7 @@ members = [ "rs/tests/consensus/tecdsa", "rs/tests/consensus/upgrade", "rs/tests/consensus/utils", + "rs/tests/consensus/vetkd", "rs/tests/cross_chain", "rs/tests/crypto", "rs/tests/driver", diff --git a/rs/tests/consensus/vetkd/BUILD.bazel b/rs/tests/consensus/vetkd/BUILD.bazel new file mode 100644 index 00000000000..5d496974163 --- /dev/null +++ b/rs/tests/consensus/vetkd/BUILD.bazel @@ -0,0 +1,31 @@ +load("//rs/tests:common.bzl", "GUESTOS_RUNTIME_DEPS") +load("//rs/tests:system_tests.bzl", "system_test_nns") + +package(default_visibility = ["//rs:system-tests-pkg"]) + +system_test_nns( + name = "vetkd_key_life_cycle_test", + extra_head_nns_tags = [], # don't run the head_nns variant on nightly since it aleady runs on long_test. + flaky = True, + tags = [ + "k8s", + "long_test", # since it takes longer than 5 minutes. + ], + target_compatible_with = ["@platforms//os:linux"], # requires libssh that does not build on Mac OS + runtime_deps = GUESTOS_RUNTIME_DEPS, + deps = [ + # Keep sorted. + "//rs/config", + "//rs/nns/constants", + "//rs/registry/subnet_type", + "//rs/rust_canisters/canister_test", + "//rs/tests/consensus/tecdsa/utils", + "//rs/tests/consensus/utils", + "//rs/tests/driver:ic-system-test-driver", + "//rs/types/management_canister_types", + "//rs/types/types", + "@crate_index//:anyhow", + "@crate_index//:ic-agent", + "@crate_index//:slog", + ], +) diff --git a/rs/tests/consensus/vetkd/Cargo.toml b/rs/tests/consensus/vetkd/Cargo.toml new file mode 100644 index 00000000000..dec10d17542 --- /dev/null +++ b/rs/tests/consensus/vetkd/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "consensus-vetkd-system-tests" +version.workspace = true +authors.workspace = true +edition.workspace = true +description.workspace = true +documentation.workspace = true + +[dependencies] +anyhow = { workspace = true } +canister-test = { path = "../../../rust_canisters/canister_test" } +ic-management-canister-types = { path = "../../../types/management_canister_types" } +ic-nns-constants = { path = "../../../nns/constants" } +ic-registry-subnet-type = { path = "../../../registry/subnet_type" } +ic-system-test-driver = { path = "../../driver" } +ic-types = { path = "../../../types/types" } +ic_consensus_system_test_utils = { path = "../utils" } +ic_consensus_threshold_sig_system_test_utils = { path = "../tecdsa/utils" } +slog = { workspace = true } +tokio = { workspace = true } + +[[bin]] +name = "ic-systest-vetkd-key-life-cycle-test" +path = "vetkd_key_life_cycle_test.rs" diff --git a/rs/tests/consensus/vetkd/vetkd_key_life_cycle_test.rs b/rs/tests/consensus/vetkd/vetkd_key_life_cycle_test.rs new file mode 100644 index 00000000000..9ea6e9fb7ce --- /dev/null +++ b/rs/tests/consensus/vetkd/vetkd_key_life_cycle_test.rs @@ -0,0 +1,113 @@ +/* tag::catalog[] +Title:: Creating, fetching and deleting a vetkey on a subnet + +Goal:: Test whether the local DKG mechanism for vetkeys works + + +Runbook:: +. Setup:: + . System subnet comprising N nodes, necessary NNS canisters +. Wait one DKG interval +. Enable vetkey on subnet +. Wait two DKG intervals, check subnet health +. TODO(CON-1420): Fetch the public key from a canister + +end::catalog[] */ + +use anyhow::Result; +use canister_test::Canister; +use ic_consensus_system_test_utils::node::await_node_certified_height; +use ic_consensus_threshold_sig_system_test_utils::{ + add_chain_keys_with_timeout_and_rotation_period, DKG_INTERVAL, +}; +use ic_management_canister_types::{MasterPublicKeyId, VetKdCurve, VetKdKeyId}; +use ic_nns_constants::GOVERNANCE_CANISTER_ID; +use ic_registry_subnet_type::SubnetType; +use ic_system_test_driver::{ + driver::{ + group::SystemTestGroup, + ic::{InternetComputer, Subnet}, + test_env::TestEnv, + test_env_api::{ + HasPublicApiUrl, HasTopologySnapshot, IcNodeContainer, NnsInstallationBuilder, + }, + }, + systest, + util::{block_on, runtime_from_url}, +}; +use ic_types::Height; +use slog::info; + +const NODES_COUNT: usize = 4; + +fn setup(env: TestEnv) { + InternetComputer::new() + .add_subnet( + Subnet::new(SubnetType::System) + .with_dkg_interval_length(Height::from(DKG_INTERVAL)) + .add_nodes(NODES_COUNT), + ) + .setup_and_start(&env) + .expect("failed to setup IC under test"); + // Check all subnet nodes are healthy. + env.topology_snapshot().subnets().for_each(|subnet| { + subnet + .nodes() + .for_each(|node| node.await_status_is_healthy().unwrap()) + }); +} + +fn test(env: TestEnv) { + let log = env.logger(); + let topology_snapshot = env.topology_snapshot(); + + let nns_subnet = topology_snapshot.root_subnet(); + let nns_node = nns_subnet.nodes().next().unwrap(); + + info!(log, "Installing nns canisters."); + NnsInstallationBuilder::new() + .install(&nns_node, &env) + .expect("Could not install NNS canisters."); + + // TODO(CON-1420): Install message canister to fetch keys + // TODO: Since installing these canisters takes some time, we should actually + // take the hight at this moment as the base for the test and then wait relative to that. + + // Wait one DKG + await_node_certified_height(&nns_node, Height::from(DKG_INTERVAL + 1), log.clone()); + + let nns_runtime = runtime_from_url(nns_node.get_public_url(), nns_node.effective_canister_id()); + let governance = Canister::new(&nns_runtime, GOVERNANCE_CANISTER_ID); + let key_ids = vec![MasterPublicKeyId::VetKd(VetKdKeyId { + curve: VetKdCurve::Bls12_381_G2, + name: String::from("some_vetkd_key"), + })]; + + block_on(async { + //enable_chain_key_signing(&governance, nns_subnet.subnet_id, key_ids.clone(), &log).await; + add_chain_keys_with_timeout_and_rotation_period( + &governance, + nns_subnet.subnet_id, + key_ids.clone(), + None, + None, + &log, + ) + .await; + }); + + // Wait two DKGs + await_node_certified_height(&nns_node, Height::from((DKG_INTERVAL + 1) * 3), log.clone()); + // TODO(CON-1420): Fetch public key from subnet + + // Wait two more DKGs + await_node_certified_height(&nns_node, Height::from((DKG_INTERVAL + 1) * 5), log.clone()); +} + +fn main() -> Result<()> { + SystemTestGroup::new() + .with_setup(setup) + .add_test(systest!(test)) + .execute_from_args()?; + Ok(()) +}