Laan Tungir 38eb721ae8 Fix relay pool zombie connections: reconnect logic, health monitoring, state sync
The relay pool had the same class of bugs as the C lib's relay pool
(fixed there in core_relay_pool.c), plus a few unique ones:

1. No reconnection at all. ReconnectConfig was defined and stored but
   never read — dead configuration. The run() event loop skipped
   non-connected relays forever; once a relay dropped, it never came
   back. Now run() attempts reconnection of any non-connected relay
   after exponential backoff (initial 1s, x2, max 60s, reset after 60s
   stable), honoring max_reconnect_attempts.

2. send_text()/ping() failures left the ws state as Connected (same
   bug as the C lib). A relay that dropped the TCP connection kept
   reporting Connected and every publish silently failed. Both now
   set state to Error on failure.

3. Error-state trap: subscribe() and publish_async() only auto-
   connected from Disconnected, but receive_text() sets Error on
   transport failure — so a relay that died mid-session was stuck
   permanently, even for publishing. Both now reconnect from any
   non-Connected state.

4. Stale RelayEntry.status: set to Disconnected in add_relay() and
   never updated again, so list_relays() reported Disconnected for
   relays connected for days. run() now syncs pool status from the
   live ws state each iteration.

5. No health monitoring: PING_INTERVAL_SECS was defined but unused,
   ping_latency stats never populated, half-open connections never
   probed. run() now sends pings on the configured interval, detects
   pong timeouts and ping-send failures, and force-closes dead
   transports so the reconnect path picks them up.

Tests: 5 new tests (backoff calculation with default and custom
configs, initial status, connect-failure Error state, entry defaults).
Full workspace suite passes: 210 tests, 0 failures.
2026-08-27 07:10:39 -04:00
2026-08-13 12:42:40 -04:00
2026-08-13 12:42:40 -04:00
2026-08-13 12:42:40 -04:00
2026-08-19 15:40:29 -04:00
2026-08-19 15:40:29 -04:00
2026-08-19 15:40:29 -04:00
2026-08-19 15:40:29 -04:00

NOSTR Core Library — Rust

A Rust implementation of the NOSTR protocol library, ported from the C nostr_core_lib project.

Version License Build Status

📋 NIP Implementation Status

Core Protocol NIPs

  • NIP-01 — Basic protocol flow — event creation, signing, and validation
  • NIP-02 — Contact List and Petnames
  • NIP-03 — OpenTimestamps Attestations for Events
  • NIP-04 — Encrypted Direct Messages (legacy)
  • NIP-05 — Mapping Nostr keys to DNS-based internet identifiers
  • NIP-06 — Basic key derivation from mnemonic seed phrase
  • NIP-07 — window.nostr capability for web browsers
  • NIP-08 — Handling Mentions
  • NIP-09 — Event Deletion
  • NIP-10 — Conventions for clients' use of e and p tags in text events
  • NIP-11 — Relay Information Document
  • NIP-12 — Generic Tag Queries
  • NIP-13 — Proof of Work
  • NIP-14 — Subject tag in text events
  • NIP-15 — Nostr Marketplace
  • NIP-16 — Event Treatment
  • NIP-17 — Private Direct Messages
  • NIP-18 — Reposts
  • NIP-19 — bech32-encoded entities
  • NIP-20 — Command Results
  • NIP-21 — nostr: URI scheme
  • NIP-22 — Event created_at Limits
  • NIP-23 — Long-form Content
  • NIP-24 — Extra metadata fields and tags
  • NIP-25 — Reactions
  • NIP-26 — Delegated Event Signing
  • NIP-27 — Text Note References
  • NIP-28 — Public Chat
  • NIP-29 — Relay-based Groups
  • NIP-30 — Custom Emoji
  • NIP-31 — Dealing with Unknown Events
  • NIP-32 — Labeling
  • NIP-33 — Parameterized Replaceable Events
  • NIP-34 — git stuff
  • NIP-35 — Torrents
  • NIP-36 — Sensitive Content
  • NIP-37 — Draft Events
  • NIP-38 — User Statuses
  • NIP-39 — External Identities in Profiles
  • NIP-40 — Expiration Timestamp
  • NIP-42 — Authentication of clients to relays
  • NIP-44 — Versioned Encryption
  • NIP-45 — Counting results
  • NIP-46 — Nostr Remote Signing
  • NIP-47 — Wallet Connect
  • NIP-48 — Proxy Tags
  • NIP-49 — Private Key Encryption
  • NIP-50 — Search Capability
  • NIP-51 — Lists
  • NIP-52 — Calendar Events
  • NIP-53 — Live Activities
  • NIP-54 — Wiki
  • NIP-55 — Android Signer Application
  • NIP-56 — Reporting
  • NIP-57 — Lightning Zaps
  • NIP-58 — Badges
  • NIP-59 — Gift Wrap
  • NIP-60 — Cashu Wallet
  • NIP-61 — Nutzaps
  • NIP-62 — Log events
  • NIP-64 — Chess (PGN)
  • NIP-65 — Relay List Metadata
  • NIP-66 — Relay Monitor
  • NIP-68 — Web badges
  • NIP-69 — Peer-to-peer Order events
  • NIP-70 — Protected Events
  • NIP-71 — Video Events
  • NIP-72 — Moderated Communities
  • NIP-73 — External Content IDs
  • NIP-75 — Zap Goals
  • NIP-77 — Arbitrary custom app data
  • NIP-78 — Application-specific data
  • NIP-84 — Highlights
  • NIP-86 — Relay Management API
  • NIP-87 — Relay List Recommendations
  • NIP-88 — Stella: A Stellar Relay
  • NIP-89 — Recommended Application Handlers
  • NIP-90 — Data Vending Machines
  • NIP-92 — Media Attachments
  • NIP-94 — File Metadata
  • NIP-96 — HTTP File Storage Integration
  • NIP-98 — HTTP Auth
  • NIP-99 — Classified Listings

Legend: ✅ Implemented | ❌ Not Implemented

Implementation Summary: 14 of 96+ NIPs fully implemented (14.6%)

Workspace Structure

nostr_core_lib_rust/
├── core/              # Core types, errors, crypto, utilities
├── relay/             # WebSocket, HTTP, relay pool
├── nips/              # All NIP implementations
├── signer/            # Signer trait, local + nsigner remote
├── services/          # Request validator, Blossom, Cashu
├── nostr-core/        # Umbrella re-export crate
├── examples/          # Example programs
│   ├── keypair_generator/  # Generate Nostr keypairs
│   └── event_signer/       # Create and sign events
└── tests/             # Integration tests (ported from C)

Building

# Build all crates
cargo build

# Build release binaries
cargo build --release

# Run all tests (202 total)
cargo test --workspace

Usage

Generate a keypair

cargo run -p keypair-generator

Sign a text note

cargo run -p event-signer -- nsec1... "Hello, Nostr!"

Use as a library dependency

Add to your Cargo.toml:

[dependencies]
nostr-core = { git = "ssh://git@laantungir.net:2222/laantungir/nostr_core_lib_rust.git" }

Test Summary

Crate Tests Description
nostr-core 34 Types, errors, crypto, utilities
nostr-nips 68 All 14 NIP implementations
nostr-relay 8 WebSocket, HTTP, relay pool
nostr-signer 23 Signer trait, local + nsigner
nostr-services 31 Validator, Blossom, Cashu
integration-tests 38 Ported from C test suite
Total 202

Versioning

This project uses Semantic Versioning with a single source of truth in the VERSION file. The workspace version in Cargo.toml and the badge in README.md are kept in sync by the increment_and_push.sh script.

Releasing a new version

# Patch bump (bug fixes): 0.2.0 → 0.2.1
./increment_and_push.sh patch

# Minor bump (new features): 0.2.0 → 0.3.0
./increment_and_push.sh minor

# Major bump (breaking changes): 0.2.0 → 1.0.0
./increment_and_push.sh major

# Prerelease bump: 0.2.0 → 0.2.0-pre.1
./increment_and_push.sh prerelease

# Set an explicit version
./increment_and_push.sh 1.2.3

# Preview without modifying files or git
./increment_and_push.sh minor --dry-run

# Bump without pushing to origin
./increment_and_push.sh patch no-push

The script:

  1. Reads the current version from VERSION.
  2. Computes the next version per the requested bump type.
  3. Updates VERSION, the workspace version in Cargo.toml, and the badge in README.md.
  4. Moves the [Unreleased] section in CHANGELOG.md to the new version with today's date.
  5. Verifies the workspace still builds with cargo build --workspace.
  6. Creates a [release] vX.Y.Z commit and an annotated vX.Y.Z git tag.
  7. Pushes the branch and tag to origin (unless no-push).

Changelog

See CHANGELOG.md for a record of notable changes per release. Follow the Keep a Changelog format when adding entries under [Unreleased].

License

MIT

S
Description
No description provided
Readme
627 MiB
Languages
Rust 97.3%
Shell 2.7%