Skip to content

refactor: Replaces the hand-rolled NNS state-tree parsing for subnet types and canister ranges with Agent::fetch_subnet_by_id from ic-agent#191

Open
shilingwang wants to merge 4 commits intomainfrom
shiling/update
Open

refactor: Replaces the hand-rolled NNS state-tree parsing for subnet types and canister ranges with Agent::fetch_subnet_by_id from ic-agent#191
shilingwang wants to merge 4 commits intomainfrom
shiling/update

Conversation

@shilingwang
Copy link
Contributor

@shilingwang shilingwang commented Mar 24, 2026

#NODE-1911

Summary

Replaces the hand-rolled NNS state-tree parsing for subnet types and canister ranges with Agent::fetch_subnet_by_id from ic-agent.
Before: SubnetsInfoFetcher performed three distinct NNS round trips per cycle:

  • Read NNS /subnet to get all subnet IDs and their types (hand-parsed from the hash tree)
  • Read NNS /canister_ranges/ once per subnet (CBOR-decoded manually)

After: The fetcher still reads NNS /subnet to discover subnet IDs, then calls agent.fetch_subnet_by_id concurrently for each subnet, which retrieves both the type and canister ranges from each subnet's own state tree in a single round trip per subnet — with all certificate verification and tree parsing handled by ic-agent.

Changes

  • fetch_subnetsfetch_subnet_ids: now only extracts subnet IDs from the NNS /subnet subtree; type extraction removed
  • fetch_canister_ranges removed: replaced by agent.fetch_subnet_by_id calls inlined into fetch()
  • map_subnet_type added: thin free function mapping ic-agent's SubnetType to the local enum, keeping the local type Copy and the public API decoupled from ic-agent internals
  • From<&[u8]> for SubnetType removed: no longer needed since raw byte parsing is handled by ic-agent
  • Test fixtures removed: testdata/subnet.bin, testdata/nns_canister_ranges.bin, and all related test infrastructure (TESTNET_ROOT_KEY, read_state_response, the extended ingress-expiry workaround). Tests that required real BLS-signed certificates are replaced by a pure in-memory subnet_type_lookup test that exercises SubnetsInfo::newArcSwapOption::storeloadsubnet_type() directly.

@shilingwang shilingwang marked this pull request as ready for review March 24, 2026 12:29
@shilingwang shilingwang requested a review from a team as a code owner March 24, 2026 12:29
b"cloud_engine" => Self::CloudEngine,
_ => Self::Unknown,
}
fn map_subnet_type(subnet_id: Principal, t: Option<&AgentSubnetType>) -> Result<SubnetType, Error> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we even need local SubnetType now? Can we use the one from the agent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have strong opinion on it. I keep the SubnetType because AI suggested:

The disadvantages are the same as before:
Copy is lost — Unknown(String) owns heap memory, so CanisterRange and anything that holds a SubnetType can no longer be Copy. The hot-path subnet_type() would need .clone() instead of a value copy.
Public API coupling — SubnetType is pub and used in domain_canister.rs. Changing it to AgentSubnetType means a semver bump in ic-agent can break your domain policy logic.
Unknown(String) complicates matching — domain_canister.rs currently does subnet_type != Some(SubnetType::CloudEngine) and exhaustive matches. With AgentSubnetType::Unknown(String) you can no longer match Unknown as a unit variant.
The Copy loss is the most impactful in practice. Given that the hot path calls subnet_type() on every request, taking a clone there for the Unknown case (which should never occur in production) is a small but unnecessary cost. The mapping is 5 lines — I'd keep it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI...

Well, okay, let's keep it, but create a From implementation for our SubnetType that would convert from the agent's one, instead of this method.

We can just map None & AgentSubnetType::Unknown(_) to our Unknown variant and this way we can simplify the conversion & make it infallible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants