Pure Go Namecoin library and daemon using btcd as dependencies (not forks).
nmcd is a library-first Namecoin implementation built using btcd libraries. It can be embedded directly into your Go applications for in-process name resolution and registration, or run as a standalone daemon for traditional RPC access.
Key Highlights:
- 🔧 Library-First Design: Import and use directly in your Go code
- 🚀 Embedded or Daemon Mode: Choose in-process or external daemon
- 🧩 Composition over Reimplementation: Built on btcd's battle-tested components
- 🔒 Thread-Safe: All operations safe for concurrent use
- 📦 Pure Go: No C dependencies, cross-platform support
go get github.com/opd-ai/nmcdpackage main
import (
"context"
"fmt"
"log"
"github.com/opd-ai/nmcd/client"
)
func main() {
// Create embedded client (runs in-process)
nc, err := client.NewClient(&client.Config{
Mode: client.ModeAuto, // Auto-detect daemon or use embedded
Network: "mainnet",
})
if err != nil {
log.Fatal(err)
}
defer nc.Close()
// Resolve a Namecoin name
ctx := context.Background()
record, err := nc.ResolveName(ctx, "d/example")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Name: %s\nValue: %s\nOwner: %s\n",
record.Name, record.Value, record.Address)
}// Register a new name
result, err := nc.RegisterName(ctx, "d/mysite", `{"ip":"1.2.3.4"}`, nil)
fmt.Printf("Registration TX: %s\n", result.TxHash)
// Update existing name
result, err = nc.UpdateName(ctx, "d/mysite", `{"ip":"5.6.7.8"}`, nil)
fmt.Printf("Update TX: %s\n", result.TxHash)
// List names with filters
names, err := nc.ListNames(ctx, &client.ListFilter{
Namespace: "d/",
Limit: 100,
})📚 See docs/EXAMPLES.md for detailed walkthroughs and patterns.
- Name Resolution: Look up Namecoin names with expiration checking
- Name Registration: Two-step NAME_NEW → NAME_FIRSTUPDATE process
- Name Updates: Update values and extend expiration (36,000 blocks)
- Name Listing: Filter by namespace, address, or pattern with pagination
- Embedded Mode: In-process blockchain and database (no external daemon)
- Daemon Mode: Connect to existing nmcd or Namecoin Core via RPC
- Auto-Detection: Automatically choose daemon or embedded based on availability
- Thread-Safe: All methods safe for concurrent goroutines
- Context Support: Timeouts and cancellation for all operations
When run as a standalone daemon, nmcd provides:
- Pure Go: Built entirely in Go using standard library and btcd
- NameDatabase: bbolt-backed storage for name operations
- Blockchain Integration: Embeds btcd's blockchain.BlockChain with name validation hooks
- Block Synchronization: Automatic Initial Block Download (IBD) and ongoing sync with the network via headers-first protocol
- Network Layer: Uses btcd/peer for P2P networking with interface-based connections (net.Conn)
- Transaction Mempool: Validates and relays unconfirmed transactions with automatic expiration
- JSON-RPC Server: Standard library net/http for RPC interface
- Thread-Safe: Mutex protection for all shared state
- Focused Implementation: ~18,000 lines of production code (excluding tests)
The daemon automatically synchronizes with the Namecoin network using a headers-first sync protocol:
- Initial Block Download (IBD): Downloads block headers from peers, validates the chain, then fetches full blocks
- Ongoing Sync: Continuously monitors peers for new blocks and processes them as they arrive
- Peer Selection: Tracks peer reliability and latency to choose the best sync sources
- Health Monitoring: Use the
/readyendpoint to check if sync is complete
The embedded client mode automatically connects to the network and syncs blocks when MaxPeers > 0 (default: 8). By default, it uses DNS seed discovery to find peers. To disable automatic network sync, set MaxPeers to 0 or provide custom BootstrapPeers.
- Installation Guide: Platform-specific installation instructions
- Operations Guide: Configuration, monitoring, backup, and troubleshooting
- Quick Start Guide: Library usage and setup
- API Reference: Complete API documentation with examples
- CHANGELOG: Version history and API stability policy
- Embedding Guide: Integration patterns for applications
- Examples Guide: Detailed walkthroughs of example code
- Mode Comparison: Embedded vs daemon tradeoffs
- Performance Guide: Benchmarks and optimization tips
Starting with v1.0.0, nmcd follows Semantic Versioning and provides strong backward compatibility guarantees:
- Stable API: The
clientpackage interface is stable and will maintain backward compatibility - Breaking changes: Only in MAJOR version releases (e.g., v1.x → v2.0)
- New features: Added in MINOR releases (e.g., v1.0 → v1.1) without breaking existing code
- Bug fixes: In PATCH releases (e.g., v1.0.0 → v1.0.1)
See CHANGELOG.md for:
- Complete version history
- Detailed semantic versioning policy
- Deprecation process
- Migration guides between versions
Current Status: v0.1.0 (development) → Working towards v1.0.0 production release
nmcd supports three operational modes:
Automatically detects if a daemon is running on localhost:8336 and uses it; otherwise runs in embedded mode.
nc, err := client.NewClient(&client.Config{
Mode: client.ModeAuto, // Default
})Use When:
- Building applications that work with or without a daemon
- Want flexibility without configuration
- Development and testing
Runs the full blockchain, database, and network stack in-process. No external daemon required.
nc, err := client.NewEmbeddedClient(&client.Config{
Mode: client.ModeEmbedded,
DataDir: "/path/to/data",
Network: "mainnet",
})Network Connectivity:
By default, embedded mode automatically connects to the Namecoin network using DNS seed discovery (MaxPeers defaults to 8). To customize network behavior:
// Disable automatic network sync (offline mode)
nc, err := client.NewEmbeddedClient(&client.Config{
Mode: client.ModeEmbedded,
MaxPeers: 0, // No peer connections
})
// Use custom bootstrap peers (skip DNS seeds)
nc, err := client.NewEmbeddedClient(&client.Config{
Mode: client.ModeEmbedded,
BootstrapPeers: []string{
"peer1.example.com:8334",
"peer2.example.com:8334",
},
})Use When:
- Embedding nmcd in your application
- Running multiple isolated instances
- Offline name resolution from local database
- No dependency on external services
Pros:
- ✅ No external dependencies
- ✅ Full control over resources
- ✅ Isolated data and state
- ✅ Simpler deployment
- ✅ Automatic network sync by default
Cons:
- ❌ Higher memory usage (~250MB UTXO cache)
- ❌ Each instance syncs independently
- ❌ Database locked to single process
Connects to an existing nmcd or Namecoin Core daemon via RPC.
nc, err := client.NewDaemonClient(&client.Config{
Mode: client.ModeDaemon,
RPCAddr: "http://localhost:8336",
RPCUser: "user",
RPCPassword: "pass",
})Use When:
- Shared blockchain state across applications
- Multiple applications need name resolution
- Centralized infrastructure
- Production deployments with managed daemon
Pros:
- ✅ Shared blockchain sync
- ✅ Lower per-application memory
- ✅ Centralized monitoring
- ✅ Multiple clients, one sync
Cons:
- ❌ Requires running daemon
- ❌ Network dependency
- ❌ RPC authentication needed
📚 See docs/MODES.md for detailed comparison and recommendations.
┌───────────────────────────────────────────────────────────────┐
│ Your Go Application │
├───────────────────────────────────────────────────────────────┤
│ nmcd Library (client/) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ NameClient Interface (Public API) │ │
│ │ • ResolveName(name) → NameRecord │ │
│ │ • RegisterName(name, value, opts) → TxHash │ │
│ │ • UpdateName(name, value, opts) → TxHash │ │
│ │ • ListNames(filter) → []NameRecord │ │
│ └────────────────────────────────────────────────────────┘ │
│ ▲ ▲ │
│ │ │ │
│ ┌─────────┴─────────┐ ┌──────────┴──────────┐ │
│ │ EmbeddedClient │ │ DaemonClient │ │
│ │ (in-process) │ │ (RPC to daemon) │ │
│ └─────────┬─────────┘ └─────────────────────┘ │
│ │ │
│ ┌─────────▼─────────────────────────┐ │
│ │ Embedded Components │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐│ │
│ │ │ chain/ │ │namedb/ │ │network/││ │
│ │ │validate│ │bbolt DB│ │ peer ││ │
│ │ └────────┘ └────────┘ └────────┘│ │
│ └───────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
-
namedb: Name database with bbolt storage
- Stores name records with expiration tracking
- Historical operation tracking
- Thread-safe with RWMutex
-
chain: Blockchain wrapper
- Embeds btcd's blockchain.BlockChain
- Extends validation with name operation hooks
- Manages name expiration (36000 blocks ~250 days)
-
network: P2P networking
- Uses btcd/peer for peer management
- Interface-based connections (net.Conn)
- Handles block/tx propagation
-
rpc: JSON-RPC server
- Standard library net/http
- Name-specific RPC methods
- Thread-safe access
-
config: Configuration management
- Network selection (mainnet/testnet/regtest)
- Data directory management
While nmcd is primarily a library, it can also run as a standalone daemon for traditional RPC access.
go build -v ./cmd/nmcd# Run with defaults (auto-discovers peers via DNS seeds)
./nmcd
# Custom data directory
./nmcd -datadir=/path/to/data
# Testnet
./nmcd -network=testnet
# Custom RPC port
./nmcd -rpcaddr=127.0.0.1:18336
# Connect to specific peer (bypasses DNS seed discovery)
./nmcd -addpeer=peer.example.com:8334
# Enable RPC authentication (recommended for security)
./nmcd -rpcuser=myuser -rpcpassword=mypasswordNote: When using nmcd as a library, you don't need to run the daemon unless you want to share blockchain state across multiple applications.
nmcd supports automatic peer discovery via DNS seeds. When started without the -addpeer flag, the node will:
- Query official Namecoin DNS seed servers
- Resolve IP addresses of active network nodes
- Connect to discovered peers automatically
Mainnet DNS Seeds:
nmc.seed.quisquis.deseed.nmc.markasoftware.comdnsseed1.nmc.dotbit.zonednsseed2.nmc.dotbit.zonednsseed.nmc.testls.spacenamecoin.seed.cypherstack.com
Testnet DNS Seeds:
dnsseed.test.namecoin.webbtc.com
To bypass DNS seed discovery and connect to specific peers, use the -addpeer flag.
When running nmcd as a daemon, it exposes a JSON-RPC interface for external access. If you're using nmcd as a library, use the Go API instead of RPC for better performance and type safety.
The RPC server supports HTTP Basic Authentication. When both -rpcuser and -rpcpassword flags are set, all RPC requests must include valid credentials.
Security Considerations:
- Use strong, unique passwords for RPC authentication
- Command-line flags are visible in process listings (
ps,top). For production use, consider environment variables or a configuration file - HTTP Basic Auth transmits credentials in base64 encoding (not encrypted). Only use RPC over localhost or with proper network security (firewall, VPN, or reverse proxy with HTTPS)
# With authentication enabled
curl -X POST http://127.0.0.1:8336 \
-u myuser:mypassword \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"getinfo","params":[],"id":1}'getinfo- Get general informationgetblockcount- Get current block heightgetbestblockhash- Get best block hashgetconnectioncount- Get peer connection countgetpeerinfo- Get connected peer information
-
name_new- Create a NAME_NEW transaction to pre-register a name commitmentcurl -X POST http://127.0.0.1:8336 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"name_new","params":["d/example"],"id":1}'
This is the first step in the two-phase name registration process. It creates a commitment hash to prevent front-running. The response includes a
randvalue (hex-encoded random bytes) that must be saved for the NAME_FIRSTUPDATE step.Returns:
{ "txid": "transaction_hash", "name": "d/example", "rand": "hex_encoded_random_bytes", "status": "broadcasted" }Important: Save the
randvalue! You'll need it forname_firstupdate. -
name_firstupdate- Complete name registration with NAME_FIRSTUPDATEcurl -X POST http://127.0.0.1:8336 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"name_firstupdate","params":["d/example","hex_rand_from_name_new","{\"ip\":\"1.2.3.4\"}"],"id":1}'
Parameters:
["name", "rand", "value"]This is the second step in the two-phase registration process. Requirements:
- Must be called at least 12 blocks after
name_new - Must be called within 36,000 blocks of
name_new - The
randparameter must match the value returned byname_new - The
valuemust be valid UTF-8 (max 1023 bytes), JSON ford/andid/namespaces
Returns:
{ "txid": "transaction_hash", "name": "d/example", "value": "{\"ip\":\"1.2.3.4\"}", "status": "broadcasted" } - Must be called at least 12 blocks after
-
name_show- Show name informationcurl -X POST http://127.0.0.1:8336 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"name_show","params":["d/example"],"id":1}'
-
name_list- List all registered namescurl -X POST http://127.0.0.1:8336 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"name_list","params":[],"id":1}'
-
name_history- Get name historycurl -X POST http://127.0.0.1:8336 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"name_history","params":["d/example"],"id":1}'
-
name_update- Update an existing name's valuecurl -X POST http://127.0.0.1:8336 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"name_update","params":["d/example","new_value"],"id":1}'
Parameters:
["name", "value"]or["name", "value", "address"]The wallet must have the private key for the address that owns the name. If no address is specified, the name stays at its current address.
-
getnewaddress- Generate a new address in the walletcurl -X POST http://127.0.0.1:8336 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"getnewaddress","params":[],"id":1}'
Returns a new address string. The address is persisted to the wallet file.
-
listaddresses- List all addresses in the walletcurl -X POST http://127.0.0.1:8336 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"listaddresses","params":[],"id":1}'
Returns an array of address strings currently stored in the wallet.
Security Warning: By default, nmcd wallets store private keys unencrypted in wallet.json with file permissions 0600. For production use, always encrypt your wallet.
-
encryptwallet- Encrypt the wallet with a password (one-time operation)curl -X POST http://127.0.0.1:8336 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"encryptwallet","params":["YourSecurePassword123"],"id":1}'
Parameters:
["password"]- Password must be at least 8 characters with 2+ character types (lowercase, uppercase, digits, special)
- Encrypts all private keys using AES-256-GCM with scrypt key derivation (N=32768)
- Wallet remains unlocked immediately after encryption
- This cannot be undone - backup your wallet before encrypting
Returns: Success message with backup reminder
-
walletpassphrase- Unlock the encrypted wallet temporarilycurl -X POST http://127.0.0.1:8336 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"walletpassphrase","params":["YourSecurePassword123",300],"id":1}'
Parameters:
["password", timeout]or["password"]password- Your wallet passwordtimeout- Seconds to keep wallet unlocked (default: 60)
Unlocks the wallet for the specified duration. The wallet will automatically lock after the timeout expires. While unlocked, you can:
- Generate new addresses
- Send transactions
- Register/update names
Security: Keys are loaded into memory while unlocked and cleared on lock.
-
walletlock- Lock the wallet immediatelycurl -X POST http://127.0.0.1:8336 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"walletlock","params":[],"id":1}'
Locks an encrypted wallet, removing all private keys from memory. The wallet must be unlocked again with
walletpassphrasebefore performing operations that require private keys.Security Best Practices:
- Use
walletlockimmediately after completing sensitive operations - Set short timeouts (1-5 minutes) when using
walletpassphrase - Never store passwords in scripts or command history
- Use strong passwords (12+ characters recommended)
- Backup encrypted wallet file regularly
- Use
nmcd provides HTTP health check endpoints suitable for Kubernetes liveness and readiness probes, load balancers, and monitoring systems.
Health Endpoint (/health):
curl http://127.0.0.1:8336/healthReturns HTTP 200 OK when the daemon is running and initialized, or 503 Service Unavailable when initializing.
Response:
{
"status": "healthy",
"block_height": 500000,
"peers": 8,
"syncing": true
}The syncing field is optional (omitempty) and appears when the node is initializing or syncing blocks.
Use this endpoint for liveness probes to detect if the process is alive and responsive.
Readiness Endpoint (/ready):
curl http://127.0.0.1:8336/readyReturns HTTP 200 OK when the daemon is ready to serve requests (sync complete), or 503 Service Unavailable when syncing or initializing.
Response:
{
"status": "ready",
"block_height": 500000,
"peers": 8,
"syncing": false
}Use this endpoint for readiness probes to detect if the node is ready to handle traffic.
Kubernetes Example:
livenessProbe:
httpGet:
path: /health
port: 8336
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8336
initialDelaySeconds: 5
periodSeconds: 5Security Note: These endpoints do not require authentication and are intended for health checking systems. Bind the RPC server to localhost (default) or use network-level controls to restrict access.
nmcd can optionally expose metrics in Prometheus format for monitoring and observability. The metrics are served on a separate HTTP endpoint from the RPC server.
Enable Prometheus metrics:
# Enable on default port 9100
./nmcd -prometheusaddr=127.0.0.1:9100
# Or use custom port
./nmcd -prometheusaddr=127.0.0.1:9999Once enabled, metrics are available at http://<address>/metrics in Prometheus text format.
Security Considerations:
The Prometheus metrics endpoint does not implement authentication and exposes operational data about the node (e.g., block processing statistics and name operation counts). For production deployments, you should:
- Prefer binding
-prometheusaddrto127.0.0.1(localhost only), or - Place the endpoint behind a reverse proxy that provides authentication and TLS.
If you bind the metrics endpoint to a non-localhost network interface, use network-level controls (firewall rules, VPN, or restricted subnets) to allow access only from trusted monitoring systems.
Available Metrics:
Block Processing:
nmcd_blocks_processed_total- Total blocks processednmcd_blocks_accepted_total- Blocks accepted on main chainnmcd_blocks_orphaned_total- Orphaned blocks receivednmcd_blocks_rejected_total- Blocks rejected due to validation errorsnmcd_last_block_height- Height of last processed blocknmcd_avg_block_process_time_seconds- Average block processing time
Name Operations:
nmcd_name_operations_total- Total name operations processednmcd_name_new_total- NAME_NEW operationsnmcd_name_firstupdate_total- NAME_FIRSTUPDATE operationsnmcd_name_update_total- NAME_UPDATE operationsnmcd_names_expired_total- Names expired during processing
Network:
nmcd_peers_connected- Currently connected peersnmcd_inbound_peers- Current inbound peersnmcd_outbound_peers- Current outbound peersnmcd_peer_disconnects_total- Total peer disconnections
Transactions:
nmcd_txs_processed_total- Total transactions processednmcd_txs_in_mempool- Current transactions in mempool
Validation Errors:
nmcd_validation_errors_total- Total validation errorsnmcd_auxpow_errors_total- AuxPoW validation errorsnmcd_subsidy_errors_total- Block subsidy validation errorsnmcd_name_theft_attempts_total- Name theft attempts detectednmcd_double_spend_attempts_total- Double-spend attempts detected
Database Performance (New):
nmcd_namedb_size_bytes- Size of name database in bytesnmcd_namedb_read_latency_seconds- Average database read latencynmcd_namedb_write_latency_seconds- Average database write latency
RPC Performance (New):
nmcd_rpc_requests_total{method="METHOD"}- Total RPC requests by methodnmcd_rpc_duration_seconds{method="METHOD"}- Average RPC duration by method
Error Breakdown (New):
nmcd_errors_total{type="validation"}- Validation errorsnmcd_errors_total{type="network"}- Network errorsnmcd_errors_total{type="database"}- Database errors
Go Runtime (New):
nmcd_go_goroutines- Number of goroutinesnmcd_go_memstats_alloc_bytes- Bytes allocated and in usenmcd_go_memstats_heap_alloc_bytes- Heap bytes allocated and in usenmcd_go_memstats_heap_idle_bytes- Heap bytes waiting to be usednmcd_go_memstats_heap_inuse_bytes- Heap bytes that are in use
Example Prometheus Query:
curl http://127.0.0.1:9100/metricsPrometheus Configuration:
scrape_configs:
- job_name: 'nmcd'
static_configs:
- targets: ['localhost:9100']Grafana Dashboard:
The metrics can be visualized in Grafana. Key panels to consider:
- Block processing rate (rate of
nmcd_blocks_processed_total) - Peer count trends (
nmcd_peers_connected) - Name operation activity (rate of
nmcd_name_*_totalmetrics) - Validation error rates (rate of
nmcd_*_errors_totalmetrics) - Mempool size over time (
nmcd_txs_in_mempool) - Database performance (
nmcd_namedb_read_latency_seconds,nmcd_namedb_write_latency_seconds) - RPC performance by method (
rate(nmcd_rpc_requests_total[5m]),nmcd_rpc_duration_seconds) - Error breakdown by category (
nmcd_errors_totalgrouped by type label) - Memory usage (
nmcd_go_memstats_alloc_bytes,nmcd_go_memstats_heap_inuse_bytes) - Goroutine count (
nmcd_go_goroutines)
Example Queries:
# Top 5 slowest RPC methods (with method label aggregation)
topk(5, avg by (method) (nmcd_rpc_duration_seconds))
# Error rate by category (per second, grouped by type)
sum by (type) (rate(nmcd_errors_total[5m]))
# Database read/write latency comparison
nmcd_namedb_read_latency_seconds
nmcd_namedb_write_latency_seconds
# RPC request rate by method
sum by (method) (rate(nmcd_rpc_requests_total[5m]))
The examples/ directory contains several working examples demonstrating library usage:
- simple_resolve: Basic name resolution with auto-detection
- embedded_client: Explicit embedded mode usage
- register_name: Two-step name registration (NAME_NEW → NAME_FIRSTUPDATE)
- update_name: Update existing name values
- list_names: Filter and paginate name listings
- namedb: Direct database operations
Run an example:
go run ./examples/simple_resolve d/example
go run ./examples/list_names --namespace=d/📚 For detailed walkthroughs, see docs/EXAMPLES.md
nmcd includes basic wallet functionality for managing name operations. The wallet stores private keys in wallet.json within the data directory.
Security Note: The wallet file contains unencrypted private keys. Ensure proper file permissions (0600) and secure the data directory.
Library Usage: When using nmcd as a library, the wallet is automatically initialized in the data directory. Use DisableWallet: true in the config to disable wallet functionality if you only need name resolution.
Best For:
- 🔍 DNS resolvers and proxies
- 🌐 Web applications with Namecoin integration
- 🤖 Bots and monitoring tools
- 📱 Mobile/desktop applications (future)
- 🔬 Research and experimentation
Example Applications:
- DNS bridge resolving Namecoin domains to IP addresses
- Identity verification service using id/ namespace
- Domain monitoring service with expiration alerts
- Decentralized website hosting with d/ namespace
Best For:
- 🖥️ Shared infrastructure serving multiple applications
- 🔧 Development and testing environments
- 📊 Blockchain explorers and analytics
- 🔌 Legacy applications using RPC interface
Example Setups:
- Central Namecoin node serving multiple microservices
- Development server for application testing
- Network monitoring and statistics collection
- github.com/btcsuite/btcd/blockchain - Blockchain management
- github.com/btcsuite/btcd/peer - P2P peer management
- github.com/btcsuite/btcd/wire - Wire protocol
- go.etcd.io/bbolt - Embedded database
- Composition over Reimplementation: Use btcd libraries directly
- Standard Library: net/http for RPC, no web frameworks
- Interface Types: net.Conn not concrete *net.TCPConn
- Thread Safety: Mutex protection for all shared state
- Minimal Code: Focus on name-specific functionality only
The implementation supports three name operations:
- NAME_NEW: Pre-register a name (prevents front-running)
- NAME_FIRSTUPDATE: First registration of a name
- NAME_UPDATE: Update existing name value
Names expire after 36000 blocks (~250 days) and must be renewed.
Namecoin does not have a separate NAME_DELETE operation. To delete a name, use NAME_UPDATE with an empty value:
// Delete a name by setting empty value
result, err := nc.UpdateName(ctx, "d/mysite", "", nil)This effectively removes the name's data while maintaining ownership on the blockchain. The name will still expire after 36,000 blocks unless renewed.
nmcd/
├── client/ # 🔧 Library public API (import this!)
│ ├── types.go # NameClient interface and types
│ ├── embedded.go # In-process embedded client
│ ├── daemon.go # RPC daemon client
│ └── *_test.go # Comprehensive test suite
│
├── cmd/nmcd/ # Daemon binary entry point
│ └── main.go # CLI flags and daemon setup
│
├── cmd/permamail/ # 📧 Permamail CLI tool
│ └── main.go # Email forwarding management
│
├── internal/ # Internal packages (not importable)
│ └── server/ # Daemon server implementation
│
├── bridge/ # Email forwarding bridge adapter
├── mail/ # SMTP routing and relay
├── namedb/ # Name database (bbolt)
├── chain/ # Blockchain wrapper (btcd integration)
├── network/ # P2P networking (btcd/peer)
├── rpc/ # JSON-RPC server (daemon mode)
├── wallet/ # Basic wallet functionality
├── config/ # Network configuration
│
├── docs/ # 📚 Documentation
│ ├── API.md # Complete API reference
│ ├── EMBEDDING.md # Integration guide
│ ├── EXAMPLES.md # Example walkthroughs
│ ├── MODES.md # Mode comparison
│ └── PERFORMANCE.md # Optimization tips
│
├── examples/ # 🎯 Working code examples
│ ├── simple_resolve/ # Basic name resolution
│ ├── embedded_client/ # Embedded mode demo
│ ├── register_name/ # Name registration
│ ├── update_name/ # Name updates
│ ├── list_names/ # Name filtering
│ ├── bridge_adapter/ # Email bridge usage
│ ├── mail_router/ # Email routing example
│ ├── smtp_relay/ # SMTP relay deployment
│ └── namedb/ # Direct database access
│
└── README.md # This file
Import Paths:
// Primary library interface
import "github.com/opd-ai/nmcd/client"
// For advanced usage (typically not needed)
import "github.com/opd-ai/nmcd/namedb"
import "github.com/opd-ai/nmcd/config"nmcd includes permamail, a command-line tool for managing decentralized email forwarding via Namecoin. It allows you to register .bit email addresses that forward to your real email address.
# Build both nmcd and permamail
make build
# Or build permamail only
go build -o permamail ./cmd/permamail# Register a new .bit email address
permamail register alice --forward user@gmail.com
# Update forwarding configuration with backup
permamail update alice --forward newemail@proton.me --backup backup@proton.me
# Look up current configuration
permamail lookup alice
# Start SMTP relay server
# Note: Avoid passing SMTP passwords directly on the command line, as they
# may be visible to other local users via process listings (ps, /proc).
# Consider using environment variables or a config file with restricted permissions.
permamail serve --upstream smtp.sendgrid.net --upstreamport 587 \
--smtpuser apikey --smtppass <api-key>Permamail consists of three main components:
- Bridge Adapter (
bridge/): Translates Namecoin name records to email forwarding configuration - Mail Router (
mail/router.go): Routes .bit addresses to real email addresses with caching - SMTP Relay (
mail/smtp.go): Accepts mail to .bit addresses and forwards to real inboxes
The permamail CLI integrates these components into a single tool for managing email forwarding.
Email forwarding is stored in Namecoin name values as JSON:
{
"email": "user@gmail.com",
"backup": ["backup@proton.me"],
"pubkey": "base64_encoded_public_key"
}To run a production SMTP relay that forwards .bit emails:
# Start relay on port 2525, forwarding via Gmail
permamail serve --listen :2525 \
--upstream smtp.gmail.com \
--upstreamport 587 \
--smtpuser your.email@gmail.com \
--smtppass your-app-password
# Users can now send email to alice@mail.bit
# The relay will resolve alice -> user@gmail.com and forwardNote: Currently, name registration and updates require a running nmcd node with wallet enabled. The register and update commands prepare the configuration and display instructions for completing the operation via nmcd RPC. Full integrated wallet support is planned for future releases.
See examples/smtp_relay/ for a complete production-ready SMTP relay deployment with systemd integration.
Authentication:
- Use
-rpcuserand-rpcpasswordto require HTTP Basic Authentication for all RPC requests - Constant-time comparison prevents timing attacks on credentials
Rate Limiting:
- Per-IP rate limiting using token bucket algorithm (default: 100 tokens/minute refill rate)
- Allows burst of up to 100 requests, then continuous refill at 100 tokens/minute
- Configurable via
Config.RateLimitwhen using as a library - Automatic cleanup of stale IP tracking entries
Request Size Limits:
- Maximum request body size enforced (default: 1MB)
- Configurable via
Config.MaxRequestSizewhen using as a library - Early rejection prevents memory exhaustion attacks
Security Headers:
X-Content-Type-Options: nosniff- Prevents MIME type sniffingX-Frame-Options: DENY- Prevents clickjacking attacksContent-Security-Policy: default-src 'none'- Restricts resource loading
Example RPC Server Configuration:
server, err := rpc.NewServer(&rpc.Config{
Blockchain: blockchain,
PeerMgr: peerMgr,
Wallet: wallet,
ListenAddr: "127.0.0.1:8336",
RPCUser: "myuser",
RPCPassword: "mypassword",
RateLimit: 100, // requests per minute (0 = use default)
MaxRequestSize: 1024 * 1024, // 1MB (0 = use default)
})- All name operations are validated before blockchain processing
- Names must be unique and unexpired
- Value size limits enforced (1023 bytes)
- Name length limits enforced (1-255 characters)
- 📖 Documentation: Start with docs/EXAMPLES.md for guided walkthroughs
- 💡 API Reference: See docs/API.md for complete method signatures
- 🔧 Integration: Check docs/EMBEDDING.md for integration patterns
- ⚡ Performance: Read docs/PERFORMANCE.md for optimization tips
- 🐛 Issues: Report bugs on GitHub Issues
nmcd has comprehensive test coverage across all packages:
# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run tests with race detector
go test -race ./...
# Generate HTML coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.htmlCritical Packages:
- chain: 68.1% (core blockchain and name validation)
- rpc: 45.8% (RPC server and methods)
- network: 43.5% (P2P networking and mempool)
- namedb: 87.3% ✅ (name database operations)
Other Packages:
- bridge: 100.0% ✅ (email bridge)
- client: 82.9% ✅ (client library)
- config: 98.6% ✅ (configuration)
- metrics: 83.9% ✅ (Prometheus metrics)
- wallet: 69.7% (wallet operations)
Note: Command-line entry points (cmd/*) and integration components have lower coverage by design, as they primarily wire together well-tested components.
📊 Detailed Coverage Analysis: See docs/development/COVERAGE.md for comprehensive coverage analysis and improvement roadmap.
To build nmcd from source, you need Go 1.24 or later:
# Clone the repository
git clone https://github.com/opd-ai/nmcd
cd nmcd
# Build the binary
make build
# Or build with custom version
go build -ldflags="-X main.version=1.0.0" ./cmd/nmcdnmcd provides automated binary releases for multiple platforms. Releases are triggered when a version tag is pushed:
Supported Platforms:
- Linux: amd64, arm64
- macOS: amd64 (Intel), arm64 (Apple Silicon)
- Windows: amd64
Download Options:
-
Pre-built Binaries: Download from GitHub Releases
- All binaries include SHA256 checksums for verification
- Extract and run directly (no installation required)
-
Docker Images: Multi-architecture images available on GitHub Container Registry
# Pull latest version docker pull ghcr.io/opd-ai/nmcd:latest # Run nmcd in Docker, exposing RPC only on localhost docker run -p 127.0.0.1:8336:8336 -v nmcd-data:/data ghcr.io/opd-ai/nmcd:latest # Pull specific version docker pull ghcr.io/opd-ai/nmcd:1.0.0
Docker images are optimized with multi-stage builds and compressed to <100MB.
Security note: The JSON-RPC interface is sensitive. Before exposing port
8336beyond localhost (for example by using-p 8336:8336or binding to a non-loopback address), configure strong RPC credentials via-rpcuserand-rpcpassword(or enforce equivalent network access controls such as a firewall, VPN, or TLS-terminating reverse proxy) to prevent unauthorized access.
Verifying Downloads:
# Verify SHA256 checksum (Linux/macOS)
sha256sum -c nmcd-linux-amd64.sha256
# Or manually compare
sha256sum nmcd-linux-amd64
cat nmcd-linux-amd64.sha256Contributions are welcome! Areas of interest:
- Examples: Add new example applications showcasing library usage
- Documentation: Improve guides, add tutorials, fix typos
- Testing: Expand test coverage, add integration tests
- Features: Implement missing Namecoin protocol features
- Performance: Optimize hot paths, reduce memory usage
Please ensure:
- Code follows Go best practices (
go fmt,go vet) - All tests pass (
make test) - Documentation is updated for API changes
- Examples are updated if public API changes
See LICENSE file for details.