Files
next.orly.dev/docs/FIND_IMPLEMENTATION_PLAN.md

16 KiB

FIND Name Binding Implementation Plan

Overview

This document outlines the implementation plan for integrating the Free Internet Name Daemon (FIND) protocol with the ORLY relay. The FIND protocol provides decentralized name-to-npub bindings that are discoverable by any client using standard Nostr queries.

Architecture

System Components

┌─────────────────────────────────────────────────────────────┐
│                        ORLY Relay                            │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐  │
│  │   WebSocket  │  │  FIND Daemon │  │   HTTP API       │  │
│  │   Handler    │  │  (Registry   │  │   (NIP-11, Web)  │  │
│  │              │  │   Service)   │  │                  │  │
│  └──────┬───────┘  └──────┬───────┘  └────────┬─────────┘  │
│         │                 │                    │             │
│         └─────────────────┼────────────────────┘             │
│                          │                                   │
│                  ┌───────▼────────┐                          │
│                  │   Database     │                          │
│                  │   (Badger/     │                          │
│                  │    DGraph)     │                          │
│                  └────────────────┘                          │
└─────────────────────────────────────────────────────────────┘
         │                                        ▲
         │  Publish FIND events                   │  Query FIND events
         │  (kinds 30100-30105)                   │  (kinds 30102, 30103)
         ▼                                        │
┌─────────────────────────────────────────────────────────────┐
│                     Nostr Network                            │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐  │
│  │   Other      │  │   Other      │  │    Clients       │  │
│  │   Relays     │  │   Registry   │  │                  │  │
│  │              │  │   Services   │  │                  │  │
│  └──────────────┘  └──────────────┘  └──────────────────┘  │
└─────────────────────────────────────────────────────────────┘

Event Flow

  1. Name Registration:

    User → FIND CLI → Registration Proposal (kind 30100) → Relay → Database
                                                            ↓
                                           Registry Service (attestation)
                                                            ↓
                                           Attestation (kind 20100) → Other Registry Services
                                                            ↓
                                           Consensus → Name State (kind 30102)
    
  2. Name Resolution:

    Client → Query kind 30102 (name state) → Relay → Database → Response
    Client → Query kind 30103 (records) → Relay → Database → Response
    

Implementation Phases

Phase 1: Database Storage for FIND Events ✓ (Already Supported)

The relay already stores all parameterized replaceable events (kind 30xxx) and ephemeral events (kind 20xxx), which includes all FIND event types:

  • ✓ Kind 30100: Registration Proposals
  • ✓ Kind 20100: Attestations (ephemeral)
  • ✓ Kind 30101: Trust Graphs
  • ✓ Kind 30102: Name State
  • ✓ Kind 30103: Name Records
  • ✓ Kind 30104: Certificates
  • ✓ Kind 30105: Witness Services

Status: No changes needed. The existing event storage system handles these automatically.

Phase 2: Registry Service Implementation

Create a new registry service that runs within the ORLY relay process (optional, can be enabled via config).

New Files:

  • pkg/find/registry.go - Core registry service
  • pkg/find/consensus.go - Consensus algorithm implementation
  • pkg/find/trust.go - Trust graph calculation
  • app/find-service.go - Integration with relay server

Key Components:

// Registry service that monitors proposals and computes consensus
type RegistryService struct {
    db              database.Database
    pubkey          []byte // Registry service identity
    trustGraph      *TrustGraph
    pendingProposals map[string]*ProposalState
    config          *RegistryConfig
}

type RegistryConfig struct {
    Enabled             bool
    ServicePubkey       string
    AttestationDelay    time.Duration // Default: 60s
    SparseAttestation   bool
    SamplingRate        int // For sparse attestation
}

// Proposal state tracking during attestation window
type ProposalState struct {
    Proposal      *RegistrationProposal
    Attestations  []*Attestation
    ReceivedAt    time.Time
    ProcessedAt   *time.Time
}

Responsibilities:

  1. Subscribe to kind 30100 (registration proposals) from database
  2. Validate proposals (name format, ownership, renewal window)
  3. Check for conflicts (competing proposals)
  4. After attestation window (60-120s):
    • Fetch attestations (kind 20100) from other registry services
    • Compute trust-weighted consensus
    • Publish name state (kind 30102) if consensus reached

Phase 3: Client Query Handlers

Enhance existing query handlers to optimize FIND event queries.

Enhancements:

  • Add specialized indexes for FIND events (already exists via d tag indexes)
  • Implement name resolution helper functions
  • Cache frequently queried name states

New Helper Functions:

// Query name state for a given name
func (d *Database) QueryNameState(name string) (*find.NameState, error)

// Query all records for a name
func (d *Database) QueryNameRecords(name string, recordType string) ([]*find.NameRecord, error)

// Check if name is available for registration
func (d *Database) IsNameAvailable(name string) (bool, error)

// Get parent domain owner (for subdomain validation)
func (d *Database) GetParentDomainOwner(name string) (string, error)

Phase 4: Configuration Integration

Add FIND-specific configuration options to app/config/config.go:

type C struct {
    // ... existing fields ...

    // FIND registry service settings
    FindEnabled           bool     `env:"ORLY_FIND_ENABLED" default:"false" usage:"enable FIND registry service for name consensus"`
    FindServicePubkey     string   `env:"ORLY_FIND_SERVICE_PUBKEY" usage:"public key for this registry service (hex)"`
    FindServicePrivkey    string   `env:"ORLY_FIND_SERVICE_PRIVKEY" usage:"private key for signing attestations (hex)"`
    FindAttestationDelay  string   `env:"ORLY_FIND_ATTESTATION_DELAY" default:"60s" usage:"delay before publishing attestations"`
    FindSparseEnabled     bool     `env:"ORLY_FIND_SPARSE_ENABLED" default:"false" usage:"use sparse attestation (probabilistic)"`
    FindSamplingRate      int      `env:"ORLY_FIND_SAMPLING_RATE" default:"10" usage:"sampling rate for sparse attestation (1/K)"`
    FindBootstrapServices []string `env:"ORLY_FIND_BOOTSTRAP_SERVICES" usage:"comma-separated list of bootstrap registry service pubkeys"`
}

Phase 5: FIND Daemon HTTP API

Add HTTP API endpoints for FIND operations (optional, for user convenience):

New Endpoints:

  • GET /api/find/names/:name - Query name state
  • GET /api/find/names/:name/records - Query all records for a name
  • GET /api/find/names/:name/records/:type - Query specific record type
  • POST /api/find/register - Submit registration proposal
  • POST /api/find/transfer - Submit transfer proposal
  • GET /api/find/trust-graph - Query this relay's trust graph

Implementation:

// app/handle-find-api.go
func (s *Server) handleFindNameQuery(w http.ResponseWriter, r *http.Request) {
    name := r.PathValue("name")

    // Validate name format
    if err := find.ValidateName(name); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // Query name state from database
    nameState, err := s.DB.QueryNameState(name)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    if nameState == nil {
        http.Error(w, "name not found", http.StatusNotFound)
        return
    }

    // Return as JSON
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(nameState)
}

Phase 6: Client Integration Examples

Provide example code for clients to use FIND:

Example: Query name ownership

// JavaScript/TypeScript example using nostr-tools
import { SimplePool } from 'nostr-tools'

async function queryNameOwner(relays, name) {
  const pool = new SimplePool()

  // Query kind 30102 events with d tag = name
  const events = await pool.list(relays, [{
    kinds: [30102],
    '#d': [name],
    limit: 5
  }])

  if (events.length === 0) {
    return null // Name not registered
  }

  // Check for majority consensus among registry services
  const ownerCounts = {}
  for (const event of events) {
    const ownerTag = event.tags.find(t => t[0] === 'owner')
    if (ownerTag) {
      const owner = ownerTag[1]
      ownerCounts[owner] = (ownerCounts[owner] || 0) + 1
    }
  }

  // Return owner with most attestations
  let maxCount = 0
  let consensusOwner = null
  for (const [owner, count] of Object.entries(ownerCounts)) {
    if (count > maxCount) {
      maxCount = count
      consensusOwner = owner
    }
  }

  return consensusOwner
}

// Example: Resolve name to IP address
async function resolveNameToIP(relays, name) {
  const owner = await queryNameOwner(relays, name)
  if (!owner) {
    throw new Error('Name not registered')
  }

  // Query kind 30103 events for A records
  const pool = new SimplePool()
  const records = await pool.list(relays, [{
    kinds: [30103],
    '#name': [name],
    '#type': ['A'],
    authors: [owner], // Only records from name owner are valid
    limit: 5
  }])

  if (records.length === 0) {
    throw new Error('No A records found')
  }

  // Extract IP addresses from value tags
  const ips = records.map(event => {
    const valueTag = event.tags.find(t => t[0] === 'value')
    return valueTag ? valueTag[1] : null
  }).filter(Boolean)

  return ips
}

Example: Register a name

import { finalizeEvent, getPublicKey } from 'nostr-tools'
import { find } from './find-helpers'

async function registerName(relays, privkey, name) {
  // Validate name format
  if (!find.validateName(name)) {
    throw new Error('Invalid name format')
  }

  const pubkey = getPublicKey(privkey)

  // Create registration proposal (kind 30100)
  const event = {
    kind: 30100,
    created_at: Math.floor(Date.now() / 1000),
    tags: [
      ['d', name],
      ['action', 'register'],
      ['expiration', String(Math.floor(Date.now() / 1000) + 300)] // 5 min expiry
    ],
    content: ''
  }

  const signedEvent = finalizeEvent(event, privkey)

  // Publish to relays
  const pool = new SimplePool()
  await Promise.all(relays.map(relay => pool.publish(relay, signedEvent)))

  // Wait for consensus (typically 1-2 minutes)
  console.log('Registration proposal submitted. Waiting for consensus...')
  await new Promise(resolve => setTimeout(resolve, 120000))

  // Check if registration succeeded
  const owner = await queryNameOwner(relays, name)
  if (owner === pubkey) {
    console.log('Registration successful!')
    return true
  } else {
    console.log('Registration failed - another proposal may have won consensus')
    return false
  }
}

Testing Plan

Unit Tests

  1. Name Validation Tests (pkg/find/validation_test.go - already exists)

    • Valid names
    • Invalid names (too long, invalid characters, etc.)
    • Subdomain authority validation
  2. Consensus Algorithm Tests (pkg/find/consensus_test.go - new)

    • Single proposal scenario
    • Competing proposals
    • Trust-weighted scoring
    • Attestation window expiry
  3. Trust Graph Tests (pkg/find/trust_test.go - new)

    • Direct trust relationships
    • Multi-hop trust inheritance
    • Trust decay calculation

Integration Tests

  1. End-to-End Registration (pkg/find/integration_test.go - new)

    • Submit proposal
    • Generate attestations
    • Compute consensus
    • Verify name state
  2. Name Renewal (pkg/find/renewal_test.go - new)

    • Renewal during preferential window
    • Rejection outside renewal window
    • Expiration handling
  3. Record Management (pkg/find/records_test.go - new)

    • Publish DNS-style records
    • Verify owner authorization
    • Query records by type

Performance Tests

  1. Concurrent Proposals - Benchmark handling 1000+ simultaneous proposals
  2. Trust Graph Calculation - Test with 10,000+ registry services
  3. Query Performance - Measure name resolution latency

Deployment Strategy

Development Phase

  1. Implement core registry service (Phase 2)
  2. Add unit tests
  3. Test with local relay and simulated registry services

Testnet Phase

  1. Deploy 5-10 test relays with FIND enabled
  2. Simulate various attack scenarios (Sybil, censorship, etc.)
  3. Tune consensus parameters based on results

Production Rollout

  1. Documentation and client libraries
  2. Enable FIND on select relays (opt-in)
  3. Monitor for issues and gather feedback
  4. Gradual adoption across relay network

Security Considerations

Attack Mitigations

  1. Sybil Attacks

    • Trust-weighted consensus prevents new services from dominating
    • Age-weighted trust (new services have reduced influence)
  2. Censorship

    • Diverse trust graphs make network-wide censorship difficult
    • Users can query different registry services aligned with their values
  3. Name Squatting

    • Mandatory 1-year expiration
    • Preferential 30-day renewal window
    • No indefinite holding
  4. Renewal Window DoS

    • 30-day window reduces attack surface
    • Owner can submit multiple renewal attempts
    • Registry services filter by pubkey during renewal window

Privacy Considerations

  • Registration proposals are public (necessary for consensus)
  • Ownership history is permanently visible
  • Clients can use Tor or private relays for sensitive queries

Documentation Updates

  1. User Guide (docs/FIND_USER_GUIDE.md - new)

    • How to register a name
    • How to manage DNS records
    • How to renew registrations
    • Client integration examples
  2. Operator Guide (docs/FIND_OPERATOR_GUIDE.md - new)

    • How to enable FIND registry service
    • Trust graph configuration
    • Monitoring and troubleshooting
    • Bootstrap recommendations
  3. Developer Guide (docs/FIND_DEVELOPER_GUIDE.md - new)

    • API reference
    • Client library examples (JS, Python, Go)
    • Event schemas and validation
    • Consensus algorithm details
  4. Update CLAUDE.md

    • Add FIND sections to project overview
    • Document new configuration options
    • Add testing instructions

Success Metrics

  • Registration Finality: < 2 minutes for 95% of registrations
  • Query Latency: < 100ms for name lookups
  • Consensus Agreement: > 99% agreement among honest registry services
  • Uptime: Registry service availability > 99.9%
  • Adoption: 100+ registered names within first month of testnet

Future Enhancements

  1. Economic Incentives - Optional registration fees via Lightning
  2. Reputation System - Track registry service quality metrics
  3. Certificate System - Implement NIP-XX certificate witnessing
  4. Noise Protocol - Secure transport layer for TLS replacement
  5. Client Libraries - Official libraries for popular languages
  6. Browser Integration - Browser extension for name resolution
  7. DNS Gateway - Traditional DNS server that queries FIND