gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated: work on keys serialization/deser


From: gnunet
Subject: [taler-exchange] branch master updated: work on keys serialization/deserialization
Date: Thu, 06 Jul 2023 00:08:06 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new c02d88c8 work on keys serialization/deserialization
c02d88c8 is described below

commit c02d88c8e3f55b109063ced037fb8cffb4d5d844
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Thu Jul 6 00:08:00 2023 +0200

    work on keys serialization/deserialization
---
 src/exchange/taler-exchange-httpd_keys.c           |  30 +-
 src/include/taler_exchange_service.h               |  10 +
 src/include/taler_testing_lib.h                    |  56 +---
 src/json/json_helper.c                             |   5 +
 src/lib/exchange_api_handle.c                      | 321 ++++++++++++++++++---
 src/testing/Makefile.am                            |   3 -
 src/testing/test_auditor_api.c                     |   2 +-
 src/testing/test_exchange_api.c                    |   2 +-
 .../test_exchange_api_keys_cherry_picking.c        |  23 +-
 .../test_exchange_api_overlapping_keys_bug.c       |  16 +-
 src/testing/test_exchange_api_revocation.c         |  13 +-
 src/testing/test_exchange_api_twisted.c            |   1 +
 src/testing/test_exchange_management_api.c         |  12 +-
 src/testing/test_exchange_p2p.c                    |   2 +-
 src/testing/test_kyc_api.c                         |   2 +-
 src/testing/test_taler_exchange_wirewatch.c        |   2 +-
 src/testing/testing_api_cmd_check_keys.c           | 202 -------------
 src/testing/testing_api_cmd_connect_with_state.c   | 208 -------------
 src/testing/testing_api_cmd_get_exchange.c         |  97 ++++++-
 src/testing/testing_api_cmd_serialize_keys.c       | 144 ---------
 20 files changed, 443 insertions(+), 708 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_keys.c 
b/src/exchange/taler-exchange-httpd_keys.c
index 8b9e54b4..bcc7b991 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -2223,10 +2223,13 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
           .age_mask = dk->meta.age_mask,
         };
 
-        memset (&meta.hash, 0, sizeof(meta.hash));
-
+        memset (&meta.hash,
+                0,
+                sizeof(meta.hash));
         /* Search the group/JSON-blob for the key */
-        GNUNET_CRYPTO_hash (&meta, sizeof(meta), &key);
+        GNUNET_CRYPTO_hash (&meta,
+                            sizeof(meta),
+                            &key);
 
         group =
           (struct groupData *) GNUNET_CONTAINER_multihashmap_get (
@@ -2237,7 +2240,7 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
         {
           /* There is no group for this meta-data yet, so we create a new 
group */
           bool age_restricted = meta.age_mask.bits != 0;
-          char *cipher;
+          const char *cipher;
 
           group = GNUNET_new (struct groupData);
           memset (group, 0, sizeof(*group));
@@ -2296,17 +2299,16 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
           {
           case TALER_DENOMINATION_RSA:
             key_spec =
-              GNUNET_JSON_pack_rsa_public_key ("rsa_pub",
-                                               dk->denom_pub.details.
-                                               rsa_public_key);
+              GNUNET_JSON_pack_rsa_public_key (
+                "rsa_pub",
+                dk->denom_pub.details.rsa_public_key);
             break;
           case TALER_DENOMINATION_CS:
             key_spec =
-              GNUNET_JSON_pack_data_varsize ("cs_pub",
-                                             &dk->denom_pub.details.
-                                             cs_public_key,
-                                             sizeof (dk->denom_pub.details.
-                                                     cs_public_key));
+              GNUNET_JSON_pack_data_varsize (
+                "cs_pub",
+                &dk->denom_pub.details.cs_public_key,
+                sizeof (dk->denom_pub.details.cs_public_key));
             break;
           default:
             GNUNET_assert (false);
@@ -2546,9 +2548,9 @@ build_key_state (struct HelperState *hs,
     ksh->helpers = hs;
   }
   ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024,
-                                                            GNUNET_YES);
+                                                            true);
   ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32,
-                                                           GNUNET_NO /* MUST 
be NO! */);
+                                                           false /* MUST be 
false! */);
   ksh->auditors = json_array ();
   GNUNET_assert (NULL != ksh->auditors);
   /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index 35a68872..1f3bbffe 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -239,6 +239,11 @@ struct TALER_EXCHANGE_Keys
    */
   struct TALER_MasterPublicKeyP master_pub;
 
+  /**
+   * Signature over extension configuration data, if any.
+   */
+  struct TALER_MasterSignatureP extensions_sig;
+
   /**
    * Array of the exchange's online signing keys.
    */
@@ -259,6 +264,11 @@ struct TALER_EXCHANGE_Keys
    */
   struct TALER_EXCHANGE_GlobalFee *global_fees;
 
+  /**
+   * Configuration data for extensions.
+   */
+  json_t *extensions;
+
   /**
    * Supported Taler protocol version by the exchange.
    * String in the format current:revision:age using the
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
index 332c3a34..4996fbe2 100644
--- a/src/include/taler_testing_lib.h
+++ b/src/include/taler_testing_lib.h
@@ -623,6 +623,7 @@ TALER_TESTING_cmd_system_start (
  *
  * @param label command label
  * @param cfg configuration to use
+ * @param last_keys_ref reference to command with prior /keys response, NULL 
for none
  * @param wait_for_keys block until we got /keys
  * @param load_private_key obtain private key from file indicated in @a cfg
  * @return the command.
@@ -631,6 +632,7 @@ struct TALER_TESTING_Command
 TALER_TESTING_cmd_get_exchange (
   const char *label,
   const struct GNUNET_CONFIGURATION_Handle *cfg,
+  const char *last_keys_ref,
   bool wait_for_keys,
   bool load_private_key);
 
@@ -1786,34 +1788,6 @@ struct TALER_TESTING_Command
 TALER_TESTING_cmd_wait_service (const char *label,
                                 const char *url);
 
-
-/**
- * Make a "check keys" command.
- *
- * @param label command label
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_keys (const char *label);
-
-
-/**
- * Make a "check keys" command.  It lets the user set a last denom issue date 
to be
- * used in the request for /keys.
- *
- * @param label command label
- * @param last_denom_date_ref previous /keys command to use to
- *        obtain the "last_denom_date" value from; "zero" can be used
- *        as a special value to force an absolute time of zero to be
- *        given to as an argument
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_keys_with_last_denom (
-  const char *label,
-  const char *last_denom_date_ref);
-
-
 /**
  * Create a "batch" command.  Such command takes a
  * end_CMD-terminated array of CMDs and executed them.
@@ -1872,31 +1846,6 @@ TALER_TESTING_cmd_batch_set_current (const struct 
TALER_TESTING_Command *cmd,
                                      unsigned int new_ip);
 
 
-/**
- * Make a serialize-keys CMD.
- *
- * @param label CMD label
- * @return the CMD.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_serialize_keys (const char *label);
-
-
-/**
- * Make a connect-with-state CMD.  This command
- * will use a serialized key state to reconnect
- * to the exchange.
- *
- * @param label command label
- * @param state_reference label of a CMD offering
- *        a serialized key state.
- * @return the CMD.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_connect_with_state (const char *label,
-                                      const char *state_reference);
-
-
 /**
  * Make the "insert-deposit" CMD.
  *
@@ -2671,7 +2620,6 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait 
*traits,
   op (bank_auth_data, const struct TALER_BANK_AuthenticationData)  \
   op (contract_terms, const json_t)                                \
   op (wire_details, const json_t)                                  \
-  op (exchange_keys, const json_t)                                 \
   op (exchange_url, const char)                                    \
   op (auditor_url, const char)                                     \
   op (exchange_bank_account_url, const char)                       \
diff --git a/src/json/json_helper.c b/src/json/json_helper.c
index 5c0f8bad..95c1be5f 100644
--- a/src/json/json_helper.c
+++ b/src/json/json_helper.c
@@ -279,6 +279,11 @@ parse_denomination_group (void *cls,
                          &emsg,
                          &eline))
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to parse %s at %u: %s\n",
+                spec[eline].field,
+                eline,
+                emsg);
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index 40ae390f..a21b4c6a 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -534,7 +534,6 @@ decode_keys_json (const json_t *resp_obj,
   const json_t *denominations_by_group;
   const json_t *auditors_array;
   const json_t *recoup_array = NULL;
-  struct TALER_MasterSignatureP extensions_sig = {0};
   const json_t *manifests = NULL;
   bool no_extensions = false;
   bool no_signature = false;
@@ -650,7 +649,7 @@ decode_keys_json (const json_t *resp_obj,
       GNUNET_JSON_spec_mark_optional (
         GNUNET_JSON_spec_fixed_auto (
           "extensions_sig",
-          &extensions_sig),
+          &key_data->extensions_sig),
         &no_signature),
       GNUNET_JSON_spec_mark_optional (
         GNUNET_JSON_spec_array_const (
@@ -666,6 +665,8 @@ decode_keys_json (const json_t *resp_obj,
                                NULL, NULL));
     key_data->currency = GNUNET_strdup (currency);
     key_data->asset_type = GNUNET_strdup (asset_type);
+    if (! no_extensions)
+      key_data->extensions = json_incref ((json_t *) manifests);
   }
 
   /* parse the global fees */
@@ -750,7 +751,7 @@ decode_keys_json (const json_t *resp_obj,
       EXITIF (GNUNET_OK !=
               TALER_extensions_verify_manifests_signature (
                 manifests,
-                &extensions_sig,
+                &key_data->extensions_sig,
                 &key_data->master_pub));
 
       /* Parse and set the the configuration of the extensions accordingly */
@@ -826,7 +827,7 @@ decode_keys_json (const json_t *resp_obj,
 
           /* Build the running xor of the SHA512-hash of the public keys */
           {
-            struct TALER_DenominationHashP hc = {0};
+            struct TALER_DenominationHashP hc;
 
             TALER_denom_pub_hash (&dk.key,
                                   &hc);
@@ -1550,6 +1551,7 @@ TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys 
*keys)
   GNUNET_array_grow (keys->auditors,
                      keys->auditors_size,
                      0);
+  json_decref (keys->extensions);
   GNUNET_free (keys->wallet_balance_limit_without_kyc);
   GNUNET_free (keys->version);
   GNUNET_free (keys->currency);
@@ -1571,8 +1573,8 @@ TALER_EXCHANGE_keys_from_json (const json_t *j)
   struct GNUNET_JSON_Specification spec[] = {
     GNUNET_JSON_spec_uint32 ("version",
                              &version),
-    GNUNET_JSON_spec_array_const ("keys",
-                                  &jkeys),
+    GNUNET_JSON_spec_object_const ("keys",
+                                   &jkeys),
     GNUNET_JSON_spec_string ("exchange_url",
                              &url),
     GNUNET_JSON_spec_mark_optional (
@@ -1615,14 +1617,98 @@ TALER_EXCHANGE_keys_from_json (const json_t *j)
 }
 
 
+/**
+ * Data we track per denomination group.
+ */
+struct GroupData
+{
+  /**
+   * The json blob with the group meta-data and list of denominations
+   */
+  json_t *json;
+
+  /**
+   * xor of all hashes of denominations in that group
+   */
+  struct GNUNET_HashCode hash_xor;
+
+  /**
+   * Meta data for this group.
+   */
+  struct TALER_DenominationGroup meta;
+};
+
+
+/**
+ * Add denomination group represented by @a value
+ * to list of denominations in @a cls. Also frees
+ * the @a value.
+ *
+ * @param[in,out] cls a `json_t *` with an array to build
+ * @param key unused
+ * @param value a `struct GroupData *`
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static enum GNUNET_GenericReturnValue
+add_grp (void *cls,
+         const struct GNUNET_HashCode *key,
+         void *value)
+{
+  json_t *denominations_by_group = cls;
+  struct GroupData *gd = value;
+  const char *cipher;
+  json_t *ge;
+  bool age_restricted = gd->meta.age_mask.bits != 0;
+
+  (void) key;
+  switch (gd->meta.cipher)
+  {
+  case TALER_DENOMINATION_RSA:
+    cipher = age_restricted ? "RSA+age_restricted" : "RSA";
+    break;
+  case TALER_DENOMINATION_CS:
+    cipher = age_restricted ? "CS+age_restricted" : "CS";
+    break;
+  default:
+    GNUNET_assert (false);
+  }
+
+  ge = GNUNET_JSON_PACK (
+    GNUNET_JSON_pack_data_auto ("hash",
+                                &gd->hash_xor),
+    GNUNET_JSON_pack_string ("cipher",
+                             cipher),
+    GNUNET_JSON_pack_array_steal ("denoms",
+                                  gd->json),
+    TALER_JSON_PACK_DENOM_FEES ("fee",
+                                &gd->meta.fees),
+    GNUNET_JSON_pack_allow_null (
+      age_restricted
+          ? GNUNET_JSON_pack_uint64 ("age_mask",
+                                     gd->meta.age_mask.bits)
+          : GNUNET_JSON_pack_string ("dummy",
+                                     NULL)),
+    TALER_JSON_pack_amount ("value",
+                            &gd->meta.value));
+  GNUNET_assert (0 ==
+                 json_array_append_new (denominations_by_group,
+                                        ge));
+  GNUNET_free (gd);
+  return GNUNET_OK;
+}
+
+
 json_t *
 TALER_EXCHANGE_keys_to_json (const struct TALER_EXCHANGE_Keys *kd)
 {
   struct GNUNET_TIME_Timestamp now;
   json_t *keys;
   json_t *signkeys;
-  json_t *denoms;
+  json_t *denominations_by_group;
   json_t *auditors;
+  json_t *recoup;
+  json_t *global_fees;
+  json_t *wblwk = NULL;
 
   now = GNUNET_TIME_timestamp_get ();
   signkeys = json_array ();
@@ -1665,43 +1751,113 @@ TALER_EXCHANGE_keys_to_json (const struct 
TALER_EXCHANGE_Keys *kd)
       return NULL;
     }
   }
-  denoms = json_array ();
-  if (NULL == denoms)
+  denominations_by_group = json_array ();
+  if (NULL == denominations_by_group)
   {
     GNUNET_break (0);
     json_decref (signkeys);
     return NULL;
   }
-  for (unsigned int i = 0; i<kd->num_denom_keys; i++)
+  // FIXME: construct denominations_by_group analogous
+  // to taler-exchange-httpd_keys!
   {
-    const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
-    json_t *denom;
+    struct GNUNET_CONTAINER_MultiHashMap *dbg;
 
-    if (GNUNET_TIME_timestamp_cmp (now,
-                                   >,
-                                   dk->expire_deposit))
-      continue; /* skip keys that have expired */
-    denom = GNUNET_JSON_PACK (
-      GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
-                                  dk->expire_deposit),
-      GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
-                                  dk->withdraw_valid_until),
-      GNUNET_JSON_pack_timestamp ("stamp_start",
-                                  dk->valid_from),
-      GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
-                                  dk->expire_legal),
-      TALER_JSON_pack_amount ("value",
-                              &dk->value),
-      TALER_JSON_PACK_DENOM_FEES ("fee",
-                                  &dk->fees),
-      GNUNET_JSON_pack_data_auto ("master_sig",
-                                  &dk->master_sig),
-      TALER_JSON_pack_denom_pub ("denom_pub",
-                                 &dk->key));
-    GNUNET_assert (0 ==
-                   json_array_append_new (denoms,
-                                          denom));
+    dbg = GNUNET_CONTAINER_multihashmap_create (128,
+                                                false);
+    for (unsigned int i = 0; i<kd->num_denom_keys; i++)
+    {
+      const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
+      struct TALER_DenominationGroup meta = {
+        .cipher = dk->key.cipher,
+        .value = dk->value,
+        .fees = dk->fees,
+        .age_mask = kd->age_mask
+      };
+      struct GNUNET_HashCode key;
+      struct GroupData *gd;
+      json_t *denom;
+      struct GNUNET_JSON_PackSpec key_spec;
+
+      if (GNUNET_TIME_timestamp_cmp (now,
+                                     >,
+                                     dk->expire_deposit))
+        continue; /* skip keys that have expired */
+      GNUNET_CRYPTO_hash (&meta,
+                          sizeof(meta),
+                          &key);
+      gd = GNUNET_CONTAINER_multihashmap_get (dbg,
+                                              &key);
+      if (NULL == gd)
+      {
+        gd = GNUNET_new (struct GroupData);
+        gd->meta = meta;
+        gd->json = json_array ();
+        GNUNET_assert (NULL != gd->json);
+        GNUNET_assert (
+          GNUNET_OK ==
+          GNUNET_CONTAINER_multihashmap_put (dbg,
+                                             &key,
+                                             gd,
+                                             
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+
+        /* Build the running xor of the SHA512-hash of the public keys */
+      }
+      {
+        struct TALER_DenominationHashP hc;
+
+        TALER_denom_pub_hash (&dk->key,
+                              &hc);
+        GNUNET_CRYPTO_hash_xor (&hc.hash,
+                                &gd->hash_xor,
+                                &gd->hash_xor);
+      }
+
+      switch (meta.cipher)
+      {
+      case TALER_DENOMINATION_RSA:
+        key_spec =
+          GNUNET_JSON_pack_rsa_public_key (
+            "rsa_pub",
+            dk->key.details.rsa_public_key);
+        break;
+      case TALER_DENOMINATION_CS:
+        key_spec =
+          GNUNET_JSON_pack_data_varsize (
+            "cs_pub",
+            &dk->key.details.cs_public_key,
+            sizeof (dk->key.details.cs_public_key));
+        break;
+      default:
+        GNUNET_assert (false);
+      }
+      denom = GNUNET_JSON_PACK (
+        GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
+                                    dk->expire_deposit),
+        GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
+                                    dk->withdraw_valid_until),
+        GNUNET_JSON_pack_timestamp ("stamp_start",
+                                    dk->valid_from),
+        GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
+                                    dk->expire_legal),
+        TALER_JSON_pack_amount ("value",
+                                &dk->value),
+        TALER_JSON_PACK_DENOM_FEES ("fee",
+                                    &dk->fees),
+        GNUNET_JSON_pack_data_auto ("master_sig",
+                                    &dk->master_sig),
+        key_spec
+        );
+      GNUNET_assert (0 ==
+                     json_array_append_new (gd->json,
+                                            denom));
+    }
+    GNUNET_CONTAINER_multihashmap_iterate (dbg,
+                                           &add_grp,
+                                           denominations_by_group);
+    GNUNET_CONTAINER_multihashmap_destroy (dbg);
   }
+
   auditors = json_array ();
   GNUNET_assert (NULL != auditors);
   for (unsigned int i = 0; i<kd->num_auditors; i++)
@@ -1711,14 +1867,7 @@ TALER_EXCHANGE_keys_to_json (const struct 
TALER_EXCHANGE_Keys *kd)
     json_t *adenoms;
 
     adenoms = json_array ();
-    if (NULL == adenoms)
-    {
-      GNUNET_break (0);
-      json_decref (denoms);
-      json_decref (signkeys);
-      json_decref (auditors);
-      return NULL;
-    }
+    GNUNET_assert (NULL != adenoms);
     for (unsigned int j = 0; j<ai->num_denom_keys; j++)
     {
       const struct TALER_EXCHANGE_AuditorDenominationInfo *adi =
@@ -1753,6 +1902,63 @@ TALER_EXCHANGE_keys_to_json (const struct 
TALER_EXCHANGE_Keys *kd)
                    json_array_append_new (auditors,
                                           a));
   }
+
+  global_fees = json_array ();
+  GNUNET_assert (NULL != global_fees);
+  for (unsigned int i = 0; i<kd->num_global_fees; i++)
+  {
+    const struct TALER_EXCHANGE_GlobalFee *gf
+      = &kd->global_fees[i];
+
+    if (GNUNET_TIME_absolute_is_past (gf->end_date.abs_time))
+      continue;
+    GNUNET_assert (
+      0 ==
+      json_array_append_new (
+        global_fees,
+        GNUNET_JSON_PACK (
+          GNUNET_JSON_pack_timestamp ("start_date",
+                                      gf->start_date),
+          GNUNET_JSON_pack_timestamp ("end_date",
+                                      gf->end_date),
+          TALER_JSON_PACK_GLOBAL_FEES (&gf->fees),
+          GNUNET_JSON_pack_time_rel ("history_expiration",
+                                     gf->history_expiration),
+          GNUNET_JSON_pack_time_rel ("purse_timeout",
+                                     gf->purse_timeout),
+          GNUNET_JSON_pack_uint64 ("purse_account_limit",
+                                   gf->purse_account_limit),
+          GNUNET_JSON_pack_data_auto ("master_sig",
+                                      &gf->master_sig))));
+  }
+  recoup = json_array ();
+  GNUNET_assert (NULL != recoup);
+  for (unsigned int i = 0; i<kd->num_denom_keys; i++)
+  {
+    const struct TALER_EXCHANGE_DenomPublicKey *dk
+      = &kd->denom_keys[i];
+    if (! dk->revoked)
+      continue;
+    GNUNET_assert (0 ==
+                   json_array_append_new (
+                     recoup,
+                     GNUNET_JSON_PACK (
+                       GNUNET_JSON_pack_data_auto ("h_denom_pub",
+                                                   &dk->h_key))));
+  }
+
+  wblwk = json_array ();
+  GNUNET_assert (NULL != wblwk);
+  for (unsigned int i = 0; i<kd->wblwk_length; i++)
+  {
+    const struct TALER_Amount *a = &kd->wallet_balance_limit_without_kyc[i];
+
+    GNUNET_assert (0 ==
+                   json_array_append_new (
+                     wblwk,
+                     TALER_JSON_from_amount (a)));
+  }
+
   keys = GNUNET_JSON_PACK (
     GNUNET_JSON_pack_string ("version",
                              kd->version),
@@ -1766,12 +1972,33 @@ TALER_EXCHANGE_keys_to_json (const struct 
TALER_EXCHANGE_Keys *kd)
                                kd->reserve_closing_delay),
     GNUNET_JSON_pack_timestamp ("list_issue_date",
                                 kd->list_issue_date),
+    GNUNET_JSON_pack_array_steal ("global_fees",
+                                  global_fees),
     GNUNET_JSON_pack_array_steal ("signkeys",
                                   signkeys),
-    GNUNET_JSON_pack_array_steal ("denoms",
-                                  denoms),
+    GNUNET_JSON_pack_array_steal ("denominations",
+                                  denominations_by_group),
+    GNUNET_JSON_pack_allow_null (
+      GNUNET_JSON_pack_array_steal ("recoup",
+                                    recoup)),
     GNUNET_JSON_pack_array_steal ("auditors",
-                                  auditors));
+                                  auditors),
+    GNUNET_JSON_pack_bool ("tipping_allowed",
+                           kd->tipping_allowed),
+    GNUNET_JSON_pack_allow_null (
+      GNUNET_JSON_pack_object_incref ("extensions",
+                                      kd->extensions)),
+    GNUNET_JSON_pack_allow_null (
+      GNUNET_is_zero (&kd->extensions_sig)
+      ? GNUNET_JSON_pack_string ("dummy",
+                                 NULL)
+      : GNUNET_JSON_pack_data_auto ("extensions_sig",
+                                    &kd->extensions_sig)),
+    GNUNET_JSON_pack_allow_null (
+      GNUNET_JSON_pack_array_steal ("wallet_balance_limit_without_kyc",
+                                    wblwk))
+
+    );
   return GNUNET_JSON_PACK (
     GNUNET_JSON_pack_uint64 ("version",
                              EXCHANGE_SERIALIZATION_FORMAT_VERSION),
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 1de9b602..a66aa742 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -59,9 +59,7 @@ libtalertesting_la_SOURCES = \
   testing_api_cmd_batch_withdraw.c \
   testing_api_cmd_check_aml_decision.c \
   testing_api_cmd_check_aml_decisions.c \
-  testing_api_cmd_check_keys.c \
   testing_api_cmd_common.c \
-  testing_api_cmd_connect_with_state.c \
   testing_api_cmd_contract_get.c \
   testing_api_cmd_deposit.c \
   testing_api_cmd_deposits_get.c \
@@ -106,7 +104,6 @@ libtalertesting_la_SOURCES = \
   testing_api_cmd_revoke_denom_key.c \
   testing_api_cmd_revoke_sign_key.c \
   testing_api_cmd_run_fakebank.c \
-  testing_api_cmd_serialize_keys.c \
   testing_api_cmd_set_officer.c \
   testing_api_cmd_set_wire_fee.c \
   testing_api_cmd_signal.c \
diff --git a/src/testing/test_auditor_api.c b/src/testing/test_auditor_api.c
index b5d6df0c..23646870 100644
--- a/src/testing/test_auditor_api.c
+++ b/src/testing/test_auditor_api.c
@@ -653,12 +653,12 @@ run (void *cls,
                                     NULL),
     TALER_TESTING_cmd_get_exchange ("get-exchange",
                                     cred.cfg,
+                                    NULL,
                                     true,
                                     true),
     TALER_TESTING_cmd_get_auditor ("get-auditor",
                                    cred.cfg,
                                    true),
-    // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"),
     TALER_TESTING_cmd_exec_auditor_offline ("auditor-offline",
                                             config_file),
     CMD_RUN_AUDITOR ("virgin-auditor"),
diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c
index e8cc6659..0ff9aa6e 100644
--- a/src/testing/test_exchange_api.c
+++ b/src/testing/test_exchange_api.c
@@ -1236,9 +1236,9 @@ run (void *cls,
                                       NULL),
       TALER_TESTING_cmd_get_exchange ("get-exchange",
                                       cred.cfg,
+                                      NULL,
                                       true,
                                       true),
-      // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"),
       TALER_TESTING_cmd_batch ("wire",
                                wire),
       TALER_TESTING_cmd_batch ("withdraw",
diff --git a/src/testing/test_exchange_api_keys_cherry_picking.c 
b/src/testing/test_exchange_api_keys_cherry_picking.c
index 11e18e5c..f2a8b88e 100644
--- a/src/testing/test_exchange_api_keys_cherry_picking.c
+++ b/src/testing/test_exchange_api_keys_cherry_picking.c
@@ -65,22 +65,21 @@ run (void *cls,
                                     NULL),
     TALER_TESTING_cmd_get_exchange ("get-exchange",
                                     cred.cfg,
+                                    NULL,
                                     true,
                                     true),
-    // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("initial-/keys"),
     TALER_TESTING_cmd_sleep ("sleep",
                              6 /* seconds */),
-    TALER_TESTING_cmd_check_keys ("check-keys-1"),
-    TALER_TESTING_cmd_check_keys_with_last_denom ("check-keys-2",
-                                                  "check-keys-1"),
-    TALER_TESTING_cmd_serialize_keys ("serialize-keys"),
-    TALER_TESTING_cmd_connect_with_state ("reconnect-with-state",
-                                          "serialize-keys"),
-    /**
-     * Make sure we have the same keys situation as
-     * it was before the serialization.
-     */
-    TALER_TESTING_cmd_check_keys ("check-keys-after-deserialization"),
+    TALER_TESTING_cmd_get_exchange ("get-exchange-1",
+                                    cred.cfg,
+                                    "get-exchange",
+                                    true,
+                                    true),
+    TALER_TESTING_cmd_get_exchange ("get-exchange-2",
+                                    cred.cfg,
+                                    "get-exchange-1",
+                                    true,
+                                    true),
     /**
      * Use one of the deserialized keys.
      */
diff --git a/src/testing/test_exchange_api_overlapping_keys_bug.c 
b/src/testing/test_exchange_api_overlapping_keys_bug.c
index 3f7353b9..e88cc2c3 100644
--- a/src/testing/test_exchange_api_overlapping_keys_bug.c
+++ b/src/testing/test_exchange_api_overlapping_keys_bug.c
@@ -69,13 +69,19 @@ run (void *cls,
                                     NULL),
     TALER_TESTING_cmd_get_exchange ("get-exchange",
                                     cred.cfg,
+                                    NULL,
+                                    true,
+                                    true),
+    TALER_TESTING_cmd_get_exchange ("get-exchange-1",
+                                    cred.cfg,
+                                    "get-exchange",
+                                    true,
+                                    true),
+    TALER_TESTING_cmd_get_exchange ("get-exchange-2",
+                                    cred.cfg,
+                                    NULL,
                                     true,
                                     true),
-    // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"),
-    TALER_TESTING_cmd_check_keys ("first-download"),
-    /* Causes GET /keys?last_denom_issue=0 */
-    TALER_TESTING_cmd_check_keys_with_last_denom ("second-download",
-                                                  "zero"),
     TALER_TESTING_cmd_end ()
   };
 
diff --git a/src/testing/test_exchange_api_revocation.c 
b/src/testing/test_exchange_api_revocation.c
index 1cb544da..70e5fa78 100644
--- a/src/testing/test_exchange_api_revocation.c
+++ b/src/testing/test_exchange_api_revocation.c
@@ -67,20 +67,9 @@ run (void *cls,
                                     NULL),
     TALER_TESTING_cmd_get_exchange ("get-exchange",
                                     cred.cfg,
+                                    NULL,
                                     true,
                                     true),
-#if 0
-    TALER_TESTING_cmd_auditor_add ("add-auditor-OK",
-                                   MHD_HTTP_NO_CONTENT,
-                                   false),
-    TALER_TESTING_cmd_wire_add ("add-wire-account",
-                                
"payto://x-taler-bank/localhost/2?receiver-name=2",
-                                MHD_HTTP_NO_CONTENT,
-                                false),
-    TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
-                                              config_file),
-#endif
-    // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"),
     /**
      * Fill reserve with EUR:10.02, as withdraw fee is 1 ct per
      * config.
diff --git a/src/testing/test_exchange_api_twisted.c 
b/src/testing/test_exchange_api_twisted.c
index 3a7455eb..5324a102 100644
--- a/src/testing/test_exchange_api_twisted.c
+++ b/src/testing/test_exchange_api_twisted.c
@@ -255,6 +255,7 @@ run (void *cls,
                                     NULL),
     TALER_TESTING_cmd_get_exchange ("get-exchange",
                                     cred.cfg,
+                                    NULL,
                                     true,
                                     true),
     TALER_TESTING_cmd_batch (
diff --git a/src/testing/test_exchange_management_api.c 
b/src/testing/test_exchange_management_api.c
index fded3f03..c92d4c22 100644
--- a/src/testing/test_exchange_management_api.c
+++ b/src/testing/test_exchange_management_api.c
@@ -59,6 +59,7 @@ run (void *cls,
                                     NULL),
     TALER_TESTING_cmd_get_exchange ("get-exchange",
                                     cred.cfg,
+                                    NULL,
                                     true,
                                     true),
     TALER_TESTING_cmd_get_auditor ("get-auditor",
@@ -145,7 +146,16 @@ run (void *cls,
                                 false),
     TALER_TESTING_cmd_exec_offline_sign_keys ("download-future-keys",
                                               config_file),
-    // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"),
+    TALER_TESTING_cmd_get_exchange ("get-exchange-1",
+                                    cred.cfg,
+                                    "get-exchange",
+                                    true,
+                                    true),
+    TALER_TESTING_cmd_get_exchange ("get-exchange-2",
+                                    cred.cfg,
+                                    NULL,
+                                    true,
+                                    true),
     TALER_TESTING_cmd_end ()
   };
 
diff --git a/src/testing/test_exchange_p2p.c b/src/testing/test_exchange_p2p.c
index 689d2460..3bf19135 100644
--- a/src/testing/test_exchange_p2p.c
+++ b/src/testing/test_exchange_p2p.c
@@ -504,9 +504,9 @@ run (void *cls,
                                     NULL),
     TALER_TESTING_cmd_get_exchange ("get-exchange",
                                     cred.cfg,
+                                    NULL,
                                     true,
                                     true),
-    // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"),
     TALER_TESTING_cmd_batch ("withdraw",
                              withdraw),
     TALER_TESTING_cmd_batch ("push",
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
index 733a5e2f..c4560419 100644
--- a/src/testing/test_kyc_api.c
+++ b/src/testing/test_kyc_api.c
@@ -523,9 +523,9 @@ run (void *cls,
                                     NULL),
     TALER_TESTING_cmd_get_exchange ("get-exchange",
                                     cred.cfg,
+                                    NULL,
                                     true,
                                     true),
-    // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"),
     TALER_TESTING_cmd_batch ("withdraw",
                              withdraw),
     TALER_TESTING_cmd_batch ("spend",
diff --git a/src/testing/test_taler_exchange_wirewatch.c 
b/src/testing/test_taler_exchange_wirewatch.c
index 54d25887..86b61645 100644
--- a/src/testing/test_taler_exchange_wirewatch.c
+++ b/src/testing/test_taler_exchange_wirewatch.c
@@ -87,9 +87,9 @@ run (void *cls,
                                     NULL),
     TALER_TESTING_cmd_get_exchange ("get-exchange",
                                     cred.cfg,
+                                    NULL,
                                     true,
                                     true),
-    // FIXME: TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys"),
     TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"),
     CMD_EXEC_AGGREGATOR ("run-aggregator-on-empty"),
     TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-empty",
diff --git a/src/testing/testing_api_cmd_check_keys.c 
b/src/testing/testing_api_cmd_check_keys.c
deleted file mode 100644
index 0097725c..00000000
--- a/src/testing/testing_api_cmd_check_keys.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
-  This file is part of TALER
-  (C) 2018, 2020, 2021 Taler Systems SA
-
-  TALER is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as
-  published by the Free Software Foundation; either version 3, or
-  (at your option) any later version.
-
-  TALER is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public
-  License along with TALER; see the file COPYING.  If not, see
-  <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_cmd_check_keys.c
- * @brief Implementation of "check keys" test command.
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_testing_lib.h"
-
-// FIXME: duplicated with testing_api_cmd_connect_with_state
-// FIXME: this is now duplicated with testing_api_cmd_get_exchange!
-
-/**
- * State for a "check keys" CMD.
- */
-struct CheckKeysState
-{
-
-  /**
-   * Label of a command to use to derive the "last_denom_issue" date to use.
-   * FIXME: actually use this!
-   */
-  const char *last_denom_date_ref;
-
-  /**
-   * Our interpreter state.
-   */
-  struct TALER_TESTING_Interpreter *is;
-
-  /**
-   * Our get keys operation.
-   */
-  struct TALER_EXCHANGE_GetKeysHandle *gkh;
-
-  /**
-   * Last denomination date we received when doing this request.
-   */
-  struct GNUNET_TIME_Timestamp my_denom_date;
-};
-
-
-/**
- * Function called with information about who is auditing
- * a particular exchange and what keys the exchange is using.
- *
- * @param cls closure
- * @param kr response from /keys
- */
-static void
-keys_cb (void *cls,
-         const struct TALER_EXCHANGE_KeysResponse *kr,
-         struct TALER_EXCHANGE_Keys *keys)
-{
-  struct CheckKeysState *cks = cls;
-
-  cks->gkh = NULL;
-  if (MHD_HTTP_OK != kr->hr.http_status)
-  {
-    TALER_TESTING_unexpected_status (cks->is,
-                                     kr->hr.http_status);
-    return;
-  }
-  cks->my_denom_date = kr->details.ok.keys->last_denom_issue_date;
-  /* FIXME: expose keys (and exchange_url) via trait! */
-  TALER_EXCHANGE_keys_decref (keys);
-  TALER_TESTING_interpreter_next (cks->is);
-}
-
-
-/**
- * Run the "check keys" command.
- *
- * @param cls closure.
- * @param cmd the command currently being executed.
- * @param is the interpreter state.
- */
-static void
-check_keys_run (void *cls,
-                const struct TALER_TESTING_Command *cmd,
-                struct TALER_TESTING_Interpreter *is)
-{
-  struct CheckKeysState *cks = cls;
-  const char *exchange_url
-    = TALER_TESTING_get_exchange_url (is);
-
-  cks->is = is;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Triggering GET /keys, cmd `%s'\n",
-              cmd->label);
-  cks->gkh = TALER_EXCHANGE_get_keys (
-    TALER_TESTING_interpreter_get_context (is),
-    exchange_url,
-    NULL, /* FIXME: get form last_denom_date_ref! */
-    &keys_cb,
-    cks);
-}
-
-
-/**
- * Cleanup the state.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-check_keys_cleanup (void *cls,
-                    const struct TALER_TESTING_Command *cmd)
-{
-  struct CheckKeysState *cks = cls;
-
-  (void) cmd;
-  if (NULL != cks->gkh)
-  {
-    TALER_EXCHANGE_get_keys_cancel (cks->gkh);
-    cks->gkh = NULL;
-  }
-  GNUNET_free (cks);
-}
-
-
-/**
- * Offer internal data to a "check_keys" CMD state to other
- * commands.
- *
- * @param cls closure
- * @param[out] ret result (could be anything)
- * @param trait name of the trait
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-check_keys_traits (void *cls,
-                   const void **ret,
-                   const char *trait,
-                   unsigned int index)
-{
-  struct CheckKeysState *cks = cls;
-  struct TALER_TESTING_Trait traits[] = {
-    TALER_TESTING_make_trait_timestamp (0,
-                                        &cks->my_denom_date),
-    TALER_TESTING_trait_end ()
-  };
-
-  return TALER_TESTING_get_trait (traits,
-                                  ret,
-                                  trait,
-                                  index);
-}
-
-
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_keys (const char *label)
-{
-  return TALER_TESTING_cmd_check_keys_with_last_denom (label,
-                                                       NULL);
-}
-
-
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_keys_with_last_denom (
-  const char *label,
-  const char *last_denom_date_ref)
-{
-  struct CheckKeysState *cks;
-
-  cks = GNUNET_new (struct CheckKeysState);
-  cks->last_denom_date_ref = last_denom_date_ref;
-  {
-    struct TALER_TESTING_Command cmd = {
-      .cls = cks,
-      .label = label,
-      .run = &check_keys_run,
-      .cleanup = &check_keys_cleanup,
-      .traits = &check_keys_traits
-    };
-
-    return cmd;
-  }
-}
-
-
-/* end of testing_api_cmd_check_keys.c */
diff --git a/src/testing/testing_api_cmd_connect_with_state.c 
b/src/testing/testing_api_cmd_connect_with_state.c
deleted file mode 100644
index caeef90b..00000000
--- a/src/testing/testing_api_cmd_connect_with_state.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
-  This file is part of TALER
-  (C) 2018-2023 Taler Systems SA
-
-  TALER is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as
-  published by the Free Software Foundation; either version 3, or
-  (at your option) any later version.
-
-  TALER is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public
-  License along with TALER; see the file COPYING.  If not, see
-  <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_cmd_connect_with_state.c
- * @brief Lets tests use the keys deserialization API.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include <jansson.h>
-#include "taler_testing_lib.h"
-
-
-// FIXME: this is now duplicated with testing_api_cmd_check_keys!
-// FIXME: this is now duplicated with testing_api_cmd_get_exchange!
-
-/**
- * Internal state for a connect-with-state CMD.
- */
-struct ConnectWithStateState
-{
-
-  /**
-   * Reference to a CMD that offers a serialized key-state
-   * that will be used in the reconnection.
-   */
-  const char *state_reference;
-
-  /**
-   * Interpreter state.
-   */
-  struct TALER_TESTING_Interpreter *is;
-
-  /**
-   * New exchange handle.
-   */
-  struct TALER_EXCHANGE_GetKeysHandle *exchange;
-
-  /**
-   * Keys handle.
-   */
-  struct TALER_EXCHANGE_Keys *keys;
-};
-
-
-static void
-cert_cb (void *cls,
-         const struct TALER_EXCHANGE_KeysResponse *kr,
-         struct TALER_EXCHANGE_Keys *keys)
-{
-  struct ConnectWithStateState *cwss = cls;
-  struct TALER_TESTING_Interpreter *is = cwss->is;
-  const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr;
-
-  cwss->exchange = NULL;
-  switch (hr->http_status)
-  {
-  case MHD_HTTP_OK:
-    /* dealt with below */
-    break;
-  default:
-    GNUNET_break (0);
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Got failure response %u/%d for /keys!\n",
-                hr->http_status,
-                (int) hr->ec);
-    TALER_TESTING_interpreter_fail (is);
-    return;
-  }
-  cwss->keys = keys;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Got %d DK from /keys\n",
-              kr->details.ok.keys->num_denom_keys);
-  TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-connect_with_state_run (void *cls,
-                        const struct TALER_TESTING_Command *cmd,
-                        struct TALER_TESTING_Interpreter *is)
-{
-  struct ConnectWithStateState *cwss = cls;
-  const struct TALER_TESTING_Command *state_cmd;
-  const json_t *serialized_keys;
-  const char *exchange_url;
-
-  cwss->is = is;
-  state_cmd = TALER_TESTING_interpreter_lookup_command (is,
-                                                        cwss->state_reference);
-  if (NULL == state_cmd)
-  {
-    /* Command providing serialized keys not found.  */
-    GNUNET_break (0);
-    TALER_TESTING_interpreter_fail (is);
-    return;
-  }
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_TESTING_get_trait_exchange_keys (state_cmd,
-                                                        &serialized_keys));
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_TESTING_get_trait_exchange_url (state_cmd,
-                                                       &exchange_url));
-  cwss->exchange
-    = TALER_EXCHANGE_get_keys (
-        TALER_TESTING_interpreter_get_context (is),
-        exchange_url,
-        TALER_EXCHANGE_keys_from_json (serialized_keys),
-        &cert_cb,
-        cwss);
-}
-
-
-/**
- * Offer exchange connection as trait.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static enum GNUNET_GenericReturnValue
-connect_with_state_traits (void *cls,
-                           const void **ret,
-                           const char *trait,
-                           unsigned int index)
-{
-  struct ConnectWithStateState *cwss = cls;
-  struct TALER_TESTING_Trait traits[] = {
-    TALER_TESTING_make_trait_keys (cwss->keys),
-    // FIXME: also expose exchange_url as trait
-    TALER_TESTING_trait_end ()
-  };
-
-  return TALER_TESTING_get_trait (traits,
-                                  ret,
-                                  trait,
-                                  index);
-}
-
-
-/**
- * Cleanup the state of a "connect with state" CMD.  Just
- * a placeholder to avoid jumping on an invalid address.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-connect_with_state_cleanup (void *cls,
-                            const struct TALER_TESTING_Command *cmd)
-{
-  struct ConnectWithStateState *cwss = cls;
-
-  TALER_EXCHANGE_keys_decref (cwss->keys);
-  cwss->keys = NULL;
-  if (NULL != cwss->exchange)
-  {
-    TALER_EXCHANGE_get_keys_cancel (cwss->exchange);
-    cwss->exchange = NULL;
-  }
-  GNUNET_free (cwss);
-}
-
-
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_connect_with_state (const char *label,
-                                      const char *state_reference)
-{
-  struct ConnectWithStateState *cwss;
-
-  cwss = GNUNET_new (struct ConnectWithStateState);
-  cwss->state_reference = state_reference;
-  {
-    struct TALER_TESTING_Command cmd = {
-      .cls = cwss,
-      .label = label,
-      .run = connect_with_state_run,
-      .cleanup = connect_with_state_cleanup,
-      .traits = connect_with_state_traits
-    };
-
-    return cmd;
-  }
-}
diff --git a/src/testing/testing_api_cmd_get_exchange.c 
b/src/testing/testing_api_cmd_get_exchange.c
index b6634286..69a6e82b 100644
--- a/src/testing/testing_api_cmd_get_exchange.c
+++ b/src/testing/testing_api_cmd_get_exchange.c
@@ -63,6 +63,17 @@ struct GetExchangeState
    */
   char *master_priv_file;
 
+  /**
+   * Label of a command to use to obtain existing
+   * keys.
+   */
+  const char *last_keys_ref;
+
+  /**
+   * Last denomination date we received when doing this request.
+   */
+  struct GNUNET_TIME_Timestamp my_denom_date;
+
   /**
    * Are we waiting for /keys before continuing?
    */
@@ -70,6 +81,14 @@ struct GetExchangeState
 };
 
 
+/**
+ * Function called with information about who is auditing
+ * a particular exchange and what keys the exchange is using.
+ *
+ * @param cls closure
+ * @param kr response from /keys
+ * @param[in] keys the keys of the exchange
+ */
 static void
 cert_cb (void *cls,
          const struct TALER_EXCHANGE_KeysResponse *kr,
@@ -90,6 +109,7 @@ cert_cb (void *cls,
       TALER_TESTING_interpreter_next (is);
       return;
     }
+    ges->my_denom_date = kr->details.ok.keys->last_denom_issue_date;
     return;
   default:
     GNUNET_break (0);
@@ -120,6 +140,7 @@ get_exchange_run (void *cls,
                   struct TALER_TESTING_Interpreter *is)
 {
   struct GetExchangeState *ges = cls;
+  struct TALER_EXCHANGE_Keys *xkeys = NULL;
 
   (void) cmd;
   if (NULL == ges->exchange_url)
@@ -128,6 +149,72 @@ get_exchange_run (void *cls,
     TALER_TESTING_interpreter_fail (is);
     return;
   }
+  if (NULL != ges->last_keys_ref)
+  {
+    const struct TALER_TESTING_Command *state_cmd;
+    struct TALER_EXCHANGE_Keys *old_keys;
+    const char *exchange_url;
+    json_t *s_keys;
+
+    state_cmd
+      = TALER_TESTING_interpreter_lookup_command (is,
+                                                  ges->last_keys_ref);
+    if (NULL == state_cmd)
+    {
+      /* Command providing serialized keys not found.  */
+      GNUNET_break (0);
+      TALER_TESTING_interpreter_fail (is);
+      return;
+    }
+    if (GNUNET_OK !=
+        TALER_TESTING_get_trait_keys (state_cmd,
+                                      &old_keys))
+    {
+      GNUNET_break (0);
+      TALER_TESTING_interpreter_fail (is);
+      return;
+    }
+    if (NULL == old_keys)
+    {
+      GNUNET_break (0);
+      TALER_TESTING_interpreter_fail (is);
+      return;
+    }
+    if (GNUNET_OK !=
+        TALER_TESTING_get_trait_exchange_url (state_cmd,
+                                              &exchange_url))
+    {
+      GNUNET_break (0);
+      TALER_TESTING_interpreter_fail (is);
+      return;
+    }
+    if (0 != strcmp (exchange_url,
+                     ges->exchange_url))
+    {
+      GNUNET_break (0);
+      TALER_TESTING_interpreter_fail (is);
+      return;
+    }
+    s_keys = TALER_EXCHANGE_keys_to_json (old_keys);
+    if (NULL == s_keys)
+    {
+      GNUNET_break (0);
+      TALER_TESTING_interpreter_fail (is);
+      return;
+    }
+    xkeys = TALER_EXCHANGE_keys_from_json (s_keys);
+    if (NULL == xkeys)
+    {
+      GNUNET_break (0);
+      json_dumpf (s_keys,
+                  stderr,
+                  JSON_INDENT (2));
+      json_decref (s_keys);
+      TALER_TESTING_interpreter_fail (is);
+      return;
+    }
+    json_decref (s_keys);
+  }
   if (NULL != ges->master_priv_file)
   {
     if (GNUNET_SYSERR ==
@@ -136,6 +223,7 @@ get_exchange_run (void *cls,
                                            &ges->master_priv.eddsa_priv))
     {
       GNUNET_break (0);
+      TALER_EXCHANGE_keys_decref (xkeys);
       TALER_TESTING_interpreter_fail (is);
       return;
     }
@@ -144,9 +232,10 @@ get_exchange_run (void *cls,
   ges->exchange
     = TALER_EXCHANGE_get_keys (TALER_TESTING_interpreter_get_context (is),
                                ges->exchange_url,
-                               NULL,
+                               xkeys,
                                &cert_cb,
                                ges);
+  TALER_EXCHANGE_keys_decref (xkeys);
   if (NULL == ges->exchange)
   {
     GNUNET_break (0);
@@ -208,6 +297,8 @@ get_exchange_traits (void *cls,
       TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub),
       TALER_TESTING_make_trait_keys (ges->keys),
       TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
+      TALER_TESTING_make_trait_timestamp (0,
+                                          &ges->my_denom_date),
       TALER_TESTING_trait_end ()
     };
 
@@ -221,6 +312,8 @@ get_exchange_traits (void *cls,
     struct TALER_TESTING_Trait traits[] = {
       TALER_TESTING_make_trait_master_priv (&ges->master_priv),
       TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
+      TALER_TESTING_make_trait_timestamp (0,
+                                          &ges->my_denom_date),
       TALER_TESTING_trait_end ()
     };
 
@@ -291,6 +384,7 @@ struct TALER_TESTING_Command
 TALER_TESTING_cmd_get_exchange (
   const char *label,
   const struct GNUNET_CONFIGURATION_Handle *cfg,
+  const char *last_keys_ref,
   bool wait_for_keys,
   bool load_private_key)
 {
@@ -298,6 +392,7 @@ TALER_TESTING_cmd_get_exchange (
 
   ges = GNUNET_new (struct GetExchangeState);
   ges->exchange_url = get_exchange_base_url (cfg);
+  ges->last_keys_ref = last_keys_ref;
   if (load_private_key)
     ges->master_priv_file = get_exchange_master_priv_file (cfg);
   ges->wait_for_keys = wait_for_keys;
diff --git a/src/testing/testing_api_cmd_serialize_keys.c 
b/src/testing/testing_api_cmd_serialize_keys.c
deleted file mode 100644
index 13464dff..00000000
--- a/src/testing/testing_api_cmd_serialize_keys.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
-  This file is part of TALER
-  (C) 2018-2023 Taler Systems SA
-
-  TALER is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as
-  published by the Free Software Foundation; either version 3, or
-  (at your option) any later version.
-
-  TALER is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public
-  License along with TALER; see the file COPYING.  If not, see
-  <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_cmd_serialize_keys.c
- * @brief Lets tests use the keys serialization API.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include <jansson.h>
-#include "taler_testing_lib.h"
-
-
-/**
- * Internal state for a serialize-keys CMD.
- */
-struct SerializeKeysState
-{
-  /**
-   * Serialized keys.
-   */
-  json_t *keys;
-
-  /**
-   * Exchange URL.  Needed because the exchange gets disconnected
-   * from, after keys serialization.  This value is then needed by
-   * subsequent commands that have to reconnect to the exchange.
-   */
-  char *exchange_url;
-};
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-serialize_keys_run (void *cls,
-                    const struct TALER_TESTING_Command *cmd,
-                    struct TALER_TESTING_Interpreter *is)
-{
-  struct SerializeKeysState *sks = cls;
-  struct TALER_EXCHANGE_Keys *keys
-    = TALER_TESTING_get_keys (is);
-
-  if (NULL == keys)
-    return;
-  sks->keys = TALER_EXCHANGE_keys_to_json (keys);
-  if (NULL == sks->keys)
-  {
-    GNUNET_break (0);
-    TALER_TESTING_interpreter_fail (is);
-  }
-  sks->exchange_url
-    = GNUNET_strdup (
-        TALER_TESTING_get_exchange_url (is));
-  TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Cleanup the state of a "serialize keys" CMD.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-serialize_keys_cleanup (void *cls,
-                        const struct TALER_TESTING_Command *cmd)
-{
-  struct SerializeKeysState *sks = cls;
-
-  if (NULL != sks->keys)
-    json_decref (sks->keys);
-  GNUNET_free (sks->exchange_url);
-  GNUNET_free (sks);
-}
-
-
-/**
- * Offer serialized keys as trait.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static enum GNUNET_GenericReturnValue
-serialize_keys_traits (void *cls,
-                       const void **ret,
-                       const char *trait,
-                       unsigned int index)
-{
-  struct SerializeKeysState *sks = cls;
-  struct TALER_TESTING_Trait traits[] = {
-    TALER_TESTING_make_trait_exchange_keys (sks->keys),
-    TALER_TESTING_make_trait_exchange_url (sks->exchange_url),
-    TALER_TESTING_trait_end ()
-  };
-
-  return TALER_TESTING_get_trait (traits,
-                                  ret,
-                                  trait,
-                                  index);
-}
-
-
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_serialize_keys (const char *label)
-{
-  struct SerializeKeysState *sks;
-
-  sks = GNUNET_new (struct SerializeKeysState);
-  {
-    struct TALER_TESTING_Command cmd = {
-      .cls = sks,
-      .label = label,
-      .run = serialize_keys_run,
-      .cleanup = serialize_keys_cleanup,
-      .traits = serialize_keys_traits
-    };
-
-    return cmd;
-  }
-}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]