133 lines
5.5 KiB
C
133 lines
5.5 KiB
C
// NIP-13 Proof of Work validation module
|
|
#include <stdio.h>
|
|
#include "debug.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
#include "../nostr_core_lib/cjson/cJSON.h"
|
|
#include "../nostr_core_lib/nostr_core/nostr_core.h"
|
|
#include "../nostr_core_lib/nostr_core/nip013.h"
|
|
#include "config.h"
|
|
|
|
|
|
// Configuration functions from config.c
|
|
extern int get_config_bool(const char* key, int default_value);
|
|
extern int get_config_int(const char* key, int default_value);
|
|
extern const char* get_config_value(const char* key);
|
|
|
|
// Initialize PoW configuration using configuration system
|
|
void init_pow_config() {
|
|
// Configuration is now handled directly through database queries
|
|
// No cache initialization needed
|
|
}
|
|
|
|
// Validate event Proof of Work according to NIP-13
|
|
int validate_event_pow(cJSON* event, char* error_message, size_t error_size) {
|
|
// Get PoW configuration directly from database
|
|
int enabled = get_config_bool("pow_enabled", 1);
|
|
int min_pow_difficulty = get_config_int("pow_min_difficulty", 0);
|
|
const char* pow_mode = get_config_value("pow_mode");
|
|
|
|
// Determine validation flags based on mode
|
|
int validation_flags = NOSTR_POW_VALIDATE_BASIC; // Default
|
|
if (pow_mode) {
|
|
if (strcmp(pow_mode, "strict") == 0) {
|
|
validation_flags = NOSTR_POW_VALIDATE_ANTI_SPAM | NOSTR_POW_STRICT_FORMAT;
|
|
} else if (strcmp(pow_mode, "full") == 0) {
|
|
validation_flags = NOSTR_POW_VALIDATE_FULL;
|
|
} else if (strcmp(pow_mode, "basic") == 0) {
|
|
validation_flags = NOSTR_POW_VALIDATE_BASIC;
|
|
} else if (strcmp(pow_mode, "disabled") == 0) {
|
|
enabled = 0;
|
|
}
|
|
free((char*)pow_mode);
|
|
}
|
|
|
|
if (!enabled) {
|
|
return 0; // PoW validation disabled
|
|
}
|
|
|
|
if (!event) {
|
|
snprintf(error_message, error_size, "pow: null event");
|
|
return NOSTR_ERROR_INVALID_INPUT;
|
|
}
|
|
|
|
// If min_pow_difficulty is 0, only validate events that have nonce tags
|
|
// This allows events without PoW when difficulty requirement is 0
|
|
if (min_pow_difficulty == 0) {
|
|
cJSON* tags = cJSON_GetObjectItem(event, "tags");
|
|
int has_nonce_tag = 0;
|
|
|
|
if (tags && cJSON_IsArray(tags)) {
|
|
cJSON* tag = NULL;
|
|
cJSON_ArrayForEach(tag, tags) {
|
|
if (cJSON_IsArray(tag) && cJSON_GetArraySize(tag) >= 2) {
|
|
cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
|
|
if (cJSON_IsString(tag_name)) {
|
|
const char* name = cJSON_GetStringValue(tag_name);
|
|
if (name && strcmp(name, "nonce") == 0) {
|
|
has_nonce_tag = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If no minimum difficulty required and no nonce tag, skip PoW validation
|
|
if (!has_nonce_tag) {
|
|
return 0; // Accept event without PoW when min_difficulty=0
|
|
}
|
|
}
|
|
|
|
// Perform PoW validation using nostr_core_lib
|
|
nostr_pow_result_t pow_result;
|
|
int validation_result = nostr_validate_pow(event, min_pow_difficulty,
|
|
validation_flags, &pow_result);
|
|
|
|
if (validation_result != NOSTR_SUCCESS) {
|
|
// Handle specific error cases with appropriate messages
|
|
switch (validation_result) {
|
|
case NOSTR_ERROR_NIP13_INSUFFICIENT:
|
|
snprintf(error_message, error_size,
|
|
"pow: insufficient difficulty: %d < %d",
|
|
pow_result.actual_difficulty, min_pow_difficulty);
|
|
DEBUG_WARN("Event rejected: insufficient PoW difficulty");
|
|
break;
|
|
case NOSTR_ERROR_NIP13_NO_NONCE_TAG:
|
|
// This should not happen with min_difficulty=0 after our check above
|
|
if (min_pow_difficulty > 0) {
|
|
snprintf(error_message, error_size, "pow: missing required nonce tag");
|
|
DEBUG_WARN("Event rejected: missing nonce tag");
|
|
} else {
|
|
return 0; // Allow when min_difficulty=0
|
|
}
|
|
break;
|
|
case NOSTR_ERROR_NIP13_INVALID_NONCE_TAG:
|
|
snprintf(error_message, error_size, "pow: invalid nonce tag format");
|
|
DEBUG_WARN("Event rejected: invalid nonce tag format");
|
|
break;
|
|
case NOSTR_ERROR_NIP13_TARGET_MISMATCH:
|
|
snprintf(error_message, error_size,
|
|
"pow: committed target (%d) lower than minimum (%d)",
|
|
pow_result.committed_target, min_pow_difficulty);
|
|
DEBUG_WARN("Event rejected: committed target too low (anti-spam protection)");
|
|
break;
|
|
case NOSTR_ERROR_NIP13_CALCULATION:
|
|
snprintf(error_message, error_size, "pow: difficulty calculation failed");
|
|
DEBUG_ERROR("PoW difficulty calculation error");
|
|
break;
|
|
case NOSTR_ERROR_EVENT_INVALID_ID:
|
|
snprintf(error_message, error_size, "pow: invalid event ID format");
|
|
DEBUG_WARN("Event rejected: invalid event ID for PoW calculation");
|
|
break;
|
|
default:
|
|
snprintf(error_message, error_size, "pow: validation failed - %s",
|
|
strlen(pow_result.error_detail) > 0 ? pow_result.error_detail : "unknown error");
|
|
DEBUG_WARN("Event rejected: PoW validation failed");
|
|
}
|
|
return validation_result;
|
|
}
|
|
|
|
return 0; // Success
|
|
} |