aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/auditor/taler-auditor-httpd_deposit-confirmation.c113
-rw-r--r--src/auditor/taler-helper-auditor-deposits.c29
-rw-r--r--src/auditordb/auditor-0001.sql7
-rw-r--r--src/auditordb/pg_get_deposit_confirmations.c45
-rw-r--r--src/auditordb/pg_insert_deposit_confirmation.c18
-rw-r--r--src/auditordb/plugin_auditordb_postgres.c2
-rw-r--r--src/exchange/taler-exchange-httpd_batch-deposit.c82
-rw-r--r--src/include/taler_auditor_service.h18
-rw-r--r--src/include/taler_auditordb_plugin.h21
-rw-r--r--src/include/taler_crypto_lib.h20
-rw-r--r--src/include/taler_exchange_service.h9
-rw-r--r--src/include/taler_testing_lib.h17
-rw-r--r--src/lib/auditor_api_deposit_confirmation.c84
-rw-r--r--src/lib/exchange_api_batch_deposit.c118
-rw-r--r--src/testing/test_auditor_api.c2
-rw-r--r--src/testing/testing_api_cmd_auditor_deposit_confirmation.c48
-rw-r--r--src/testing/testing_api_cmd_batch_deposit.c31
-rw-r--r--src/testing/testing_api_cmd_deposit.c15
-rw-r--r--src/util/exchange_signatures.c48
19 files changed, 432 insertions, 295 deletions
diff --git a/src/auditor/taler-auditor-httpd_deposit-confirmation.c b/src/auditor/taler-auditor-httpd_deposit-confirmation.c
index a19e7c1ff..020d43d56 100644
--- a/src/auditor/taler-auditor-httpd_deposit-confirmation.c
+++ b/src/auditor/taler-auditor-httpd_deposit-confirmation.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -115,6 +115,11 @@ verify_and_execute_deposit_confirmation (
.end = GNUNET_TIME_timestamp_hton (es->ep_end),
.signkey_pub = es->exchange_pub
};
+ const struct TALER_CoinSpendSignatureP *coin_sigps[
+ GNUNET_NZL (dc->num_coins)];
+
+ for (unsigned int i = 0; i<dc->num_coins; i++)
+ coin_sigps[i] = &dc->coin_sigs[i];
if (GNUNET_TIME_absolute_is_future (es->ep_start.abs_time) ||
GNUNET_TIME_absolute_is_past (es->ep_expire.abs_time) )
@@ -231,8 +236,9 @@ verify_and_execute_deposit_confirmation (
dc->exchange_timestamp,
dc->wire_deadline,
dc->refund_deadline,
- &dc->amount_without_fee,
- &dc->coin_pub,
+ &dc->total_without_fee,
+ dc->num_coins,
+ coin_sigps,
&dc->merchant,
&dc->exchange_pub,
&dc->exchange_sig))
@@ -265,16 +271,19 @@ verify_and_execute_deposit_confirmation (
MHD_RESULT
-TAH_DEPOSIT_CONFIRMATION_handler (struct TAH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
+TAH_DEPOSIT_CONFIRMATION_handler (
+ struct TAH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
{
struct TALER_AUDITORDB_DepositConfirmation dc = {
.refund_deadline = GNUNET_TIME_UNIT_ZERO_TS
};
struct TALER_AUDITORDB_ExchangeSigningKey es;
+ const json_t *jcoin_sigs;
+ const json_t *jcoin_pubs;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
&dc.h_contract_terms),
@@ -290,11 +299,13 @@ TAH_DEPOSIT_CONFIRMATION_handler (struct TAH_RequestHandler *rh,
NULL),
GNUNET_JSON_spec_timestamp ("wire_deadline",
&dc.wire_deadline),
- TALER_JSON_spec_amount ("amount_without_fee",
+ TALER_JSON_spec_amount ("total_without_fee",
TAH_currency,
- &dc.amount_without_fee),
- GNUNET_JSON_spec_fixed_auto ("coin_pub",
- &dc.coin_pub),
+ &dc.total_without_fee),
+ GNUNET_JSON_spec_array_const ("coin_pubs",
+ &jcoin_pubs),
+ GNUNET_JSON_spec_array_const ("coin_sigs",
+ &jcoin_sigs),
GNUNET_JSON_spec_fixed_auto ("merchant_pub",
&dc.merchant),
GNUNET_JSON_spec_fixed_auto ("exchange_sig",
@@ -313,13 +324,14 @@ TAH_DEPOSIT_CONFIRMATION_handler (struct TAH_RequestHandler *rh,
&es.master_sig),
GNUNET_JSON_spec_end ()
};
+ unsigned int num_coins;
+ json_t *json;
(void) rh;
(void) connection_cls;
(void) upload_data;
(void) upload_data_size;
{
- json_t *json;
enum GNUNET_GenericReturnValue res;
res = TALER_MHD_parse_post_json (connection,
@@ -335,22 +347,89 @@ TAH_DEPOSIT_CONFIRMATION_handler (struct TAH_RequestHandler *rh,
res = TALER_MHD_parse_json_data (connection,
json,
spec);
- json_decref (json);
if (GNUNET_SYSERR == res)
+ {
+ json_decref (json);
return MHD_NO; /* hard failure */
+ }
if (GNUNET_NO == res)
+ {
+ json_decref (json);
return MHD_YES; /* failure */
+ }
}
-
- es.exchange_pub = dc.exchange_pub; /* used twice! */
- dc.master_public_key = es.master_public_key;
+ num_coins = json_array_size (jcoin_sigs);
+ if (num_coins != json_array_size (jcoin_pubs))
{
+ GNUNET_break_op (0);
+ json_decref (json);
+ return TALER_MHD_reply_with_ec (
+ connection,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "coin_pubs.length != coin_sigs.length");
+ }
+ if (0 == num_coins)
+ {
+ GNUNET_break_op (0);
+ json_decref (json);
+ return TALER_MHD_reply_with_ec (
+ connection,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "coin_pubs array is empty");
+ }
+ {
+ struct TALER_CoinSpendPublicKeyP coin_pubs[num_coins];
+ struct TALER_CoinSpendSignatureP coin_sigs[num_coins];
MHD_RESULT res;
+ for (unsigned int i = 0; i<num_coins; i++)
+ {
+ json_t *jpub = json_array_get (jcoin_pubs,
+ i);
+ json_t *jsig = json_array_get (jcoin_sigs,
+ i);
+ const char *ps = json_string_value (jpub);
+ const char *ss = json_string_value (jsig);
+
+ if ( (NULL == ps) ||
+ (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (ps,
+ strlen (ps),
+ &coin_pubs[i],
+ sizeof (coin_pubs[i]))) )
+ {
+ GNUNET_break_op (0);
+ json_decref (json);
+ return TALER_MHD_reply_with_ec (
+ connection,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "coin_pub[] malformed");
+ }
+ if ( (NULL == ss) ||
+ (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (ss,
+ strlen (ss),
+ &coin_sigs[i],
+ sizeof (coin_sigs[i]))) )
+ {
+ GNUNET_break_op (0);
+ json_decref (json);
+ return TALER_MHD_reply_with_ec (
+ connection,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "coin_sig[] malformed");
+ }
+ }
+ dc.num_coins = num_coins;
+ dc.coin_pubs = coin_pubs;
+ dc.coin_sigs = coin_sigs;
+ es.exchange_pub = dc.exchange_pub; /* used twice! */
+ dc.master_public_key = es.master_public_key;
res = verify_and_execute_deposit_confirmation (connection,
&dc,
&es);
GNUNET_JSON_parse_free (spec);
+ json_decref (json);
return res;
}
}
diff --git a/src/auditor/taler-helper-auditor-deposits.c b/src/auditor/taler-helper-auditor-deposits.c
index c08727d37..fc7395994 100644
--- a/src/auditor/taler-helper-auditor-deposits.c
+++ b/src/auditor/taler-helper-auditor-deposits.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2016-2021 Taler Systems SA
+ Copyright (C) 2016-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero Public License as published by the Free Software
@@ -108,8 +108,10 @@ test_dc (void *cls,
const struct TALER_AUDITORDB_DepositConfirmation *dc)
{
struct DepositConfirmationContext *dcc = cls;
+ bool missing = false;
dcc->last_seen_coin_serial = serial_id;
+ for (unsigned int i = 0; i<dc->num_coins; i++)
{
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Timestamp exchange_timestamp;
@@ -118,20 +120,12 @@ test_dc (void *cls,
qs = TALER_ARL_edb->have_deposit2 (TALER_ARL_edb->cls,
&dc->h_contract_terms,
&dc->h_wire,
- &dc->coin_pub,
+ &dc->coin_pubs[i],
&dc->merchant,
dc->refund_deadline,
&deposit_fee,
&exchange_timestamp);
- if (qs > 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Found deposit %s in exchange database\n",
- GNUNET_h2s (&dc->h_contract_terms.hash));
- if (TALER_ARL_do_abort ())
- return GNUNET_SYSERR;
- return GNUNET_OK; /* found, all good */
- }
+ missing |= (0 == qs);
if (qs < 0)
{
GNUNET_break (0); /* DB error, complain */
@@ -139,6 +133,15 @@ test_dc (void *cls,
return GNUNET_SYSERR;
}
}
+ if (! missing)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Found deposit %s in exchange database\n",
+ GNUNET_h2s (&dc->h_contract_terms.hash));
+ if (TALER_ARL_do_abort ())
+ return GNUNET_SYSERR;
+ return GNUNET_OK; /* all coins found, all good */
+ }
/* deposit confirmation missing! report! */
TALER_ARL_report (
report_deposit_confirmation_inconsistencies,
@@ -146,7 +149,7 @@ test_dc (void *cls,
TALER_JSON_pack_time_abs_human ("timestamp",
dc->exchange_timestamp.abs_time),
TALER_JSON_pack_amount ("amount",
- &dc->amount_without_fee),
+ &dc->total_without_fee),
GNUNET_JSON_pack_uint64 ("rowid",
serial_id),
GNUNET_JSON_pack_data_auto ("account",
@@ -156,7 +159,7 @@ test_dc (void *cls,
dcc->missed_count++;
TALER_ARL_amount_add (&dcc->missed_amount,
&dcc->missed_amount,
- &dc->amount_without_fee);
+ &dc->total_without_fee);
if (TALER_ARL_do_abort ())
return GNUNET_SYSERR;
return GNUNET_OK;
diff --git a/src/auditordb/auditor-0001.sql b/src/auditordb/auditor-0001.sql
index a167e8555..b755da4b0 100644
--- a/src/auditordb/auditor-0001.sql
+++ b/src/auditordb/auditor-0001.sql
@@ -289,13 +289,14 @@ CREATE TABLE IF NOT EXISTS deposit_confirmations
,exchange_timestamp INT8 NOT NULL
,refund_deadline INT8 NOT NULL
,wire_deadline INT8 NOT NULL
- ,amount_without_fee taler_amount NOT NULL
- ,coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)
+ ,total_without_fee taler_amount NOT NULL
+ ,coin_pubs BYTEA[] NOT NULL CHECK (CARDINALITY(coin_pubs)>0)
+ ,coin_sigs BYTEA[] NOT NULL CHECK (CARDINALITY(coin_sigs)=CARDINALITY(coin_pubs))
,merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)
,exchange_sig BYTEA NOT NULL CHECK (LENGTH(exchange_sig)=64)
,exchange_pub BYTEA NOT NULL CHECK (LENGTH(exchange_pub)=32)
,master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)
- ,PRIMARY KEY (h_contract_terms,h_wire,coin_pub,merchant_pub,exchange_sig,exchange_pub,master_sig)
+ ,PRIMARY KEY (h_contract_terms,h_wire,merchant_pub,exchange_sig,exchange_pub,master_sig)
);
COMMENT ON TABLE deposit_confirmations
IS 'deposit confirmation sent to us by merchants; we must check that the exchange reported these properly.';
diff --git a/src/auditordb/pg_get_deposit_confirmations.c b/src/auditordb/pg_get_deposit_confirmations.c
index 56306e105..86b6cdd8b 100644
--- a/src/auditordb/pg_get_deposit_confirmations.c
+++ b/src/auditordb/pg_get_deposit_confirmations.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-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
@@ -82,6 +82,10 @@ deposit_confirmation_cb (void *cls,
struct TALER_AUDITORDB_DepositConfirmation dc = {
.master_public_key = *dcc->master_pub
};
+ struct TALER_CoinSpendPublicKeyP *coin_pubs = NULL;
+ struct TALER_CoinSpendSignatureP *coin_sigs = NULL;
+ size_t num_pubs = 0;
+ size_t num_sigs = 0;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("serial_id",
&serial_id),
@@ -97,10 +101,16 @@ deposit_confirmation_cb (void *cls,
&dc.refund_deadline),
GNUNET_PQ_result_spec_timestamp ("wire_deadline",
&dc.wire_deadline),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_without_fee",
- &dc.amount_without_fee),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &dc.coin_pub),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("total_without_fee",
+ &dc.total_without_fee),
+ GNUNET_PQ_result_spec_auto_array_from_type (pg->conn,
+ "coin_pub",
+ &num_pubs,
+ coin_pubs),
+ GNUNET_PQ_result_spec_auto_array_from_type (pg->conn,
+ "coin_sigs",
+ &num_sigs,
+ coin_sigs),
GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
&dc.merchant),
GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
@@ -111,6 +121,7 @@ deposit_confirmation_cb (void *cls,
&dc.master_sig),
GNUNET_PQ_result_spec_end
};
+ enum GNUNET_GenericReturnValue rval;
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
@@ -121,11 +132,22 @@ deposit_confirmation_cb (void *cls,
dcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
+ if (num_sigs != num_pubs)
+ {
+ GNUNET_break (0);
+ dcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ GNUNET_PQ_cleanup_result (rs);
+ return;
+ }
dcc->qs = i + 1;
- if (GNUNET_OK !=
- dcc->cb (dcc->cb_cls,
- serial_id,
- &dc))
+ dc.coin_pubs = coin_pubs;
+ dc.coin_sigs = coin_sigs;
+ dc.num_coins = num_sigs;
+ rval = dcc->cb (dcc->cb_cls,
+ serial_id,
+ &dc);
+ GNUNET_PQ_cleanup_result (rs);
+ if (GNUNET_OK != rval)
break;
}
}
@@ -163,8 +185,9 @@ TAH_PG_get_deposit_confirmations (
",exchange_timestamp"
",wire_deadline"
",refund_deadline"
- ",amount_without_fee"
- ",coin_pub"
+ ",total_without_fee"
+ ",coin_pubs"
+ ",coin_sigs"
",merchant_pub"
",exchange_sig"
",exchange_pub"
diff --git a/src/auditordb/pg_insert_deposit_confirmation.c b/src/auditordb/pg_insert_deposit_confirmation.c
index 7c54494d6..b811e267a 100644
--- a/src/auditordb/pg_insert_deposit_confirmation.c
+++ b/src/auditordb/pg_insert_deposit_confirmation.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022, 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
@@ -41,8 +41,13 @@ TAH_PG_insert_deposit_confirmation (
GNUNET_PQ_query_param_timestamp (&dc->wire_deadline),
GNUNET_PQ_query_param_timestamp (&dc->refund_deadline),
TALER_PQ_query_param_amount (pg->conn,
- &dc->amount_without_fee),
- GNUNET_PQ_query_param_auto_from_type (&dc->coin_pub),
+ &dc->total_without_fee),
+ GNUNET_PQ_query_param_array_auto_from_type (dc->num_coins,
+ dc->coin_pubs,
+ pg->conn),
+ GNUNET_PQ_query_param_array_auto_from_type (dc->num_coins,
+ dc->coin_sigs,
+ pg->conn),
GNUNET_PQ_query_param_auto_from_type (&dc->merchant),
GNUNET_PQ_query_param_auto_from_type (&dc->exchange_sig),
GNUNET_PQ_query_param_auto_from_type (&dc->exchange_pub),
@@ -60,13 +65,14 @@ TAH_PG_insert_deposit_confirmation (
",exchange_timestamp"
",wire_deadline"
",refund_deadline"
- ",amount_without_fee"
- ",coin_pub"
+ ",total_without_fee"
+ ",coin_pubs"
+ ",coin_sigs"
",merchant_pub"
",exchange_sig"
",exchange_pub"
",master_sig" /* master_sig could be normalized... */
- ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13);");
+ ") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"auditor_deposit_confirmation_insert",
params);
diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c
index 24d1768bf..2b722a5ea 100644
--- a/src/auditordb/plugin_auditordb_postgres.c
+++ b/src/auditordb/plugin_auditordb_postgres.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2022 Taler Systems SA
+ Copyright (C) 2014-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
diff --git a/src/exchange/taler-exchange-httpd_batch-deposit.c b/src/exchange/taler-exchange-httpd_batch-deposit.c
index 894f8fb4e..bc8b20de8 100644
--- a/src/exchange/taler-exchange-httpd_batch-deposit.c
+++ b/src/exchange/taler-exchange-httpd_batch-deposit.c
@@ -108,65 +108,33 @@ reply_batch_deposit_success (
const struct BatchDepositContext *dc)
{
const struct TALER_EXCHANGEDB_BatchDeposit *bd = &dc->bd;
- json_t *arr;
+ const struct TALER_CoinSpendSignatureP *csigs[GNUNET_NZL (bd->num_cdis)];
+ enum TALER_ErrorCode ec;
struct TALER_ExchangePublicKeyP pub;
+ struct TALER_ExchangeSignatureP sig;
-again:
- arr = json_array ();
- GNUNET_assert (NULL != arr);
for (unsigned int i = 0; i<bd->num_cdis; i++)
+ csigs[i] = &bd->cdis[i].csig;
+ if (TALER_EC_NONE !=
+ (ec = TALER_exchange_online_deposit_confirmation_sign (
+ &TEH_keys_exchange_sign_,
+ &bd->h_contract_terms,
+ &dc->h_wire,
+ NULL != dc->policy_json ? &dc->h_policy : NULL,
+ dc->exchange_timestamp,
+ bd->wire_deadline,
+ bd->refund_deadline,
+ &dc->policy_details.accumulated_total, /* excludes fees */
+ bd->num_cdis,
+ csigs,
+ &dc->bd.merchant_pub,
+ &pub,
+ &sig)))
{
- const struct TALER_EXCHANGEDB_CoinDepositInformation *cdi
- = &bd->cdis[i];
- struct TALER_ExchangePublicKeyP pubi;
- struct TALER_ExchangeSignatureP sig;
- enum TALER_ErrorCode ec;
- struct TALER_Amount amount_without_fee;
-
- GNUNET_assert (0 <=
- TALER_amount_subtract (&amount_without_fee,
- &cdi->amount_with_fee,
- &dc->deposit_fees[i]));
- if (TALER_EC_NONE !=
- (ec = TALER_exchange_online_deposit_confirmation_sign (
- &TEH_keys_exchange_sign_,
- &bd->h_contract_terms,
- &dc->h_wire,
- NULL != dc->policy_json ? &dc->h_policy : NULL,
- dc->exchange_timestamp,
- bd->wire_deadline,
- bd->refund_deadline,
- &amount_without_fee,
- &cdi->coin.coin_pub,
- &dc->bd.merchant_pub,
- &pubi,
- &sig)))
- {
- GNUNET_break (0);
- return TALER_MHD_reply_with_ec (connection,
- ec,
- NULL);
- }
- if (0 == i)
- pub = pubi;
- if (0 !=
- GNUNET_memcmp (&pub,
- &pubi))
- {
- /* note: in the future, maybe have batch sign API to avoid having to
- handle key rollover... */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Exchange public key changed during batch deposit, trying again\n");
- json_decref (arr);
- goto again;
- }
- GNUNET_assert (
- 0 ==
- json_array_append_new (arr,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_data_auto (
- "exchange_sig",
- &sig))));
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_ec (connection,
+ ec,
+ NULL);
}
return TALER_MHD_REPLY_JSON_PACK (
connection,
@@ -175,8 +143,8 @@ again:
dc->exchange_timestamp),
GNUNET_JSON_pack_data_auto ("exchange_pub",
&pub),
- GNUNET_JSON_pack_array_steal ("exchange_sigs",
- arr));
+ GNUNET_JSON_pack_data_auto ("exchange_sig",
+ &sig));
}
diff --git a/src/include/taler_auditor_service.h b/src/include/taler_auditor_service.h
index 3d8ca9efb..409faca7d 100644
--- a/src/include/taler_auditor_service.h
+++ b/src/include/taler_auditor_service.h
@@ -226,11 +226,11 @@ TALER_AUDITOR_get_config (struct GNUNET_CURL_Context *ctx,
/**
* Cancel auditor config request.
*
- * @param auditor the auditor handle
+ * @param[in] auditor the auditor handle
*/
void
-TALER_AUDITOR_get_config_cancel (struct
- TALER_AUDITOR_GetConfigHandle *auditor);
+TALER_AUDITOR_get_config_cancel (
+ struct TALER_AUDITOR_GetConfigHandle *auditor);
/**
@@ -284,8 +284,10 @@ typedef void
* @param exchange_timestamp timestamp when the contract was finalized, must not be too far in the future
* @param wire_deadline date until which the exchange should wire the funds
* @param refund_deadline date until which the merchant can issue a refund to the customer via the auditor (can be zero if refunds are not allowed); must not be after the @a wire_deadline
- * @param amount_without_fee the amount confirmed to be wired by the exchange to the merchant
- * @param coin_pub coin’s public key
+ * @param total_without_fee the amount confirmed to be wired by the exchange to the merchant
+ * @param num_coins number of coins involved in the batch deposit
+ * @param coin_pubs array of the coin’s public keys
+ * @param coin_sigs array of the original deposit signatures of the coins in the batch
* @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
* @param exchange_sig the signature made with purpose #TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT
* @param exchange_pub the public key of the exchange that matches @a exchange_sig
@@ -309,8 +311,10 @@ TALER_AUDITOR_deposit_confirmation (
struct GNUNET_TIME_Timestamp exchange_timestamp,
struct GNUNET_TIME_Timestamp wire_deadline,
struct GNUNET_TIME_Timestamp refund_deadline,
- const struct TALER_Amount *amount_without_fee,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *total_without_fee,
+ unsigned int num_coins,
+ const struct TALER_CoinSpendPublicKeyP *coin_pubs[static num_coins],
+ const struct TALER_CoinSpendSignatureP *coin_sigs[static num_coins],
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const struct TALER_ExchangeSignatureP *exchange_sig,
diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h
index eebb31e06..31e6723a5 100644
--- a/src/include/taler_auditordb_plugin.h
+++ b/src/include/taler_auditordb_plugin.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2022 Taler Systems SA
+ Copyright (C) 2014-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
@@ -421,14 +421,23 @@ struct TALER_AUDITORDB_DepositConfirmation
* Amount to be deposited, excluding fee. Calculated from the
* amount with fee and the fee from the deposit request.
*/
- struct TALER_Amount amount_without_fee;
+ struct TALER_Amount total_without_fee;
/**
- * The coin's public key. This is the value that must have been
- * signed (blindly) by the Exchange. The deposit request is to be
- * signed by the corresponding private key (using EdDSA).
+ * Length of the @e coin_pubs and @e coin_sigs arrays.
*/
- struct TALER_CoinSpendPublicKeyP coin_pub;
+ unsigned int num_coins;
+
+ /**
+ * Array of the coin public keys involved in the
+ * batch deposit operation.
+ */
+ const struct TALER_CoinSpendPublicKeyP *coin_pubs;
+
+ /**
+ * Array of coin deposit signatures from the deposit operation.
+ */
+ const struct TALER_CoinSpendSignatureP *coin_sigs;
/**
* The Merchant's public key. Allows the merchant to later refund
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index b7666610e..cef8f55a5 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -4045,8 +4045,9 @@ typedef enum TALER_ErrorCode
* @param exchange_timestamp timestamp when the contract was finalized, must not be too far off
* @param wire_deadline date until which the exchange should wire the funds
* @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed); must not be after the @a wire_deadline
- * @param amount_without_fee the amount to be deposited after fees
- * @param coin_pub public key of the deposited coin
+ * @param total_without_fee the total amount to be deposited after fees over all coins
+ * @param num_coins length of @a coin_sigs array
+ * @param coin_sigs signatures of the deposited coins
* @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
* @param[out] pub where to write the public key
* @param[out] sig where to write the signature
@@ -4061,8 +4062,9 @@ TALER_exchange_online_deposit_confirmation_sign (
struct GNUNET_TIME_Timestamp exchange_timestamp,
struct GNUNET_TIME_Timestamp wire_deadline,
struct GNUNET_TIME_Timestamp refund_deadline,
- const struct TALER_Amount *amount_without_fee,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *total_without_fee,
+ unsigned int num_coins,
+ const struct TALER_CoinSpendSignatureP *coin_sigs[static num_coins],
const struct TALER_MerchantPublicKeyP *merchant_pub,
struct TALER_ExchangePublicKeyP *pub,
struct TALER_ExchangeSignatureP *sig);
@@ -4077,8 +4079,9 @@ TALER_exchange_online_deposit_confirmation_sign (
* @param exchange_timestamp timestamp when the contract was finalized, must not be too far off
* @param wire_deadline date until which the exchange should wire the funds
* @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed); must not be after the @a wire_deadline
- * @param amount_without_fee the amount to be deposited after fees
- * @param coin_pub public key of the deposited coin
+ * @param total_without_fee the total amount to be deposited after fees over all coins
+ * @param num_coins length of @a coin_sigs array
+ * @param coin_sigs signatures of the deposited coins
* @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
* @param pub where to write the public key
* @param sig where to write the signature
@@ -4092,8 +4095,9 @@ TALER_exchange_online_deposit_confirmation_verify (
struct GNUNET_TIME_Timestamp exchange_timestamp,
struct GNUNET_TIME_Timestamp wire_deadline,
struct GNUNET_TIME_Timestamp refund_deadline,
- const struct TALER_Amount *amount_without_fee,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *total_without_fee,
+ unsigned int num_coins,
+ const struct TALER_CoinSpendSignatureP *coin_sigs[static num_coins],
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_ExchangePublicKeyP *pub,
const struct TALER_ExchangeSignatureP *sig);
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index c344a93ae..662700d48 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -1143,9 +1143,9 @@ struct TALER_EXCHANGE_BatchDepositResult
struct GNUNET_TIME_Timestamp deposit_timestamp;
/**
- * Array of signatures provided by the exchange
+ * Deposit confirmation signature provided by the exchange
*/
- const struct TALER_ExchangeSignatureP *exchange_sigs;
+ const struct TALER_ExchangeSignatureP *exchange_sig;
/**
* exchange key used to sign @a exchange_sig.
@@ -1158,11 +1158,6 @@ struct TALER_EXCHANGE_BatchDepositResult
*/
const char *transaction_base_url;
- /**
- * Length of the @e exchange_sigs array.
- */
- unsigned int num_signatures;
-
} ok;
/**
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
index 5506f025c..026798027 100644
--- a/src/include/taler_testing_lib.h
+++ b/src/include/taler_testing_lib.h
@@ -811,20 +811,18 @@ TALER_TESTING_cmd_exec_auditor_dbinit (const char *label,
* @param label command label.
* @param deposit_reference reference to any operation that can
* provide a coin.
- * @param coin_index if @a deposit_reference offers an array of
- * coins, this parameter selects which one in that array.
- * This value is currently ignored, as only one-coin
- * deposits are implemented.
+ * @param num_coins number of coins expected in the batch deposit
* @param amount_without_fee deposited amount without the fee
* @param expected_response_code expected HTTP response code.
* @return the command.
*/
struct TALER_TESTING_Command
-TALER_TESTING_cmd_deposit_confirmation (const char *label,
- const char *deposit_reference,
- unsigned int coin_index,
- const char *amount_without_fee,
- unsigned int expected_response_code);
+TALER_TESTING_cmd_deposit_confirmation (
+ const char *label,
+ const char *deposit_reference,
+ unsigned int num_coins,
+ const char *amount_without_fee,
+ unsigned int expected_response_code);
/**
@@ -2729,6 +2727,7 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
op (exchange_wd_value, const struct TALER_ExchangeWithdrawValues) \
op (coin_priv, const struct TALER_CoinSpendPrivateKeyP) \
op (coin_pub, const struct TALER_CoinSpendPublicKeyP) \
+ op (coin_sig, const struct TALER_CoinSpendSignatureP) \
op (absolute_time, const struct GNUNET_TIME_Absolute) \
op (timestamp, const struct GNUNET_TIME_Timestamp) \
op (wire_deadline, const struct GNUNET_TIME_Timestamp) \
diff --git a/src/lib/auditor_api_deposit_confirmation.c b/src/lib/auditor_api_deposit_confirmation.c
index 0b0f4dd4d..1e2ecc6cc 100644
--- a/src/lib/auditor_api_deposit_confirmation.c
+++ b/src/lib/auditor_api_deposit_confirmation.c
@@ -167,22 +167,25 @@ handle_deposit_confirmation_finished (void *cls,
* @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not
*/
static enum GNUNET_GenericReturnValue
-verify_signatures (const struct TALER_MerchantWireHashP *h_wire,
- const struct TALER_ExtensionPolicyHashP *h_policy,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- struct GNUNET_TIME_Timestamp exchange_timestamp,
- struct GNUNET_TIME_Timestamp wire_deadline,
- struct GNUNET_TIME_Timestamp refund_deadline,
- const struct TALER_Amount *amount_without_fee,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const struct TALER_ExchangeSignatureP *exchange_sig,
- const struct TALER_MasterPublicKeyP *master_pub,
- struct GNUNET_TIME_Timestamp ep_start,
- struct GNUNET_TIME_Timestamp ep_expire,
- struct GNUNET_TIME_Timestamp ep_end,
- const struct TALER_MasterSignatureP *master_sig)
+verify_signatures (
+ const struct TALER_MerchantWireHashP *h_wire,
+ const struct TALER_ExtensionPolicyHashP *h_policy,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ struct GNUNET_TIME_Timestamp exchange_timestamp,
+ struct GNUNET_TIME_Timestamp wire_deadline,
+ struct GNUNET_TIME_Timestamp refund_deadline,
+ const struct TALER_Amount *amount_without_fee,
+ unsigned int num_coins,
+ const struct TALER_CoinSpendSignatureP *coin_sigs[
+ static num_coins],
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_ExchangePublicKeyP *exchange_pub,
+ const struct TALER_ExchangeSignatureP *exchange_sig,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ struct GNUNET_TIME_Timestamp ep_start,
+ struct GNUNET_TIME_Timestamp ep_expire,
+ struct GNUNET_TIME_Timestamp ep_end,
+ const struct TALER_MasterSignatureP *master_sig)
{
if (GNUNET_OK !=
TALER_exchange_online_deposit_confirmation_verify (
@@ -193,7 +196,8 @@ verify_signatures (const struct TALER_MerchantWireHashP *h_wire,
wire_deadline,
refund_deadline,
amount_without_fee,
- coin_pub,
+ num_coins,
+ coin_sigs,
merchant_pub,
exchange_pub,
exchange_sig))
@@ -241,8 +245,12 @@ TALER_AUDITOR_deposit_confirmation (
struct GNUNET_TIME_Timestamp exchange_timestamp,
struct GNUNET_TIME_Timestamp wire_deadline,
struct GNUNET_TIME_Timestamp refund_deadline,
- const struct TALER_Amount *amount_without_fee,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *total_without_fee,
+ unsigned int num_coins,
+ const struct TALER_CoinSpendPublicKeyP *coin_pubs[
+ static num_coins],
+ const struct TALER_CoinSpendSignatureP *coin_sigs[
+ static num_coins],
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const struct TALER_ExchangeSignatureP *exchange_sig,
@@ -257,7 +265,14 @@ TALER_AUDITOR_deposit_confirmation (
struct TALER_AUDITOR_DepositConfirmationHandle *dh;
json_t *deposit_confirmation_obj;
CURL *eh;
+ json_t *jcoin_sigs;
+ json_t *jcoin_pubs;
+ if (0 == num_coins)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
if (GNUNET_OK !=
verify_signatures (h_wire,
h_policy,
@@ -265,8 +280,9 @@ TALER_AUDITOR_deposit_confirmation (
exchange_timestamp,
wire_deadline,
refund_deadline,
- amount_without_fee,
- coin_pub,
+ total_without_fee,
+ num_coins,
+ coin_sigs,
merchant_pub,
exchange_pub,
exchange_sig,
@@ -279,7 +295,21 @@ TALER_AUDITOR_deposit_confirmation (
GNUNET_break_op (0);
return NULL;
}
-
+ jcoin_sigs = json_array ();
+ GNUNET_assert (NULL != jcoin_sigs);
+ jcoin_pubs = json_array ();
+ GNUNET_assert (NULL != jcoin_pubs);
+ for (unsigned int i = 0; i<num_coins; i++)
+ {
+ GNUNET_assert (0 ==
+ json_array_append_new (jcoin_sigs,
+ GNUNET_JSON_from_data_auto (
+ coin_sigs[i])));
+ GNUNET_assert (0 ==
+ json_array_append_new (jcoin_pubs,
+ GNUNET_JSON_from_data_auto (
+ coin_pubs[i])));
+ }
deposit_confirmation_obj
= GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("h_wire",
@@ -295,10 +325,12 @@ TALER_AUDITOR_deposit_confirmation (
refund_deadline)),
GNUNET_JSON_pack_timestamp ("wire_deadline",
wire_deadline),
- TALER_JSON_pack_amount ("amount_without_fee",
- amount_without_fee),
- GNUNET_JSON_pack_data_auto ("coin_pub",
- coin_pub),
+ TALER_JSON_pack_amount ("total_without_fee",
+ total_without_fee),
+ GNUNET_JSON_pack_array_steal ("coin_pubs",
+ jcoin_pubs),
+ GNUNET_JSON_pack_array_steal ("coin_sigs",
+ jcoin_sigs),
GNUNET_JSON_pack_data_auto ("merchant_pub",
merchant_pub),
GNUNET_JSON_pack_data_auto ("exchange_sig",
diff --git a/src/lib/exchange_api_batch_deposit.c b/src/lib/exchange_api_batch_deposit.c
index 273b25e85..f9d505dcd 100644
--- a/src/lib/exchange_api_batch_deposit.c
+++ b/src/lib/exchange_api_batch_deposit.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2022 Taler Systems SA
+ Copyright (C) 2014-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
@@ -146,9 +146,9 @@ struct TALER_EXCHANGE_BatchDepositHandle
struct GNUNET_TIME_Timestamp exchange_timestamp;
/**
- * Exchange signatures, set for #auditor_cb.
+ * Exchange signature, set for #auditor_cb.
*/
- struct TALER_ExchangeSignatureP *exchange_sigs;
+ struct TALER_ExchangeSignatureP exchange_sig;
/**
* Head of DLL of interactions with this auditor.
@@ -171,6 +171,11 @@ struct TALER_EXCHANGE_BatchDepositHandle
struct TALER_ExchangePublicKeyP exchange_pub;
/**
+ * Total amount deposited without fees as calculated by us.
+ */
+ struct TALER_Amount total_without_fee;
+
+ /**
* Response object to free at the end.
*/
json_t *response;
@@ -251,9 +256,20 @@ auditor_cb (void *cls,
struct TALER_EXCHANGE_BatchDepositHandle *dh = cls;
const struct TALER_EXCHANGE_SigningPublicKey *spk;
struct TEAH_AuditorInteractionEntry *aie;
- struct TALER_Amount amount_without_fee;
const struct TALER_EXCHANGE_DenomPublicKey *dki;
unsigned int coin;
+ const struct TALER_CoinSpendSignatureP *csigs[GNUNET_NZL (
+ dh->num_cdds)];
+ const struct TALER_CoinSpendPublicKeyP *cpubs[GNUNET_NZL (
+ dh->num_cdds)];
+
+ for (unsigned int i = 0; i<dh->num_cdds; i++)
+ {
+ const struct TALER_EXCHANGE_CoinDepositDetail *cdd = &dh->cdds[i];
+
+ csigs[i] = &cdd->coin_sig;
+ cpubs[i] = &cdd->coin_pub;
+ }
if (0 !=
GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
@@ -278,10 +294,6 @@ auditor_cb (void *cls,
GNUNET_break_op (0);
return;
}
- GNUNET_assert (0 <=
- TALER_amount_subtract (&amount_without_fee,
- &dh->cdds[coin].amount,
- &dki->fees.deposit));
aie = GNUNET_new (struct TEAH_AuditorInteractionEntry);
aie->dh = dh;
aie->auditor_url = auditor_url;
@@ -294,11 +306,13 @@ auditor_cb (void *cls,
dh->exchange_timestamp,
dh->dcd.wire_deadline,
dh->dcd.refund_deadline,
- &amount_without_fee,
- &dh->cdds[coin].coin_pub,
+ &dh->total_without_fee,
+ dh->num_cdds,
+ cpubs,
+ csigs,
&dh->dcd.merchant_pub,
&dh->exchange_pub,
- &dh->exchange_sigs[coin],
+ &dh->exchange_sig,
&dh->keys->master_pub,
spk->valid_from,
spk->valid_until,
@@ -340,12 +354,9 @@ handle_deposit_finished (void *cls,
break;
case MHD_HTTP_OK:
{
- const json_t *sigs;
- json_t *sig;
- unsigned int idx;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_array_const ("exchange_sigs",
- &sigs),
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &dh->exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&dh->exchange_pub),
GNUNET_JSON_spec_mark_optional (
@@ -367,15 +378,6 @@ handle_deposit_finished (void *cls,
dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
}
- if (json_array_size (sigs) != dh->num_cdds)
- {
- GNUNET_break_op (0);
- dr->hr.http_status = 0;
- dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- break;
- }
- dh->exchange_sigs = GNUNET_new_array (dh->num_cdds,
- struct TALER_ExchangeSignatureP);
if (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key (dh->keys,
&dh->exchange_pub))
@@ -385,35 +387,12 @@ handle_deposit_finished (void *cls,
dr->hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
break;
}
- json_array_foreach (sigs, idx, sig)
{
- struct GNUNET_JSON_Specification ispec[] = {
- GNUNET_JSON_spec_fixed_auto ("exchange_sig",
- &dh->exchange_sigs[idx]),
- GNUNET_JSON_spec_end ()
- };
- struct TALER_Amount amount_without_fee;
- const struct TALER_EXCHANGE_DenomPublicKey *dki;
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (sig,
- ispec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- dr->hr.http_status = 0;
- dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- break;
- }
- dki = TALER_EXCHANGE_get_denomination_key_by_hash (dh->keys,
- &dh->cdds[idx].
- h_denom_pub);
- GNUNET_assert (NULL != dki);
- GNUNET_assert (0 <=
- TALER_amount_subtract (&amount_without_fee,
- &dh->cdds[idx].amount,
- &dki->fees.deposit));
+ const struct TALER_CoinSpendSignatureP *csigs[
+ GNUNET_NZL (dh->num_cdds)];
+ for (unsigned int i = 0; i<dh->num_cdds; i++)
+ csigs[i] = &dh->cdds[i].coin_sig;
if (GNUNET_OK !=
TALER_exchange_online_deposit_confirmation_verify (
&dh->dcd.h_contract_terms,
@@ -422,11 +401,12 @@ handle_deposit_finished (void *cls,
dh->exchange_timestamp,
dh->dcd.wire_deadline,
dh->dcd.refund_deadline,
- &amount_without_fee,
- &dh->cdds[idx].coin_pub,
+ &dh->total_without_fee,
+ dh->num_cdds,
+ csigs,
&dh->dcd.merchant_pub,
&dh->exchange_pub,
- &dh->exchange_sigs[idx]))
+ &dh->exchange_sig))
{
GNUNET_break_op (0);
dr->hr.http_status = 0;
@@ -438,10 +418,9 @@ handle_deposit_finished (void *cls,
&auditor_cb,
dh);
}
- dr->details.ok.exchange_sigs = dh->exchange_sigs;
+ dr->details.ok.exchange_sig = &dh->exchange_sig;
dr->details.ok.exchange_pub = &dh->exchange_pub;
dr->details.ok.deposit_timestamp = dh->exchange_timestamp;
- dr->details.ok.num_signatures = dh->num_cdds;
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy
@@ -531,9 +510,13 @@ TALER_EXCHANGE_batch_deposit (
json_t *deposit_obj;
json_t *deposits;
CURL *eh;
- struct TALER_Amount amount_without_fee;
const struct GNUNET_HashCode *wallet_data_hashp;
+ if (0 == num_cdds)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
if (GNUNET_TIME_timestamp_cmp (dcd->refund_deadline,
>,
dcd->wire_deadline))
@@ -547,8 +530,7 @@ TALER_EXCHANGE_batch_deposit (
dh->cb = cb;
dh->cb_cls = cb_cls;
dh->cdds = GNUNET_memdup (cdds,
- num_cdds
- * sizeof (*cdds));
+ num_cdds * sizeof (*cdds));
dh->num_cdds = num_cdds;
dh->dcd = *dcd;
if (NULL != dcd->policy_details)
@@ -559,11 +541,15 @@ TALER_EXCHANGE_batch_deposit (
&dh->h_wire);
deposits = json_array ();
GNUNET_assert (NULL != deposits);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (cdds[0].amount.currency,
+ &dh->total_without_fee));
for (unsigned int i = 0; i<num_cdds; i++)
{
const struct TALER_EXCHANGE_CoinDepositDetail *cdd = &cdds[i];
const struct TALER_EXCHANGE_DenomPublicKey *dki;
const struct TALER_AgeCommitmentHash *h_age_commitmentp;
+ struct TALER_Amount amount_without_fee;
dki = TALER_EXCHANGE_get_denomination_key_by_hash (keys,
&cdd->h_denom_pub);
@@ -580,17 +566,14 @@ TALER_EXCHANGE_batch_deposit (
{
*ec = TALER_EC_EXCHANGE_DEPOSIT_FEE_ABOVE_AMOUNT;
GNUNET_break_op (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Amount: %s\n",
- TALER_amount2s (&cdd->amount));
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Fee: %s\n",
- TALER_amount2s (&dki->fees.deposit));
GNUNET_free (dh->cdds);
GNUNET_free (dh);
return NULL;
}
-
+ GNUNET_assert (0 <=
+ TALER_amount_add (&dh->total_without_fee,
+ &dh->total_without_fee,
+ &amount_without_fee));
if (GNUNET_OK !=
TALER_EXCHANGE_verify_deposit_signature_ (dcd,
&dh->h_policy,
@@ -737,7 +720,6 @@ TALER_EXCHANGE_batch_deposit_cancel (
TALER_EXCHANGE_keys_decref (deposit->keys);
GNUNET_free (deposit->url);
GNUNET_free (deposit->cdds);
- GNUNET_free (deposit->exchange_sigs);
TALER_curl_easy_post_finished (&deposit->post_ctx);
json_decref (deposit->response);
GNUNET_free (deposit);
diff --git a/src/testing/test_auditor_api.c b/src/testing/test_auditor_api.c
index 8c45f732f..ac147d931 100644
--- a/src/testing/test_auditor_api.c
+++ b/src/testing/test_auditor_api.c
@@ -635,7 +635,7 @@ run (void *cls,
MHD_HTTP_OK),
TALER_TESTING_cmd_deposit_confirmation ("deposit-confirmation",
"massive-deposit-10",
- 0,
+ 1,
"EUR:0.99",
MHD_HTTP_OK),
CMD_RUN_AUDITOR ("massive-auditor"),
diff --git a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c
index 1e5a63447..9477a5d7e 100644
--- a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c
+++ b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c
@@ -59,9 +59,9 @@ struct DepositConfirmationState
const char *amount_without_fee;
/**
- * Which coin of the @e deposit_reference should we confirm.
+ * How many coins were there in the @e deposit_reference?
*/
- unsigned int coin_index;
+ unsigned int num_coins;
/**
* DepositConfirmation handle while operation is running.
@@ -201,14 +201,15 @@ deposit_confirmation_run (void *cls,
struct GNUNET_TIME_Timestamp refund_deadline
= GNUNET_TIME_UNIT_ZERO_TS;
struct TALER_Amount amount_without_fee;
- struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_CoinSpendPublicKeyP coin_pubs[dcs->num_coins];
+ const struct TALER_CoinSpendPublicKeyP *coin_pubps[dcs->num_coins];
+ const struct TALER_CoinSpendSignatureP *coin_sigps[dcs->num_coins];
const struct TALER_MerchantPrivateKeyP *merchant_priv;
struct TALER_MerchantPublicKeyP merchant_pub;
const struct TALER_ExchangePublicKeyP *exchange_pub;
const struct TALER_ExchangeSignatureP *exchange_sig;
const json_t *wire_details;
const json_t *contract_terms;
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
const struct TALER_EXCHANGE_Keys *keys;
const struct TALER_EXCHANGE_SigningPublicKey *spk;
const char *auditor_url;
@@ -249,19 +250,19 @@ deposit_confirmation_run (void *cls,
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_exchange_pub (deposit_cmd,
- dcs->coin_index,
+ 0,
&exchange_pub));
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_exchange_sig (deposit_cmd,
- dcs->coin_index,
+ 0,
&exchange_sig));
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_timestamp (deposit_cmd,
- dcs->coin_index,
+ 0,
&exchange_timestamp));
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_wire_deadline (deposit_cmd,
- dcs->coin_index,
+ 0,
&wire_deadline));
GNUNET_assert (NULL != exchange_timestamp);
keys = TALER_TESTING_get_keys (is);
@@ -283,12 +284,23 @@ deposit_confirmation_run (void *cls,
GNUNET_assert (GNUNET_OK ==
TALER_JSON_merchant_wire_signature_hash (wire_details,
&h_wire));
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_coin_priv (deposit_cmd,
- dcs->coin_index,
- &coin_priv));
- GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
- &coin_pub.eddsa_pub);
+
+ for (unsigned int i = 0; i<dcs->num_coins; i++)
+ {
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_coin_priv (deposit_cmd,
+ i,
+ &coin_priv));
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &coin_pubs[i].eddsa_pub);
+ coin_pubps[i] = &coin_pubs[i];
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_coin_sig (deposit_cmd,
+ i,
+ &coin_sigps[i]));
+ }
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_merchant_priv (deposit_cmd,
&merchant_priv));
@@ -331,7 +343,9 @@ deposit_confirmation_run (void *cls,
*wire_deadline,
refund_deadline,
&amount_without_fee,
- &coin_pub,
+ dcs->num_coins,
+ coin_pubps,
+ coin_sigps,
&merchant_pub,
exchange_pub,
exchange_sig,
@@ -385,7 +399,7 @@ deposit_confirmation_cleanup (void *cls,
struct TALER_TESTING_Command
TALER_TESTING_cmd_deposit_confirmation (const char *label,
const char *deposit_reference,
- unsigned int coin_index,
+ unsigned int num_coins,
const char *amount_without_fee,
unsigned int expected_response_code)
{
@@ -393,7 +407,7 @@ TALER_TESTING_cmd_deposit_confirmation (const char *label,
dcs = GNUNET_new (struct DepositConfirmationState);
dcs->deposit_reference = deposit_reference;
- dcs->coin_index = coin_index;
+ dcs->num_coins = num_coins;
dcs->amount_without_fee = amount_without_fee;
dcs->expected_response_code = expected_response_code;
diff --git a/src/testing/testing_api_cmd_batch_deposit.c b/src/testing/testing_api_cmd_batch_deposit.c
index a3c25e355..ef54e6a03 100644
--- a/src/testing/testing_api_cmd_batch_deposit.c
+++ b/src/testing/testing_api_cmd_batch_deposit.c
@@ -59,6 +59,11 @@ struct Coin
struct TALER_Amount deposit_fee;
/**
+ * Our coin signature.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
+ /**
* Reference to any command that is able to provide a coin,
* possibly using $LABEL#$INDEX notation.
*/
@@ -151,10 +156,9 @@ struct BatchDepositState
struct GNUNET_SCHEDULER_Task *retry_task;
/**
- * Array of @e num_coins signatures from the exchange on the
- * deposit confirmation.
+ * Deposit confirmation signature from the exchange.
*/
- struct TALER_ExchangeSignatureP *exchange_sigs;
+ struct TALER_ExchangeSignatureP exchange_sig;
/**
* Reference to previous deposit operation.
@@ -205,19 +209,10 @@ batch_deposit_cb (void *cls,
}
if (MHD_HTTP_OK == dr->hr.http_status)
{
- if (ds->num_coins != dr->details.ok.num_signatures)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (ds->is);
- return;
- }
ds->deposit_succeeded = GNUNET_YES;
ds->exchange_timestamp = dr->details.ok.deposit_timestamp;
ds->exchange_pub = *dr->details.ok.exchange_pub;
- ds->exchange_sigs = GNUNET_memdup (dr->details.ok.exchange_sigs,
- dr->details.ok.num_signatures
- * sizeof (struct
- TALER_ExchangeSignatureP));
+ ds->exchange_sig = *dr->details.ok.exchange_sig;
}
TALER_TESTING_interpreter_next (ds->is);
}
@@ -373,6 +368,7 @@ batch_deposit_run (void *cls,
ds->refund_deadline,
coin_priv,
&cdd->coin_sig);
+ coin->coin_sig = cdd->coin_sig;
}
GNUNET_assert (NULL == ds->dh);
@@ -439,7 +435,6 @@ batch_deposit_cleanup (void *cls,
for (unsigned int i = 0; i<ds->num_coins; i++)
GNUNET_free (ds->coins[i].coin_reference);
GNUNET_free (ds->coins);
- GNUNET_free (ds->exchange_sigs);
json_decref (ds->wire_details);
json_decref (ds->contract_terms);
GNUNET_free (ds);
@@ -495,10 +490,10 @@ batch_deposit_traits (void *cls,
struct TALER_TESTING_Trait traits[] = {
/* First two traits are only available if
ds->traits is #GNUNET_YES */
- TALER_TESTING_make_trait_exchange_pub (index,
+ TALER_TESTING_make_trait_exchange_pub (0,
&ds->exchange_pub),
- TALER_TESTING_make_trait_exchange_sig (index,
- &ds->exchange_sigs[index]),
+ TALER_TESTING_make_trait_exchange_sig (0,
+ &ds->exchange_sig),
/* These traits are always available */
TALER_TESTING_make_trait_wire_details (ds->wire_details),
TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
@@ -507,6 +502,8 @@ batch_deposit_traits (void *cls,
age_commitment_proof),
TALER_TESTING_make_trait_coin_priv (index,
coin_spent_priv),
+ TALER_TESTING_make_trait_coin_sig (index,
+ &coin->coin_sig),
TALER_TESTING_make_trait_deposit_amount (index,
&coin->amount),
TALER_TESTING_make_trait_deposit_fee_amount (index,
diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c
index 0ee6aa447..61074afa7 100644
--- a/src/testing/testing_api_cmd_deposit.c
+++ b/src/testing/testing_api_cmd_deposit.c
@@ -69,6 +69,11 @@ struct DepositState
unsigned int coin_index;
/**
+ * Our coin signature.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
+ /**
* Wire details of who is depositing -- this would be merchant
* wire details in a normal scenario.
*/
@@ -258,11 +263,10 @@ deposit_cb (void *cls,
}
if (MHD_HTTP_OK == dr->hr.http_status)
{
- GNUNET_assert (1 == dr->details.ok.num_signatures);
ds->deposit_succeeded = GNUNET_YES;
ds->exchange_timestamp = dr->details.ok.deposit_timestamp;
ds->exchange_pub = *dr->details.ok.exchange_pub;
- ds->exchange_sig = dr->details.ok.exchange_sigs[0];
+ ds->exchange_sig = *dr->details.ok.exchange_sig;
}
TALER_TESTING_interpreter_next (ds->is);
}
@@ -287,7 +291,6 @@ deposit_run (void *cls,
const struct TALER_AgeCommitmentHash *phac;
const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
const struct TALER_DenominationSignature *denom_pub_sig;
- struct TALER_CoinSpendSignatureP coin_sig;
struct TALER_MerchantPublicKeyP merchant_pub;
struct TALER_PrivateContractHashP h_contract_terms;
enum TALER_ErrorCode ec;
@@ -449,14 +452,14 @@ deposit_run (void *cls,
&merchant_pub,
ds->refund_deadline,
coin_priv,
- &coin_sig);
+ &ds->coin_sig);
}
GNUNET_assert (NULL == ds->dh);
{
struct TALER_EXCHANGE_CoinDepositDetail cdd = {
.amount = ds->amount,
.coin_pub = coin_pub,
- .coin_sig = coin_sig,
+ .coin_sig = ds->coin_sig,
.denom_sig = *denom_pub_sig,
.h_denom_pub = denom_pub->h_key,
.h_age_commitment = {{{0}}},
@@ -595,6 +598,8 @@ deposit_traits (void *cls,
/* These traits are always available */
TALER_TESTING_make_trait_coin_priv (0,
coin_spent_priv),
+ TALER_TESTING_make_trait_coin_sig (0,
+ &ds->coin_sig),
TALER_TESTING_make_trait_age_commitment_proof (0,
age_commitment_proof),
TALER_TESTING_make_trait_h_age_commitment (0,
diff --git a/src/util/exchange_signatures.c b/src/util/exchange_signatures.c
index 3aa464aa7..bc5fe439f 100644
--- a/src/util/exchange_signatures.c
+++ b/src/util/exchange_signatures.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2021, 2022 Taler Systems SA
+ Copyright (C) 2021-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
@@ -78,12 +78,12 @@ struct TALER_DepositConfirmationPS
* Amount to be deposited, excluding fee. Calculated from the
* amount with fee and the fee from the deposit request.
*/
- struct TALER_AmountNBO amount_without_fee;
+ struct TALER_AmountNBO total_without_fee;
/**
- * The public key of the coin that was deposited.
+ * Hash over all of the coin signatures.
*/
- struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct GNUNET_HashCode h_coin_sigs;
/**
* The Merchant's public key. Allows the merchant to later refund
@@ -105,8 +105,9 @@ TALER_exchange_online_deposit_confirmation_sign (
struct GNUNET_TIME_Timestamp exchange_timestamp,
struct GNUNET_TIME_Timestamp wire_deadline,
struct GNUNET_TIME_Timestamp refund_deadline,
- const struct TALER_Amount *amount_without_fee,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *total_without_fee,
+ unsigned int num_coins,
+ const struct TALER_CoinSpendSignatureP *coin_sigs[static num_coins],
const struct TALER_MerchantPublicKeyP *merchant_pub,
struct TALER_ExchangePublicKeyP *pub,
struct TALER_ExchangeSignatureP *sig)
@@ -119,14 +120,21 @@ TALER_exchange_online_deposit_confirmation_sign (
.exchange_timestamp = GNUNET_TIME_timestamp_hton (exchange_timestamp),
.wire_deadline = GNUNET_TIME_timestamp_hton (wire_deadline),
.refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline),
- .coin_pub = *coin_pub,
.merchant_pub = *merchant_pub
};
-
+ struct GNUNET_HashContext *hc;
+
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ for (unsigned int i = 0; i<num_coins; i++)
+ GNUNET_CRYPTO_hash_context_read (hc,
+ coin_sigs[i],
+ sizeof (*coin_sigs[i]));
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ &dcs.h_coin_sigs);
if (NULL != h_policy)
dcs.h_policy = *h_policy;
- TALER_amount_hton (&dcs.amount_without_fee,
- amount_without_fee);
+ TALER_amount_hton (&dcs.total_without_fee,
+ total_without_fee);
return scb (&dcs.purpose,
pub,
sig);
@@ -141,8 +149,9 @@ TALER_exchange_online_deposit_confirmation_verify (
struct GNUNET_TIME_Timestamp exchange_timestamp,
struct GNUNET_TIME_Timestamp wire_deadline,
struct GNUNET_TIME_Timestamp refund_deadline,
- const struct TALER_Amount *amount_without_fee,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *total_without_fee,
+ unsigned int num_coins,
+ const struct TALER_CoinSpendSignatureP *coin_sigs[static num_coins],
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const struct TALER_ExchangeSignatureP *exchange_sig)
@@ -155,14 +164,21 @@ TALER_exchange_online_deposit_confirmation_verify (
.exchange_timestamp = GNUNET_TIME_timestamp_hton (exchange_timestamp),
.wire_deadline = GNUNET_TIME_timestamp_hton (wire_deadline),
.refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline),
- .coin_pub = *coin_pub,
.merchant_pub = *merchant_pub
};
-
+ struct GNUNET_HashContext *hc;
+
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ for (unsigned int i = 0; i<num_coins; i++)
+ GNUNET_CRYPTO_hash_context_read (hc,
+ coin_sigs[i],
+ sizeof (*coin_sigs[i]));
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ &dcs.h_coin_sigs);
if (NULL != h_policy)
dcs.h_policy = *h_policy;
- TALER_amount_hton (&dcs.amount_without_fee,
- amount_without_fee);
+ TALER_amount_hton (&dcs.total_without_fee,
+ total_without_fee);
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT,
&dcs,