commit 049951b644dab6f6ac8286d27a95f69892e5f2ba
parent da8389e8f2950cbb3727332844ade33c5e51d329
Author: Christian Grothoff <christian@grothoff.org>
Date: Sat, 30 Aug 2025 21:57:13 +0200
fix skr_size counting logic, keep helper connections open for the entire process in a global and do not re-connect merely because we couldn't yet bootstrap /keys (#10313)
Diffstat:
3 files changed, 102 insertions(+), 175 deletions(-)
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
@@ -2712,7 +2712,6 @@ do_shutdown (void *cls)
TEH_aml_decision_cleanup ();
TALER_KYCLOGIC_kyc_done ();
TALER_MHD_daemons_destroy ();
- TEH_wire_done ();
TEH_extensions_done ();
TEH_keys_finished ();
if (NULL != TEH_plugin)
@@ -2862,14 +2861,6 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
- if (GNUNET_OK !=
- TEH_wire_init ())
- {
- GNUNET_break (0);
- global_ret = EXIT_NO_RESTART;
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
TEH_load_terms (TEH_cfg);
TEH_curl_ctx
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2020-2024 Taler Systems SA
+ Copyright (C) 2020-2025 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -212,6 +212,13 @@ struct HelperState
/**
+ * Information we track for the crypto helpers. Preserved
+ * when the @e key_generation changes, thus kept separate.
+ */
+static struct HelperState helpers;
+
+
+/**
* Entry in (sorted) array with possible pre-build responses for /keys.
* We keep pre-build responses for the various (valid) cherry-picking
* values around.
@@ -328,12 +335,6 @@ struct TEH_KeyStateHandle
unsigned int krd_array_length;
/**
- * Information we track for thecrypto helpers. Preserved
- * when the @e key_generation changes, thus kept separate.
- */
- struct HelperState *helpers;
-
- /**
* Cached reply for a GET /management/keys request. Used so we do not
* re-create the reply every time.
*/
@@ -539,13 +540,6 @@ static struct SuspendedKeysRequests *skr_tail;
static unsigned int skr_size;
/**
- * Handle to a connection that should be force-resumed
- * with a hard error due to @a skr_size hitting
- * #SKR_LIMIT.
- */
-static struct MHD_Connection *skr_connection;
-
-/**
* Task to force timeouts on /keys requests.
*/
static struct GNUNET_SCHEDULER_Task *keys_tt;
@@ -631,45 +625,6 @@ wire_update_event_cb (void *cls,
}
-enum GNUNET_GenericReturnValue
-TEH_wire_init ()
-{
- struct GNUNET_DB_EventHeaderP es = {
- .size = htons (sizeof (es)),
- .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
- };
-
- wire_eh = TEH_plugin->event_listen (TEH_plugin->cls,
- GNUNET_TIME_UNIT_FOREVER_REL,
- &es,
- &wire_update_event_cb,
- NULL);
- if (NULL == wire_eh)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-void
-TEH_wire_done ()
-{
- if (NULL != wire_state)
- {
- destroy_wire_state (wire_state);
- wire_state = NULL;
- }
- if (NULL != wire_eh)
- {
- TEH_plugin->event_listen_cancel (TEH_plugin->cls,
- wire_eh);
- wire_eh = NULL;
- }
-}
-
-
/**
* Add information about a wire account to @a cls.
*
@@ -1046,6 +1001,7 @@ keys_timeout_cb (void *cls)
GNUNET_CONTAINER_DLL_remove (skr_head,
skr_tail,
skr);
+ skr_size--;
MHD_resume_connection (skr->connection);
TALER_MHD_daemon_trigger ();
GNUNET_free (skr);
@@ -1084,6 +1040,7 @@ suspend_request (struct MHD_Connection *connection)
GNUNET_CONTAINER_DLL_insert (skr_head,
skr_tail,
skr);
+ skr_size++;
skr->timeout = GNUNET_TIME_relative_to_absolute (KEYS_TIMEOUT);
if (NULL == keys_tt)
{
@@ -1091,15 +1048,13 @@ suspend_request (struct MHD_Connection *connection)
&keys_timeout_cb,
NULL);
}
- skr_size++;
- if (skr_size > SKR_LIMIT)
+ while (skr_size > SKR_LIMIT)
{
- skr = skr_head;
+ skr = skr_tail;
GNUNET_CONTAINER_DLL_remove (skr_head,
skr_tail,
skr);
skr_size--;
- skr_connection = skr->connection;
MHD_resume_connection (skr->connection);
TALER_MHD_daemon_trigger ();
GNUNET_free (skr);
@@ -1175,6 +1130,7 @@ TEH_resume_keys_requests (bool do_shutdown)
TALER_MHD_daemon_trigger ();
GNUNET_free (skr);
}
+ GNUNET_assert (0 == skr_size);
}
@@ -1650,28 +1606,19 @@ setup_key_helpers (struct HelperState *hs)
&helper_rsa_cb,
hs);
if (NULL == hs->rsadh)
- {
- destroy_key_helpers (hs);
return GNUNET_SYSERR;
- }
hs->csdh = TALER_CRYPTO_helper_cs_connect (TEH_cfg,
"taler-exchange",
&helper_cs_cb,
hs);
if (NULL == hs->csdh)
- {
- destroy_key_helpers (hs);
return GNUNET_SYSERR;
- }
hs->esh = TALER_CRYPTO_helper_esign_connect (TEH_cfg,
"taler-exchange",
&helper_esign_cb,
hs);
if (NULL == hs->esh)
- {
- destroy_key_helpers (hs);
return GNUNET_SYSERR;
- }
return GNUNET_OK;
}
@@ -1748,11 +1695,9 @@ clear_signkey_cb (void *cls,
* the helper data.
*
* @param[in] ksh key state to release
- * @param free_helper true to also release the helper state
*/
static void
-destroy_key_state (struct TEH_KeyStateHandle *ksh,
- bool free_helper)
+destroy_key_state (struct TEH_KeyStateHandle *ksh)
{
struct TEH_GlobalFee *gf;
@@ -1777,11 +1722,6 @@ destroy_key_state (struct TEH_KeyStateHandle *ksh,
ksh->auditors = NULL;
json_decref (ksh->global_fees);
ksh->global_fees = NULL;
- if (free_helper)
- {
- destroy_key_helpers (ksh->helpers);
- GNUNET_free (ksh->helpers);
- }
if (NULL != ksh->management_keys_reply)
{
json_decref (ksh->management_keys_reply);
@@ -1819,11 +1759,12 @@ keys_update_event_cb (void *cls,
enum GNUNET_GenericReturnValue
TEH_keys_init ()
{
- struct GNUNET_DB_EventHeaderP es = {
- .size = htons (sizeof (es)),
- .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
- };
-
+ if (GNUNET_OK !=
+ setup_key_helpers (&helpers))
+ {
+ destroy_key_helpers (&helpers);
+ return GNUNET_SYSERR;
+ }
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
"exchange",
@@ -1846,15 +1787,39 @@ TEH_keys_init ()
"ASSET_TYPE");
asset_type = GNUNET_strdup ("fiat");
}
- keys_eh = TEH_plugin->event_listen (TEH_plugin->cls,
- GNUNET_TIME_UNIT_FOREVER_REL,
- &es,
- &keys_update_event_cb,
- NULL);
- if (NULL == keys_eh)
{
- GNUNET_break (0);
- return GNUNET_SYSERR;
+ struct GNUNET_DB_EventHeaderP es = {
+ .size = htons (sizeof (es)),
+ .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
+ };
+
+ keys_eh = TEH_plugin->event_listen (TEH_plugin->cls,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &es,
+ &keys_update_event_cb,
+ NULL);
+ if (NULL == keys_eh)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ {
+ struct GNUNET_DB_EventHeaderP es = {
+ .size = htons (sizeof (es)),
+ .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
+ };
+
+ wire_eh = TEH_plugin->event_listen (TEH_plugin->cls,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &es,
+ &wire_update_event_cb,
+ NULL);
+ if (NULL == wire_eh)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
}
return GNUNET_OK;
}
@@ -1866,20 +1831,31 @@ TEH_keys_init ()
void
TEH_keys_finished ()
{
+ if (NULL != wire_state)
+ {
+ destroy_wire_state (wire_state);
+ wire_state = NULL;
+ }
+ if (NULL != wire_eh)
+ {
+ TEH_plugin->event_listen_cancel (TEH_plugin->cls,
+ wire_eh);
+ wire_eh = NULL;
+ }
if (NULL != keys_tt)
{
GNUNET_SCHEDULER_cancel (keys_tt);
keys_tt = NULL;
}
if (NULL != key_state)
- destroy_key_state (key_state,
- true);
+ destroy_key_state (key_state);
if (NULL != keys_eh)
{
TEH_plugin->event_listen_cancel (TEH_plugin->cls,
keys_eh);
keys_eh = NULL;
}
+ destroy_key_helpers (&helpers);
}
@@ -3036,7 +3012,7 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
struct GNUNET_JSON_PackSpec key_spec;
bool private_key_lost;
- hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
+ hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys,
&dk->h_denom_pub.hash);
private_key_lost
= (NULL == hd) ||
@@ -3242,14 +3218,12 @@ global_fee_info_cb (
/**
* Create a key state.
*
- * @param[in] hs helper state to (re)use, NULL if not available
* @param management_only if we should NOT run 'finish_keys_response()'
* because we only need the state for the /management/keys API
* @return NULL on error (i.e. failed to access database)
*/
static struct TEH_KeyStateHandle *
-build_key_state (struct HelperState *hs,
- bool management_only)
+build_key_state (bool management_only)
{
struct TEH_KeyStateHandle *ksh;
enum GNUNET_DB_QueryStatus qs;
@@ -3259,22 +3233,6 @@ build_key_state (struct HelperState *hs,
ksh->reload_time = GNUNET_TIME_timestamp_get ();
/* We must use the key_generation from when we STARTED the process! */
ksh->key_generation = key_generation;
- if (NULL == hs)
- {
- ksh->helpers = GNUNET_new (struct HelperState);
- if (GNUNET_OK !=
- setup_key_helpers (ksh->helpers))
- {
- GNUNET_free (ksh->helpers);
- GNUNET_assert (NULL == ksh->management_keys_reply);
- GNUNET_free (ksh);
- return NULL;
- }
- }
- else
- {
- ksh->helpers = hs;
- }
ksh->denomserial_map = GNUNET_CONTAINER_multihashmap32_create (1024);
ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024,
true);
@@ -3299,8 +3257,7 @@ build_key_state (struct HelperState *hs,
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
- destroy_key_state (ksh,
- true);
+ destroy_key_state (ksh);
return NULL;
}
qs = TEH_plugin->iterate_denominations (TEH_plugin->cls,
@@ -3310,8 +3267,7 @@ build_key_state (struct HelperState *hs,
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
- destroy_key_state (ksh,
- true);
+ destroy_key_state (ksh);
return NULL;
}
/* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */
@@ -3321,8 +3277,7 @@ build_key_state (struct HelperState *hs,
if (qs < 0)
{
GNUNET_break (0);
- destroy_key_state (ksh,
- true);
+ destroy_key_state (ksh);
return NULL;
}
qs = TEH_plugin->iterate_auditor_denominations (TEH_plugin->cls,
@@ -3331,8 +3286,7 @@ build_key_state (struct HelperState *hs,
if (qs < 0)
{
GNUNET_break (0);
- destroy_key_state (ksh,
- true);
+ destroy_key_state (ksh);
return NULL;
}
qs = TEH_plugin->iterate_active_auditors (TEH_plugin->cls,
@@ -3341,8 +3295,7 @@ build_key_state (struct HelperState *hs,
if (qs < 0)
{
GNUNET_break (0);
- destroy_key_state (ksh,
- true);
+ destroy_key_state (ksh);
return NULL;
}
@@ -3357,8 +3310,7 @@ build_key_state (struct HelperState *hs,
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Could not finish /keys response (required data not configured yet)\n");
- destroy_key_state (ksh,
- true);
+ destroy_key_state (ksh);
return NULL;
}
@@ -3392,8 +3344,7 @@ keys_get_state (bool management_only)
old_ksh = key_state;
if (NULL == old_ksh)
{
- ksh = build_key_state (NULL,
- management_only);
+ ksh = build_key_state (management_only);
if (NULL == ksh)
return NULL;
key_state = ksh;
@@ -3406,15 +3357,12 @@ keys_get_state (bool management_only)
"Rebuilding /keys, generation upgrade from %llu to %llu\n",
(unsigned long long) old_ksh->key_generation,
(unsigned long long) key_generation);
- ksh = build_key_state (old_ksh->helpers,
- management_only);
+ ksh = build_key_state (management_only);
key_state = ksh;
- old_ksh->helpers = NULL;
- destroy_key_state (old_ksh,
- false);
+ destroy_key_state (old_ksh);
return ksh;
}
- sync_key_helpers (old_ksh->helpers);
+ sync_key_helpers (&helpers);
return old_ksh;
}
@@ -3555,7 +3503,7 @@ TEH_keys_denomination_batch_sign (
const struct TALER_DenominationHashP *h_denom_pub = csds[i].h_denom_pub;
const struct TALER_BlindedPlanchet *bp = csds[i].bp;
- hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
+ hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys,
&h_denom_pub->hash);
if (NULL == hd)
return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
@@ -3599,7 +3547,7 @@ TEH_keys_denomination_batch_sign (
if (0 != csrs_pos)
{
ec = TALER_CRYPTO_helper_cs_batch_sign (
- ksh->helpers->csdh,
+ helpers.csdh,
csrs_pos,
csrs,
for_melt,
@@ -3615,7 +3563,7 @@ TEH_keys_denomination_batch_sign (
if (0 != rsrs_pos)
{
ec = TALER_CRYPTO_helper_rsa_batch_sign (
- ksh->helpers->rsadh,
+ helpers.rsadh,
rsrs_pos,
rsrs,
(0 == csrs_pos) ? bss : rs);
@@ -3672,7 +3620,7 @@ TEH_keys_denomination_cs_r_pub (
{
return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
}
- hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
+ hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys,
&h_denom_pub->hash);
if (NULL == hd)
{
@@ -3689,7 +3637,7 @@ TEH_keys_denomination_cs_r_pub (
.h_cs = &hd->h_details.h_cs,
.nonce = nonce
};
- return TALER_CRYPTO_helper_cs_r_derive (ksh->helpers->csdh,
+ return TALER_CRYPTO_helper_cs_r_derive (helpers.csdh,
&cdr,
for_melt,
r_pub);
@@ -3718,7 +3666,7 @@ TEH_keys_denomination_cs_batch_r_pub_simple (
const struct TALER_DenominationHashP *h_denom_pub = cdds[i].h_denom_pub;
const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdds[i].nonce;
- hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
+ hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys,
&h_denom_pub->hash);
if (NULL == hd)
{
@@ -3733,7 +3681,7 @@ TEH_keys_denomination_cs_batch_r_pub_simple (
cdrs[i].nonce = nonce;
}
- return TALER_CRYPTO_helper_cs_r_batch_derive (ksh->helpers->csdh,
+ return TALER_CRYPTO_helper_cs_r_batch_derive (helpers.csdh,
cdds_length,
cdrs,
for_melt,
@@ -3764,7 +3712,7 @@ TEH_keys_denomination_cs_batch_r_pub (
* TEH_DenominationKey and HelperDenomination,
* because only TEH_DenominationKey has .recoup_possible
*/
- hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
+ hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys,
&h_denom_pubs[i].hash);
dk = TEH_keys_denomination_by_hash_from_state (ksh,
&h_denom_pubs[i],
@@ -3793,7 +3741,7 @@ TEH_keys_denomination_cs_batch_r_pub (
cdrs[i].nonce = &nonces[i];
}
- return TALER_CRYPTO_helper_cs_r_batch_derive (ksh->helpers->csdh,
+ return TALER_CRYPTO_helper_cs_r_batch_derive (helpers.csdh,
num,
cdrs,
for_melt,
@@ -3813,7 +3761,7 @@ TEH_keys_denomination_revoke (const struct TALER_DenominationHashP *h_denom_pub)
GNUNET_break (0);
return;
}
- hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
+ hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys,
&h_denom_pub->hash);
if (NULL == hd)
{
@@ -3825,12 +3773,12 @@ TEH_keys_denomination_revoke (const struct TALER_DenominationHashP *h_denom_pub)
case GNUNET_CRYPTO_BSA_INVALID:
break;
case GNUNET_CRYPTO_BSA_RSA:
- TALER_CRYPTO_helper_rsa_revoke (ksh->helpers->rsadh,
+ TALER_CRYPTO_helper_rsa_revoke (helpers.rsadh,
&hd->h_details.h_rsa);
TEH_keys_update_states ();
return;
case GNUNET_CRYPTO_BSA_CS:
- TALER_CRYPTO_helper_cs_revoke (ksh->helpers->csdh,
+ TALER_CRYPTO_helper_cs_revoke (helpers.csdh,
&hd->h_details.h_cs);
TEH_keys_update_states ();
return;
@@ -3875,7 +3823,7 @@ TEH_keys_exchange_sign2_ (
enum TALER_ErrorCode ec;
TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_EDDSA]++;
- ec = TALER_CRYPTO_helper_esign_sign_ (ksh->helpers->esh,
+ ec = TALER_CRYPTO_helper_esign_sign_ (helpers.esh,
purpose,
pub,
sig);
@@ -3901,7 +3849,7 @@ TEH_keys_exchange_sign2_ (
memset (sig,
0,
sizeof (*sig));
- return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+ return TALER_EC_EXCHANGE_SIGNKEY_HELPER_OFFLINE_MISSING;
}
}
return ec;
@@ -3919,7 +3867,7 @@ TEH_keys_exchange_revoke (const struct TALER_ExchangePublicKeyP *exchange_pub)
GNUNET_break (0);
return;
}
- TALER_CRYPTO_helper_esign_revoke (ksh->helpers->esh,
+ TALER_CRYPTO_helper_esign_revoke (helpers.esh,
exchange_pub);
TEH_keys_update_states ();
}
@@ -4004,8 +3952,11 @@ TEH_keys_get_handler (struct TEH_RequestContext *rc,
if ( (NULL == ksh) ||
(0 == ksh->krd_array_length) )
{
- if ( ( (SKR_LIMIT == skr_size) &&
- (rc->connection == skr_connection) ) ||
+ if ( ( (SKR_LIMIT <= skr_size) &&
+ (GNUNET_TIME_relative_cmp (
+ GNUNET_TIME_absolute_get_duration (rc->start_time),
+ >,
+ GNUNET_TIME_UNIT_SECONDS)) ) ||
TEH_suicide)
{
return TALER_MHD_reply_with_error (
@@ -4151,7 +4102,7 @@ TEH_keys_load_fees (struct TEH_KeyStateHandle *ksh,
struct HelperDenomination *hd;
enum GNUNET_GenericReturnValue ok;
- hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
+ hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys,
&h_denom_pub->hash);
if (NULL == hd)
{
@@ -4202,7 +4153,7 @@ TEH_keys_get_timing (const struct TALER_ExchangePublicKeyP *exchange_pub,
}
pid.public_key = exchange_pub->eddsa_pub;
- hsk = GNUNET_CONTAINER_multipeermap_get (ksh->helpers->esign_keys,
+ hsk = GNUNET_CONTAINER_multipeermap_get (helpers.esign_keys,
&pid);
if (NULL == hsk)
{
@@ -4377,7 +4328,7 @@ TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
"no key state");
}
- sync_key_helpers (ksh->helpers);
+ sync_key_helpers (&helpers);
if (NULL == ksh->management_keys_reply)
{
struct FutureBuilderContext fbc = {
@@ -4404,10 +4355,10 @@ TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
}
GNUNET_assert (NULL != fbc.denoms);
GNUNET_assert (NULL != fbc.signkeys);
- GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->denom_keys,
+ GNUNET_CONTAINER_multihashmap_iterate (helpers.denom_keys,
&add_future_denomkey_cb,
&fbc);
- GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys,
+ GNUNET_CONTAINER_multipeermap_iterate (helpers.esign_keys,
&add_future_signkey_cb,
&fbc);
reply = GNUNET_JSON_PACK (
diff --git a/src/exchange/taler-exchange-httpd_keys.h b/src/exchange/taler-exchange-httpd_keys.h
@@ -155,12 +155,6 @@ struct TEH_KeyStateHandle;
void
TEH_check_invariants (void);
-/**
- * Clean up wire subsystem.
- */
-void
-TEH_wire_done (void);
-
/**
* Look up wire fee structure by @a ts.
@@ -177,15 +171,6 @@ TEH_wire_fees_by_time (
/**
- * Initialize wire subsystem.
- *
- * @return #GNUNET_OK on success
- */
-enum GNUNET_GenericReturnValue
-TEH_wire_init (void);
-
-
-/**
* Something changed in the database. Rebuild the wire replies. This function
* should be called if the exchange learns about a new signature from our
* master key.