Skip to content

feat: add InternetComputer.subnetSelfNodeCount - #565

Open
eichhorl wants to merge 1 commit into
caffeinelabs:mainfrom
eichhorl:eichhorl/subnet-self-node-count
Open

eichhorl wants to merge 1 commit into
caffeinelabs:mainfrom
eichhorl:eichhorl/subnet-self-node-count

Conversation

@eichhorl

@eichhorl eichhorl commented Nov 5, 2026

Copy link
Copy Markdown

What

One wrapper:

/// The number of nodes on the subnet this canister runs on.
public let subnetSelfNodeCount : () -> Nat32 = Prim.subnetSelfNodeCount;

InternetComputer already wraps Prim.call_raw, Prim.isReplicatedExecution and Prim.performanceCounter. ic0.subnet_self_node_count was the one left out, so a canister that needs the subnet's node count has to import Prim "mo:⛔" itself.

Why now

Flexible HTTPS outcalls need it. flexible_http_request takes ReplicationCounts, and total_requests must not exceed the number of nodes on the subnet, so asking a committee smaller than the subnet means sizing it against the count:

let totalRequests = Nat32.min(InternetComputer.subnetSelfNodeCount(), 5);

A smaller committee is the point of the feature: fewer requests cost less and are gentler on the endpoint's rate limits. Hardcoding a number instead breaks on a subnet smaller than that number.

Rust has this as ordinary public API, ic_cdk::api::subnet_self_node_count(), so Motoko is the only side reaching into a module named "no entry" for it. That is now visible in published material: the Motoko flexible outcall example in dfinity/examples#1490 and the https-outcalls agent skill both import mo:⛔ and carry a comment explaining why.

Why CI will be red, and what you have to decide

Prim.subnetSelfNodeCount exists from moc 2.1.0. This repo pins [toolchain] moc = "1.16.0" and runs a second CI leg on moc 2.0.0. Verified with check:orphans on this branch:

moc 2.1.0    ✓ src/InternetComputer.mo
moc 1.16.0   src/InternetComputer.mo:49.55-49.74: type error [M0072],
             field subnetSelfNodeCount does not exist in module.

So this cannot merge as-is, and the change that makes it mergeable is not mine to make. core is foundational: anything that stops type-checking below moc 2.1.0 raises the floor for every consumer, not just callers of the new function. Projects on moc 1.x would fail mops check the way a moc 2.x project does today against base and its ExperimentalStableMemory.

I am opening it as a one-line proposal so the cost is visible rather than described, and I have deliberately not bundled the pin bump, the CI leg change, validation/api/api.lock.json, or a [requirements] raise. Happy to do any of that, split it differently, or close this if the floor should not move yet.

The Changelog.md entry under ## Next carries a #TBD that wants this PR number.

🤖 Generated with Claude Code

`InternetComputer` wraps the system calls a canister needs, several of
them straight from `Prim`: `call_raw`, `isReplicatedExecution`,
`performanceCounter`. `ic0.subnet_self_node_count` had no wrapper, so a
canister that needs the subnet's node count imports `mo:⛔` itself.

Flexible HTTPS outcalls need it: `flexible_http_request` takes
`ReplicationCounts`, whose `total_requests` must not exceed the number of
nodes, so a committee smaller than the subnet has to be sized against the
count rather than hardcoded. Rust has it as ordinary public API,
`ic_cdk::api::subnet_self_node_count()`.

The primitive exists from moc 2.1.0, so this does not compile on the
currently pinned 1.16.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@eichhorl
eichhorl requested a review from a team as a code owner November 5, 2026 14:45

This branch has not been deployed

No deployments
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.

1 participant