Skip to main content

Registry System Implementation

The HCS-12 registry system provides decentralized discovery and management of actions, assemblies, and HashLinks. All registries are built on HCS topics for guaranteed consensus and immutability.


What It DoesDirect link to What It Does

  • Manages three registry types: Actions (Type 0), Assemblies (Type 2), HashLinks (Type 3)
  • Provides decentralized discovery through HCS topic synchronization
  • Implements caching strategies for optimal performance
  • Supports search and filtering with tag-based organization
  • Handles registry migrations and version management

Registry ArchitectureDirect link to Registry Architecture

Each registry type serves a specific purpose in the HashLinks ecosystem:

enum RegistryType {
ACTION = 0, // WASM action modules
ASSEMBLY = 2, // Assembly compositions
HASHLINKS = 3, // Global HashLinks directory
}

interface RegistryConfig {
topicId: string; // HCS topic ID
type: RegistryType; // Registry type
cacheStrategy: CacheStrategy; // Caching approach
syncInterval: number; // Sync frequency (ms)
maxCacheSize: number; // Cache size limit
auditEnabled: boolean; // Enable audit logging
}

Registry Types Deep-DiveDirect link to Registry Types Deep-Dive

ActionRegistry (Type 0)Direct link to ActionRegistry (Type 0)

Manages WASM action module registrations and lookups:

import { ActionRegistry, HCS12Client, Logger } from '@hashgraphonline/standards-sdk';

// Initialize action registry
const client = new HCS12Client(config);
const actionRegistry = new ActionRegistry(
'0.0.456789', // Action registry topic ID
client.hederaMirrorNode,
client.hcs1Client,
new Logger({ module: 'ActionRegistry' })
);

// Register a new action
const actionRegistration = {
p: 'hcs-12',
op: 'register',
t_id: '0.0.123456', // WASM module topic ID
hash: 'abc123...', // INFO method result hash
wasm_hash: 'def456...', // WASM binary hash
js_t_id: '0.0.123457', // Optional JS wrapper topic
js_hash: '789abc...', // Optional JS wrapper hash
interface_version: '0.2.95', // wasm-bindgen version
validation_rules: {
swap: {
type: 'object',
properties: {
amount: { type: 'number', minimum: 0 },
tokenIn: { type: 'string', pattern: '^0\\.0\\.[0-9]+$' }
}
}
}
};

await actionRegistry.register(actionRegistration);

// Query actions by hash
const action = await actionRegistry.getByHash('abc123...');
if (action) {
console.log('Found action:', {
topicId: action.t_id,
wasmHash: action.wasm_hash,
hasJsWrapper: !!action.js_t_id
});
}

// Get all registered actions
const allActions = await actionRegistry.getAll();
console.log(`Total actions registered: ${allActions.length}`);

// Search actions by capabilities
const tokenActions = allActions.filter(action =>
action.validation_rules &&
Object.keys(action.validation_rules).some(rule =>
rule.includes('token') || rule.includes('swap')
)
);

AssemblyRegistry (Type 2)Direct link to AssemblyRegistry (Type 2)

Manages assembly compositions with incremental operations:

import { AssemblyRegistry } from '@hashgraphonline/standards-sdk';

// Initialize assembly registry
const assemblyRegistry = new AssemblyRegistry(
'0.0.567890', // Assembly registry topic ID
client.hederaMirrorNode,
client.hcs1Client,
logger
);

// Process assembly registration
const assemblyRegistration = {
p: 'hcs-12',
op: 'register',
name: 'defi-dashboard',
version: '1.0.0',
title: 'DeFi Trading Dashboard',
description: 'Complete DeFi trading interface',
tags: ['defi', 'trading', 'swap'],
author: '0.0.123456',
license: 'MIT'
};

await assemblyRegistry.register(assemblyRegistration);

// Process add-action operation
const addActionOp = {
p: 'hcs-12',
op: 'add-action',
t_id: '0.0.action123',
alias: 'swapEngine'
};

await assemblyRegistry.processOperation(addActionOp);

// Process add-block operation
const addBlockOp = {
p: 'hcs-12',
op: 'add-block',
block_t_id: '0.0.block456',
actions: {
executeSwap: '0.0.action123',
getQuote: '0.0.action123'
},
attributes: {
title: 'Token Swap Interface',
theme: 'dark'
}
};

await assemblyRegistry.processOperation(addBlockOp);

// Get complete assembly state
const assembly = await assemblyRegistry.getAssemblyState('defi-dashboard', '1.0.0');
if (assembly) {
console.log('Assembly state:', {
name: assembly.name,
version: assembly.version,
actionsCount: assembly.actions.length,
blocksCount: assembly.blocks.length,
created: assembly.created,
updated: assembly.updated
});
}

// Search assemblies by tags
const defiAssemblies = await assemblyRegistry.searchByTags(['defi']);
console.log(`Found ${defiAssemblies.length} DeFi assemblies`);

HashLinksRegistry (Type 3)Direct link to HashLinksRegistry (Type 3)

Global directory for HashLink discovery and organization:

import { HashLinksRegistry } from '@hashgraphonline/standards-sdk';

// Initialize HashLinks registry
const hashLinksRegistry = new HashLinksRegistry(
'0.0.678901', // HashLinks registry topic ID
client.hederaMirrorNode,
client.hcs1Client,
logger
);

// Register a HashLink
const hashLinkRegistration = {
p: 'hcs-12',
op: 'register',
name: 'token-swap-app',
version: '2.1.0',
title: 'Advanced Token Swap',
description: 'Professional token swapping with advanced features',
category: 'defi',
tags: ['swap', 'defi', 'tokens', 'liquidity'],
author: '0.0.123456',
license: 'MIT',
assembly_t_id: '0.0.assembly789',
icon: 'exchange-alt',
screenshots: ['0.0.screenshot1', '0.0.screenshot2'],
featured: false,
rating: 4.8,
downloads: 1250,
keywords: ['token', 'swap', 'trade', 'exchange']
};

await hashLinksRegistry.register(hashLinkRegistration);

// Search HashLinks by various criteria
const searchResults = await hashLinksRegistry.search({
query: 'token swap',
category: 'defi',
tags: ['swap'],
minRating: 4.0,
limit: 10,
sortBy: 'popularity' // or 'rating', 'recent', 'name'
});

console.log('Search results:', searchResults.map(result => ({
name: result.name,
title: result.title,
rating: result.rating,
downloads: result.downloads
})));

// Get featured HashLinks
const featured = await hashLinksRegistry.getFeatured();
console.log(`Featured HashLinks: ${featured.length}`);

// Get HashLinks by category
const defiHashLinks = await hashLinksRegistry.getByCategory('defi');
console.log(`DeFi HashLinks: ${defiHashLinks.length}`);

// Get HashLinks by tags
const swapHashLinks = await hashLinksRegistry.searchByTags(['swap', 'exchange']);
console.log(`Swap-related HashLinks: ${swapHashLinks.length}`);

// Update HashLink rating (simulated)
await hashLinksRegistry.updateRating('token-swap-app', 4.9, 1300);

Registry Initialization and ManagementDirect link to Registry Initialization and Management

Client-Side Registry SetupDirect link to Client-Side Registry Setup

Initialize all registries through the HCS12 client:

import { HCS12Client, NetworkType, Logger } from '@hashgraphonline/standards-sdk';

const client = new HCS12Client({
network: NetworkType.TESTNET,
hcs12: {
operatorId: process.env.HEDERA_OPERATOR_ID!,
operatorPrivateKey: process.env.HEDERA_OPERATOR_KEY!,
registryTopics: {
action: '0.0.456789',
assembly: '0.0.567890',
hashlinks: '0.0.678901'
}
},
logger: new Logger({ module: 'HCS12Client' })
});

// Initialize all registries
await client.initializeRegistries({
cacheStrategy: 'hybrid', // memory + storage
syncInterval: 30000, // 30 seconds
maxCacheSize: 100 * 1024 * 1024, // 100MB
auditEnabled: true,
preloadFeatured: true // Preload featured HashLinks
});

// Verify registries are ready
const registryStatus = await client.getRegistryStatus();
console.log('Registry status:', {
action: registryStatus.action.ready,
assembly: registryStatus.assembly.ready,
hashlinks: registryStatus.hashlinks.ready,
totalEntries: registryStatus.totalEntries,
lastSync: registryStatus.lastSync
});

Manual Registry SynchronizationDirect link to Manual Registry Synchronization

Control registry synchronization for optimal performance:

// Sync specific registry
await client.syncRegistry('action', {
fromSequence: 0, // Start from beginning
batchSize: 100, // Process 100 messages per batch
maxMessages: 1000, // Limit total messages
onProgress: (current, total, registry) => {
const percent = Math.round((current / total) * 100);
console.log(`Syncing ${registry}: ${percent}% (${current}/${total})`);
},
onError: (error, registry, sequence) => {
console.error(`Sync error in ${registry} at sequence ${sequence}:`, error);
return 'continue'; // or 'abort', 'retry'
}
});

// Sync all registries in parallel
const syncPromises = ['action', 'assembly', 'hashlinks'].map(type =>
client.syncRegistry(type as any, {
maxMessages: 500,
batchSize: 50
})
);

try {
await Promise.all(syncPromises);
console.log('All registries synchronized');
} catch (error) {
console.error('Registry sync failed:', error.message);
}

// Force refresh cached data
await client.refreshRegistryCache('hashlinks');

Caching StrategiesDirect link to Caching Strategies

Memory-First CachingDirect link to Memory-First Caching

Optimal for frequently accessed data:

// Configure memory-first strategy
const cacheConfig = {
strategy: 'memory-first',
memoryLimit: 50 * 1024 * 1024, // 50MB memory cache
storageLimit: 200 * 1024 * 1024, // 200MB storage cache
ttl: {
action: 3600000, // 1 hour
assembly: 1800000, // 30 minutes
hashlinks: 7200000 // 2 hours
},
evictionPolicy: 'lru', // Least Recently Used
compressionEnabled: true
};

// Apply cache configuration
client.configureRegistryCache(cacheConfig);

// Cache statistics
const cacheStats = client.getRegistryCacheStats();
console.log('Cache statistics:', {
memoryUsage: cacheStats.memoryUsage,
storageUsage: cacheStats.storageUsage,
hitRate: cacheStats.hitRate,
missCount: cacheStats.missCount
});

Hybrid CachingDirect link to Hybrid Caching

Balance between memory and storage:

// Hybrid strategy configuration
const hybridConfig = {
strategy: 'hybrid',
hotDataMemory: 20 * 1024 * 1024, // 20MB for hot data
coldDataStorage: 100 * 1024 * 1024, // 100MB for cold data
hotThreshold: 10, // Access count to be "hot"
coldThreshold: 1440, // Minutes before data becomes "cold"
preloadPatterns: [
'featured:*', // All featured HashLinks
'category:defi', // All DeFi HashLinks
'recent:7d' // Recent 7 days
]
};

client.configureRegistryCache(hybridConfig);

Advanced Search and FilteringDirect link to Advanced Search and Filtering

Complex Search QueriesDirect link to Complex Search Queries

Implement sophisticated search across registries:

// Advanced HashLink search
const advancedSearch = await hashLinksRegistry.advancedSearch({
// Text search
query: 'swap OR exchange OR trade',
queryFields: ['title', 'description', 'keywords'],

// Filters
filters: {
category: ['defi', 'tools'],
tags: ['swap', 'liquidity'],
minRating: 4.0,
minDownloads: 100,
author: '0.0.123456',
license: ['MIT', 'Apache-2.0'],
hasScreenshots: true,
recentlyUpdated: '30d' // Updated within 30 days
},

// Sorting and pagination
sortBy: 'relevance', // or 'rating', 'downloads', 'recent', 'name'
sortOrder: 'desc',
offset: 0,
limit: 20,

// Faceted search
facets: ['category', 'tags', 'author'],

// Highlighting
highlight: {
fields: ['title', 'description'],
preTag: '<mark>',
postTag: '</mark>'
}
});

console.log('Advanced search results:', {
total: advancedSearch.total,
results: advancedSearch.results,
facets: advancedSearch.facets,
took: advancedSearch.took
});

// Search assemblies with filters
const assemblySearch = await assemblyRegistry.search({
hasActions: true, // Must have actions
hasBlocks: true, // Must have blocks
minActionsCount: 2, // At least 2 actions
maxBlocksCount: 10, // At most 10 blocks
tags: ['interactive'], // Must have 'interactive' tag
author: '0.0.123456', // By specific author
versionRange: '^1.0.0', // Version compatibility
updatedAfter: new Date('2024-01-01')
});

Tag-Based OrganizationDirect link to Tag-Based Organization

Implement hierarchical tag systems:

// Hierarchical tag search
const tagHierarchy = {
'defi': ['swap', 'lending', 'staking', 'yield'],
'gaming': ['nft', 'collectibles', 'marketplace'],
'tools': ['analytics', 'monitoring', 'development'],
'social': ['messaging', 'voting', 'governance']
};

// Search with tag expansion
const expandedSearch = await hashLinksRegistry.searchWithTagExpansion('defi', {
includeSubtags: true, // Include all defi subtags
tagWeights: { // Weight different tags
'defi': 1.0,
'swap': 1.2, // Boost swap results
'lending': 0.8
}
});

// Tag-based recommendations
const recommendations = await hashLinksRegistry.getRecommendations({
basedOnTags: ['defi', 'swap'],
excludeAlreadyUsed: true,
maxResults: 5,
diversityFactor: 0.7 // Balance relevance vs diversity
});

Registry Audit and AnalyticsDirect link to Registry Audit and Analytics

Audit TrailDirect link to Audit Trail

Track all registry operations for compliance:

// Enable comprehensive auditing
const auditConfig = {
enabled: true,
logLevel: 'detailed', // or 'basic', 'minimal'
includeContent: false, // Don't log full content for privacy
retentionDays: 365, // Keep audit logs for 1 year
exportFormat: 'json', // or 'csv', 'xml'
};

client.configureRegistryAudit(auditConfig);

// Query audit logs
const auditLogs = await client.getRegistryAuditLogs({
registry: 'hashlinks',
operation: ['register', 'update'],
dateRange: {
from: new Date('2024-01-01'),
to: new Date('2024-12-31')
},
author: '0.0.123456',
limit: 100
});

console.log('Audit trail:', auditLogs.map(log => ({
timestamp: log.timestamp,
operation: log.operation,
registry: log.registry,
itemId: log.itemId,
author: log.author,
success: log.success,
changes: log.changes
})));

// Generate compliance report
const complianceReport = await client.generateComplianceReport({
startDate: new Date('2024-01-01'),
endDate: new Date('2024-12-31'),
includeMetrics: true,
format: 'pdf'
});

Registry AnalyticsDirect link to Registry Analytics

Monitor registry usage and performance:

// Get registry analytics
const analytics = await client.getRegistryAnalytics({
timeRange: '30d', // Last 30 days
granularity: 'daily', // Daily breakdown
includeGrowth: true, // Include growth rates
includePopular: true // Include popular items
});

console.log('Registry analytics:', {
totalRegistrations: analytics.totalRegistrations,
dailyGrowth: analytics.dailyGrowth,
popularItems: analytics.popularItems,
topCategories: analytics.topCategories,
activeAuthors: analytics.activeAuthors,
searchMetrics: analytics.searchMetrics
});

// Monitor registry health
const healthMetrics = await client.getRegistryHealth();
console.log('Registry health:', {
uptime: healthMetrics.uptime,
syncLatency: healthMetrics.syncLatency,
cacheHitRate: healthMetrics.cacheHitRate,
errorRate: healthMetrics.errorRate,
throughput: healthMetrics.throughput
});

Common Issues and SolutionsDirect link to Common Issues and Solutions

1. Registry Synchronization LagDirect link to 1. Registry Synchronization Lag

Problem: Registry data is out of sync with network

Warning: Registry last sync was 2 hours ago, data may be stale

Solution: Implement proper sync monitoring and retry logic

// Monitor sync health
const syncMonitor = new RegistrySyncMonitor(client);
syncMonitor.on('sync_lag', async (registry, lagMinutes) => {
if (lagMinutes > 60) {
console.warn(`Registry ${registry} lag detected: ${lagMinutes} minutes`);

// Force sync
await client.syncRegistry(registry, {
priority: 'high',
timeout: 30000
});
}
});

// Auto-sync on network reconnect
client.on('network_connected', async () => {
await client.syncAllRegistries({
catchUp: true,
maxLag: 3600000 // 1 hour max lag
});
});

2. Cache Memory IssuesDirect link to 2. Cache Memory Issues

Problem: Registry cache consuming too much memory

Error: Registry cache exceeded memory limit (100MB)

Solution: Optimize cache configuration and eviction

// Implement intelligent cache eviction
const cacheManager = new RegistryCacheManager({
maxMemory: 50 * 1024 * 1024, // 50MB limit
evictionPolicy: 'lru-with-priority',
priorities: {
'featured': 'high', // Keep featured items
'recent': 'medium', // Keep recent items
'cold': 'low' // Evict cold items first
},
compressionThreshold: 10 * 1024 // Compress items > 10KB
});

// Monitor memory usage
cacheManager.on('memory_pressure', (usage) => {
console.log(`Memory pressure detected: ${usage}%`);
// Trigger aggressive cleanup
cacheManager.cleanup({ aggressive: true });
});

3. Search Performance IssuesDirect link to 3. Search Performance Issues

Problem: Registry searches are too slow

Warning: Search query took 5.2s, consider optimization

Solution: Implement search optimization and indexing

// Optimize search with proper indexing
const searchOptimizer = new RegistrySearchOptimizer({
enableFullTextIndex: true,
enableTagIndex: true,
enableCategoryIndex: true,
enableAuthorIndex: true,
maxSearchTime: 1000, // 1 second timeout
useApproximateResults: true // Allow approximate for speed
});

// Implement search caching
const searchCache = new SearchCache({
maxCacheSize: 1000, // Cache 1000 searches
ttl: 300000, // 5 minute cache
keyStrategy: 'hash' // Hash search parameters
});

// Pre-warm popular searches
await searchCache.preWarm([
{ query: 'defi', category: 'finance' },
{ tags: ['swap'] },
{ featured: true }
]);

4. Registry Topic Message OrderingDirect link to 4. Registry Topic Message Ordering

Problem: Registry messages processed out of order

Error: Operation sequence mismatch, expected 156 but got 158

Solution: Implement proper message ordering and gap handling

// Handle message ordering issues
class RegistryMessageProcessor {
private messageBuffer = new Map<number, any>();
private expectedSequence = 0;

async processMessage(message: any, sequence: number) {
if (sequence === this.expectedSequence) {
// Process immediately
await this.handleMessage(message);
this.expectedSequence++;

// Process any buffered messages
while (this.messageBuffer.has(this.expectedSequence)) {
const bufferedMessage = this.messageBuffer.get(this.expectedSequence);
await this.handleMessage(bufferedMessage);
this.messageBuffer.delete(this.expectedSequence);
this.expectedSequence++;
}
} else if (sequence > this.expectedSequence) {
// Buffer future message
this.messageBuffer.set(sequence, message);

// Check for gaps after timeout
setTimeout(() => this.checkForGaps(), 5000);
} else {
// Ignore old message
console.warn(`Ignoring old message: ${sequence} < ${this.expectedSequence}`);
}
}

private async checkForGaps() {
if (this.messageBuffer.size > 0) {
console.warn('Message gaps detected, requesting missing messages');
// Request missing messages from mirror node
}
}
}

5. Registry Migration IssuesDirect link to 5. Registry Migration Issues

Problem: Registry format changes breaking compatibility

Error: Unknown registry message format version 1.3

Solution: Implement proper version handling and migration

// Registry version compatibility
class RegistryVersionHandler {
private readonly supportedVersions = ['1.0', '1.1', '1.2', '1.3'];
private readonly migrators = new Map();

constructor() {
this.migrators.set('1.0->1.1', this.migrateV10ToV11);
this.migrators.set('1.1->1.2', this.migrateV11ToV12);
this.migrators.set('1.2->1.3', this.migrateV12ToV13);
}

async processMessage(message: any) {
const version = message.version || '1.0';

if (!this.supportedVersions.includes(version)) {
throw new Error(`Unsupported registry version: ${version}`);
}

// Migrate if necessary
let processedMessage = message;
let currentVersion = version;

while (currentVersion !== '1.3') {
const migrator = this.migrators.get(`${currentVersion}->1.3`);
if (migrator) {
processedMessage = migrator(processedMessage);
break;
}

// Step-by-step migration
const nextVersion = this.getNextVersion(currentVersion);
const stepMigrator = this.migrators.get(`${currentVersion}->${nextVersion}`);
if (stepMigrator) {
processedMessage = stepMigrator(processedMessage);
currentVersion = nextVersion;
} else {
break;
}
}

return processedMessage;
}
}

This comprehensive registry documentation provides developers with everything they need to effectively use and manage the HCS-12 registry system.