Skip to main content

Overview

The Internet Computer registry is a system canister that stores and manages network configuration, node metadata, subnet information, and cryptographic keys. It provides versioned, immutable records that enable coordination across the distributed network. Source Location: rs/registry/

Registry Architecture

Version-Based Storage

The registry uses a version-based storage model where:
  • Each mutation creates a new version (monotonically increasing)
  • Historical versions are preserved (immutable history)
  • Clients can query any past version
  • Version 0 represents the empty registry

Storage Representations

The registry supports two stable storage formats:
Changelog-based representation indexed by version:
[v1] => { (UPSERT, key1, value11) }
[v2] => { (UPSERT, key2, value21) }
[v3] => { (UPSERT, key1, value12), (UPSERT, key2, value22) }
Preserves complete history of changes applied to the registry.

Protocol Buffer Definitions

Defined in rs/registry/canister/proto/ic_registry_canister/pb/v1/registry.proto

ChangelogEntry

ChangelogEntry
message
Represents a single mutation in the registry’s version history.
Proto Definition:
message ChangelogEntry {
    uint64 version = 1;
    bytes encoded_mutation = 2;
}
Fields:
version
uint64
The registry version produced by this mutation
encoded_mutation
bytes
Serialized RegistryAtomicMutateRequest with preconditions removed. Stored as bytes to ensure hash stability across schema changes.

RegistryStableStorage

RegistryStableStorage
message
Container for registry data that gets persisted to stable memory.
Proto Definition:
message RegistryStableStorage {
    enum Version {
        VERSION_UNSPECIFIED = 0;
        VERSION_1 = 1;
    }
    Version version = 2;
    repeated ChangelogEntry changelog = 3;
}
Fields:
version
Version
Indicates which storage representation is used
changelog
repeated ChangelogEntry
List of all mutations in chronological order (VERSION_1 only)

RegistryCanisterStableStorage

RegistryCanisterStableStorage
message
Top-level container written to stable storage during canister upgrades.
Proto Definition:
message RegistryCanisterStableStorage {
    RegistryStableStorage registry = 2;
    optional uint64 pre_upgrade_version = 3;
}
Fields:
registry
RegistryStableStorage
The actual registry data
pre_upgrade_version
uint64
Version before upgrade, used to detect rollbacks after upgrade

Registry Canister API

Defined in rs/registry/canister/api/src/lib.rs

Node Registration

AddNodePayload

AddNodePayload
struct
Request to add a new node to the network.
Candid Definition:
pub struct AddNodePayload {
    pub node_signing_pk: Vec<u8>,
    pub committee_signing_pk: Vec<u8>,
    pub ni_dkg_dealing_encryption_pk: Vec<u8>,
    pub transport_tls_cert: Vec<u8>,
    pub idkg_dealing_encryption_pk: Option<Vec<u8>>,
    pub xnet_endpoint: String,
    pub http_endpoint: String,
    pub node_registration_attestation: Option<SevAttestationPackage>,
    pub public_ipv4_config: Option<IPv4Config>,
    pub domain: Option<String>,
    pub p2p_flow_endpoints: Vec<String>,
    pub prometheus_metrics_endpoint: String,
    pub node_reward_type: Option<String>,
}
Key Fields:
node_signing_pk
Vec<u8>
required
Node’s public signing key (raw protobuf PublicKey bytes)
committee_signing_pk
Vec<u8>
required
Public key for committee participation
ni_dkg_dealing_encryption_pk
Vec<u8>
required
Non-interactive DKG encryption public key
transport_tls_cert
Vec<u8>
required
X.509 certificate for transport layer security
idkg_dealing_encryption_pk
Option<Vec<u8>>
Interactive DKG encryption public key (optional for backward compatibility)
xnet_endpoint
String
required
Endpoint for cross-subnet communication
http_endpoint
String
required
HTTP endpoint for client requests
node_registration_attestation
Option<SevAttestationPackage>
SEV-SNP attestation for secure node registration. When provided, the registry verifies the attestation and extracts the chip_id.
public_ipv4_config
Option<IPv4Config>
IPv4 network configuration

IPv4Config

IPv4Config
struct
Network configuration for IPv4 connectivity.
Candid Definition:
pub struct IPv4Config {
    ip_addr: String,
    gateway_ip_addr: String,
    prefix_length: u32,
}
Validation Rules:
1

IPv4 Address Validation

Both ip_addr and gateway_ip_addr must be valid IPv4 addresses
2

Prefix Length

Must be ≤ 32 (valid CIDR notation)
3

Subnet Consistency

IP and gateway must be in the same subnet given the prefix length
4

Global Address

IP address must be a globally routable address (not private, loopback, link-local, etc.)
Constructor:
pub fn try_new(
    ip_addr: String,
    gateway_ip_addr: String,
    prefix_length: u32,
) -> Result<Self, IPv4ConfigError>

UpdateNodeDirectlyPayload

UpdateNodeDirectlyPayload
struct
Request to update an existing node’s cryptographic keys.
pub struct UpdateNodeDirectlyPayload {
    pub idkg_dealing_encryption_pk: Option<Vec<u8>>,
}

UpdateNodeIPv4ConfigDirectlyPayload

UpdateNodeIPv4ConfigDirectlyPayload
struct
Request to update a node’s IPv4 configuration.
pub struct UpdateNodeIPv4ConfigDirectlyPayload {
    pub node_id: NodeId,
    pub ipv4_config: Option<IPv4Config>,
}

Subnet Queries

GetSubnetForCanisterRequest

GetSubnetForCanisterRequest
message
Query which subnet a canister is assigned to.
Proto Definition:
message GetSubnetForCanisterRequest {
    ic_base_types.pb.v1.PrincipalId principal = 1;
}
Request:
principal
PrincipalId
required
The canister’s principal ID
Response:
message SubnetForCanister {
    ic_base_types.pb.v1.PrincipalId subnet_id = 1;
}
There is no guarantee that the canister exists, even if a subnet ID is returned. This query only checks the routing table.

Rewards

GetNodeProvidersMonthlyXdrRewardsRequest

GetNodeProvidersMonthlyXdrRewardsRequest
struct
Query monthly XDR rewards for node providers.
pub struct GetNodeProvidersMonthlyXdrRewardsRequest {
    pub registry_version: Option<u64>,
}

NodeProvidersMonthlyXdrRewards

NodeProvidersMonthlyXdrRewards
message
Maps node provider IDs to their monthly rewards.
Proto Definition:
message NodeProvidersMonthlyXdrRewards {
    map<string, uint64> rewards = 1;
    optional uint64 registry_version = 2;
}
Fields:
rewards
map<string, uint64>
Map from node provider principal ID to reward amount in 10,000ths of an SDR (XDR)
registry_version
uint64
Registry version at which rewards were calculated

API Boundary Nodes

GetApiBoundaryNodeIdsRequest

GetApiBoundaryNodeIdsRequest
message
Query for API boundary node IDs.
message GetApiBoundaryNodeIdsRequest {}

ApiBoundaryNodeIdRecord

ApiBoundaryNodeIdRecord
message
Response containing boundary node IDs.
message ApiBoundaryNodeIdRecord {
    ic_base_types.pb.v1.PrincipalId id = 1;
}

Chunk Management

GetChunkRequest

GetChunkRequest
struct
Request for large registry entries split into chunks.
pub struct GetChunkRequest {
    pub content_sha256: Option<Vec<u8>>,
}
When a registry entry is too large for a single response, it’s split into chunks that must be fetched individually.

Chunk

Chunk
struct
Response containing chunk data.
pub struct Chunk {
    pub content: Option<Vec<u8>>,
}

Registry Client Interface

See Registry Client Interface for details on the RegistryClient trait.

Query Methods

get_versioned_value

Get a value at a specific version with metadata

get_value

Get a value at a specific version

get_key_family

Get all keys matching a prefix

get_latest_version

Get the current registry version

Stored Configuration Types

The registry stores various types of network configuration:

Node Records

  • Node public keys (signing, committee, DKG)
  • Network endpoints (XNet, HTTP, P2P)
  • TLS certificates
  • IPv4 configuration
  • SEV attestation data
  • Reward types

Subnet Records

  • Subnet membership (list of nodes)
  • DKG transcripts
  • Threshold signature keys
  • Subnet configuration parameters
  • Canister routing table

Cryptographic Keys

  • NI-DKG dealing encryption keys
  • I-DKG dealing encryption keys
  • Threshold signature public keys
  • Chain key configurations

Network Topology

  • Subnet assignments
  • Node provider information
  • API boundary nodes
  • Routing tables

Security Features

SEV-SNP Attestation

NodeRegistrationAttestationCustomData
struct
Custom data embedded in SEV attestation reports for secure node registration.
DER Encoding:
pub struct NodeRegistrationAttestationCustomData<'a> {
    pub node_signing_pk: OctetStringRef<'a>,
}
Purpose:
  • Binds the attestation to the node by including node_signing_pk
  • Used to construct and verify node_registration_attestation
  • Ensures registered nodes have valid hardware attestations
Namespace:
fn namespace(&self) -> SevCustomDataNamespace {
    SevCustomDataNamespace::NodeRegistration
}

Version Management

Version Guarantees

Monotonically Increasing: Each mutation produces version n+1 from version n
Immutability: Historical versions never change once created
Availability: Latest version is always fully available to clients
Determinism: Same query parameters always return the same result

Empty Registry

pub const ZERO_REGISTRY_VERSION: RegistryVersion = RegistryVersion::new(0);
Version 0 represents the empty registry state. All keys return None at this version.

Example Usage

Querying Registry

use ic_interfaces_registry::RegistryClient;
use ic_types::RegistryVersion;

fn get_node_record(client: &dyn RegistryClient, node_id: &str) -> Option<Vec<u8>> {
    let latest = client.get_latest_version();
    let key = format!("node_record_{}", node_id);
    
    client.get_value(&key, latest).ok().flatten()
}

Adding a Node

use registry_canister_api::AddNodePayload;

let payload = AddNodePayload {
    node_signing_pk: signing_key_bytes,
    committee_signing_pk: committee_key_bytes,
    ni_dkg_dealing_encryption_pk: dkg_key_bytes,
    transport_tls_cert: tls_cert_bytes,
    idkg_dealing_encryption_pk: Some(idkg_key_bytes),
    xnet_endpoint: "https://node.example.com:8080".to_string(),
    http_endpoint: "https://node.example.com:8443".to_string(),
    node_registration_attestation: Some(attestation_package),
    public_ipv4_config: Some(IPv4Config::try_new(
        "203.0.113.42".to_string(),
        "203.0.113.1".to_string(),
        24,
    )?),
    domain: Some("node.example.com".to_string()),
    // ...
};

Polling for Updates

use ic_interfaces_registry::POLLING_PERIOD;
use std::time::Duration;

async fn poll_registry(client: &dyn RegistryClient) {
    let mut last_version = client.get_latest_version();
    
    loop {
        tokio::time::sleep(POLLING_PERIOD).await;
        
        let current = client.get_latest_version();
        if current > last_version {
            // Handle new version
            last_version = current;
        }
    }
}

See Also

Build docs developers (and LLMs) love