commit 99f8abcc556159faffab39f6dfe62c70df279aba
parent f6147b01989563435ea723da76aabca9a3a69959
Author: Matyja Lukas Adam <lukas.matyja@students.bfh.ch>
Date: Tue, 2 Apr 2024 11:58:16 +0200
[json][pq] some functions for issue receipts
Diffstat:
9 files changed, 705 insertions(+), 36 deletions(-)
diff --git a/src/donau/Makefile.am b/src/donau/Makefile.am
@@ -48,8 +48,8 @@ donau_httpd_SOURCES = \
donau-httpd_get-charity.c donau-httpd_post-charity.c \
donau-httpd_get-history.c \
donau-httpd_post-submit-receipts.c donau_httpd_submit-receipts.h \
- donau-httpd_terms.c donau-httpd_terms.h
- #donau-httpd_post-batch-issue.c donau_httpd_batch-issue.h
+ donau-httpd_terms.c donau-httpd_terms.h \
+ donau-httpd_post-batch-issue.c donau_httpd_batch-issue.h
# Testcases
diff --git a/src/donau/donau-httpd_keys.c b/src/donau/donau-httpd_keys.c
@@ -1787,4 +1787,56 @@ DH_RESPONSE_reply_not_modified (struct MHD_Connection *connection,
}
+struct DH_DonationUnitKey *
+DH_keys_donation_unit_by_hash (
+ const struct DONAU_DonationUnitHashP *h_du_pub,
+ struct MHD_Connection *conn,
+ MHD_RESULT *mret)
+{
+ struct DH_KeyStateHandle *ksh;
+
+ ksh = DH_keys_get_state ();
+ if (NULL == ksh)
+ {
+ *mret = TALER_MHD_reply_with_error (conn,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
+ NULL);
+ return NULL;
+ }
+ return DH_keys_donation_unit_by_hash_from_state (ksh,
+ h_du_pub,
+ conn,
+ mret);
+}
+
+
+struct DH_DonationUnitKey *
+DH_keys_donation_unit_by_hash_from_state (
+ const struct DH_KeyStateHandle *ksh,
+ const struct DONAU_DonationUnitHashP *h_du_pub,
+ struct MHD_Connection *conn,
+ MHD_RESULT *mret)
+{
+ struct DH_DonationUnitKey *dk;
+
+ dk = GNUNET_CONTAINER_multihashmap_get (ksh->donation_unit_map,
+ &h_du_pub->hash);
+ if (NULL == dk)
+ {
+ if (NULL == conn)
+ return NULL;
+ // FIXME: server error or not found?
+ // *mret = TEH_RESPONSE_reply_unknown_denom_pub_hash (conn,
+ // h_denom_pub);
+ *mret = TALER_MHD_reply_with_error (conn,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_DONAU_GENERIC_KEYS_MISSING,
+ NULL);
+ return NULL;
+ }
+ return dk;
+}
+
+
/* end of donau-httpd_keys.c */
diff --git a/src/donau/donau-httpd_keys.h b/src/donau/donau-httpd_keys.h
@@ -32,6 +32,18 @@
/**
+ * Snapshot of the (coin and signing) keys (including private keys) of
+ * the exchange. There can be multiple instances of this struct, as it is
+ * reference counted and only destroyed once the last user is done
+ * with it. The current instance is acquired using
+ * #TEH_KS_acquire(). Using this function increases the
+ * reference count. The contents of this structure (except for the
+ * reference counter) should be considered READ-ONLY until it is
+ * ultimately destroyed (as there can be many concurrent users).
+ */
+struct DH_KeyStateHandle;
+
+/**
* @brief All information about a donation unit key (which is used to
* sign donation receipts into existence).
*/
@@ -174,7 +186,6 @@ DH_handler_keys (struct DH_RequestContext *rc,
const char *const args[]);
-// TODO: Implement
/**
* Look up the issue for a donation unit public key. Note that the result
* must only be used in this thread and only until another key or
@@ -192,6 +203,25 @@ DH_keys_donation_unit_by_hash (
struct MHD_Connection *conn,
MHD_RESULT *mret);
+/**
+ * Look up the issue for a donation unit public key using a given @a ksh. This allows
+ * requesting multiple donation units with the same @a ksh which thus will
+ * remain valid until the next call to #TEH_keys_donation_unit_by_hash() or
+ * #DH_keys_get_state() or #DH_keys_donau_sign().
+ *
+ * @param ksh key state state to look in
+ * @param h_du_pub hash of donation unit public key
+ * @param[in,out] conn connection used to return status message if NULL is returned
+ * @param[out] mret set to the MHD status if NULL is returned
+ * @return the donation unit key issue,
+ * or NULL if @a h_du_pub could not be found
+ */
+struct DH_DonationUnitKey *
+DH_keys_donation_unit_by_hash_from_state (
+ const struct DH_KeyStateHandle *ksh,
+ const struct DONAU_DonationUnitHashP *h_du_pub,
+ struct MHD_Connection *conn,
+ MHD_RESULT *mret);
/**
* Initialize keys subsystem.
diff --git a/src/donau/donau-httpd_post-batch-issue.c b/src/donau/donau-httpd_post-batch-issue.c
@@ -47,6 +47,11 @@ struct IssueReceiptsContext
};
/**
+ * insert failure because of a bad issued receipt lookup? Try another time...
+ */
+bool second_time = false;
+
+/**
* Parse a bkp encoded in JSON.
*
* @param[out] bkp where to return the result
@@ -61,8 +66,8 @@ parse_json_bkp (struct DONAU_BlindedUniqueDonationIdentifierKeyPair *bkp,
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("h_du_pub",
&bkp->h_donation_unit_pub),
- DONAU_JSON_spec_blinded_udi ("blinded_udi",
- &bkp->blinded_udi),
+ DONAU_JSON_spec_blinded_donation_identifier ("blinded_udi",
+ &bkp->blinded_udi),
GNUNET_JSON_spec_end ()
};
@@ -82,19 +87,18 @@ parse_json_bkp (struct DONAU_BlindedUniqueDonationIdentifierKeyPair *bkp,
/**
* Parse signatures to JSON.
*
- * @param[out] sign_arr_obj JSON object
- * @param signatures
* @param num_sig number of signatures
+ * @param signatures
+ * @param[out] j_signatures JSON object
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if we could not parse
* is malformed.
*/
void
-signatures_to_JSON (const unsigned int num_sig,
+signatures_to_JSON (const size_t num_sig,
struct DONAU_BlindedDonationUnitSignature*signatures,
json_t *j_signatures)
{
- int i = 0;
- while (i < num_sig)
+ for (size_t i = 0; i < num_sig; i++)
{
struct DONAU_BlindedDonationUnitSignature*signature = &signatures[i];
GNUNET_assert (
@@ -103,7 +107,6 @@ signatures_to_JSON (const unsigned int num_sig,
GNUNET_JSON_PACK (
DONAU_JSON_pack_blinded_donation_unit_sig ("blinded_signatures",
signature))));
- i++;
}
}
@@ -171,7 +174,7 @@ DH_handler_issue_receipts_post (struct DH_RequestContext *rc,
if (0 != num_bkp)
{
json_t *bkp_obj;
- unsigned int index;
+ size_t index;
struct DONAU_BlindedUniqueDonationIdentifierKeyPair *bkp
= GNUNET_new_array
@@ -251,8 +254,9 @@ DH_handler_issue_receipts_post (struct DH_RequestContext *rc,
struct DONAUDB_IssuedReceiptsMetaData check_receipts_meta;
struct DONAU_DonationReceiptHashP h_receipts = {0};
json_t *blind_signatures = json_array ();
+ GNUNET_assert (NULL != blind_signatures);
- for (int i = 0; i < num_bkp; i++)
+ for (size_t i = 0; i < num_bkp; i++)
{
struct GNUNET_HashCode temp_hash;
GNUNET_CRYPTO_hash (irc.bkp,
@@ -290,7 +294,7 @@ start:
}
/* calculate new receipts to date and check annual limit */
struct TALER_Amount receipts_sum;
- for (int i = 0; i < num_bkp; i++)
+ for (size_t i = 0; i < num_bkp; i++)
{
MHD_RESULT mret;
struct DH_DonationUnitKey *dk;
@@ -319,8 +323,7 @@ start:
/* sign budis and send the signatures back */
struct DONAU_BlindedDonationUnitSignature *du_sigs = {0};
{
- int i = 0;
- while (i < num_bkp)
+ for (size_t i = 0; i < num_bkp; i++)
{
// TODO: get donation unit private key
const struct DONAU_DonationUnitPrivateKey du_priv;
@@ -337,7 +340,6 @@ start:
NULL);
}
- i++;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"made blind signatures!");
diff --git a/src/include/donau_json_lib.h b/src/include/donau_json_lib.h
@@ -59,7 +59,7 @@ DONAU_JSON_spec_donation_unit_group (const char *field,
const char *currency,
struct DONAU_DonationUnitGroup *group);
-// TODO: Implement (like exchange TALER_JSON_spec_blinded_planchet method)
+
/**
* Generate line in parser specification for a
* blinded unique identifier.
@@ -69,9 +69,11 @@ DONAU_JSON_spec_donation_unit_group (const char *field,
* @return corresponding field spec
*/
struct GNUNET_JSON_Specification
-DONAU_JSON_spec_blinded_udi (const char *field,
- struct DONAU_BlindedUniqueDonationIdentifier *
- blinded_udi);
+DONAU_JSON_spec_blinded_donation_identifier (const char *field,
+ struct
+ DONAU_BlindedUniqueDonationIdentifier
+ *
+ blinded_udi);
/**
@@ -99,7 +101,6 @@ DONAU_JSON_pack_donation_unit_pub (
const char *name,
const struct DONAU_DonationUnitPublicKey *pk);
-// TODO: implement
/**
* Generate packer instruction for a JSON field of type
* blinded donation unit signature (that needs to be
diff --git a/src/json/donau_json.c b/src/json/donau_json.c
@@ -24,7 +24,7 @@
#include <taler/taler_json_lib.h>
#include <unistr.h>
#include "donau_json_lib.h"
-#
+
/**
* Parse given JSON object partially into a donation unit public key.
@@ -38,8 +38,8 @@
*/
static enum GNUNET_GenericReturnValue
parse_donation_unit_pub_cipher (void *cls,
- json_t *root,
- struct GNUNET_JSON_Specification *spec)
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
{
struct DONAU_DonationUnitPublicKey *donation_unit_pub = spec->ptr;
enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher =
@@ -105,6 +105,7 @@ parse_donation_unit_pub_cipher (void *cls,
return GNUNET_SYSERR;
}
+
/**
* Cleanup data left from parsing donation unit public key.
*
@@ -113,7 +114,7 @@ parse_donation_unit_pub_cipher (void *cls,
*/
static void
clean_donation_unit_pub (void *cls,
- struct GNUNET_JSON_Specification *spec)
+ struct GNUNET_JSON_Specification *spec)
{
struct DONAU_DonationUnitPublicKey *donation_unit_pub = spec->ptr;
@@ -121,9 +122,12 @@ clean_donation_unit_pub (void *cls,
DONAU_donation_unit_pub_free (donation_unit_pub);
}
+
struct GNUNET_JSON_Specification
DONAU_JSON_spec_donation_unit_pub_cipher (const char *field,
- enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher,
+ enum
+ GNUNET_CRYPTO_BlindSignatureAlgorithm
+ cipher,
struct DONAU_DonationUnitPublicKey *pk)
{
struct GNUNET_JSON_Specification ret = {
@@ -137,6 +141,7 @@ DONAU_JSON_spec_donation_unit_pub_cipher (const char *field,
return ret;
}
+
/**
* Convert string value to numeric cipher value.
*
@@ -147,18 +152,19 @@ static enum GNUNET_CRYPTO_BlindSignatureAlgorithm
string_to_cipher (const char *cipher_s)
{
if (0 == strcasecmp (cipher_s,
- "RSA"))
+ "RSA"))
return GNUNET_CRYPTO_BSA_RSA;
if (0 == strcasecmp (cipher_s,
- "CS"))
+ "CS"))
return GNUNET_CRYPTO_BSA_CS;
return GNUNET_CRYPTO_BSA_INVALID;
}
+
static enum GNUNET_GenericReturnValue
parse_donation_unit_group (void *cls,
- json_t *root,
- struct GNUNET_JSON_Specification *spec)
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
{
struct DONAU_DonationUnitGroup *group = spec->ptr;
const char *cipher;
@@ -199,10 +205,11 @@ parse_donation_unit_group (void *cls,
return GNUNET_OK;
}
+
struct GNUNET_JSON_Specification
DONAU_JSON_spec_donation_unit_group (const char *name,
- const char *currency,
- struct DONAU_DonationUnitGroup *group)
+ const char *currency,
+ struct DONAU_DonationUnitGroup *group)
{
struct GNUNET_JSON_Specification ret = {
.cls = (void *) currency,
@@ -213,4 +220,181 @@ DONAU_JSON_spec_donation_unit_group (const char *name,
};
return ret;
-}
-\ No newline at end of file
+}
+
+
+/**
+ * Parse given JSON object to blinded planchet.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_blinded_planchet (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
+ struct GNUNET_CRYPTO_BlindedMessage *blinded_message;
+ const char *cipher;
+ struct GNUNET_JSON_Specification dspec[] = {
+ GNUNET_JSON_spec_string ("cipher",
+ &cipher),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ dspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ blinded_message = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
+ blinded_message->rc = 1;
+ blinded_message->cipher = string_to_cipher (cipher);
+ switch (blinded_message->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_varsize (
+ "rsa_blinded_planchet",
+ &blinded_message->details.rsa_blinded_message.blinded_msg,
+ &blinded_message->details.rsa_blinded_message.blinded_msg_size),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_message);
+ return GNUNET_SYSERR;
+ }
+ blinded_planchet->blinded_message = blinded_message;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed_auto (
+ "cs_nonce",
+ &blinded_message->details.cs_blinded_message.nonce),
+ GNUNET_JSON_spec_fixed_auto (
+ "cs_blinded_c0",
+ &blinded_message->details.cs_blinded_message.c[0]),
+ GNUNET_JSON_spec_fixed_auto (
+ "cs_blinded_c1",
+ &blinded_message->details.cs_blinded_message.c[1]),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_message);
+ return GNUNET_SYSERR;
+ }
+ blinded_planchet->blinded_message = blinded_message;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_message);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing blinded planchet.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_blinded_planchet (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
+
+ (void) cls;
+ TALER_blinded_planchet_free (blinded_planchet);
+}
+
+
+struct GNUNET_JSON_Specification
+DONAU_JSON_spec_blinded_donation_identifier (const char *field,
+ struct
+ DONAU_BlindedUniqueDonationIdentifier
+ *
+ blinded_udi)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_blinded_planchet,
+ .cleaner = &clean_blinded_planchet,
+ .field = field,
+ .ptr = blinded_udi
+ };
+
+ blinded_udi->blinded_message = NULL;
+ return ret;
+}
+
+
+struct GNUNET_JSON_PackSpec
+DONAU_JSON_pack_blinded_donation_unit_sig (
+ const char *name,
+ const struct DONAU_BlindedDonationUnitSignature *sig)
+{
+ const struct GNUNET_CRYPTO_BlindedSignature *bs;
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == sig)
+ return ps;
+ bs = sig->blinded_sig;
+ switch (bs->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "RSA"),
+ GNUNET_JSON_pack_rsa_signature ("blinded_rsa_signature",
+ bs->details.blinded_rsa_signature));
+ return ps;
+ case GNUNET_CRYPTO_BSA_CS:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "CS"),
+ GNUNET_JSON_pack_uint64 ("b",
+ bs->details.blinded_cs_answer.b),
+ GNUNET_JSON_pack_data_auto ("s",
+ &bs->details.blinded_cs_answer.s_scalar));
+ return ps;
+ }
+ GNUNET_assert (0);
+ return ps;
+}
+
+
+/* end of json/donau_json.c */
+\ No newline at end of file
diff --git a/src/json/json_helper.c b/src/json/json_helper.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2024 Taler Systems SA
+ Copyright (C) 2024 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
diff --git a/src/json/json_pack.c b/src/json/json_pack.c
@@ -17,6 +17,7 @@
* @file json/json_pack.c
* @brief helper functions for JSON object packing
* @author Christian Grothoff
+ * @author Lukas Matyja
*/
#include <taler/platform.h>
#include <gnunet/gnunet_util_lib.h>
diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c
@@ -122,4 +122,403 @@ DONAU_PQ_query_param_donation_unit_pub (
}
+// FIXME:
+// /**
+// * Function to generate a typ specific query parameter and corresponding closure
+// *
+// * @param num Number of elements in @a elements
+// * @param continuous If true, @a elements is an continuous array of data
+// * @param elements Array of @a num elements, either continuous or pointers
+// * @param sizes Array of @a num sizes, one per element, may be NULL
+// * @param same_size If not 0, all elements in @a elements have this size
+// * @param typ Supported internal type of each element in @a elements
+// * @param oid Oid of the type to be used in Postgres
+// * @param[in,out] db our database handle for looking up OIDs
+// * @return Query parameter
+// */
+// static struct GNUNET_PQ_QueryParam
+// query_param_array_generic (
+// unsigned int num,
+// bool continuous,
+// const void *elements,
+// const size_t *sizes,
+// size_t same_size,
+// enum TALER_PQ_ArrayType typ,
+// Oid oid,
+// struct GNUNET_PQ_Context *db)
+// {
+// struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls);
+
+// meta->typ = typ;
+// meta->oid = oid;
+// meta->sizes = sizes;
+// meta->same_size = same_size;
+// meta->continuous = continuous;
+// meta->db = db;
+
+// {
+// struct GNUNET_PQ_QueryParam res = {
+// .conv = qconv_array,
+// .conv_cls = meta,
+// .conv_cls_cleanup = qconv_array_cls_cleanup,
+// .data = elements,
+// .size = num,
+// .num_params = 1,
+// };
+
+// return res;
+// }
+// }
+
+// struct GNUNET_PQ_QueryParam
+// DONAU_PQ_query_param_array_blinded_donation_unit_sig (
+// size_t num,
+// const struct DONAU_BlindedDonationUnitSignature *du_sigs,
+// struct GNUNET_PQ_Context *db)
+// {
+// Oid oid;
+
+// GNUNET_assert (GNUNET_OK ==
+// GNUNET_PQ_get_oid_by_name (db,
+// "bytea",
+// &oid));
+// return query_param_array_generic (num,
+// true,
+// du_sigs,
+// NULL,
+// 0,
+// TALER_PQ_array_of_blinded_denom_sig,
+// oid,
+// NULL);
+// }
+
+// /**
+// * Extract data from a Postgres database @a result as array of a specific type
+// * from row @a row. The type information and optionally additional
+// * out-parameters are given in @a cls which is of type array_result_cls.
+// *
+// * @param cls closure of type array_result_cls
+// * @param result where to extract data from
+// * @param row row to extract data from
+// * @param fname name (or prefix) of the fields to extract from
+// * @param[in,out] dst_size where to store size of result, may be NULL
+// * @param[out] dst where to store the result
+// * @return
+// * #GNUNET_YES if all results could be extracted
+// * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+// */
+// static enum GNUNET_GenericReturnValue
+// extract_array_generic (
+// void *cls,
+// PGresult *result,
+// int row,
+// const char *fname,
+// size_t *dst_size,
+// void *dst)
+// {
+// const struct ArrayResultCls *info = cls;
+// int data_sz;
+// char *data;
+// void *out = NULL;
+// struct GNUNET_PQ_ArrayHeader_P header;
+// int col_num;
+
+// GNUNET_assert (NULL != dst);
+// *((void **) dst) = NULL;
+
+// #define FAIL_IF(cond) \
+// do { \
+// if ((cond)) \
+// { \
+// GNUNET_break (! (cond)); \
+// goto FAIL; \
+// } \
+// } while (0)
+
+// col_num = PQfnumber (result, fname);
+// FAIL_IF (0 > col_num);
+
+// data_sz = PQgetlength (result, row, col_num);
+// FAIL_IF (0 > data_sz);
+// FAIL_IF (sizeof(header) > (size_t) data_sz);
+
+// data = PQgetvalue (result, row, col_num);
+// FAIL_IF (NULL == data);
+
+// {
+// struct GNUNET_PQ_ArrayHeader_P *h =
+// (struct GNUNET_PQ_ArrayHeader_P *) data;
+
+// header.ndim = ntohl (h->ndim);
+// header.has_null = ntohl (h->has_null);
+// header.oid = ntohl (h->oid);
+// header.dim = ntohl (h->dim);
+// header.lbound = ntohl (h->lbound);
+
+// FAIL_IF (1 != header.ndim);
+// FAIL_IF (INT_MAX <= header.dim);
+// FAIL_IF (0 != header.has_null);
+// FAIL_IF (1 != header.lbound);
+// FAIL_IF (info->oid != header.oid);
+// }
+
+// if (NULL != info->num)
+// *info->num = header.dim;
+
+// {
+// char *in = data + sizeof(header);
+
+// switch (info->typ)
+// {
+// case TALER_PQ_array_of_amount:
+// {
+// struct TALER_Amount *amounts;
+// if (NULL != dst_size)
+// *dst_size = sizeof(struct TALER_Amount) * (header.dim);
+
+// amounts = GNUNET_new_array (header.dim,
+// struct TALER_Amount);
+// *((void **) dst) = amounts;
+
+// for (uint32_t i = 0; i < header.dim; i++)
+// {
+// struct TALER_PQ_AmountP ap;
+// struct TALER_Amount *amount = &amounts[i];
+// uint32_t val;
+// size_t sz;
+
+// GNUNET_memcpy (&val,
+// in,
+// sizeof(val));
+// sz = ntohl (val);
+// in += sizeof(val);
+
+// /* total size for this array-entry */
+// FAIL_IF (sizeof(ap) != sz);
+
+// GNUNET_memcpy (&ap,
+// in,
+// sz);
+// FAIL_IF (2 != ntohl (ap.cnt));
+
+// amount->value = GNUNET_ntohll (ap.v);
+// amount->fraction = ntohl (ap.f);
+// GNUNET_memcpy (amount->currency,
+// info->currency,
+// TALER_CURRENCY_LEN);
+
+// in += sizeof(struct TALER_PQ_AmountP);
+// }
+// return GNUNET_OK;
+// }
+// case TALER_PQ_array_of_denom_hash:
+// if (NULL != dst_size)
+// *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim);
+// out = GNUNET_new_array (header.dim,
+// struct TALER_DenominationHashP);
+// *((void **) dst) = out;
+// for (uint32_t i = 0; i < header.dim; i++)
+// {
+// uint32_t val;
+// size_t sz;
+
+// GNUNET_memcpy (&val,
+// in,
+// sizeof(val));
+// sz = ntohl (val);
+// FAIL_IF (sz != sizeof(struct TALER_DenominationHashP));
+// in += sizeof(uint32_t);
+// *(struct TALER_DenominationHashP *) out =
+// *(struct TALER_DenominationHashP *) in;
+// in += sz;
+// out += sz;
+// }
+// return GNUNET_OK;
+
+// case TALER_PQ_array_of_hash_code:
+// if (NULL != dst_size)
+// *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim);
+// out = GNUNET_new_array (header.dim,
+// struct GNUNET_HashCode);
+// *((void **) dst) = out;
+// for (uint32_t i = 0; i < header.dim; i++)
+// {
+// uint32_t val;
+// size_t sz;
+
+// GNUNET_memcpy (&val,
+// in,
+// sizeof(val));
+// sz = ntohl (val);
+// FAIL_IF (sz != sizeof(struct GNUNET_HashCode));
+// in += sizeof(uint32_t);
+// *(struct GNUNET_HashCode *) out =
+// *(struct GNUNET_HashCode *) in;
+// in += sz;
+// out += sz;
+// }
+// return GNUNET_OK;
+
+// case TALER_PQ_array_of_blinded_coin_hash:
+// if (NULL != dst_size)
+// *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim);
+// out = GNUNET_new_array (header.dim,
+// struct TALER_BlindedCoinHashP);
+// *((void **) dst) = out;
+// for (uint32_t i = 0; i < header.dim; i++)
+// {
+// uint32_t val;
+// size_t sz;
+
+// GNUNET_memcpy (&val,
+// in,
+// sizeof(val));
+// sz = ntohl (val);
+// FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP));
+// in += sizeof(uint32_t);
+// *(struct TALER_BlindedCoinHashP *) out =
+// *(struct TALER_BlindedCoinHashP *) in;
+// in += sz;
+// out += sz;
+// }
+// return GNUNET_OK;
+
+// case TALER_PQ_array_of_blinded_denom_sig:
+// {
+// struct TALER_BlindedDenominationSignature *denom_sigs;
+// if (0 == header.dim)
+// {
+// if (NULL != dst_size)
+// *dst_size = 0;
+// break;
+// }
+
+// denom_sigs = GNUNET_new_array (header.dim,
+// struct TALER_BlindedDenominationSignature);
+// *((void **) dst) = denom_sigs;
+
+// /* copy data */
+// for (uint32_t i = 0; i < header.dim; i++)
+// {
+// struct TALER_BlindedDenominationSignature *denom_sig = &denom_sigs[i];
+// struct GNUNET_CRYPTO_BlindedSignature *bs;
+// uint32_t be[2];
+// uint32_t val;
+// size_t sz;
+
+// GNUNET_memcpy (&val,
+// in,
+// sizeof(val));
+// sz = ntohl (val);
+// FAIL_IF (sizeof(be) > sz);
+
+// in += sizeof(val);
+// GNUNET_memcpy (&be,
+// in,
+// sizeof(be));
+// FAIL_IF (0x01 != ntohl (be[1])); /* magic marker: blinded */
+
+// in += sizeof(be);
+// sz -= sizeof(be);
+// bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
+// bs->cipher = ntohl (be[0]);
+// bs->rc = 1;
+// switch (bs->cipher)
+// {
+// case GNUNET_CRYPTO_BSA_RSA:
+// bs->details.blinded_rsa_signature
+// = GNUNET_CRYPTO_rsa_signature_decode (in,
+// sz);
+// if (NULL == bs->details.blinded_rsa_signature)
+// {
+// GNUNET_free (bs);
+// FAIL_IF (true);
+// }
+// break;
+// case GNUNET_CRYPTO_BSA_CS:
+// if (sizeof(bs->details.blinded_cs_answer) != sz)
+// {
+// GNUNET_free (bs);
+// FAIL_IF (true);
+// }
+// GNUNET_memcpy (&bs->details.blinded_cs_answer,
+// in,
+// sz);
+// break;
+// default:
+// GNUNET_free (bs);
+// FAIL_IF (true);
+// }
+// denom_sig->blinded_sig = bs;
+// in += sz;
+// }
+// return GNUNET_OK;
+// }
+// default:
+// FAIL_IF (true);
+// }
+// }
+// FAIL:
+// GNUNET_free (*(void **) dst);
+// return GNUNET_SYSERR;
+// #undef FAIL_IF
+// }
+
+
+// /**
+// * Cleanup of the data and closure of an array spec.
+// */
+// static void
+// array_cleanup (void *cls,
+// void *rd)
+// {
+// struct ArrayResultCls *info = cls;
+// void **dst = rd;
+
+// if ((0 == info->same_size) &&
+// (NULL != info->sizes))
+// GNUNET_free (*(info->sizes));
+
+// /* Clean up signatures, if applicable */
+// if (TALER_PQ_array_of_blinded_denom_sig == info->typ)
+// {
+// struct TALER_BlindedDenominationSignature *denom_sigs = *dst;
+// GNUNET_assert (NULL != info->num);
+// for (size_t i = 0; i < *info->num; i++)
+// GNUNET_free (denom_sigs[i].blinded_sig);
+// }
+
+// GNUNET_free (cls);
+// GNUNET_free (*dst);
+// *dst = NULL;
+// }
+
+
+// struct GNUNET_PQ_ResultSpec
+// DONAU_PQ_result_spec_array_blinded_donation_unit_sig (
+// struct GNUNET_PQ_Context *db,
+// const char *name,
+// size_t *num,
+// struct DONAU_BlindedDonationUnitSignature **du_sigs)
+// {
+// struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
+
+// info->num = num;
+// info->typ = TALER_PQ_array_of_blinded_denom_sig;
+// GNUNET_assert (GNUNET_OK ==
+// GNUNET_PQ_get_oid_by_name (db,
+// "bytea",
+// &info->oid));
+
+// struct GNUNET_PQ_ResultSpec res = {
+// .conv = extract_array_generic,
+// .cleaner = array_cleanup,
+// .dst = (void *) du_sigs,
+// .fname = name,
+// .cls = info
+// };
+// return res;
+
+// }
+
/* end of pq/pq_query_helper.c */