v0.1.18 - Auto-clean spent Cashu proofs in check_proofs, publish deletions, and add spent token events to kind-10000 ignore list
This commit is contained in:
@@ -55,11 +55,11 @@ Skills compose by adoption-list order (`10123`) and trigger tags carry runtime e
|
||||
|
||||
Didactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers.
|
||||
|
||||
## Current Status — v0.1.17
|
||||
## Current Status — v0.1.18
|
||||
|
||||
**Active build — this project is barely working. Experiment at your own risk.**
|
||||
|
||||
> Last release update: v0.1.17 — Fix Cashu v4 token field encoding (i bytes, s text, c bytes) and rebuild nostr_core_lib integration
|
||||
> Last release update: v0.1.18 — Auto-clean spent Cashu proofs in check_proofs, publish deletions, and add spent token events to kind-10000 ignore list
|
||||
|
||||
- Connects to configured relays with auto-reconnect and relay state transition logging
|
||||
- Publishes configured startup events per relay as each relay becomes connected
|
||||
|
||||
+79
-2
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "nostr_handler.h"
|
||||
#include "nostr_block_list.h"
|
||||
#include "../../nostr_core_lib/nostr_core/nostr_core.h"
|
||||
|
||||
#define CASHU_WALLET_QUERY_TIMEOUT_MS 6000
|
||||
@@ -1354,6 +1355,7 @@ int cashu_wallet_check_proofs(const char* mint_url, cJSON** out_json) {
|
||||
if (!resolved) return -1;
|
||||
|
||||
pthread_mutex_lock(&g_wallet.mutex);
|
||||
int token_count_snapshot = g_wallet.token_count;
|
||||
int target_proofs = 0;
|
||||
for (int i = 0; i < g_wallet.token_count; i++) {
|
||||
if (!g_wallet.tokens[i].token.mint_url || strcmp(g_wallet.tokens[i].token.mint_url, resolved) != 0) continue;
|
||||
@@ -1371,6 +1373,9 @@ int cashu_wallet_check_proofs(const char* mint_url, cJSON** out_json) {
|
||||
cJSON_AddNumberToObject(root, "proof_count", 0);
|
||||
cJSON_AddNumberToObject(root, "spent_count", 0);
|
||||
cJSON_AddNumberToObject(root, "unknown_count", 0);
|
||||
cJSON_AddNumberToObject(root, "deleted_token_events", 0);
|
||||
cJSON_AddNumberToObject(root, "ignored_token_events", 0);
|
||||
cJSON_AddNumberToObject(root, "remaining_balance", 0);
|
||||
*out_json = root;
|
||||
pthread_mutex_unlock(&g_wallet.mutex);
|
||||
return 0;
|
||||
@@ -1378,9 +1383,15 @@ int cashu_wallet_check_proofs(const char* mint_url, cJSON** out_json) {
|
||||
|
||||
const char** ys = (const char**)calloc((size_t)target_proofs, sizeof(char*));
|
||||
char (*y_hexes)[67] = (char(*)[67])calloc((size_t)target_proofs, sizeof(*y_hexes));
|
||||
if (!ys || !y_hexes) {
|
||||
int* proof_to_token_idx = (int*)calloc((size_t)target_proofs, sizeof(int));
|
||||
int* token_total_counts = (int*)calloc((size_t)token_count_snapshot, sizeof(int));
|
||||
int* token_spent_counts = (int*)calloc((size_t)token_count_snapshot, sizeof(int));
|
||||
if (!ys || !y_hexes || !proof_to_token_idx || !token_total_counts || !token_spent_counts) {
|
||||
free(ys);
|
||||
free(y_hexes);
|
||||
free(proof_to_token_idx);
|
||||
free(token_total_counts);
|
||||
free(token_spent_counts);
|
||||
pthread_mutex_unlock(&g_wallet.mutex);
|
||||
return -1;
|
||||
}
|
||||
@@ -1393,10 +1404,15 @@ int cashu_wallet_check_proofs(const char* mint_url, cJSON** out_json) {
|
||||
if (!secret || cashu_secret_to_y_hex(secret, y_hexes[y_idx]) != 0) {
|
||||
free(ys);
|
||||
free(y_hexes);
|
||||
free(proof_to_token_idx);
|
||||
free(token_total_counts);
|
||||
free(token_spent_counts);
|
||||
pthread_mutex_unlock(&g_wallet.mutex);
|
||||
return -1;
|
||||
}
|
||||
ys[y_idx] = y_hexes[y_idx];
|
||||
proof_to_token_idx[y_idx] = i;
|
||||
token_total_counts[i]++;
|
||||
y_idx++;
|
||||
}
|
||||
}
|
||||
@@ -1406,6 +1422,9 @@ int cashu_wallet_check_proofs(const char* mint_url, cJSON** out_json) {
|
||||
if (cashu_build_checkstate_request(ys, y_idx, &request_body) != 0 || !request_body) {
|
||||
free(ys);
|
||||
free(y_hexes);
|
||||
free(proof_to_token_idx);
|
||||
free(token_total_counts);
|
||||
free(token_spent_counts);
|
||||
cJSON_Delete(request_body);
|
||||
return -1;
|
||||
}
|
||||
@@ -1416,6 +1435,9 @@ int cashu_wallet_check_proofs(const char* mint_url, cJSON** out_json) {
|
||||
free(ys);
|
||||
free(y_hexes);
|
||||
if (rc != 0 || !response_body) {
|
||||
free(proof_to_token_idx);
|
||||
free(token_total_counts);
|
||||
free(token_spent_counts);
|
||||
cJSON_Delete(response_body);
|
||||
return -1;
|
||||
}
|
||||
@@ -1425,22 +1447,71 @@ int cashu_wallet_check_proofs(const char* mint_url, cJSON** out_json) {
|
||||
rc = cashu_parse_checkstate_response(response_body, &parsed);
|
||||
cJSON_Delete(response_body);
|
||||
if (rc != 0) {
|
||||
free(proof_to_token_idx);
|
||||
free(token_total_counts);
|
||||
free(token_spent_counts);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int spent_count = 0;
|
||||
int unknown_count = 0;
|
||||
for (int i = 0; i < parsed.state_count; i++) {
|
||||
int state_n = parsed.state_count < y_idx ? parsed.state_count : y_idx;
|
||||
for (int i = 0; i < state_n; i++) {
|
||||
if (strcasecmp(parsed.states[i].state, "SPENT") == 0) {
|
||||
spent_count++;
|
||||
int token_idx = proof_to_token_idx[i];
|
||||
if (token_idx >= 0 && token_idx < token_count_snapshot) {
|
||||
token_spent_counts[token_idx]++;
|
||||
}
|
||||
} else if (strcasecmp(parsed.states[i].state, "UNSPENT") != 0) {
|
||||
unknown_count++;
|
||||
}
|
||||
}
|
||||
|
||||
int deleted_token_events = 0;
|
||||
int ignored_token_events = 0;
|
||||
uint64_t remaining = 0;
|
||||
|
||||
pthread_mutex_lock(&g_wallet.mutex);
|
||||
for (int i = 0; i < g_wallet.token_count && i < token_count_snapshot; i++) {
|
||||
if (!g_wallet.tokens[i].token.mint_url || strcmp(g_wallet.tokens[i].token.mint_url, resolved) != 0) continue;
|
||||
if (token_total_counts[i] <= 0) continue;
|
||||
if (token_spent_counts[i] < token_total_counts[i]) continue;
|
||||
|
||||
if (g_wallet.tokens[i].event_id[0] != '\0') {
|
||||
if (publish_token_deletion_event(g_wallet.tokens[i].event_id) == 0) {
|
||||
deleted_token_events++;
|
||||
}
|
||||
if (nostr_block_list_add("e", g_wallet.tokens[i].event_id, 0) == 0) {
|
||||
ignored_token_events++;
|
||||
}
|
||||
}
|
||||
|
||||
nostr_nip60_free_token_data(&g_wallet.tokens[i].token);
|
||||
memset(&g_wallet.tokens[i], 0, sizeof(g_wallet.tokens[i]));
|
||||
}
|
||||
|
||||
int compact = 0;
|
||||
for (int i = 0; i < g_wallet.token_count; i++) {
|
||||
if (g_wallet.tokens[i].event_id[0] == '\0' && !g_wallet.tokens[i].token.mint_url) continue;
|
||||
if (compact != i) g_wallet.tokens[compact] = g_wallet.tokens[i];
|
||||
compact++;
|
||||
}
|
||||
g_wallet.token_count = compact;
|
||||
if (g_wallet.token_count == 0) {
|
||||
free(g_wallet.tokens);
|
||||
g_wallet.tokens = NULL;
|
||||
}
|
||||
|
||||
token_proofs_total_for_mint_locked(resolved, &remaining);
|
||||
pthread_mutex_unlock(&g_wallet.mutex);
|
||||
|
||||
cJSON* root = cJSON_CreateObject();
|
||||
if (!root) {
|
||||
cashu_mint_free_checkstate_response(&parsed);
|
||||
free(proof_to_token_idx);
|
||||
free(token_total_counts);
|
||||
free(token_spent_counts);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1449,10 +1520,16 @@ int cashu_wallet_check_proofs(const char* mint_url, cJSON** out_json) {
|
||||
cJSON_AddNumberToObject(root, "proof_count", y_idx);
|
||||
cJSON_AddNumberToObject(root, "spent_count", spent_count);
|
||||
cJSON_AddNumberToObject(root, "unknown_count", unknown_count);
|
||||
cJSON_AddNumberToObject(root, "deleted_token_events", deleted_token_events);
|
||||
cJSON_AddNumberToObject(root, "ignored_token_events", ignored_token_events);
|
||||
cJSON_AddNumberToObject(root, "remaining_balance", (double)remaining);
|
||||
|
||||
*out_json = root;
|
||||
|
||||
cashu_mint_free_checkstate_response(&parsed);
|
||||
free(proof_to_token_idx);
|
||||
free(token_total_counts);
|
||||
free(token_spent_counts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -12,8 +12,8 @@
|
||||
// Using DIDACTYL_ prefix to avoid conflicts with nostr_core_lib VERSION macros
|
||||
#define DIDACTYL_VERSION_MAJOR 0
|
||||
#define DIDACTYL_VERSION_MINOR 1
|
||||
#define DIDACTYL_VERSION_PATCH 17
|
||||
#define DIDACTYL_VERSION "v0.1.17"
|
||||
#define DIDACTYL_VERSION_PATCH 18
|
||||
#define DIDACTYL_VERSION "v0.1.18"
|
||||
|
||||
// Agent metadata
|
||||
#define DIDACTYL_NAME "Didactyl"
|
||||
|
||||
Reference in New Issue
Block a user