v0.7.14 - Remove unified config cache system and fix first-time startup - All config values now queried directly from database, eliminating cache inconsistency bugs. Fixed startup sequence to use output parameters for pubkey passing.

This commit is contained in:
Your Name
2025-10-13 19:06:27 -04:00
parent 62e17af311
commit 670329700c
13 changed files with 377 additions and 1799 deletions

View File

@@ -1,358 +0,0 @@
# Event-Based Configuration System Implementation Plan
## Overview
This document provides a detailed implementation plan for transitioning the C Nostr Relay from command line arguments and file-based configuration to a pure event-based configuration system using kind 33334 Nostr events stored directly in the database.
## Implementation Phases
### Phase 0: File Structure Preparation ✅ COMPLETED
#### 0.1 Backup and Prepare Files ✅ COMPLETED
**Actions:**
1. ✅ Rename `src/config.c` to `src/config.c.old` - DONE
2. ✅ Rename `src/config.h` to `src/config.h.old` - DONE
3. ✅ Create new empty `src/config.c` and `src/config.h` - DONE
4. ✅ Create new `src/default_config_event.h` - DONE
### Phase 1: Database Schema and Core Infrastructure ✅ COMPLETED
#### 1.1 Update Database Naming System ✅ COMPLETED
**File:** `src/main.c`, new `src/config.c`, new `src/config.h`
```c
// New functions implemented: ✅
char* get_database_name_from_relay_pubkey(const char* relay_pubkey);
int create_database_with_relay_pubkey(const char* relay_pubkey);
```
**Changes Completed:**
- ✅ Create completely new `src/config.c` and `src/config.h` files
- ✅ Rename old files to `src/config.c.old` and `src/config.h.old`
- ✅ Modify `init_database()` to use relay pubkey for database naming
- ✅ Use `nostr_core_lib` functions for all keypair generation
- ✅ Database path: `./<relay_pubkey>.nrdb`
- ✅ Remove all database path command line argument handling
#### 1.2 Configuration Event Storage ✅ COMPLETED
**File:** new `src/config.c`, new `src/default_config_event.h`
```c
// Configuration functions implemented: ✅
int store_config_event_in_database(const cJSON* event);
cJSON* load_config_event_from_database(const char* relay_pubkey);
```
**Changes Completed:**
- ✅ Create new `src/default_config_event.h` for default configuration values
- ✅ Add functions to store/retrieve kind 33334 events from events table
- ✅ Use `nostr_core_lib` functions for all event validation
- ✅ Clean separation: default config values isolated in header file
- ✅ Remove existing config table dependencies
### Phase 2: Event Processing Integration ✅ COMPLETED
#### 2.1 Real-time Configuration Processing ✅ COMPLETED
**File:** `src/main.c` (event processing functions)
**Integration Points:** ✅ IMPLEMENTED
```c
// In existing event processing loop: ✅ IMPLEMENTED
// Added kind 33334 event detection in main event loop
if (kind_num == 33334) {
if (handle_configuration_event(event, error_message, sizeof(error_message)) == 0) {
// Configuration event processed successfully
}
}
// Configuration event processing implemented: ✅
int process_configuration_event(const cJSON* event);
int handle_configuration_event(cJSON* event, char* error_message, size_t error_size);
```
#### 2.2 Configuration Application System ⚠️ PARTIALLY COMPLETED
**File:** `src/config.c`
**Status:** Configuration access functions implemented, field handlers need completion
```c
// Configuration access implemented: ✅
const char* get_config_value(const char* key);
int get_config_int(const char* key, int default_value);
int get_config_bool(const char* key, int default_value);
// Field handlers need implementation: ⏳ IN PROGRESS
// Need to implement specific apply functions for runtime changes
```
### Phase 3: First-Time Startup System ✅ COMPLETED
#### 3.1 Key Generation and Initial Setup ✅ COMPLETED
**File:** new `src/config.c`, `src/default_config_event.h`
**Status:** ✅ FULLY IMPLEMENTED with secure /dev/urandom + nostr_core_lib validation
```c
int first_time_startup_sequence() {
// 1. Generate admin keypair using nostr_core_lib
unsigned char admin_privkey_bytes[32];
char admin_privkey[65], admin_pubkey[65];
if (nostr_generate_private_key(admin_privkey_bytes) != 0) {
return -1;
}
nostr_bytes_to_hex(admin_privkey_bytes, 32, admin_privkey);
unsigned char admin_pubkey_bytes[32];
if (nostr_ec_public_key_from_private_key(admin_privkey_bytes, admin_pubkey_bytes) != 0) {
return -1;
}
nostr_bytes_to_hex(admin_pubkey_bytes, 32, admin_pubkey);
// 2. Generate relay keypair using nostr_core_lib
unsigned char relay_privkey_bytes[32];
char relay_privkey[65], relay_pubkey[65];
if (nostr_generate_private_key(relay_privkey_bytes) != 0) {
return -1;
}
nostr_bytes_to_hex(relay_privkey_bytes, 32, relay_privkey);
unsigned char relay_pubkey_bytes[32];
if (nostr_ec_public_key_from_private_key(relay_privkey_bytes, relay_pubkey_bytes) != 0) {
return -1;
}
nostr_bytes_to_hex(relay_pubkey_bytes, 32, relay_pubkey);
// 3. Create database with relay pubkey name
if (create_database_with_relay_pubkey(relay_pubkey) != 0) {
return -1;
}
// 4. Create initial configuration event using defaults from header
cJSON* config_event = create_default_config_event(admin_privkey_bytes, relay_privkey, relay_pubkey);
// 5. Store configuration event in database
store_config_event_in_database(config_event);
// 6. Print admin private key for user to save
printf("=== SAVE THIS ADMIN PRIVATE KEY ===\n");
printf("Admin Private Key: %s\n", admin_privkey);
printf("===================================\n");
return 0;
}
```
#### 3.2 Database Detection Logic ✅ COMPLETED
**File:** `src/main.c`
**Status:** ✅ FULLY IMPLEMENTED
```c
// Implemented functions: ✅
char** find_existing_nrdb_files(void);
char* extract_pubkey_from_filename(const char* filename);
int is_first_time_startup(void);
int first_time_startup_sequence(void);
int startup_existing_relay(const char* relay_pubkey);
```
### Phase 4: Legacy System Removal ✅ PARTIALLY COMPLETED
#### 4.1 Remove Command Line Arguments ✅ COMPLETED
**File:** `src/main.c`
**Status:** ✅ COMPLETED
- ✅ All argument parsing logic removed except --help and --version
-`--port`, `--config-dir`, `--config-file`, `--database-path` handling removed
- ✅ Environment variable override systems removed
- ✅ Clean help and version functions implemented
#### 4.2 Remove Configuration File System ✅ COMPLETED
**File:** `src/config.c`
**Status:** ✅ COMPLETED - New file created from scratch
- ✅ All legacy file-based configuration functions removed
- ✅ XDG configuration directory logic removed
- ✅ Pure event-based system implemented
#### 4.3 Remove Legacy Database Tables ⏳ PENDING
**File:** `src/sql_schema.h`
**Status:** ⏳ NEEDS COMPLETION
```sql
-- Still need to remove these tables:
DROP TABLE IF EXISTS config;
DROP TABLE IF EXISTS config_history;
DROP TABLE IF EXISTS config_file_cache;
DROP VIEW IF EXISTS active_config;
```
### Phase 5: Configuration Management
#### 5.1 Configuration Field Mapping
**File:** `src/config.c`
```c
// Map configuration tags to current system
static const config_field_handler_t config_handlers[] = {
{"auth_enabled", 0, apply_auth_enabled},
{"relay_port", 1, apply_relay_port}, // requires restart
{"max_connections", 0, apply_max_connections},
{"relay_description", 0, apply_relay_description},
{"relay_contact", 0, apply_relay_contact},
{"relay_pubkey", 1, apply_relay_pubkey}, // requires restart
{"relay_privkey", 1, apply_relay_privkey}, // requires restart
{"pow_min_difficulty", 0, apply_pow_difficulty},
{"nip40_expiration_enabled", 0, apply_expiration_enabled},
{"max_subscriptions_per_client", 0, apply_max_subscriptions},
{"max_event_tags", 0, apply_max_event_tags},
{"max_content_length", 0, apply_max_content_length},
{"default_limit", 0, apply_default_limit},
{"max_limit", 0, apply_max_limit},
// ... etc
};
```
#### 5.2 Startup Configuration Loading
**File:** `src/main.c`
```c
int startup_existing_relay(const char* relay_pubkey) {
// 1. Open database
if (init_database_with_pubkey(relay_pubkey) != 0) {
return -1;
}
// 2. Load configuration event from database
cJSON* config_event = load_config_event_from_database(relay_pubkey);
if (!config_event) {
log_error("No configuration event found in database");
return -1;
}
// 3. Apply all configuration from event
if (apply_configuration_from_event(config_event) != 0) {
return -1;
}
// 4. Continue with normal startup
return start_relay_services();
}
```
## Implementation Order - PROGRESS STATUS
### Step 1: Core Infrastructure ✅ COMPLETED
1. ✅ Implement database naming with relay pubkey
2. ✅ Add key generation functions using `nostr_core_lib`
3. ✅ Create configuration event storage/retrieval functions
4. ✅ Test basic event creation and storage
### Step 2: Event Processing Integration ✅ MOSTLY COMPLETED
1. ✅ Add kind 33334 event detection to event processing loop
2. ✅ Implement configuration event validation
3. ⚠️ Create configuration application handlers (basic access implemented, runtime handlers pending)
4. ⏳ Test real-time configuration updates (infrastructure ready)
### Step 3: First-Time Startup ✅ COMPLETED
1. ✅ Implement first-time startup detection
2. ✅ Add automatic key generation and database creation
3. ✅ Create default configuration event generation
4. ✅ Test complete first-time startup flow
### Step 4: Legacy Removal ⚠️ MOSTLY COMPLETED
1. ✅ Remove command line argument parsing
2. ✅ Remove configuration file system
3. ⏳ Remove legacy database tables (pending)
4. ✅ Update all references to use event-based config
### Step 5: Testing and Validation ⚠️ PARTIALLY COMPLETED
1. ✅ Test complete startup flow (first time and existing)
2. ⏳ Test configuration updates via events (infrastructure ready)
3. ⚠️ Test error handling and recovery (basic error handling implemented)
4. ⏳ Performance testing and optimization (pending)
## Migration Strategy
### For Existing Installations
Since the new system uses a completely different approach:
1. **No Automatic Migration**: The new system starts fresh
2. **Manual Migration**: Users can manually copy configuration values
3. **Documentation**: Provide clear migration instructions
4. **Coexistence**: Old and new systems use different database names
### Migration Steps for Users
1. Stop existing relay
2. Note current configuration values
3. Start new relay (generates keys and new database)
4. Create kind 33334 event with desired configuration using admin private key
5. Send event to relay to update configuration
## Testing Requirements
### Unit Tests
- Key generation functions
- Configuration event creation and validation
- Database naming logic
- Configuration application handlers
### Integration Tests
- Complete first-time startup flow
- Configuration update via events
- Error handling scenarios
- Database operations
### Performance Tests
- Startup time comparison
- Configuration update response time
- Memory usage analysis
## Security Considerations
1. **Admin Private Key**: Never stored, only printed once
2. **Event Validation**: All configuration events must be signed by admin
3. **Database Security**: Relay database contains relay private key
4. **Key Generation**: Use `nostr_core_lib` for cryptographically secure generation
## Files to Modify
### Major Changes
- `src/main.c` - Startup logic, event processing, argument removal
- `src/config.c` - Complete rewrite for event-based configuration
- `src/config.h` - Update function signatures and structures
- `src/sql_schema.h` - Remove config tables
### Minor Changes
- `Makefile` - Remove any config file generation
- `systemd/` - Update service files if needed
- Documentation updates
## Backwards Compatibility
**Breaking Changes:**
- Command line arguments removed (except --help, --version)
- Configuration files no longer used
- Database naming scheme changed
- Configuration table removed
**Migration Required:** This is a breaking change that requires manual migration for existing installations.
## Success Criteria - CURRENT STATUS
1.**Zero Command Line Arguments**: Relay starts with just `./c-relay`
2.**Automatic First-Time Setup**: Generates keys and database automatically
3. ⚠️ **Real-Time Configuration**: Infrastructure ready, handlers need completion
4.**Single Database File**: All configuration and data in one `.nrdb` file
5. ⚠️ **Admin Control**: Event processing implemented, signature validation ready
6. ⚠️ **Clean Codebase**: Most legacy code removed, database tables cleanup pending
## Risk Mitigation
1. **Backup Strategy**: Document manual backup procedures for relay database
2. **Key Loss Recovery**: Document recovery procedures if admin key is lost
3. **Testing Coverage**: Comprehensive test suite before deployment
4. **Rollback Plan**: Keep old version available during transition period
5. **Documentation**: Comprehensive user and developer documentation
This implementation plan provides a clear path from the current system to the new event-based configuration architecture while maintaining security and reliability.

View File

@@ -1,128 +0,0 @@
# Startup Configuration Design Analysis
## Review of startup_config_design.md
### Key Design Principles Identified
1. **Zero Command Line Arguments**: Complete elimination of CLI arguments for true "quick start"
2. **Event-Based Configuration**: Configuration stored as Nostr event (kind 33334) in events table
3. **Self-Contained Database**: Database named after relay pubkey (`<pubkey>.nrdb`)
4. **First-Time Setup**: Automatic key generation and initial configuration creation
5. **Configuration Consistency**: Always read from event, never from hardcoded defaults
### Implementation Gaps and Specifications Needed
#### 1. Key Generation Process
**Specification:**
```
First Startup Key Generation:
1. Generate all keys on first startup (admin private/public, relay private/public)
2. Use nostr_core_lib for key generation entropy
3. Keys are encoded in hex format
4. Print admin private key to stdout for user to save (never stored)
5. Store admin public key, relay private key, and relay public key in configuration event
6. Admin can later change the 33334 event to alter stored keys
```
#### 2. Database Naming and Location
**Specification:**
```
Database Naming:
1. Database is named using relay pubkey: ./<relay_pubkey>.nrdb
2. Database path structure: ./<relay_pubkey>.nrdb
3. If database creation fails, program quits (can't run without database)
4. c_nostr_relay.db should never exist in new system
```
#### 3. Configuration Event Structure (Kind 33334)
**Specification:**
```
Event Structure:
- Kind: 33334 (parameterized replaceable event)
- Event validation: Use nostr_core_lib to validate event
- Event content field: "C Nostr Relay Configuration" (descriptive text)
- Configuration update mechanism: TBD
- Complete tag structure provided in configuration section below
```
#### 4. Configuration Change Monitoring
**Configuration Monitoring System:**
```
Every event that is received is checked to see if it is a kind 33334 event from the admin pubkey.
If so, it is processed as a configuration update.
```
#### 5. Error Handling and Recovery
**Specification:**
```
Error Recovery Priority:
1. Try to load latest valid config event
2. Generate new default configuration event if none exists
3. Exit with error if all recovery attempts fail
Note: There is only ever one configuration event (parameterized replaceable event),
so no fallback to previous versions.
```
### Design Clarifications
**Key Management:**
- Admin private key is never stored, only printed once at first startup
- Single admin system (no multi-admin support)
- No key rotation support
**Configuration Management:**
- No configuration versioning/timestamping
- No automatic backup of configuration events
- Configuration events are not broadcastable to other relays
- Future: Auth system to restrict admin access to configuration events
---
## Complete Current Configuration Structure
Based on analysis of [`src/config.c`](src/config.c:753-795), here is the complete current configuration structure that will be converted to event tags:
### Complete Event Structure Example
```json
{
"kind": 33334,
"created_at": 1725661483,
"tags": [
["d", "<relay_pubkey>"],
["auth_enabled", "false"],
["relay_port", "8888"],
["max_connections", "100"],
["relay_description", "High-performance C Nostr relay with SQLite storage"],
["relay_contact", ""],
["relay_pubkey", "<relay_public_key>"],
["relay_privkey", "<relay_private_key>"],
["relay_software", "https://git.laantungir.net/laantungir/c-relay.git"],
["relay_version", "v1.0.0"],
["pow_min_difficulty", "0"],
["pow_mode", "basic"],
["nip40_expiration_enabled", "true"],
["nip40_expiration_strict", "true"],
["nip40_expiration_filter", "true"],
["nip40_expiration_grace_period", "300"],
["max_subscriptions_per_client", "25"],
["max_total_subscriptions", "5000"],
["max_filters_per_subscription", "10"],
["max_event_tags", "100"],
["max_content_length", "8196"],
["max_message_length", "16384"],
["default_limit", "500"],
["max_limit", "5000"]
],
"content": "C Nostr Relay Configuration",
"pubkey": "<admin_public_key>",
"id": "<computed_event_id>",
"sig": "<event_signature>"
}
```
**Note:** The `admin_pubkey` tag is omitted as it's redundant with the event's `pubkey` field.