Skip to content

Commit 2e062e3

Browse files
pierugo-dfinityIDX GitHub Automation
andauthored
test(mainnet-nns): reintroduction of the mainnet NNS testnet (#8170)
This PR introduces a new testnet `mainnet_nns`: A single-node NNS subnet holding mainnet state, along with 1 API BN and 1 HTTP Gateway, for general use-case. In a separate PR, the current `nns_recovery` testnet will be adapted to also be able to spawn it with mainnet state. Finally, that second PR will also introduce an NNS recovery system test that will use mainnet state. Most of the changes are the revert of e38941a, but some changes were required in `ic-replay`: - Bumping the ingress messages' expiry, otherwise some messages would expire if delivered in multiple batches. This was already done for certain `SubCommand`s, so we generalize it to all of them. - The list of trusted neurons was outdated. - Now neurons need to be made public to be followed. - Trusted neurons will follow the new neuron on all topics and not just `Unspecified` to be more robust. The code lives in its own crate in `//rs/tests/testnets/mainnet_nns/` as a library such that one can turn any testnet or system test into a variant that holds mainnet state, with as few modifications as possible to their original code. For example, the setup of the IC can be done by running the provided `setup` and making proposals to change the topology to achieve the intended initial topology. Such proposals can be made as easily as calling `ProposalWithMainnetState::[name_of_the_proposal]`. Finally, it is intended to use the mainnet's version of `ic-replay` and `ic-recovery` like [previously](https://github.com/dfinity/ic/blob/6cd54499b0ec4f4190043f66769e54e78ffa0ccf/rs/tests/nns/ic_mainnet_nns_recovery/src/lib.rs#L206-L212), but since I needed to modify those to create this testnet, we need to wait for this change to reach mainnet NNS before downloading those. This is tracked in ticket CON-1624. --------- Co-authored-by: IDX GitHub Automation <infra+github-automation@dfinity.org>
1 parent af1e995 commit 2e062e3

File tree

15 files changed

+1337
-60
lines changed

15 files changed

+1337
-60
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ go.sum @dfinity/idx
245245
/rs/tests/ @dfinity/idx
246246
/rs/tests/idx/ @dfinity/idx
247247
/rs/tests/testnets/ @dfinity/idx
248+
/rs/tests/testnets/mainnet_nns/ @dfinity/consensus
249+
/rs/tests/testnets/mainnet_nns.rs @dfinity/consensus
248250
/rs/tests/testnets/nns_recovery.rs @dfinity/consensus
249251
/rs/tests/driver/src/driver/simulate_network.rs @dfinity/consensus @dfinity/idx
250252
/rs/tests/boundary_nodes/ @dfinity/node

Cargo.lock

Lines changed: 34 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rs/recovery/src/admin_helper.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,8 @@ impl AdminHelper {
248248

249249
ic_admin
250250
.add_positional_argument("propose-to-create-subnet")
251-
.add_argument("unit-delay-millis", 2000)
252-
.add_argument("subnet-handler-id", "unused")
253251
.add_argument("replica-version-id", replica_version)
254252
.add_argument("subnet-id-override", subnet_id_override)
255-
.add_argument("dkg-interval-length", 12)
256253
.add_positional_argument("--is-halted")
257254
.add_argument("subnet-type", "system")
258255
.add_argument(
@@ -395,11 +392,8 @@ mod tests {
395392
"/fake/ic/admin/dir/ic-admin \
396393
--nns-url \"https://fake_nns_url.com:8080/\" \
397394
propose-to-create-subnet \
398-
--unit-delay-millis 2000 \
399-
--subnet-handler-id unused \
400395
--replica-version-id fake_replica_version \
401396
--subnet-id-override gpvux-2ejnk-3hgmh-cegwf-iekfc-b7rzs-hrvep-5euo2-3ywz3-k3hcb-cqe \
402-
--dkg-interval-length 12 \
403397
--is-halted \
404398
--subnet-type system \
405399
--summary Create subnet with id gpvux-2ejnk-3hgmh-cegwf-iekfc-b7rzs-hrvep-5euo2-3ywz3-k3hcb-cqe nqpqw-cp42a-rmdsx-fpui3-ncne5-kzq6o-m67an-w25cx-zu636-lcf2v-fqe \

rs/replay/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ DEPENDENCIES = [
5050
"@crate_index//:serde_json",
5151
"@crate_index//:slog",
5252
"@crate_index//:slog-async",
53+
"@crate_index//:strum",
5354
"@crate_index//:tempfile",
5455
"@crate_index//:time",
5556
"@crate_index//:tokio",
@@ -69,7 +70,6 @@ DEV_DEPENDENCIES = [
6970
"//rs/test_utilities/consensus",
7071
"//rs/test_utilities/types",
7172
"@crate_index//:pretty_assertions",
72-
"@crate_index//:strum",
7373
]
7474

7575
MACRO_DEPENDENCIES = [

rs/replay/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ serde = { workspace = true }
5555
serde_json = { workspace = true }
5656
slog = { workspace = true }
5757
slog-async = { workspace = true }
58+
strum = { workspace = true }
5859
tempfile = { workspace = true }
5960
time = { workspace = true }
6061
tokio = { workspace = true }
@@ -73,7 +74,6 @@ ic-test-utilities-consensus = { path = "../test_utilities/consensus" }
7374
ic-test-utilities-types = { path = "../test_utilities/types" }
7475
pocket-ic = { path = "../../packages/pocket-ic" }
7576
pretty_assertions = { workspace = true }
76-
strum = { workspace = true }
7777

7878
[[bin]]
7979
name = "ic-replay"

rs/replay/src/ingress.rs

Lines changed: 64 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ use ic_nervous_system_common::ledger;
1212
use ic_nns_common::pb::v1::NeuronId;
1313
use ic_nns_constants::{GOVERNANCE_CANISTER_ID, LEDGER_CANISTER_ID, REGISTRY_CANISTER_ID};
1414
use ic_nns_governance_api::{
15-
ManageNeuronCommandRequest, ManageNeuronRequest, ManageNeuronResponse, Topic,
15+
ManageNeuronCommandRequest, ManageNeuronRequest, ManageNeuronResponse, Topic, Visibility,
1616
manage_neuron::{
17-
ClaimOrRefresh, Configure, Follow, IncreaseDissolveDelay, NeuronIdOrSubaccount,
17+
self, ClaimOrRefresh, Configure, IncreaseDissolveDelay, NeuronIdOrSubaccount, SetFollowing,
1818
claim_or_refresh::{By, MemoAndController},
19-
configure::Operation,
19+
configure::{self, Operation},
20+
set_following::FolloweesForTopic,
2021
},
2122
manage_neuron_response,
2223
};
@@ -39,8 +40,14 @@ use ic_types::{
3940
use icp_ledger::{AccountIdentifier, Memo, SendArgs, Tokens};
4041
use prost::Message;
4142
use std::{convert::TryFrom, str::FromStr, time::Duration};
43+
use strum::IntoEnumIterator;
4244
use time::OffsetDateTime;
4345

46+
// This is the buffer time added to the expiry time of added ingress messages to make sure those
47+
// messages do not expire too early, in particular in case the original expiry time was chosen to be
48+
// the current time.
49+
const INGRESS_EXPIRY_BUFFER_SECS: u64 = 180;
50+
4451
pub struct IngressWithPrinter {
4552
pub ingress: SignedIngress,
4653
pub print: Option<fn(Vec<u8>)>,
@@ -89,8 +96,12 @@ fn make_signed_ingress(
8996
.update(&Principal::from(canister_id), method)
9097
.with_arg(payload)
9198
.expire_at(
92-
OffsetDateTime::from_unix_timestamp_nanos(expiry.as_nanos_since_unix_epoch().into())
93-
.map_err(|err| format!("Error preparing update message: {err:?}"))?,
99+
OffsetDateTime::from_unix_timestamp_nanos(
100+
(expiry + Duration::from_secs(INGRESS_EXPIRY_BUFFER_SECS))
101+
.as_nanos_since_unix_epoch()
102+
.into(),
103+
)
104+
.map_err(|err| format!("Error preparing update message: {err:?}"))?,
94105
)
95106
.sign()
96107
.map_err(|err| format!("Error preparing update message: {err:?}"))?;
@@ -188,43 +199,55 @@ pub fn cmd_make_trusted_neurons_follow_neuron(
188199
) -> Result<Vec<SignedIngress>, String> {
189200
let mut msgs = Vec::new();
190201

191-
let trusted_neurons: &[(&str, u64)] = &[
192-
(
193-
"pkjng-fnb6a-zzirr-kykal-ghbjs-ndmj2-tfoma-bzski-wtbsl-2fgbu-hae",
194-
16,
195-
),
196-
(
197-
"ilqei-ofqjz-v7jbw-usmzf-jtdss-6mvzv-puesh-3kfga-nhr3v-zmgig-eqe",
198-
15,
199-
),
200-
(
201-
"2q5kv-5vcol-eh2je-udy6s-j74gx-djqza-siucy-2jxyq-u5kw6-imugq-uae",
202-
18,
203-
),
204-
(
205-
"wyzjx-3pde2-wzr4k-fblse-7hzgm-v2kkx-lcuhl-dftmv-5ywr7-gsszf-6ae",
206-
1_947_868_782_075_274_250,
207-
),
208-
(
209-
"j2xaq-c6ph5-e4oa7-nleph-joz7b-nvv4r-if4ol-ilz7w-mzetf-jof6l-mae",
210-
5_091_612_375_828_828_066,
211-
),
212-
(
213-
"2yjpj-uumzi-wnefi-5tum7-qt6yq-7gtxo-i4jt5-enll5-pma6q-2gild-mqe",
214-
12_262_067_573_992_506_876,
215-
),
216-
];
202+
// It is enough to be followed only by Neuron 27 to pass all proposals as of December 2025.
203+
let trusted_neurons = [(
204+
"4vnki-cqaaa-aaaaa-aaaaa-aaaaa-aaaaa-aaaaa-aaaaa-aaaaa-aaaaa-aae",
205+
27,
206+
)];
207+
208+
let user_agent = &agent_with_principal_as_sender(&cmd.neuron_controller)?;
209+
let make_public_payload = Encode!(&ManageNeuronRequest {
210+
id: None,
211+
neuron_id_or_subaccount: Some(NeuronIdOrSubaccount::NeuronId(NeuronId {
212+
id: cmd.neuron_id,
213+
})),
214+
command: Some(ManageNeuronCommandRequest::Configure(Configure {
215+
operation: Some(configure::Operation::SetVisibility(
216+
manage_neuron::SetVisibility {
217+
visibility: Some(Visibility::Public as i32),
218+
}
219+
))
220+
})),
221+
})
222+
.expect("Couldn't encode payload for manage neuron command");
223+
msgs.push(
224+
make_signed_ingress(
225+
user_agent,
226+
GOVERNANCE_CANISTER_ID,
227+
"manage_neuron",
228+
make_public_payload,
229+
time,
230+
)
231+
.expect("Couldn't create message to make the neuron public"),
232+
);
217233

218234
for (principal, neuron_id) in trusted_neurons {
219235
let principal = PrincipalId::from_str(principal).expect("Invalid principal");
220-
let follow_payload = Encode!(&ManageNeuronRequest {
236+
let set_following_payload = Encode!(&ManageNeuronRequest {
221237
id: None,
222238
neuron_id_or_subaccount: Some(NeuronIdOrSubaccount::NeuronId(NeuronId {
223-
id: *neuron_id,
239+
id: neuron_id,
224240
})),
225-
command: Some(ManageNeuronCommandRequest::Follow(Follow {
226-
topic: Topic::Unspecified as i32,
227-
followees: [NeuronId { id: cmd.neuron_id }].to_vec(),
241+
// Make trusted neuron follow the test neuron on all topics
242+
command: Some(ManageNeuronCommandRequest::SetFollowing(SetFollowing {
243+
topic_following: Some(
244+
Topic::iter()
245+
.map(|topic| FolloweesForTopic {
246+
topic: Some(topic as i32),
247+
followees: Some(vec![NeuronId { id: cmd.neuron_id }]),
248+
})
249+
.collect()
250+
),
228251
})),
229252
})
230253
.expect("Couldn't encode payload for manage neuron command");
@@ -234,7 +257,7 @@ pub fn cmd_make_trusted_neurons_follow_neuron(
234257
user_agent,
235258
GOVERNANCE_CANISTER_ID,
236259
"manage_neuron",
237-
follow_payload,
260+
set_following_payload,
238261
time,
239262
)
240263
.expect("Couldn't create message to make trusted neurons follow test neuron"),
@@ -399,7 +422,7 @@ pub fn cmd_add_registry_content(
399422
REGISTRY_CANISTER_ID,
400423
mutations,
401424
req.preconditions,
402-
context_time + Duration::from_secs(60),
425+
context_time,
403426
))
404427
} else {
405428
None
@@ -476,7 +499,7 @@ pub(crate) fn bless_replica_version(
476499
REGISTRY_CANISTER_ID,
477500
vec![mutation],
478501
vec![],
479-
context_time + Duration::from_secs(60),
502+
context_time,
480503
)
481504
}
482505

@@ -501,7 +524,7 @@ pub fn add_replica_version(
501524
REGISTRY_CANISTER_ID,
502525
vec![mutation],
503526
vec![],
504-
context_time + Duration::from_secs(60),
527+
context_time,
505528
)
506529
}
507530

@@ -526,6 +549,6 @@ pub fn update_subnet_record(
526549
REGISTRY_CANISTER_ID,
527550
vec![mutation],
528551
vec![],
529-
context_time + Duration::from_secs(60),
552+
context_time,
530553
)
531554
}

rs/tests/driver/src/driver/ic_gateway_vm.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
55
use slog::{Logger, info};
66
use std::{
77
fs,
8-
net::{Ipv4Addr, Ipv6Addr},
8+
net::{IpAddr, Ipv4Addr, Ipv6Addr},
99
path::Path,
1010
time::Duration,
1111
};
@@ -19,7 +19,7 @@ use crate::{
1919
resource::AllocatedVm,
2020
test_env::{TestEnv, TestEnvAttribute},
2121
test_env_api::{
22-
AcquirePlaynetCertificate, CreatePlaynetDnsRecords, HasPublicApiUrl,
22+
AcquirePlaynetCertificate, CreatePlaynetDnsRecords, HasPublicApiUrl, HasTestEnv,
2323
HasTopologySnapshot, IcNodeSnapshot, RetrieveIpv4Addr, SshSession, get_dependency_path,
2424
},
2525
test_setup::InfraProvider,
@@ -49,6 +49,7 @@ pub struct IcGatewayVm {
4949
/// Represents a deployed IC HTTP Gateway VM.
5050
#[derive(Debug)]
5151
pub struct DeployedIcGatewayVm {
52+
env: TestEnv,
5253
vm: AllocatedVm,
5354
https_url: Url,
5455
}
@@ -64,6 +65,18 @@ impl DeployedIcGatewayVm {
6465
}
6566
}
6667

68+
impl HasTestEnv for DeployedIcGatewayVm {
69+
fn test_env(&self) -> TestEnv {
70+
self.env.clone()
71+
}
72+
}
73+
74+
impl SshSession for DeployedIcGatewayVm {
75+
fn get_host_ip(&self) -> Result<IpAddr> {
76+
Ok(self.get_vm().ipv6.into())
77+
}
78+
}
79+
6780
impl Default for IcGatewayVm {
6881
fn default() -> Self {
6982
Self::new(IC_GATEWAY_VM_NAME)
@@ -373,12 +386,13 @@ impl HasIcGatewayVm for TestEnv {
373386
.then(|| playnet_url.clone())
374387
.context("Expected a TLS URL")?;
375388

376-
let vm = self
389+
let uvm = self
377390
.get_deployed_universal_vm(name)
378-
.context("Failed to retrieve deployed universal VM")?
379-
.get_vm()?;
391+
.context("Failed to retrieve deployed universal VM")?;
392+
let env = uvm.test_env();
393+
let vm = uvm.get_vm()?;
380394

381-
Ok(DeployedIcGatewayVm { vm, https_url })
395+
Ok(DeployedIcGatewayVm { env, vm, https_url })
382396
}
383397

384398
fn get_deployed_ic_gateways(&self) -> Result<Vec<DeployedIcGatewayVm>> {

0 commit comments

Comments
 (0)