[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-merchant] 03/03: implement #5299
From: |
gnunet |
Subject: |
[taler-merchant] 03/03: implement #5299 |
Date: |
Fri, 10 Apr 2020 20:15:03 +0200 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to branch master
in repository merchant.
commit 0b945df357bf820540b67b412d47aa9073797267
Author: Christian Grothoff <address@hidden>
AuthorDate: Fri Apr 10 20:14:57 2020 +0200
implement #5299
---
src/backend/taler-merchant-httpd.c | 1 +
src/backend/taler-merchant-httpd_check-payment.c | 4 +-
src/backend/taler-merchant-httpd_order.c | 8 +-
src/backend/taler-merchant-httpd_pay.c | 35 +-
src/backend/taler-merchant-httpd_poll-payment.c | 4 +-
src/backend/taler-merchant-httpd_refund.c | 5 +-
src/backend/taler-merchant-httpd_refund.h | 8 +
src/backend/taler-merchant-httpd_refund_lookup.c | 619 ++++++++++++++++++---
.../taler-merchant-httpd_tip-reserve-helper.c | 12 +-
.../taler-merchant-httpd_track-transaction.c | 18 +-
src/backend/taler-merchant-httpd_track-transfer.c | 12 +-
src/backenddb/merchant-0001.sql | 38 +-
src/backenddb/plugin_merchantdb_postgres.c | 75 ++-
src/backenddb/test_merchantdb.c | 4 +-
src/include/taler_merchant_service.h | 57 +-
src/include/taler_merchantdb_plugin.h | 4 +-
src/lib/merchant_api_common.c | 14 +-
src/lib/merchant_api_pay.c | 2 +-
src/lib/merchant_api_refund.c | 195 ++++++-
src/lib/test_merchant_api.c | 84 ++-
src/lib/test_merchant_api_twisted.c | 579 ++++++++-----------
src/lib/testing_api_cmd_check_payment.c | 1 +
src/lib/testing_api_cmd_history.c | 24 +-
src/lib/testing_api_cmd_pay_abort_refund.c | 4 +-
src/lib/testing_api_cmd_poll_payment.c | 1 +
src/lib/testing_api_cmd_proposal.c | 3 +-
src/lib/testing_api_cmd_refund_increase.c | 7 +
src/lib/testing_api_cmd_refund_lookup.c | 302 +++++-----
src/lib/testing_api_cmd_track_transaction.c | 15 +-
29 files changed, 1424 insertions(+), 711 deletions(-)
diff --git a/src/backend/taler-merchant-httpd.c
b/src/backend/taler-merchant-httpd.c
index 7e8f70f..f577c47 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -406,6 +406,7 @@ do_shutdown (void *cls)
(void) cls;
MH_force_pc_resume ();
MH_force_trh_resume ();
+ MH_force_refund_resume ();
if (NULL != mhd_task)
{
GNUNET_SCHEDULER_cancel (mhd_task);
diff --git a/src/backend/taler-merchant-httpd_check-payment.c
b/src/backend/taler-merchant-httpd_check-payment.c
index a72a6e3..66b4941 100644
--- a/src/backend/taler-merchant-httpd_check-payment.c
+++ b/src/backend/taler-merchant-httpd_check-payment.c
@@ -140,14 +140,16 @@ cprc_cleanup (struct TM_HandlerContext *hc)
*
* @param cls closure
* @param coin_pub public coin from which the refund comes from
+ * @param exchange_url URL of the exchange that issued @a coin_pub
* @param rtransaction_id identificator of the refund
* @param reason human-readable explanation of the refund
- * @param refund_amount refund amount which is being taken from coin_pub
+ * @param refund_amount refund amount which is being taken from @a coin_pub
* @param refund_fee cost of this refund operation
*/
static void
process_refunds_cb (void *cls,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const char *exchange_url,
uint64_t rtransaction_id,
const char *reason,
const struct TALER_Amount *refund_amount,
diff --git a/src/backend/taler-merchant-httpd_order.c
b/src/backend/taler-merchant-httpd_order.c
index 374274e..1cf3463 100644
--- a/src/backend/taler-merchant-httpd_order.c
+++ b/src/backend/taler-merchant-httpd_order.c
@@ -488,12 +488,14 @@ proposal_put (struct MHD_Connection *connection,
refund_deadline.abs_value_us)
{
GNUNET_JSON_parse_free (spec);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"invariant failed: wire_transfer_deadline >=
refund_deadline\n");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "wire_transfer_deadline: %s\n",
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "wire_transfer_deadline: %s\n",
GNUNET_STRINGS_absolute_time_to_string (
wire_transfer_deadline));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "refund_deadline: %s\n",
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "refund_deadline: %s\n",
GNUNET_STRINGS_absolute_time_to_string (refund_deadline));
return TALER_MHD_reply_with_error
(connection,
diff --git a/src/backend/taler-merchant-httpd_pay.c
b/src/backend/taler-merchant-httpd_pay.c
index de65102..2d3bfcd 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -934,7 +934,7 @@ check_payment_sufficient (struct PayContext *pc)
{
GNUNET_break_op (0);
resume_pay_with_error (pc,
- MHD_HTTP_BAD_REQUEST,
+ MHD_HTTP_NOT_ACCEPTABLE,
TALER_EC_PAY_PAYMENT_INSUFFICIENT_DUE_TO_FEES,
"contract not paid up due to fees (client may
have calculated them badly)");
}
@@ -942,7 +942,7 @@ check_payment_sufficient (struct PayContext *pc)
{
GNUNET_break_op (0);
resume_pay_with_error (pc,
- MHD_HTTP_BAD_REQUEST,
+ MHD_HTTP_NOT_ACCEPTABLE,
TALER_EC_PAY_PAYMENT_INSUFFICIENT,
"payment insufficient");
@@ -1021,9 +1021,9 @@ deposit_cb (void *cls,
"exchange had an internal server error",
"code",
(json_int_t) TALER_EC_PAY_EXCHANGE_FAILED,
- "exchange-code",
+ "exchange_code",
(json_int_t) hr->ec,
- "exchange-http-status",
+ "exchange_http_status",
(json_int_t) hr->http_status));
}
else if (NULL == hr->reply)
@@ -1037,9 +1037,9 @@ deposit_cb (void *cls,
"exchange failed, response body not even in
JSON",
"code",
(json_int_t) TALER_EC_PAY_EXCHANGE_FAILED,
- "exchange-code",
+ "exchange_code",
(json_int_t) hr->ec,
- "exchange-http-status",
+ "exchange_http_status",
(json_int_t) hr->http_status));
}
else
@@ -1055,13 +1055,13 @@ deposit_cb (void *cls,
"exchange failed on deposit of a coin",
"code",
(json_int_t) TALER_EC_PAY_EXCHANGE_FAILED,
- "exchange-code",
+ "exchange_code",
(json_int_t) hr->ec,
- "exchange-http-status",
+ "exchange_http_status",
(json_int_t) hr->http_status,
"coin_pub",
GNUNET_JSON_from_data_auto (&dc->coin_pub),
- "exchange-reply",
+ "exchange_reply",
hr->reply));
else
resume_pay_with_response (
@@ -1072,13 +1072,13 @@ deposit_cb (void *cls,
"exchange failed on deposit of a coin",
"code",
(json_int_t) TALER_EC_PAY_EXCHANGE_FAILED,
- "exchange-code",
+ "exchange_code",
(json_int_t) hr->ec,
- "exchange-http-status",
+ "exchange_http_status",
(json_int_t) hr->http_status,
"coin_pub",
GNUNET_JSON_from_data_auto (&dc->coin_pub),
- "exchange-reply",
+ "exchange_reply",
hr->reply));
}
return;
@@ -1172,11 +1172,11 @@ process_pay_with_exchange (void *cls,
"failed to obtain meta-data from exchange",
"code",
(json_int_t) TALER_EC_PAY_EXCHANGE_KEYS_FAILURE,
- "exchange-http-status",
+ "exchange_http_status",
(json_int_t) http_status,
- "exchange-code",
+ "exchange_code",
(json_int_t) ec,
- "exchange-reply",
+ "exchange_reply",
error_reply));
return;
}
@@ -1789,14 +1789,16 @@ parse_pay (struct MHD_Connection *connection,
*
* @param cls closure with a `struct PayContext`
* @param coin_pub public coin from which the refund comes from
+ * @param exchange_url URL of the exchange that issued @a coin_pub
* @param rtransaction_id identificator of the refund
* @param reason human-readable explanation of the refund
- * @param refund_amount refund amount which is being taken from coin_pub
+ * @param refund_amount refund amount which is being taken from @a coin_pub
* @param refund_fee cost of this refund operation
*/
static void
check_coin_refunded (void *cls,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const char *exchange_url,
uint64_t rtransaction_id,
const char *reason,
const struct TALER_Amount *refund_amount,
@@ -1804,6 +1806,7 @@ check_coin_refunded (void *cls,
{
struct PayContext *pc = cls;
+ (void) exchange_url;
for (unsigned int i = 0; i<pc->coins_cnt; i++)
{
struct DepositConfirmation *dc = &pc->dc[i];
diff --git a/src/backend/taler-merchant-httpd_poll-payment.c
b/src/backend/taler-merchant-httpd_poll-payment.c
index 281730f..8db7289 100644
--- a/src/backend/taler-merchant-httpd_poll-payment.c
+++ b/src/backend/taler-merchant-httpd_poll-payment.c
@@ -140,14 +140,16 @@ pprc_cleanup (struct TM_HandlerContext *hc)
*
* @param cls closure
* @param coin_pub public coin from which the refund comes from
+ * @param exchange_url URL of the exchange that issued @a coin_pub
* @param rtransaction_id identificator of the refund
* @param reason human-readable explanation of the refund
- * @param refund_amount refund amount which is being taken from coin_pub
+ * @param refund_amount refund amount which is being taken from @a coin_pub
* @param refund_fee cost of this refund operation
*/
static void
process_refunds_cb (void *cls,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const char *exchange_url,
uint64_t rtransaction_id,
const char *reason,
const struct TALER_Amount *refund_amount,
diff --git a/src/backend/taler-merchant-httpd_refund.c
b/src/backend/taler-merchant-httpd_refund.c
index 79cb954..62ebf45 100644
--- a/src/backend/taler-merchant-httpd_refund.c
+++ b/src/backend/taler-merchant-httpd_refund.c
@@ -66,14 +66,16 @@ struct ProcessRefundData
*
* @param cls closure
* @param coin_pub public coin from which the refund comes from
+ * @param exchange_url URL of the exchange that issued @a coin_pub
* @param rtransaction_id identificator of the refund
* @param reason human-readable explanation of the refund
- * @param refund_amount refund amount which is being taken from coin_pub
+ * @param refund_amount refund amount which is being taken from @a coin_pub
* @param refund_fee cost of this refund operation
*/
static void
process_refunds_cb (void *cls,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const char *exchange_url,
uint64_t rtransaction_id,
const char *reason,
const struct TALER_Amount *refund_amount,
@@ -83,6 +85,7 @@ process_refunds_cb (void *cls,
struct GNUNET_CRYPTO_EddsaSignature sig;
json_t *element;
+ (void) exchange_url;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Found refund of %s for coin %s with reason `%s' in database\n",
TALER_B2S (coin_pub),
diff --git a/src/backend/taler-merchant-httpd_refund.h
b/src/backend/taler-merchant-httpd_refund.h
index 1270f80..f0fb44d 100644
--- a/src/backend/taler-merchant-httpd_refund.h
+++ b/src/backend/taler-merchant-httpd_refund.h
@@ -45,6 +45,14 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh,
size_t *upload_data_size,
struct MerchantInstance *mi);
+
+/**
+ * Force resuming all suspended refund lookups, needed during shutdown.
+ */
+void
+MH_force_refund_resume (void);
+
+
/**
* Get the JSON representation of a refund.
*
diff --git a/src/backend/taler-merchant-httpd_refund_lookup.c
b/src/backend/taler-merchant-httpd_refund_lookup.c
index 2cae271..e80241b 100644
--- a/src/backend/taler-merchant-httpd_refund_lookup.c
+++ b/src/backend/taler-merchant-httpd_refund_lookup.c
@@ -22,9 +22,402 @@
#include <jansson.h>
#include <taler/taler_signatures.h>
#include <taler/taler_json_lib.h>
+#include <taler/taler_exchange_service.h>
#include "taler-merchant-httpd.h"
+#include "taler-merchant-httpd_exchanges.h"
#include "taler-merchant-httpd_refund.h"
+/**
+ * How often do we retry DB transactions on serialization failures?
+ */
+#define MAX_RETRIES 5
+
+/**
+ * Information we keep for each coin to be refunded.
+ */
+struct CoinRefund
+{
+
+ /**
+ * Kept in a DLL.
+ */
+ struct CoinRefund *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct CoinRefund *prev;
+
+ /**
+ * Request to connect to the target exchange.
+ */
+ struct TMH_EXCHANGES_FindOperation *fo;
+
+ /**
+ * Handle for the refund operation with the exchange.
+ */
+ struct TALER_EXCHANGE_RefundHandle *rh;
+
+ /**
+ * PRD this operation is part of.
+ */
+ struct ProcessRefundData *prd;
+
+ /**
+ * Coin to refund.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Refund transaction ID to use.
+ */
+ uint64_t rtransaction_id;
+
+ /**
+ * Amount to refund.
+ */
+ struct TALER_Amount refund_amount;
+
+ /**
+ * Applicable refund transaction fee.
+ */
+ struct TALER_Amount refund_fee;
+
+ /**
+ * Public key of the exchange affirming the refund.
+ */
+ struct TALER_ExchangePublicKeyP exchange_pub;
+
+ /**
+ * Signature of the exchange affirming the refund.
+ */
+ struct TALER_ExchangeSignatureP exchange_sig;
+
+ /**
+ * HTTP status from the exchange, #MHD_HTTP_OK if
+ * @a exchange_pub and @a exchange_sig are valid.
+ */
+ unsigned int exchange_status;
+
+ /**
+ * HTTP error code from the exchange.
+ */
+ enum TALER_ErrorCode exchange_code;
+
+ /**
+ * Fully reply from the exchange, only possibly set if
+ * we got a JSON reply and a non-#MHD_HTTP_OK error code
+ */
+ json_t *exchange_reply;
+
+};
+
+
+/**
+ * Closure for #process_refunds_cb.
+ */
+struct ProcessRefundData
+{
+ /**
+ * Must be first for #handle_mhd_completion_callback() cleanup
+ * logic to work.
+ */
+ struct TM_HandlerContext hc;
+
+ /**
+ * Hashed version of contract terms.
+ */
+ struct GNUNET_HashCode h_contract_terms;
+
+ /**
+ * DLL of (suspended) requests.
+ */
+ struct ProcessRefundData *next;
+
+ /**
+ * DLL of (suspended) requests.
+ */
+ struct ProcessRefundData *prev;
+
+ /**
+ * Head of DLL of coin refunds for this request.
+ */
+ struct CoinRefund *cr_head;
+
+ /**
+ * Tail of DLL of coin refunds for this request.
+ */
+ struct CoinRefund *cr_tail;
+
+ /**
+ * Both public and private key are needed by the callback
+ */
+ const struct MerchantInstance *merchant;
+
+ /**
+ * Connection we are handling.
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * Did we suspend @a connection?
+ */
+ int suspended;
+
+ /**
+ * Return code: #TALER_EC_NONE if successful.
+ */
+ enum TALER_ErrorCode ec;
+};
+
+
+/**
+ * HEad of DLL of (suspended) requests.
+ */
+static struct ProcessRefundData *prd_head;
+
+/**
+ * Tail of DLL of (suspended) requests.
+ */
+static struct ProcessRefundData *prd_tail;
+
+
+/**
+ * Clean up memory in @a cls, the connection was closed.
+ *
+ * @param cls a `struct ProcessRefundData` to clean up.
+ */
+static void
+cleanup_prd (struct TM_HandlerContext *cls)
+{
+ struct ProcessRefundData *prd = (struct ProcessRefundData *) cls;
+ struct CoinRefund *cr;
+
+ while (NULL != (cr = prd->cr_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (prd->cr_head,
+ prd->cr_tail,
+ cr);
+ if (NULL != cr->fo)
+ {
+ TMH_EXCHANGES_find_exchange_cancel (cr->fo);
+ cr->fo = NULL;
+ }
+ if (NULL != cr->rh)
+ {
+ TALER_EXCHANGE_refund_cancel (cr->rh);
+ cr->rh = NULL;
+ }
+ if (NULL != cr->exchange_reply)
+ {
+ json_decref (cr->exchange_reply);
+ cr->exchange_reply = NULL;
+ }
+ GNUNET_free (cr);
+ }
+ GNUNET_free (prd);
+}
+
+
+/**
+ * Check if @a prd has sub-activities still pending.
+ *
+ * @param prd request to check
+ * @return #GNUNET_YES if activities are still pending
+ */
+static int
+prd_pending (struct ProcessRefundData *prd)
+{
+ int pending = GNUNET_NO;
+
+ for (struct CoinRefund *cr = prd->cr_head;
+ NULL != cr;
+ cr = cr->next)
+ {
+ if ( (NULL != cr->fo) ||
+ (NULL != cr->rh) )
+ {
+ pending = GNUNET_YES;
+ break;
+ }
+ }
+ return pending;
+}
+
+
+/**
+ * Check if @a prd is ready to be resumed, and if so, do it.
+ *
+ * @param prd refund request to be possibly ready
+ */
+static void
+check_resume_prd (struct ProcessRefundData *prd)
+{
+ if (prd_pending (prd))
+ return;
+ GNUNET_CONTAINER_DLL_remove (prd_head,
+ prd_tail,
+ prd);
+ GNUNET_assert (prd->suspended);
+ prd->suspended = GNUNET_NO;
+ MHD_resume_connection (prd->connection);
+ TMH_trigger_daemon ();
+}
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting a
+ * refund request to an exchange.
+ *
+ * @param cls a `struct CoinRefund`
+ * @param hr HTTP response data
+ * @param exchange_pub exchange key used to sign refund confirmation
+ * @param exchange_sig exchange's signature over refund
+ */
+static void
+refund_cb (void *cls,
+ const struct TALER_EXCHANGE_HttpResponse *hr,
+ const struct TALER_ExchangePublicKeyP *exchange_pub,
+ const struct TALER_ExchangeSignatureP *exchange_sig)
+{
+ struct CoinRefund *cr = cls;
+
+ cr->rh = NULL;
+ cr->exchange_status = hr->http_status;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Exchange refund status for coin %s is %u\n",
+ TALER_B2S (&cr->coin_pub),
+ hr->http_status);
+ if (MHD_HTTP_OK != hr->http_status)
+ {
+ cr->exchange_code = hr->ec;
+ cr->exchange_reply = json_incref ((json_t*) hr->reply);
+ }
+ else
+ {
+ cr->exchange_pub = *exchange_pub;
+ cr->exchange_sig = *exchange_sig;
+ /* FIXME: store in our database,
+ 1) as evidence for us that the refund happened, and
+ 2) to possibly avoid doing another exchange iteration
+ the next time around. */
+ }
+ check_resume_prd (cr->prd);
+}
+
+
+/**
+ * Function called with the result of a #TMH_EXCHANGES_find_exchange()
+ * operation.
+ *
+ * @param cls a `struct CoinRefund *`
+ * @param eh handle to the exchange context
+ * @param wire_fee current applicable wire fee for dealing with @a eh, NULL if
not available
+ * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config
+ * @param ec error code, #TALER_EC_NONE on success
+ * @param http_status the HTTP status we got from the exchange
+ * @param error_reply the full reply from the exchange, NULL if
+ * the response was NOT in JSON or on success
+ */
+static void
+exchange_found_cb (void *cls,
+ struct TALER_EXCHANGE_Handle *eh,
+ const struct TALER_Amount *wire_fee,
+ int exchange_trusted,
+ enum TALER_ErrorCode ec,
+ unsigned int http_status,
+ const json_t *error_reply)
+{
+ struct CoinRefund *cr = cls;
+
+ cr->fo = NULL;
+ if (TALER_EC_NONE == ec)
+ {
+ cr->rh = TALER_EXCHANGE_refund (eh,
+ &cr->refund_amount,
+ &cr->refund_fee,
+ &cr->prd->h_contract_terms,
+ &cr->coin_pub,
+ cr->rtransaction_id,
+ &cr->prd->merchant->privkey,
+ &refund_cb,
+ cr);
+ return;
+ }
+ cr->exchange_status = http_status;
+ cr->exchange_code = ec;
+ cr->exchange_reply = json_incref ((json_t*) error_reply);
+ check_resume_prd (cr->prd);
+}
+
+
+/**
+ * Function called with information about a refund.
+ * It is responsible for packing up the data to return.
+ *
+ * @param cls closure
+ * @param coin_pub public coin from which the refund comes from
+ * @param exchange_url URL of the exchange that issued @a coin_pub
+ * @param rtransaction_id identificator of the refund
+ * @param reason human-readable explanation of the refund
+ * @param refund_amount refund amount which is being taken from @a coin_pub
+ * @param refund_fee cost of this refund operation
+ */
+static void
+process_refunds_cb (void *cls,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const char *exchange_url,
+ uint64_t rtransaction_id,
+ const char *reason,
+ const struct TALER_Amount *refund_amount,
+ const struct TALER_Amount *refund_fee)
+{
+ struct ProcessRefundData *prd = cls;
+ struct CoinRefund *cr;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Found refund of %s for coin %s with reason `%s' in database\n",
+ TALER_B2S (coin_pub),
+ TALER_amount2s (refund_amount),
+ reason);
+ cr = GNUNET_new (struct CoinRefund);
+ cr->prd = prd;
+ cr->coin_pub = *coin_pub;
+ cr->rtransaction_id = rtransaction_id;
+ cr->refund_amount = *refund_amount;
+ cr->refund_fee = *refund_fee;
+ GNUNET_CONTAINER_DLL_insert (prd->cr_head,
+ prd->cr_tail,
+ cr);
+ /* FIXME: check in database if we already got the
+ results from #refund_cb() from an earlier request,
+ if so, avoid this step: */
+ cr->fo = TMH_EXCHANGES_find_exchange (exchange_url,
+ NULL,
+ &exchange_found_cb,
+ cr);
+}
+
+
+/**
+ * Force resuming all suspended refund lookups, needed during shutdown.
+ */
+void
+MH_force_refund_resume (void)
+{
+ struct ProcessRefundData *prd;
+
+ while (NULL != (prd = prd_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (prd_head,
+ prd_tail,
+ prd);
+ GNUNET_assert (prd->suspended);
+ prd->suspended = GNUNET_NO;
+ MHD_resume_connection (prd->connection);
+ }
+}
+
/**
* Return refund situation about a contract.
@@ -45,91 +438,181 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh,
size_t *upload_data_size,
struct MerchantInstance *mi)
{
+ struct ProcessRefundData *prd;
const char *order_id;
- struct GNUNET_HashCode h_contract_terms;
json_t *contract_terms;
enum GNUNET_DB_QueryStatus qs;
- order_id = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "order_id");
- if (NULL == order_id)
+ prd = *connection_cls;
+ if (NULL == prd)
{
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_PARAMETER_MISSING,
- "order_id");
+ order_id = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "order_id");
+ if (NULL == order_id)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_PARAMETER_MISSING,
+ "order_id");
+ }
+
+ /* Convert order id to h_contract_terms */
+ contract_terms = NULL;
+ db->preflight (db->cls);
+ qs = db->find_contract_terms (db->cls,
+ &contract_terms,
+ order_id,
+ &mi->pubkey);
+ if (0 > qs)
+ {
+ /* single, read-only SQL statements should never cause
+ serialization problems */
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+ /* Always report on hard error as well to enable diagnostics */
+ GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_REFUND_LOOKUP_DB_ERROR,
+ "database error looking up order_id
from merchant_contract_terms table");
+ }
+
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Unknown order id given: `%s'\n",
+ order_id);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_REFUND_ORDER_ID_UNKNOWN,
+ "order_id not found in database");
+ }
+
+ prd = GNUNET_new (struct ProcessRefundData);
+ if (GNUNET_OK !=
+ TALER_JSON_hash (contract_terms,
+ &prd->h_contract_terms))
+ {
+ GNUNET_break (0);
+ json_decref (contract_terms);
+ GNUNET_free (prd);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_INTERNAL_LOGIC_ERROR,
+ "Could not hash contract terms");
+ }
+ json_decref (contract_terms);
+ prd->hc.cc = &cleanup_prd;
+ prd->merchant = mi;
+ prd->ec = TALER_EC_NONE;
+ prd->connection = connection;
+ *connection_cls = prd;
+
+ for (unsigned int i = 0; i<MAX_RETRIES; i++)
+ {
+ qs = db->get_refunds_from_contract_terms_hash (db->cls,
+ &mi->pubkey,
+ &prd->h_contract_terms,
+ &process_refunds_cb,
+ prd);
+ if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+ break;
+ }
+ if (0 > qs)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Database hard error on refunds_from_contract_terms_hash
lookup: %s\n",
+ GNUNET_h2s (&prd->h_contract_terms));
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_REFUND_LOOKUP_DB_ERROR,
+ "Failed to lookup refunds for
contract");
+ }
}
- /* Convert order id to h_contract_terms */
- contract_terms = NULL;
- db->preflight (db->cls);
- qs = db->find_contract_terms (db->cls,
- &contract_terms,
- order_id,
- &mi->pubkey);
- if (0 > qs)
+ /* Check if there are still exchange operations pending */
+ if (GNUNET_YES == prd_pending (prd))
{
- /* single, read-only SQL statements should never cause
- serialization problems */
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
- /* Always report on hard error as well to enable diagnostics */
- GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_REFUND_LOOKUP_DB_ERROR,
- "database error looking up order_id
from merchant_contract_terms table");
+ if (! prd->suspended)
+ {
+ prd->suspended = GNUNET_YES;
+ MHD_suspend_connection (connection);
+ GNUNET_CONTAINER_DLL_insert (prd_head,
+ prd_tail,
+ prd);
+ }
+ return MHD_YES; /* we're still talking to the exchange */
}
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ /* All operations done, build final response */
+ if (NULL == prd->cr_head)
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Unknown order id given: `%s'\n",
- order_id);
+ /* There ARE no refunds scheduled, bitch */
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
- TALER_EC_REFUND_ORDER_ID_UNKNOWN,
- "order_id not found in database");
+ TALER_EC_REFUND_LOOKUP_NO_REFUND,
+ "This contract is not currently
eligible for refunds");
}
- if (GNUNET_OK !=
- TALER_JSON_hash (contract_terms,
- &h_contract_terms))
{
- GNUNET_break (0);
- json_decref (contract_terms);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_INTERNAL_LOGIC_ERROR,
- "Could not hash contract terms");
- }
- json_decref (contract_terms);
+ json_t *ra;
- {
- json_t *response;
- enum TALER_ErrorCode ec;
- const char *errmsg;
-
- response = TM_get_refund_json (mi,
- &h_contract_terms,
- &ec,
- &errmsg);
- if (NULL == response)
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- ec,
- errmsg);
- return TALER_MHD_reply_json_pack (connection, MHD_HTTP_OK,
- "{s:o, s:o, s:o}",
- "refund_permissions",
- response,
- "merchant_pub",
- GNUNET_JSON_from_data_auto (
- &mi->pubkey),
- "h_contract_terms",
- GNUNET_JSON_from_data_auto (
- &h_contract_terms));
+ ra = json_array ();
+ GNUNET_assert (NULL != ra);
+ for (struct CoinRefund *cr = prd->cr_head;
+ NULL != cr;
+ cr = cr->next)
+ {
+ GNUNET_assert (
+ 0 ==
+ json_array_append_new (
+ ra,
+ (MHD_HTTP_OK != cr->exchange_status)
+ ? json_pack ((NULL != cr->exchange_reply)
+ ? "{s:o,s:o,s:o,s:I,s:I,s:I,s:O}"
+ : "{s:o,s:o,s:o,s:I,s:I:s:I}",
+ "coin_pub",
+ GNUNET_JSON_from_data_auto (&cr->coin_pub),
+ "refund_amount",
+ TALER_JSON_from_amount (&cr->refund_amount),
+ "refund_fee",
+ TALER_JSON_from_amount (&cr->refund_fee),
+ "exchange_http_status",
+ (json_int_t) cr->exchange_status,
+ "rtransaction_id",
+ (json_int_t) cr->rtransaction_id,
+ "exchange_code",
+ (json_int_t) cr->exchange_code,
+ "exchange_reply",
+ cr->exchange_reply)
+ : json_pack ("{s:o,s:o,s:o,s:I,s:I,s:o,s:o}",
+ "coin_pub",
+ GNUNET_JSON_from_data_auto (&cr->coin_pub),
+ "refund_amount",
+ TALER_JSON_from_amount (&cr->refund_amount),
+ "refund_fee",
+ TALER_JSON_from_amount (&cr->refund_fee),
+ "exchange_http_status",
+ (json_int_t) cr->exchange_status,
+ "rtransaction_id",
+ (json_int_t) cr->rtransaction_id,
+ "exchange_pub",
+ GNUNET_JSON_from_data_auto (&cr->exchange_pub),
+ "exchange_sig",
+ GNUNET_JSON_from_data_auto (&cr->exchange_sig)
+ )));
+ }
+ return TALER_MHD_reply_json_pack (
+ connection,
+ MHD_HTTP_OK,
+ "{s:o, s:o, s:o}",
+ "refunds",
+ ra,
+ "merchant_pub",
+ GNUNET_JSON_from_data_auto (&mi->pubkey),
+ "h_contract_terms",
+ GNUNET_JSON_from_data_auto (&prd->h_contract_terms));
}
}
diff --git a/src/backend/taler-merchant-httpd_tip-reserve-helper.c
b/src/backend/taler-merchant-httpd_tip-reserve-helper.c
index 190aba2..fc5a1aa 100644
--- a/src/backend/taler-merchant-httpd_tip-reserve-helper.c
+++ b/src/backend/taler-merchant-httpd_tip-reserve-helper.c
@@ -101,10 +101,10 @@ handle_status (void *cls,
TALER_MHD_make_json_pack (
"{s:I, s:I, s:s, s:I, s:O}",
"code", (json_int_t) TALER_EC_TIP_QUERY_RESERVE_UNKNOWN_TO_EXCHANGE,
- "exchange-http-status", hr->http_status,
+ "exchange_http_status", hr->http_status,
"hint", "tipping reserve unknown at exchange",
- "exchange-code", hr->ec,
- "exchange-reply", hr->reply));
+ "exchange_code", hr->ec,
+ "exchange_reply", hr->reply));
return;
}
if (MHD_HTTP_OK != hr->http_status)
@@ -116,10 +116,10 @@ handle_status (void *cls,
TALER_MHD_make_json_pack (
"{s:I, s:I, s:s, s:I, s:O}",
"code", (json_int_t) TALER_EC_TIP_QUERY_RESERVE_HISTORY_FAILED,
- "exchange-http-status", hr->http_status,
+ "exchange_http_status", hr->http_status,
"hint", "exchange failed to provide reserve history",
- "exchange-code", (json_int_t) hr->ec,
- "exchange-reply", hr->reply));
+ "exchange_code", (json_int_t) hr->ec,
+ "exchange_reply", hr->reply));
return;
}
diff --git a/src/backend/taler-merchant-httpd_track-transaction.c
b/src/backend/taler-merchant-httpd_track-transaction.c
index 290e8dc..b64bf2e 100644
--- a/src/backend/taler-merchant-httpd_track-transaction.c
+++ b/src/backend/taler-merchant-httpd_track-transaction.c
@@ -471,11 +471,11 @@ wire_deposits_cb (void *cls,
"{s:I, s:I, s:I, s:O}",
"code",
(json_int_t) TALER_EC_TRACK_TRANSACTION_WIRE_TRANSFER_TRACE_ERROR,
- "exchange-http-status",
+ "exchange_http_status",
(json_int_t) hr->http_status,
- "exchange-code",
+ "exchange_code",
(json_int_t) hr->ec,
- "exchange-reply",
+ "exchange_reply",
hr->reply));
return;
}
@@ -629,11 +629,11 @@ wtid_cb (void *cls,
"{s:I, s:I, s:I, s:O}",
"code",
(json_int_t) TALER_EC_TRACK_TRANSACTION_COIN_TRACE_ERROR,
- "exchange-http-status",
+ "exchange_http_status",
(json_int_t) hr->http_status,
- "exchange-code",
+ "exchange_code",
(json_int_t) hr->ec,
- "exchange-reply",
+ "exchange_reply",
hr->reply));
return;
}
@@ -905,9 +905,9 @@ process_track_transaction_with_exchange (void *cls,
: "{s:s, s:I, s:I, s:I}",
"hint", "failed to obtain meta-data from exchange",
"code", (json_int_t) TALER_EC_TRACK_TRANSACTION_EXCHANGE_KEYS_FAILURE,
- "exchange-http-status", (json_int_t) http_status,
- "exchange-code", (json_int_t) ec,
- "exchange-reply", error_reply));
+ "exchange_http_status", (json_int_t) http_status,
+ "exchange_code", (json_int_t) ec,
+ "exchange_reply", error_reply));
return;
}
tctx->eh = eh;
diff --git a/src/backend/taler-merchant-httpd_track-transfer.c
b/src/backend/taler-merchant-httpd_track-transfer.c
index 2ddcc16..000738b 100644
--- a/src/backend/taler-merchant-httpd_track-transfer.c
+++ b/src/backend/taler-merchant-httpd_track-transfer.c
@@ -617,9 +617,9 @@ wire_transfer_cb (void *cls,
TALER_MHD_make_json_pack (
"{s:I, s:I, s:I, s:O}",
"code", (json_int_t) TALER_EC_TRACK_TRANSFER_EXCHANGE_ERROR,
- "exchange-code", (json_int_t) hr->ec,
- "exchange-http-status", (json_int_t) hr->http_status,
- "exchange-reply", hr->reply));
+ "exchange_code", (json_int_t) hr->ec,
+ "exchange_http_status", (json_int_t) hr->http_status,
+ "exchange_reply", hr->reply));
return;
}
for (unsigned int i = 0; i<MAX_RETRIES; i++)
@@ -828,9 +828,9 @@ process_track_transfer_with_exchange (void *cls,
: "{s:s, s:I, s:I, s:I}",
"hint", "failed to obtain meta-data from exchange",
"code", (json_int_t) TALER_EC_TRACK_TRANSFER_EXCHANGE_KEYS_FAILURE,
- "exchange-http-status", (json_int_t) http_status,
- "exchange-code", (json_int_t) ec,
- "exchange-reply", error_reply));
+ "exchange_http_status", (json_int_t) http_status,
+ "exchange_code", (json_int_t) ec,
+ "exchange_reply", error_reply));
return;
}
rctx->eh = eh;
diff --git a/src/backenddb/merchant-0001.sql b/src/backenddb/merchant-0001.sql
index 98f20a2..bfcc828 100644
--- a/src/backenddb/merchant-0001.sql
+++ b/src/backenddb/merchant-0001.sql
@@ -21,7 +21,7 @@ BEGIN;
SELECT _v.register_patch('merchant-0001', NULL, NULL);
-CREATE TABLE IF NOT EXISTS merchant_orders
+CREATE TABLE IF NOT EXISTS merchant_orders
(order_id VARCHAR NOT NULL
,merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)
,contract_terms BYTEA NOT NULL
@@ -29,7 +29,7 @@ CREATE TABLE IF NOT EXISTS merchant_orders
,PRIMARY KEY (order_id, merchant_pub)
);
--- Offers we made to customers
+-- Offers we made to customers
CREATE TABLE IF NOT EXISTS merchant_contract_terms
(order_id VARCHAR NOT NULL
,merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)
@@ -42,7 +42,7 @@ CREATE TABLE IF NOT EXISTS merchant_contract_terms
,UNIQUE (h_contract_terms, merchant_pub)
);
--- Table with the proofs for each coin we deposited at the exchange
+-- Table with the proofs for each coin we deposited at the exchange
CREATE TABLE IF NOT EXISTS merchant_deposits
(h_contract_terms BYTEA NOT NULL
,merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)
@@ -62,7 +62,7 @@ CREATE TABLE IF NOT EXISTS merchant_deposits
,FOREIGN KEY (h_contract_terms, merchant_pub) REFERENCES
merchant_contract_terms (h_contract_terms, merchant_pub)
);
-CREATE TABLE IF NOT EXISTS merchant_proofs
+CREATE TABLE IF NOT EXISTS merchant_proofs
(exchange_url VARCHAR NOT NULL
,wtid BYTEA CHECK (LENGTH(wtid)=32)
,execution_time INT8 NOT NULL
@@ -70,10 +70,10 @@ CREATE TABLE IF NOT EXISTS merchant_proofs
,proof BYTEA NOT NULL
,PRIMARY KEY (wtid, exchange_url)
);
-
+
-- Note that h_contract_terms + coin_pub may actually be unknown to
-- us, e.g. someone else deposits something for us at the exchange.
--- Hence those cannot be foreign keys into deposits/transactions!
+-- Hence those cannot be foreign keys into deposits/transactions!
CREATE TABLE IF NOT EXISTS merchant_transfers
(h_contract_terms BYTEA NOT NULL
,coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)
@@ -88,7 +88,7 @@ CREATE INDEX IF NOT EXISTS merchant_transfers_by_wtid
ON merchant_transfers
(wtid);
-CREATE TABLE IF NOT EXISTS exchange_wire_fees
+CREATE TABLE IF NOT EXISTS exchange_wire_fees
(exchange_pub BYTEA NOT NULL CHECK (LENGTH(exchange_pub)=32)
,h_wire_method BYTEA NOT NULL CHECK (LENGTH(h_wire_method)=64)
,wire_fee_val INT8 NOT NULL
@@ -100,20 +100,20 @@ CREATE TABLE IF NOT EXISTS exchange_wire_fees
,exchange_sig BYTEA NOT NULL CHECK (LENGTH(exchange_sig)=64)
,PRIMARY KEY (exchange_pub,h_wire_method,start_date,end_date)
);
-
+
CREATE TABLE IF NOT EXISTS merchant_refunds
(rtransaction_id BIGSERIAL UNIQUE
- ,merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)
+ ,merchant_pub BYTEA NOT NULL
,h_contract_terms BYTEA NOT NULL
- ,coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)
+ ,coin_pub BYTEA NOT NULL
,reason VARCHAR NOT NULL
,refund_amount_val INT8 NOT NULL
,refund_amount_frac INT4 NOT NULL
- ,refund_fee_val INT8 NOT NULL
- ,refund_fee_frac INT4 NOT NULL
+ ,FOREIGN KEY (h_contract_terms, coin_pub) REFERENCES merchant_deposits
(h_contract_terms, coin_pub)
+ ,FOREIGN KEY (h_contract_terms, merchant_pub) REFERENCES
merchant_contract_terms (h_contract_terms, merchant_pub)
);
--- balances of the reserves available for tips
+-- balances of the reserves available for tips
CREATE TABLE IF NOT EXISTS merchant_tip_reserves
(reserve_priv BYTEA NOT NULL CHECK (LENGTH(reserve_priv)=32)
,expiration INT8 NOT NULL
@@ -121,8 +121,8 @@ CREATE TABLE IF NOT EXISTS merchant_tip_reserves
,balance_frac INT4 NOT NULL
,PRIMARY KEY (reserve_priv)
);
-
--- table where we remember when tipping reserves where established / enabled
+
+-- table where we remember when tipping reserves where established / enabled
CREATE TABLE IF NOT EXISTS merchant_tip_reserve_credits
(reserve_priv BYTEA NOT NULL CHECK (LENGTH(reserve_priv)=32)
,credit_uuid BYTEA UNIQUE NOT NULL CHECK (LENGTH(credit_uuid)=64)
@@ -132,8 +132,8 @@ CREATE TABLE IF NOT EXISTS merchant_tip_reserve_credits
,PRIMARY KEY (credit_uuid)
);
--- tips that have been authorized
-CREATE TABLE IF NOT EXISTS merchant_tips
+-- tips that have been authorized
+CREATE TABLE IF NOT EXISTS merchant_tips
(reserve_priv BYTEA NOT NULL CHECK (LENGTH(reserve_priv)=32)
,tip_id BYTEA NOT NULL CHECK (LENGTH(tip_id)=64)
,exchange_url VARCHAR NOT NULL
@@ -148,7 +148,7 @@ CREATE TABLE IF NOT EXISTS merchant_tips
);
-- tips that have been picked up
-CREATE TABLE IF NOT EXISTS merchant_tip_pickups
+CREATE TABLE IF NOT EXISTS merchant_tip_pickups
(tip_id BYTEA NOT NULL REFERENCES merchant_tips (tip_id) ON DELETE CASCADE
,pickup_id BYTEA NOT NULL CHECK (LENGTH(pickup_id)=64)
,amount_val INT8 NOT NULL
@@ -156,7 +156,7 @@ CREATE TABLE IF NOT EXISTS merchant_tip_pickups
,PRIMARY KEY (pickup_id)
);
--- sessions and their order_id/fulfillment_url mapping
+-- sessions and their order_id/fulfillment_url mapping
CREATE TABLE IF NOT EXISTS merchant_session_info
(session_id VARCHAR NOT NULL
,fulfillment_url VARCHAR NOT NULL
diff --git a/src/backenddb/plugin_merchantdb_postgres.c
b/src/backenddb/plugin_merchantdb_postgres.c
index 61de4a5..18b4f76 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -1742,9 +1742,12 @@ get_refunds_cb (void *cls,
struct TALER_Amount refund_amount;
struct TALER_Amount refund_fee;
char *reason;
+ char *exchange_url;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
&coin_pub),
+ GNUNET_PQ_result_spec_string ("exchange_url",
+ &exchange_url),
GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
&rtransaction_id),
TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
@@ -1768,6 +1771,7 @@ get_refunds_cb (void *cls,
grc->qs = i + 1;
grc->rc (grc->rc_cls,
&coin_pub,
+ exchange_url,
rtransaction_id,
reason,
&refund_amount,
@@ -1788,15 +1792,12 @@ get_refunds_cb (void *cls,
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_get_refunds_from_contract_terms_hash (void *cls,
- const struct
- TALER_MerchantPublicKeyP *
- merchant_pub,
- const struct
- GNUNET_HashCode
*h_contract_terms,
- TALER_MERCHANTDB_RefundCallback
- rc,
- void *rc_cls)
+postgres_get_refunds_from_contract_terms_hash (
+ void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_contract_terms,
+ TALER_MERCHANTDB_RefundCallback rc,
+ void *rc_cls)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -1837,7 +1838,6 @@ postgres_get_refunds_from_contract_terms_hash (void *cls,
* @param coin_pub public key of the coin giving the (part of) refund
* @param reason human readable explanation behind the refund
* @param refund how much this coin is refunding
- * @param refund_fee refund fee for this coin
*/
static enum GNUNET_DB_QueryStatus
insert_refund (void *cls,
@@ -1845,8 +1845,7 @@ insert_refund (void *cls,
const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const char *reason,
- const struct TALER_Amount *refund,
- const struct TALER_Amount *refund_fee)
+ const struct TALER_Amount *refund)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -1855,7 +1854,6 @@ insert_refund (void *cls,
GNUNET_PQ_query_param_auto_from_type (coin_pub),
GNUNET_PQ_query_param_string (reason),
TALER_PQ_query_param_amount (refund),
- TALER_PQ_query_param_amount (refund_fee),
GNUNET_PQ_query_param_end
};
@@ -1886,17 +1884,18 @@ insert_refund (void *cls,
* @return transaction status code
*/
static enum GNUNET_DB_QueryStatus
-postgres_store_wire_fee_by_exchange (void *cls,
- const struct
- TALER_MasterPublicKeyP *exchange_pub,
- const struct
- GNUNET_HashCode *h_wire_method,
- const struct TALER_Amount *wire_fee,
- const struct TALER_Amount *closing_fee,
- struct GNUNET_TIME_Absolute start_date,
- struct GNUNET_TIME_Absolute end_date,
- const struct
- TALER_MasterSignatureP *exchange_sig)
+postgres_store_wire_fee_by_exchange (
+ void *cls,
+ const struct
+ TALER_MasterPublicKeyP *exchange_pub,
+ const struct
+ GNUNET_HashCode *h_wire_method,
+ const struct TALER_Amount *wire_fee,
+ const struct TALER_Amount *closing_fee,
+ struct GNUNET_TIME_Absolute start_date,
+ struct GNUNET_TIME_Absolute end_date,
+ const struct
+ TALER_MasterSignatureP *exchange_sig)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -2109,7 +2108,6 @@ process_deposits_for_refund_cb (void *cls,
struct TALER_Amount deposit_refund[GNUNET_NZL (num_results)];
struct TALER_CoinSpendPublicKeyP deposit_coin_pubs[GNUNET_NZL (num_results)];
struct TALER_Amount deposit_amount_with_fee[GNUNET_NZL (num_results)];
- struct TALER_Amount deposit_refund_fee[GNUNET_NZL (num_results)];
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (ctx->refund->currency,
@@ -2121,14 +2119,11 @@ process_deposits_for_refund_cb (void *cls,
{
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_Amount amount_with_fee;
- struct TALER_Amount refund_fee;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
&coin_pub),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
&amount_with_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_fee",
- &refund_fee),
GNUNET_PQ_result_spec_end
};
struct FindRefundContext ictx = {
@@ -2173,7 +2168,6 @@ process_deposits_for_refund_cb (void *cls,
deposit_refund[i] = ictx.refunded_amount;
deposit_amount_with_fee[i] = amount_with_fee;
deposit_coin_pubs[i] = coin_pub;
- deposit_refund_fee[i] = refund_fee;
if (0 >
TALER_amount_add (¤t_refund,
¤t_refund,
@@ -2283,8 +2277,7 @@ process_deposits_for_refund_cb (void *cls,
ctx->h_contract_terms,
&deposit_coin_pubs[i],
ctx->reason,
- increment,
- &deposit_refund_fee[i])))
+ increment)))
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
ctx->qs = qs;
@@ -3074,11 +3067,9 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
",reason"
",refund_amount_val"
",refund_amount_frac"
- ",refund_fee_val"
- ",refund_fee_frac"
") VALUES"
- "($1, $2, $3, $4, $5, $6, $7, $8)",
- 8),
+ "($1, $2, $3, $4, $5, $6)",
+ 6),
GNUNET_PQ_make_prepare ("insert_proof",
"INSERT INTO merchant_proofs"
"(exchange_url"
@@ -3228,15 +3219,17 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
GNUNET_PQ_make_prepare ("find_refunds_from_contract_terms_hash",
"SELECT"
" coin_pub"
+ ",merchant_deposits.exchange_url"
",rtransaction_id"
",refund_amount_val"
",refund_amount_frac"
- ",refund_fee_val"
- ",refund_fee_frac"
+ ",merchant_deposits.refund_fee_val"
+ ",merchant_deposits.refund_fee_frac"
",reason"
" FROM merchant_refunds"
- " WHERE merchant_pub=$1"
- " AND h_contract_terms=$2",
+ " JOIN merchant_deposits USING (merchant_pub,
coin_pub)"
+ " WHERE merchant_refunds.merchant_pub=$1"
+ " AND merchant_refunds.h_contract_terms=$2",
2),
GNUNET_PQ_make_prepare ("find_contract_terms_by_date_and_range_asc",
"SELECT"
@@ -3354,9 +3347,7 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
",merchant_deposits.exchange_proof"
" FROM merchant_transfers"
" JOIN merchant_deposits"
- " ON (merchant_deposits.h_contract_terms =
merchant_transfers.h_contract_terms"
- " AND"
- " merchant_deposits.coin_pub =
merchant_transfers.coin_pub)"
+ " USING (h_contract_terms,coin_pub)"
" WHERE wtid=$1",
1),
GNUNET_PQ_make_prepare ("find_proof_by_wtid",
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index 87b8c73..9e3dd22 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -199,14 +199,16 @@ static json_t *contract_terms_future;
*
* @param cls closure
* @param coin_pub public coin from which the refund comes from
+ * @param exchange_url URL of the exchange that issued the @a coin_pub
* @param rtransaction_id identificator of the refund
* @param reason human-readable explanation of the refund
- * @param refund_amount refund amount which is being taken from coin_pub
+ * @param refund_amount refund amount which is being taken from @a coin_pub
* @param refund_fee cost of this refund operation
*/
static void
refund_cb (void *cls,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const char *exchange_url,
uint64_t rtransaction_id,
const char *reason,
const struct TALER_Amount *refund_amount,
diff --git a/src/include/taler_merchant_service.h
b/src/include/taler_merchant_service.h
index ac7e427..ef616c1 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -298,16 +298,71 @@ TALER_MERCHANT_config_get_cancel (struct
TALER_MERCHANT_ConfigGetHandle *vgh);
struct TALER_MERCHANT_RefundLookupOperation;
+/**
+ * Detail about a refund lookup result.
+ */
+struct TALER_MERCHANT_RefundDetail
+{
+
+ /**
+ * Exchange response details. Full details are only included
+ * upon failure (HTTP status is not #MHD_HTTP_OK).
+ */
+ struct TALER_EXCHANGE_HttpResponse hr;
+
+ /**
+ * Coin this detail is about.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Refund transaction ID used.
+ */
+ uint64_t rtransaction_id;
+
+ /**
+ * Amount to be refunded for this coin.
+ */
+ struct TALER_Amount refund_amount;
+
+ /**
+ * Applicable refund transaction fee.
+ */
+ struct TALER_Amount refund_fee;
+
+ /**
+ * Public key of the exchange affirming the refund,
+ * only valid if the @e hr http_status is #MHD_HTTP_OK.
+ */
+ struct TALER_ExchangePublicKeyP exchange_pub;
+
+ /**
+ * Signature of the exchange affirming the refund,
+ * only valid if the @e hr http_status is #MHD_HTTP_OK.
+ */
+ struct TALER_ExchangeSignatureP exchange_sig;
+
+};
+
+
/**
* Callback to process a GET /refund request
*
* @param cls closure
* @param hr HTTP response details
+ * @param h_contract_terms hash of the contract terms to which the refund is
applied
+ * @param merchant_pub public key of the merchant
+ * @param num_details length of the @a details array
+ * @param details details about the refund processing
*/
typedef void
(*TALER_MERCHANT_RefundLookupCallback) (
void *cls,
- const struct TALER_MERCHANT_HttpResponse *hr);
+ const struct TALER_MERCHANT_HttpResponse *hr,
+ const struct GNUNET_HashCode *h_contract_terms,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ unsigned int num_details,
+ const struct TALER_MERCHANT_RefundDetail *details);
/**
diff --git a/src/include/taler_merchantdb_plugin.h
b/src/include/taler_merchantdb_plugin.h
index cc2e6bd..3ac4339 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -138,15 +138,17 @@ typedef void
*
* @param cls closure
* @param coin_pub public coin from which the refund comes from
+ * @param exchange_url URL of the exchange that issued @a coin_pub
* @param rtransaction_id identificator of the refund
* @param reason human-readable explanation of the refund
- * @param refund_amount refund amount which is being taken from coin_pub
+ * @param refund_amount refund amount which is being taken from @a coin_pub
* @param refund_fee cost of this refund operation
*/
typedef void
(*TALER_MERCHANTDB_RefundCallback)(
void *cls,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const char *exchange_url,
uint64_t rtransaction_id,
const char *reason,
const struct TALER_Amount *refund_amount,
diff --git a/src/lib/merchant_api_common.c b/src/lib/merchant_api_common.c
index 3317595..cb8de65 100644
--- a/src/lib/merchant_api_common.c
+++ b/src/lib/merchant_api_common.c
@@ -57,13 +57,13 @@ TALER_MERCHANT_parse_error_details_ (const json_t *response,
hr->ec = TALER_JSON_get_error_code (response);
hr->hint = TALER_JSON_get_error_hint (response);
- /* handle 'exchange-http-status' */
+ /* handle 'exchange_http_status' */
jc = json_object_get (response,
- "exchange-http-status");
+ "exchange_http_status");
/* The caller already knows that the JSON represents an error,
so we are dealing with a missing error code here. */
if (NULL == jc)
- return; /* no need to bother with exchange-code/hint if we had no status */
+ return; /* no need to bother with exchange_code/hint if we had no status */
if (! json_is_integer (jc))
{
GNUNET_break_op (0);
@@ -71,9 +71,9 @@ TALER_MERCHANT_parse_error_details_ (const json_t *response,
}
hr->exchange_http_status = (unsigned int) json_integer_value (jc);
- /* handle 'exchange-reply' */
+ /* handle 'exchange_reply' */
jc = json_object_get (response,
- "exchange-reply");
+ "exchange_reply");
if (! json_is_object (jc))
{
GNUNET_break_op (0);
@@ -83,9 +83,9 @@ TALER_MERCHANT_parse_error_details_ (const json_t *response,
hr->exchange_reply = jc;
}
- /* handle 'exchange-code' */
+ /* handle 'exchange_code' */
jc = json_object_get (response,
- "exchange-code");
+ "exchange_code");
/* The caller already knows that the JSON represents an error,
so we are dealing with a missing error code here. */
if (NULL == jc)
diff --git a/src/lib/merchant_api_pay.c b/src/lib/merchant_api_pay.c
index 97a0b44..2bbc19c 100644
--- a/src/lib/merchant_api_pay.c
+++ b/src/lib/merchant_api_pay.c
@@ -298,7 +298,7 @@ check_conflict (struct TALER_MERCHANT_Pay *ph,
json_t *ereply;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("exchange-reply", &ereply),
+ GNUNET_JSON_spec_json ("exchange_reply", &ereply),
GNUNET_JSON_spec_fixed_auto ("coin_pub", &coin_pub),
GNUNET_JSON_spec_end ()
};
diff --git a/src/lib/merchant_api_refund.c b/src/lib/merchant_api_refund.c
index a1a5715..c056c78 100644
--- a/src/lib/merchant_api_refund.c
+++ b/src/lib/merchant_api_refund.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015, 2016, 2017, 2019 Taler Systems SA
+ Copyright (C) 2014-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free
Software
@@ -32,6 +32,9 @@
#include <taler/taler_curl_lib.h>
+/**
+ * Handle to the refund lookup operation.
+ */
struct TALER_MERCHANT_RefundLookupOperation
{
/**
@@ -81,6 +84,180 @@ TALER_MERCHANT_refund_lookup_cancel (
}
+/**
+ * Check that the @a reply to the @a rlo is valid
+ *
+ * @param rlo lookup operation
+ * @param reply JSON reply to verify
+ * @return #TALER_EC_NONE if @a reply is well-formed
+ */
+static enum TALER_ErrorCode
+check_refund_result (struct TALER_MERCHANT_RefundLookupOperation *rlo,
+ const json_t *reply)
+{
+ json_t *refunds;
+ unsigned int num_refunds;
+ struct GNUNET_HashCode h_contract_terms;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("refunds", &refunds),
+ GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &h_contract_terms),
+ GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (reply,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return TALER_EC_REFUND_LOOKUP_INVALID_RESPONSE;
+ }
+ num_refunds = json_array_size (refunds);
+ {
+ struct TALER_MERCHANT_RefundDetail rds[GNUNET_NZL (num_refunds)];
+ json_t *ercp[GNUNET_NZL (num_refunds)];
+
+ memset (rds,
+ 0,
+ sizeof (rds));
+ memset (ercp,
+ 0,
+ sizeof (ercp));
+ for (unsigned int i = 0; i<num_refunds; i++)
+ {
+ struct TALER_MERCHANT_RefundDetail *rd = &rds[i];
+ json_t *refund = json_array_get (refunds, i);
+ uint32_t hs;
+ struct GNUNET_JSON_Specification spec_detail[] = {
+ GNUNET_JSON_spec_fixed_auto ("coin_pub",
+ &rd->coin_pub),
+ TALER_JSON_spec_amount ("refund_amount",
+ &rd->refund_amount),
+ TALER_JSON_spec_amount ("refund_fee",
+ &rd->refund_fee),
+ GNUNET_JSON_spec_uint32 ("exchange_http_status",
+ &hs),
+ GNUNET_JSON_spec_uint64 ("rtransaction_id",
+ &rd->rtransaction_id),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (refund,
+ spec_detail,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ return TALER_EC_REFUND_LOOKUP_INVALID_RESPONSE;
+ }
+ rd->hr.http_status = (unsigned int) hs;
+ }
+
+ for (unsigned int i = 0; i<num_refunds; i++)
+ {
+ struct TALER_MERCHANT_RefundDetail *rd = &rds[i];
+ json_t *refund = json_array_get (refunds, i);
+
+ if (MHD_HTTP_OK == rd->hr.http_status)
+ {
+ struct GNUNET_JSON_Specification spec_detail[] = {
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &rd->exchange_pub),
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &rd->exchange_sig),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (refund,
+ spec_detail,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ for (unsigned int j = 0; j<i; j++)
+ if (NULL != ercp[j])
+ json_decref (ercp[j]);
+ GNUNET_JSON_parse_free (spec);
+ return TALER_EC_REFUND_LOOKUP_INVALID_RESPONSE;
+ }
+ /* verify exchange sig (we should not trust the merchant) */
+ {
+ struct TALER_RefundConfirmationPS depconf = {
+ .purpose.size = htonl (sizeof (depconf)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND),
+ .h_contract_terms = h_contract_terms,
+ .coin_pub = rd->coin_pub,
+ .merchant = merchant_pub,
+ .rtransaction_id = GNUNET_htonll (rd->rtransaction_id)
+ };
+
+ TALER_amount_hton (&depconf.refund_amount,
+ &rd->refund_amount);
+ TALER_amount_hton (&depconf.refund_fee,
+ &rd->refund_fee);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (
+ TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND,
+ &depconf,
+ &rd->exchange_sig.eddsa_signature,
+ &rd->exchange_pub.eddsa_pub))
+ {
+ /* While the *exchange* signature is invalid, we do blame the
+ merchant here, because the merchant should have checked and
+ sent us an error code (with exchange HTTP status code 0) instead
+ of claiming that the exchange yielded a good response. *///
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ return TALER_EC_REFUND_LOOKUP_INVALID_RESPONSE;
+ }
+ }
+ }
+ else
+ {
+ uint32_t ec;
+ struct GNUNET_JSON_Specification spec_detail[] = {
+ GNUNET_JSON_spec_uint32 ("exchange_code",
+ &ec),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (refund,
+ spec_detail,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ rd->hr.ec = TALER_EC_INVALID;
+ }
+ ercp[i] = json_incref (json_object_get (refund,
+ "exchange_reply"));
+ rd->hr.reply = ercp[i];
+ }
+ }
+ {
+ struct TALER_MERCHANT_HttpResponse hr = {
+ .http_status = MHD_HTTP_OK,
+ .reply = reply
+ };
+ rlo->cb (rlo->cb_cls,
+ &hr,
+ &h_contract_terms,
+ &merchant_pub,
+ num_refunds,
+ rds);
+ }
+ for (unsigned int j = 0; j<num_refunds; j++)
+ if (NULL != ercp[j])
+ json_decref (ercp[j]);
+ }
+ GNUNET_JSON_parse_free (spec);
+ return TALER_EC_NONE;
+}
+
+
/**
* Process GET /refund response
*
@@ -109,7 +286,15 @@ handle_refund_lookup_finished (void *cls,
hr.ec = TALER_EC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
- /* nothing to do, all good! */
+ if (TALER_EC_NONE ==
+ (hr.ec = check_refund_result (rlo,
+ json)))
+ {
+ TALER_MERCHANT_refund_lookup_cancel (rlo);
+ return;
+ }
+ /* failure, report! */
+ hr.http_status = 0;
break;
case MHD_HTTP_NOT_FOUND:
hr.ec = TALER_JSON_get_error_code (json);
@@ -122,7 +307,11 @@ handle_refund_lookup_finished (void *cls,
break;
}
rlo->cb (rlo->cb_cls,
- &hr);
+ &hr,
+ NULL,
+ NULL,
+ 0,
+ NULL);
TALER_MERCHANT_refund_lookup_cancel (rlo);
}
diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c
index 5f366f0..f16cf5f 100644
--- a/src/lib/test_merchant_api.c
+++ b/src/lib/test_merchant_api.c
@@ -99,6 +99,11 @@ static struct GNUNET_CONTAINER_MultiHashMap
*interned_strings;
*/
#define USER_ACCOUNT_NAME "62"
+/**
+ * Account number of some other user.
+ */
+#define USER_ACCOUNT_NAME2 "63"
+
/**
* Account number used by the merchant
*/
@@ -232,7 +237,8 @@ run (void *cls,
* Make a reserve exist,
* according to the previous
* transfer.
- */cmd_exec_wirewatch ("wirewatch-1"),
+ *///
+ cmd_exec_wirewatch ("wirewatch-1"),
TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-2",
"EUR:10.02",
payer_payto,
@@ -445,24 +451,70 @@ run (void *cls,
};
struct TALER_TESTING_Command refund[] = {
- TALER_TESTING_cmd_refund_increase ("refund-increase-1",
+ cmd_transfer_to_exchange ("create-reserve-1r",
+ "EUR:10.02"),
+ /**
+ * Make a reserve exist, according to the previous transfer.
+ *///
+ cmd_exec_wirewatch ("wirewatch-1r"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-2r",
+ "EUR:10.02",
+ payer_payto,
+ exchange_payto,
+ "create-reserve-1r"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1r",
+ "create-reserve-1r",
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2r",
+ "create-reserve-1r",
+ "EUR:5",
+ MHD_HTTP_OK),
+ /**
+ * Check the reserve is depleted.
+ */
+ TALER_TESTING_cmd_status ("withdraw-status-1r",
+ "create-reserve-1r",
+ "EUR:0",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_proposal ("create-proposal-1r",
+ merchant_url,
+ MHD_HTTP_OK,
+ "{\"max_fee\":\"EUR:0.5\",\
+ \"order_id\":\"1r\",\
+ \"refund_deadline\": {\"t_ms\": 0},\
+ \"pay_deadline\": {\"t_ms\": \"never\" },\
+ \"amount\":\"EUR:5.0\",\
+ \"summary\": \"merchant-lib testcase\",\
+ \"fulfillment_url\": \"https://example.com/\",\
+ \"products\": [ {\"description\":\"ice cream\",\
+ \"value\":\"{EUR:5}\"} ] }"),
+ TALER_TESTING_cmd_pay ("pay-for-refund-1r",
+ merchant_url,
+ MHD_HTTP_OK,
+ "create-proposal-1r",
+ "withdraw-coin-1r",
+ "EUR:5",
+ "EUR:4.99",
+ "EUR:0.01"),
+ TALER_TESTING_cmd_refund_increase ("refund-increase-1r",
merchant_url,
"refund test",
- "1", /* order ID */
+ "1r", /* order ID */
"EUR:0.1",
"EUR:0.01",
MHD_HTTP_OK),
/* Ordinary refund. */
- TALER_TESTING_cmd_refund_lookup ("refund-lookup-1",
+ TALER_TESTING_cmd_refund_lookup ("refund-lookup-1r",
merchant_url,
- "refund-increase-1",
- "deposit-simple",
- "1",
+ "refund-increase-1r",
+ "pay-for-refund-1r",
+ "1r",
MHD_HTTP_OK),
/* Trying to pick up refund from non existent proposal. */
TALER_TESTING_cmd_refund_lookup ("refund-lookup-non-existent",
merchant_url,
- "refund-increase-1",
+ "refund-increase-1r",
"deposit-simple",
"non-existend-id",
MHD_HTTP_NOT_FOUND),
@@ -522,7 +574,7 @@ run (void *cls,
"{\"max_fee\":\"EUR:0.5\",\
\"order_id\":\"unincreased-proposal\",\
\"refund_deadline\":{\"t_ms\":0},\
- \"pay_deadline\":{\"t_ms\":9999999999999},\
+ \"pay_deadline\":{\"t_ms\":\"never\"},\
\"amount\":\"EUR:5.0\",\
\"summary\": \"merchant-lib testcase\",\
\"fulfillment_url\": \"https://example.com/\",\
@@ -538,19 +590,19 @@ run (void *cls,
"EUR:0.01"),
CMD_EXEC_AGGREGATOR ("run-aggregator-unincreased-refund"),
TALER_TESTING_cmd_check_bank_transfer (
- "check_bank_transfer-unincreased-refund",
+ "check_bank_transfer-paid-unincreased-refund",
EXCHANGE_URL,
- "EUR:4.98",
+ "EUR:9.88", /* '4.98 from above', plus 4.99 from 'pay-for-refund-1r'
+ and MINUS 0.1 PLUS 0.01 (deposit fee) from
'refund-increase-1r' */
exchange_payto,
merchant_payto),
- /* Actually try to pick up the refund from the
- * "unincreased proposal". */
+ /* Actually try to pick up the refund from the "unincreased proposal". */
TALER_TESTING_cmd_refund_lookup_with_amount ("refund-lookup-unincreased",
merchant_url,
NULL,
"pay-unincreased-proposal",
"unincreased-proposal",
- MHD_HTTP_OK,
+ MHD_HTTP_NOT_FOUND,
/* If a lookup is attempted
* on an unincreased
* proposal, the backend will
@@ -802,7 +854,7 @@ run (void *cls,
\"value\":\"{EUR:10}\"} ] }"),
TALER_TESTING_cmd_pay ("pay-fail-partial-double-11-good",
merchant_url,
- MHD_HTTP_BAD_REQUEST,
+ MHD_HTTP_NOT_ACCEPTABLE,
"create-proposal-11",
"withdraw-coin-11a",
"EUR:5",
@@ -865,7 +917,7 @@ run (void *cls,
merchant_url,
MHD_HTTP_OK,
GNUNET_TIME_UNIT_ZERO_ABS,
- 4, /* Expected number of records
*/
+ 5, /* Expected number of records
*/
-100), /* Delta */
/**
* End the suite. Fixme: better to have a label for this
diff --git a/src/lib/test_merchant_api_twisted.c
b/src/lib/test_merchant_api_twisted.c
index ccd868b..e49e238 100644
--- a/src/lib/test_merchant_api_twisted.c
+++ b/src/lib/test_merchant_api_twisted.c
@@ -152,16 +152,14 @@ CMD_EXEC_WIREWATCH (const char *label)
/**
- * Execute the taler-exchange-aggregator command with
+ * Execute the taler-exchange-aggregator, closer and transfer commands with
* our configuration file.
*
* @param label label to use for the command.
*/
-static struct TALER_TESTING_Command
-CMD_EXEC_AGGREGATOR (const char *label)
-{
- return TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE);
-}
+#define CMD_EXEC_AGGREGATOR(label) \
+ TALER_TESTING_cmd_exec_aggregator (label "-aggregator", CONFIG_FILE), \
+ TALER_TESTING_cmd_exec_transfer (label "-transfer", CONFIG_FILE)
/**
@@ -173,7 +171,8 @@ CMD_EXEC_AGGREGATOR (const char *label)
* @param url exchange_url
*/
static struct TALER_TESTING_Command
-CMD_TRANSFER_TO_EXCHANGE (const char *label, const char *amount)
+CMD_TRANSFER_TO_EXCHANGE (const char *label,
+ const char *amount)
{
return TALER_TESTING_cmd_admin_add_incoming (label,
amount,
@@ -192,10 +191,8 @@ static void
run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
-
/**** Triggering #5719 ****/
struct TALER_TESTING_Command bug_5719[] = {
-
/**
* Move money to the exchange's bank account.
*/
@@ -206,30 +203,26 @@ run (void *cls,
* transfer.
*/
CMD_EXEC_WIREWATCH ("5719-wirewatch"),
- TALER_TESTING_cmd_check_bank_admin_transfer
- ("5719-check-transfer",
- "EUR:1.01",
- payer_payto,
- exchange_payto,
- "5719-create-reserve"),
-
+ TALER_TESTING_cmd_check_bank_admin_transfer ("5719-check-transfer",
+ "EUR:1.01",
+ payer_payto,
+ exchange_payto,
+ "5719-create-reserve"),
TALER_TESTING_cmd_withdraw_amount ("5719-withdraw",
"5719-create-reserve",
"EUR:1",
MHD_HTTP_OK),
-
TALER_TESTING_cmd_status ("5719-reserve-status",
"5719-create-reserve",
"EUR:0",
MHD_HTTP_OK),
- TALER_TESTING_cmd_proposal
- ("5719-create-proposal",
- twister_merchant_url,
- MHD_HTTP_OK,
- "{\"max_fee\":\"EUR:0.5\",\
+ TALER_TESTING_cmd_proposal ("5719-create-proposal",
+ twister_merchant_url,
+ MHD_HTTP_OK,
+ "{\"max_fee\":\"EUR:0.5\",\
\"order_id\":\"5719TRIGGER\",\
\"refund_deadline\":{\"t_ms\":0},\
- \"pay_deadline\":{\"t_ms\":99999999999},\
+ \"pay_deadline\":{\"t_ms\":\"never\"},\
\"fulfillment_url\": \"https://example.com/\",\
\"amount\":\"EUR:1.0\",\
\"summary\": \"merchant-lib testcase\",\
@@ -242,13 +235,12 @@ run (void *cls,
* not manage to pass the callback a valid JSON and will
* instead pass a NULL pointer. This should trigger the path
* mentioned in the bug report #5719.
- */TALER_TESTING_cmd_malform_response
- ("5719-malform-exchange-resp",
- PROXY_EXCHANGE_CONFIG_FILE),
-
+ *///
+ TALER_TESTING_cmd_malform_response ("5719-malform-exchange-resp",
+ PROXY_EXCHANGE_CONFIG_FILE),
TALER_TESTING_cmd_pay ("5719-deposit",
twister_merchant_url,
- MHD_HTTP_SERVICE_UNAVAILABLE,
+ MHD_HTTP_FAILED_DEPENDENCY,
"5719-create-proposal",
"5719-withdraw",
"EUR:1",
@@ -268,7 +260,7 @@ run (void *cls,
"{\"max_fee\":\"EUR:0.5\",\
\"order_id\":\"fail-check-payment-1\",\
\"refund_deadline\":{\"t_ms\":0},\
- \"pay_deadline\":{\"t_ms\":99999999999},\
+ \"pay_deadline\":{\"t_ms\":\"never\"},\
\"fulfillment_url\": \"https://example.com/\",\
\"amount\":\"EUR:2.0\",\
\"summary\": \"merchant-lib testcase\",\
@@ -276,41 +268,31 @@ run (void *cls,
\"value\":\"EUR:3\"} ] }"),
/* Need any response code != 200. */
- TALER_TESTING_cmd_hack_response_code
- ("non-200-response-code",
- PROXY_MERCHANT_CONFIG_FILE,
- MHD_HTTP_MULTIPLE_CHOICES),
-
- TALER_TESTING_cmd_check_payment
- ("check-payment-fail",
- twister_merchant_url,
- MHD_HTTP_MULTIPLE_CHOICES,
- "proposal-for-check-payment",
- GNUNET_SYSERR), // any response != 200 gives "syserr"
-
+ TALER_TESTING_cmd_hack_response_code ("non-200-response-code",
+ PROXY_MERCHANT_CONFIG_FILE,
+ MHD_HTTP_MULTIPLE_CHOICES),
+ TALER_TESTING_cmd_check_payment ("check-payment-fail",
+ twister_merchant_url,
+ MHD_HTTP_MULTIPLE_CHOICES,
+ "proposal-for-check-payment",
+ GNUNET_SYSERR), // any response != 200
gives "syserr"
TALER_TESTING_cmd_delete_object ("hack-check-payment-0",
PROXY_MERCHANT_CONFIG_FILE,
"taler_pay_uri"),
- TALER_TESTING_cmd_check_payment
- ("check-payment-fail-invalid",
- twister_merchant_url,
- 0,
- "proposal-for-check-payment",
- GNUNET_SYSERR),
-
- TALER_TESTING_cmd_modify_object_dl
- ("paid-true-for-unpaid",
- PROXY_MERCHANT_CONFIG_FILE,
- "paid",
- "true"),
-
- TALER_TESTING_cmd_check_payment
- ("check-payment-fail-invalid-0",
- twister_merchant_url,
- 0,
- "proposal-for-check-payment",
- GNUNET_SYSERR),
-
+ TALER_TESTING_cmd_check_payment ("check-payment-fail-invalid",
+ twister_merchant_url,
+ 0,
+ "proposal-for-check-payment",
+ GNUNET_SYSERR),
+ TALER_TESTING_cmd_modify_object_dl ("paid-true-for-unpaid",
+ PROXY_MERCHANT_CONFIG_FILE,
+ "paid",
+ "true"),
+ TALER_TESTING_cmd_check_payment ("check-payment-fail-invalid-0",
+ twister_merchant_url,
+ 0,
+ "proposal-for-check-payment",
+ GNUNET_SYSERR),
TALER_TESTING_cmd_end ()
};
@@ -321,49 +303,41 @@ run (void *cls,
* Make the merchant return a 400 Bad Request response
* due to uploaded body malformation.
*/
- TALER_TESTING_cmd_malform_request
- ("malform-order",
- PROXY_MERCHANT_CONFIG_FILE),
-
- TALER_TESTING_cmd_proposal
- ("create-proposal-0",
- twister_merchant_url,
- MHD_HTTP_BAD_REQUEST,
- /* giving a valid JSON to not make it fail before
- * data reaches the merchant. */
- "{\"not\": \"used\"}"),
-
- TALER_TESTING_cmd_hack_response_code
- ("proposal-500",
- PROXY_MERCHANT_CONFIG_FILE,
- MHD_HTTP_INTERNAL_SERVER_ERROR),
-
- TALER_TESTING_cmd_proposal
- ("create-proposal-1",
- twister_merchant_url,
- /* This status code == 0 is gotten via a 500 Internal Server
- * Error handed to the library. */
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- /* giving a valid JSON to not make it fail before
- * data reaches the merchant. */
- "{\"not\": \"used\"}"),
+ TALER_TESTING_cmd_malform_request ("malform-order",
+ PROXY_MERCHANT_CONFIG_FILE),
+ TALER_TESTING_cmd_proposal ("create-proposal-0",
+ twister_merchant_url,
+ MHD_HTTP_BAD_REQUEST,
+ /* giving a valid JSON to not make it fail
before
+ * data reaches the merchant. */
+ "{\"not\": \"used\"}"),
+ TALER_TESTING_cmd_hack_response_code ("proposal-500",
+ PROXY_MERCHANT_CONFIG_FILE,
+ MHD_HTTP_INTERNAL_SERVER_ERROR),
+ TALER_TESTING_cmd_proposal ("create-proposal-1",
+ twister_merchant_url,
+ /* This status code == 0 is gotten via a 500
Internal Server
+ * Error handed to the library. */
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ /* giving a valid JSON to not make it fail
before
+ * data reaches the merchant. */
+ "{\"not\": \"used\"}"),
/**
* Cause the PUT /proposal callback to be called
* with a response code == 0. We achieve this by malforming
* the response body.
- */TALER_TESTING_cmd_malform_response
- ("malform-proposal",
- PROXY_MERCHANT_CONFIG_FILE),
-
- TALER_TESTING_cmd_proposal
- ("create-proposal-2",
- twister_merchant_url,
- 0,
- "{\"max_fee\":\"EUR:0.5\",\
+ *///
+ TALER_TESTING_cmd_malform_response ("malform-proposal",
+ PROXY_MERCHANT_CONFIG_FILE),
+
+ TALER_TESTING_cmd_proposal ("create-proposal-2",
+ twister_merchant_url,
+ 0,
+ "{\"max_fee\":\"EUR:0.5\",\
\"order_id\":\"1\",\
\"refund_deadline\":{\"t_ms\":0},\
- \"pay_deadline\":{\"t_ms\":99999999999},\
+ \"pay_deadline\":{\"t_ms\":\"never\"},\
\"amount\":\"EUR:5.0\",\
\"summary\": \"merchant-lib testcase\",\
\"products\": [ {\"description\":\"ice cream\",\
@@ -375,15 +349,14 @@ run (void *cls,
TALER_TESTING_cmd_delete_object ("remove-order-id",
PROXY_MERCHANT_CONFIG_FILE,
"order_id"),
- TALER_TESTING_cmd_proposal
- ("create-proposal-3",
- twister_merchant_url,
- 0,
- "{\"max_fee\":\"EUR:0.5\",\
+ TALER_TESTING_cmd_proposal ("create-proposal-3",
+ twister_merchant_url,
+ 0,
+ "{\"max_fee\":\"EUR:0.5\",\
\"fulfillment_url\": \"https://example.com/\",\
\"order_id\":\"2\",\
\"refund_deadline\":{\"t_ms\":0},\
- \"pay_deadline\":{\"t_ms\":99999999999},\
+ \"pay_deadline\":{\"t_ms\":\"never\"},\
\"amount\":\"EUR:5.0\",\
\"summary\": \"merchant-lib testcase\",\
\"products\": [ {\"description\":\"ice cream\",\
@@ -392,11 +365,10 @@ run (void *cls,
* Cause a 404 Not Found response code,
* due to a non existing merchant instance.
*/
- TALER_TESTING_cmd_proposal
- ("create-proposal-4",
- twister_merchant_url_instance_nonexistent,
- MHD_HTTP_NOT_FOUND,
- "{\"amount\":\"EUR:5\",\
+ TALER_TESTING_cmd_proposal ("create-proposal-4",
+ twister_merchant_url_instance_nonexistent,
+ MHD_HTTP_NOT_FOUND,
+ "{\"amount\":\"EUR:5\",\
\"fulfillment_url\": \"https://example.com/\",\
\"summary\": \"merchant-lib testcase\"}"),
@@ -426,14 +398,13 @@ run (void *cls,
/* First step is to create a _valid_ proposal, so that
* we can lookup for it later. */
- TALER_TESTING_cmd_proposal
- ("create-proposal-5",
- twister_merchant_url,
- MHD_HTTP_OK,
- "{\"max_fee\":\"EUR:0.5\",\
+ TALER_TESTING_cmd_proposal ("create-proposal-5",
+ twister_merchant_url,
+ MHD_HTTP_OK,
+ "{\"max_fee\":\"EUR:0.5\",\
\"order_id\":\"5\",\
\"refund_deadline\":{\"t_ms\":0},\
- \"pay_deadline\":{\"t_ms\":99999999999},\
+ \"pay_deadline\":{\"t_ms\":\"never\"},\
\"amount\":\"EUR:5.0\",\
\"fulfillment_url\": \"https://example.com/\",\
\"summary\": \"merchant-lib testcase\",\
@@ -464,14 +435,13 @@ run (void *cls,
* code, that is then expected to trigger some
* emergency behaviour, like setting the response
* code to zero before calling the callback.
- */TALER_TESTING_cmd_hack_response_code
- ("twist-history",
- PROXY_MERCHANT_CONFIG_FILE,
- MHD_HTTP_GONE),
-
+ *///
+ TALER_TESTING_cmd_hack_response_code ("twist-history",
+ PROXY_MERCHANT_CONFIG_FILE,
+ MHD_HTTP_GONE),
TALER_TESTING_cmd_history ("history-0",
twister_merchant_url,
- 0,
+ MHD_HTTP_GONE,
GNUNET_TIME_UNIT_ZERO_ABS,
1, // nresult
10, // start
@@ -480,9 +450,9 @@ run (void *cls,
* Making the returned response malformed, in order
* to make the JSON downloader+parser fail and call
* the lib passing a response code as zero.
- */TALER_TESTING_cmd_malform_response
- ("malform-history",
- PROXY_MERCHANT_CONFIG_FILE),
+ *///
+ TALER_TESTING_cmd_malform_response ("malform-history",
+ PROXY_MERCHANT_CONFIG_FILE),
TALER_TESTING_cmd_history ("history-1",
twister_merchant_url,
@@ -500,64 +470,49 @@ run (void *cls,
* This block tests whether a refund_deadline and/or
* wire_transfer_deadline very far in the future do NOT
* result in any wire transfer from the aggregator (#5366).
- */struct TALER_TESTING_Command unaggregation[] = {
-
- CMD_TRANSFER_TO_EXCHANGE
- ("create-reserve-unaggregation",
- "EUR:5.01"),
-
- CMD_EXEC_WIREWATCH
- ("wirewatch-unaggregation"),
- TALER_TESTING_cmd_check_bank_admin_transfer
- ("check_bank_transfer-unaggregation",
+ *///
+ struct TALER_TESTING_Command unaggregation[] = {
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-unaggregation",
+ "EUR:5.01"),
+ CMD_EXEC_WIREWATCH ("wirewatch-unaggregation"),
+ TALER_TESTING_cmd_check_bank_admin_transfer (
+ "check_bank_transfer-unaggregation",
"EUR:5.01",
payer_payto,
exchange_payto,
"create-reserve-unaggregation"),
-
- TALER_TESTING_cmd_check_bank_empty
- ("check_bank_unaggregated-a"),
-
- TALER_TESTING_cmd_withdraw_amount
- ("withdraw-coin-unaggregation",
- "create-reserve-unaggregation",
- "EUR:5",
- MHD_HTTP_OK),
-
- TALER_TESTING_cmd_proposal
- ("create-proposal-unaggregation",
- /* Need a fresh instance in order to associate this
- * proposal with a fresh h_wire; this way, this proposal
- * won't get hooked by the aggregator gathering same-h_wire'd
- * transactions. */
- twister_merchant_url_instance_tor,
- MHD_HTTP_OK,
- "{\"max_fee\":\"EUR:0.5\",\
+ TALER_TESTING_cmd_check_bank_empty ("check_bank_unaggregated-a"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregation",
+ "create-reserve-unaggregation",
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_proposal ("create-proposal-unaggregation",
+ /* Need a fresh instance in order to associate
this
+ * proposal with a fresh h_wire; this way,
this proposal
+ * won't get hooked by the aggregator
gathering same-h_wire'd
+ * transactions. */
+ twister_merchant_url_instance_tor,
+ MHD_HTTP_OK,
+ "{\"max_fee\":\"EUR:0.5\",\
\"refund_deadline\":{\"t_ms\":2000},\
- \"pay_deadline\":{\"t_ms\":1000},\
+ \"pay_deadline\":{\"t_ms\":2366841500000},\
\"wire_transfer_deadline\":{\"t_ms\":2366841600000},\
\"amount\":\"EUR:0.5\",\
\"summary\": \"unaggregated product\",\
\"fulfillment_url\": \"https://example.com/\",\
\"products\": [ {\"description\":\"unaggregated cream\",\
\"value\":\"{EUR:5}\"} ] }"),
-
- TALER_TESTING_cmd_pay
- ("pay-unaggregation",
- twister_merchant_url_instance_tor,
- MHD_HTTP_OK,
- "create-proposal-unaggregation",
- "withdraw-coin-unaggregation",
- "EUR:5", // amount + fee
- "EUR:4.99", // amount - fee
- "EUR:0.01"), // refund fee
-
- CMD_EXEC_AGGREGATOR
- ("aggregation-attempt"),
-
+ TALER_TESTING_cmd_pay ("pay-unaggregation",
+ twister_merchant_url_instance_tor,
+ MHD_HTTP_OK,
+ "create-proposal-unaggregation",
+ "withdraw-coin-unaggregation",
+ "EUR:5", // amount + fee
+ "EUR:4.99", // amount - fee
+ "EUR:0.01"), // refund fee
+ CMD_EXEC_AGGREGATOR ("aggregation-attempt"),
/* Make sure NO aggregation took place. */
- TALER_TESTING_cmd_check_bank_empty
- ("check_bank_unaggregated-b"),
+ TALER_TESTING_cmd_check_bank_empty ("check_bank_unaggregated-b"),
TALER_TESTING_cmd_end ()
};
@@ -567,30 +522,26 @@ run (void *cls,
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-5383",
"EUR:2.02"),
CMD_EXEC_WIREWATCH ("wirewatch-5383"),
- TALER_TESTING_cmd_check_bank_admin_transfer
- ("check_bank_transfer-5383",
- "EUR:2.02",
- payer_payto,
- exchange_payto,
- "create-reserve-5383"),
- TALER_TESTING_cmd_withdraw_amount
- ("withdraw-coin-5383a",
- "create-reserve-5383",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_withdraw_amount
- ("withdraw-coin-5383b",
- "create-reserve-5383",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_proposal
- ("create-proposal-5383",
- twister_merchant_url,
- MHD_HTTP_OK,
- "{\"max_fee\":\"EUR:0.5\",\
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-5383",
+ "EUR:2.02",
+ payer_payto,
+ exchange_payto,
+ "create-reserve-5383"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-5383a",
+ "create-reserve-5383",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-5383b",
+ "create-reserve-5383",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_proposal ("create-proposal-5383",
+ twister_merchant_url,
+ MHD_HTTP_OK,
+ "{\"max_fee\":\"EUR:0.5\",\
\"order_id\":\"5383\",\
\"refund_deadline\":{\"t_ms\":0},\
- \"pay_deadline\":{\"t_ms\":99999999999},\
+ \"pay_deadline\":{\"t_ms\":\"never\"},\
\"fulfillment_url\": \"https://example.com/\",\
\"amount\":\"EUR:2.0\",\
\"summary\": \"merchant-lib testcase\",\
@@ -606,27 +557,23 @@ run (void *cls,
"EUR:1.99", // no sense now
"EUR:0.01"), // no sense now
CMD_EXEC_AGGREGATOR ("run-aggregator-5383"),
- TALER_TESTING_cmd_check_bank_transfer
- ("check_aggregation_transfer-5383",
- twister_exchange_url,
- /* paid, 1.97 =
- brutto 2.00 -
- deposit fee 0.01 * 2 -
- wire fee 0.01
- */"EUR:1.97",
- exchange_payto,
- merchant_payto),
- TALER_TESTING_cmd_modify_object_dl
- ("hack-5383",
- PROXY_EXCHANGE_CONFIG_FILE,
- "total",
- "EUR:0.98"),
- TALER_TESTING_cmd_merchant_track_transfer
- ("track-5383",
- twister_merchant_url,
- MHD_HTTP_FAILED_DEPENDENCY,
- "check_aggregation_transfer-5383"),
-
+ TALER_TESTING_cmd_check_bank_transfer ("check_aggregation_transfer-5383",
+ twister_exchange_url,
+ /* paid, 1.97 =
+ brutto 2.00 -
+ deposit fee 0.01 * 2 -
+ wire fee 0.01
+ */"EUR:1.97",
+ exchange_payto,
+ merchant_payto),
+ TALER_TESTING_cmd_modify_object_dl ("hack-5383",
+ PROXY_EXCHANGE_CONFIG_FILE,
+ "total",
+ "EUR:0.98"),
+ TALER_TESTING_cmd_merchant_track_transfer ("track-5383",
+ twister_merchant_url,
+ MHD_HTTP_FAILED_DEPENDENCY,
+
"check_aggregation_transfer-5383"),
TALER_TESTING_cmd_end ()
};
@@ -645,17 +592,12 @@ run (void *cls,
* transfer.
*/
CMD_EXEC_WIREWATCH ("wirewatch-1"),
-
- TALER_TESTING_cmd_check_bank_admin_transfer
- ("check_bank_transfer-2",
- "EUR:2.02",
- payer_payto,
- exchange_payto,
- "create-reserve-1"),
-
- TALER_TESTING_cmd_check_bank_empty
- ("track_chunk_check_empty-a"),
-
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-2",
+ "EUR:2.02",
+ payer_payto,
+ exchange_payto,
+ "create-reserve-1"),
+ TALER_TESTING_cmd_check_bank_empty ("track_chunk_check_empty-a"),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
"create-reserve-1",
"EUR:1",
@@ -668,15 +610,13 @@ run (void *cls,
"create-reserve-1",
"EUR:0",
MHD_HTTP_OK),
-
- TALER_TESTING_cmd_proposal
- ("create-proposal-6",
- twister_merchant_url,
- MHD_HTTP_OK,
- "{\"max_fee\":\"EUR:0.5\",\
+ TALER_TESTING_cmd_proposal ("create-proposal-6",
+ twister_merchant_url,
+ MHD_HTTP_OK,
+ "{\"max_fee\":\"EUR:0.5\",\
\"order_id\":\"11\",\
\"refund_deadline\":{\"t_ms\":0},\
- \"pay_deadline\":{\"t_ms\":99999999999},\
+ \"pay_deadline\":{\"t_ms\":\"never\"},\
\"fulfillment_url\": \"https://example.com/\",\
\"amount\":\"EUR:2.0\",\
\"summary\": \"merchant-lib testcase\",\
@@ -688,7 +628,6 @@ run (void *cls,
MHD_HTTP_OK,
"create-proposal-6",
GNUNET_NO),
-
TALER_TESTING_cmd_pay ("deposit-simple",
twister_merchant_url,
MHD_HTTP_OK,
@@ -698,23 +637,22 @@ run (void *cls,
"EUR:2",
"EUR:1.99", // no sense now
"EUR:0.01"), // no sense now
-
TALER_TESTING_cmd_check_payment ("check-payment-2",
twister_merchant_url,
MHD_HTTP_OK,
"create-proposal-6",
GNUNET_YES),
CMD_EXEC_AGGREGATOR ("run-aggregator"),
- TALER_TESTING_cmd_check_bank_transfer
- ("check_bank_transfer-1",
- twister_exchange_url, /* has the 8888-port thing. */
- /* paid, 1.97 =
- brutto 2.00 -
- deposit fee 0.01 * 2 -
- wire fee 0.01
- */"EUR:1.97",
- exchange_payto,
- merchant_payto),
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-1",
+ twister_exchange_url, /* has the
8888-port thing. */
+ /* paid, 1.97 =
+ brutto 2.00 -
+ deposit fee 0.01 * 2 -
+ wire fee 0.01
+ *///
+ "EUR:1.97",
+ exchange_payto,
+ merchant_payto),
/**
* Fake total to include only one coin. Math: each 1-EUR
@@ -727,21 +665,18 @@ run (void *cls,
* In particular, they are supposed to modify the call
* to /track/transfer issued from the merchant to the
* exchange that happens _before_ the call to /track/transaction
- * issued below by the test case (to the merchant backend.)
*/TALER_TESTING_cmd_modify_object_dl
- ("hack-0",
- PROXY_EXCHANGE_CONFIG_FILE,
- "total",
- "EUR:0.98"),
- TALER_TESTING_cmd_delete_object
- ("hack-1",
- PROXY_EXCHANGE_CONFIG_FILE,
- "deposits.0"),
- TALER_TESTING_cmd_merchant_track_transaction
- ("track-transaction-1",
- twister_merchant_url,
- MHD_HTTP_FAILED_DEPENDENCY,
- "deposit-simple"),
-
+ * issued below by the test case (to the merchant backend.) *///
+ TALER_TESTING_cmd_modify_object_dl ("hack-0",
+ PROXY_EXCHANGE_CONFIG_FILE,
+ "total",
+ "EUR:0.98"),
+ TALER_TESTING_cmd_delete_object ("hack-1",
+ PROXY_EXCHANGE_CONFIG_FILE,
+ "deposits.0"),
+ TALER_TESTING_cmd_merchant_track_transaction ("track-transaction-1",
+ twister_merchant_url,
+ MHD_HTTP_FAILED_DEPENDENCY,
+ "deposit-simple"),
TALER_TESTING_cmd_end ()
};
@@ -756,42 +691,34 @@ run (void *cls,
"EUR:1.01"),
/**
- * Make a reserve exist, according to the previous
- * transfer.
+ * Make a reserve exist, according to the previous transfer.
*/
CMD_EXEC_WIREWATCH ("wirewatch-abort-1"),
-
- TALER_TESTING_cmd_check_bank_admin_transfer
- ("check_bank_transfer-abort-1",
- "EUR:1.01",
- payer_payto,
- exchange_payto,
- "create-reserve-abort-1"),
-
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-abort-1",
+ "EUR:1.01",
+ payer_payto,
+ exchange_payto,
+ "create-reserve-abort-1"),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-abort-1",
"create-reserve-abort-1",
"EUR:1",
MHD_HTTP_OK),
-
TALER_TESTING_cmd_status ("withdraw-status-abort-1",
"create-reserve-abort-1",
"EUR:0",
MHD_HTTP_OK),
-
- TALER_TESTING_cmd_proposal
- ("create-proposal-abort-1",
- twister_merchant_url,
- MHD_HTTP_OK,
- "{\"max_fee\":\"EUR:0.5\",\
+ TALER_TESTING_cmd_proposal ("create-proposal-abort-1",
+ twister_merchant_url,
+ MHD_HTTP_OK,
+ "{\"max_fee\":\"EUR:0.5\",\
\"order_id\":\"abort-one\",\
\"refund_deadline\":{\"t_ms\":0},\
- \"pay_deadline\":{\"t_ms\":99999999999},\
+ \"pay_deadline\":{\"t_ms\":\"never\"},\
\"fulfillment_url\": \"https://example.com/\",\
\"amount\":\"EUR:3.0\",\
\"summary\": \"merchant-lib testcase\",\
\"products\": [ {\"description\":\"ice cream\",\
\"value\":\"{EUR:3}\"} ] }"),
-
/* Will only pay _half_ the supposed price,
* so we'll then have the right to abort. */
TALER_TESTING_cmd_pay ("deposit-simple-for-abort",
@@ -802,94 +729,73 @@ run (void *cls,
"EUR:1",
"EUR:1.99", // no sense now
"EUR:0.01"), // no sense now
-
TALER_TESTING_cmd_delete_object ("hack-abort-1",
PROXY_MERCHANT_CONFIG_FILE,
"merchant_pub"),
-
TALER_TESTING_cmd_pay_abort ("pay-abort-1",
twister_merchant_url,
"deposit-simple-for-abort",
0),
-
- TALER_TESTING_cmd_delete_object
- ("hack-abort-2",
- PROXY_MERCHANT_CONFIG_FILE,
- "refund_permissions.0.rtransaction_id"),
-
+ TALER_TESTING_cmd_delete_object ("hack-abort-2",
+ PROXY_MERCHANT_CONFIG_FILE,
+ "refund_permissions.0.rtransaction_id"),
TALER_TESTING_cmd_pay_abort ("pay-abort-2",
twister_merchant_url,
"deposit-simple-for-abort",
0),
-
- TALER_TESTING_cmd_modify_object_dl
- ("hack-abort-3",
- PROXY_MERCHANT_CONFIG_FILE,
- "refund_permissions.0.coin_pub",
- /* dummy coin. */
- "8YX10E41ZWHX0X2RK4XFAXB2D3M05M1HNG14ZFZZB8M7SA4QCKCG"),
-
+ TALER_TESTING_cmd_modify_object_dl ("hack-abort-3",
+ PROXY_MERCHANT_CONFIG_FILE,
+ "refund_permissions.0.coin_pub",
+ /* dummy coin. */
+
"8YX10E41ZWHX0X2RK4XFAXB2D3M05M1HNG14ZFZZB8M7SA4QCKCG"),
TALER_TESTING_cmd_pay_abort ("pay-abort-3",
twister_merchant_url,
"deposit-simple-for-abort",
0),
-
- TALER_TESTING_cmd_flip_download
- ("hack-abort-4",
- PROXY_MERCHANT_CONFIG_FILE,
- "refund_permissions.0.merchant_sig"),
-
+ TALER_TESTING_cmd_flip_download ("hack-abort-4",
+ PROXY_MERCHANT_CONFIG_FILE,
+ "refund_permissions.0.merchant_sig"),
TALER_TESTING_cmd_pay_abort ("pay-abort-4",
twister_merchant_url,
"deposit-simple-for-abort",
0),
/* just malforming the response. */
- TALER_TESTING_cmd_malform_response
- ("malform-abortion",
- PROXY_MERCHANT_CONFIG_FILE),
-
+ TALER_TESTING_cmd_malform_response ("malform-abortion",
+ PROXY_MERCHANT_CONFIG_FILE),
TALER_TESTING_cmd_pay_abort ("pay-abort-5",
twister_merchant_url,
"deposit-simple-for-abort",
0),
-
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-double-spend",
"EUR:1.01"),
-
CMD_EXEC_WIREWATCH ("wirewatch-double-spend"),
-
- TALER_TESTING_cmd_proposal
- ("create-proposal-double-spend",
- twister_merchant_url,
- MHD_HTTP_OK,
- "{\"max_fee\":\"EUR:0.5\",\
+ TALER_TESTING_cmd_proposal ("create-proposal-double-spend",
+ twister_merchant_url,
+ MHD_HTTP_OK,
+ "{\"max_fee\":\"EUR:0.5\",\
\"order_id\":\"DS-1\",\
\"refund_deadline\":{\"t_ms\":0},\
- \"pay_deadline\":{\"t_ms\":99999999999},\
+ \"pay_deadline\":{\"t_ms\":\"never\"},\
\"fulfillment_url\": \"https://example.com/\",\
\"amount\":\"EUR:1.0\",\
\"summary\": \"merchant-lib testcase\",\
\"products\": [ {\"description\": \"will succeed\"}] }"),
-
- TALER_TESTING_cmd_proposal
- ("create-proposal-double-spend-1",
- twister_merchant_url,
- MHD_HTTP_OK,
- "{\"max_fee\":\"EUR:0.5\",\
+ TALER_TESTING_cmd_proposal ("create-proposal-double-spend-1",
+ twister_merchant_url,
+ MHD_HTTP_OK,
+ "{\"max_fee\":\"EUR:0.5\",\
\"order_id\":\"DS-2\",\
\"refund_deadline\":{\"t_ms\":0},\
- \"pay_deadline\":{\"t_ms\":99999999999},\
+ \"pay_deadline\":{\"t_ms\":\"never\"},\
\"fulfillment_url\": \"https://example.com/\",\
\"amount\":\"EUR:1.0\",\
\"summary\": \"merchant-lib testcase\",\
\"products\": [ {\"description\": \"will fail\"}] }"),
- TALER_TESTING_cmd_withdraw_amount
- ("withdraw-coin-double-spend",
- "create-reserve-double-spend",
- "EUR:1",
- MHD_HTTP_OK),
-
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-double-spend",
+ "create-reserve-double-spend",
+ "EUR:1",
+ MHD_HTTP_OK),
TALER_TESTING_cmd_pay ("deposit-simple-ok",
twister_merchant_url,
MHD_HTTP_OK,
@@ -898,57 +804,40 @@ run (void *cls,
"EUR:1",
"EUR:1.99", // no sense now
"EUR:0.01"), // no sense now
-
- TALER_TESTING_cmd_flip_download
- ("hack-coin-history",
- PROXY_MERCHANT_CONFIG_FILE,
- "history.0.coin_sig"),
-
+ TALER_TESTING_cmd_flip_download ("hack-coin-history",
+ PROXY_MERCHANT_CONFIG_FILE,
+ "history.0.coin_sig"),
/* Coin history check will fail,
* due to coin's bad signature. */
TALER_TESTING_cmd_pay ("deposit-simple-fail",
twister_merchant_url,
- 0,
+ MHD_HTTP_CONFLICT,
"create-proposal-double-spend-1",
"withdraw-coin-double-spend",
"EUR:1",
"EUR:1.99", // no sense now
"EUR:0.01"), // no sense now
-
/* max uint64 number: 9223372036854775807; try to overflow! */
-
TALER_TESTING_cmd_end ()
};
struct TALER_TESTING_Command commands[] = {
-
TALER_TESTING_cmd_batch ("check-payment",
check_payment),
-
TALER_TESTING_cmd_batch ("proposal",
proposal),
-
TALER_TESTING_cmd_batch ("history",
history),
-
TALER_TESTING_cmd_batch ("unaggregation",
unaggregation),
-
TALER_TESTING_cmd_batch ("track",
track),
-
TALER_TESTING_cmd_batch ("track-5383",
track_5383),
-
TALER_TESTING_cmd_batch ("pay",
pay),
-
TALER_TESTING_cmd_batch ("bug-5719",
bug_5719),
- /**
- * End the suite. Fixme: better to have a label for this
- * too, as it shows a "(null)" token on logs.
- */
TALER_TESTING_cmd_end ()
};
diff --git a/src/lib/testing_api_cmd_check_payment.c
b/src/lib/testing_api_cmd_check_payment.c
index f72ab92..8d59129 100644
--- a/src/lib/testing_api_cmd_check_payment.c
+++ b/src/lib/testing_api_cmd_check_payment.c
@@ -418,6 +418,7 @@ check_payment_conclude_cleanup (void *cls,
GNUNET_SCHEDULER_cancel (cps->task);
cps->task = NULL;
}
+ GNUNET_free (cps);
}
diff --git a/src/lib/testing_api_cmd_history.c
b/src/lib/testing_api_cmd_history.c
index b87a604..dabbf3c 100644
--- a/src/lib/testing_api_cmd_history.c
+++ b/src/lib/testing_api_cmd_history.c
@@ -109,10 +109,9 @@ history_cb (void *cls,
if (hs->http_status != hr->http_status)
TALER_TESTING_FAIL (hs->is);
- if (0 == hs->http_status)
+ if (MHD_HTTP_OK != hs->http_status)
{
- /* 0 was caused intentionally by the tests,
- * move on without further checking. */
+ /* move on without further checking. */
TALER_TESTING_interpreter_next (hs->is);
return;
}
@@ -277,15 +276,16 @@ cmd_history2 (const char *label,
hs->nrows = nrows;
hs->merchant_url = merchant_url;
hs->use_default_start = use_default_start;
-
- struct TALER_TESTING_Command cmd = {
- .cls = hs,
- .label = label,
- .run = &history_run,
- .cleanup = &history_cleanup
- };
-
- return cmd;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = hs,
+ .label = label,
+ .run = &history_run,
+ .cleanup = &history_cleanup
+ };
+
+ return cmd;
+ }
}
diff --git a/src/lib/testing_api_cmd_pay_abort_refund.c
b/src/lib/testing_api_cmd_pay_abort_refund.c
index 0d811c1..7ecf8b7 100644
--- a/src/lib/testing_api_cmd_pay_abort_refund.c
+++ b/src/lib/testing_api_cmd_pay_abort_refund.c
@@ -85,11 +85,13 @@ struct PayAbortRefundState
* @param cls closure
* @param hr HTTP response code details
* @param sign_key exchange key used to sign @a obj, or NULL
+ * @param signature the actual signature, or NULL on error
*/
static void
abort_refund_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_ExchangePublicKeyP *sign_key)
+ const struct TALER_ExchangePublicKeyP *sign_key,
+ const struct TALER_ExchangeSignatureP *signature)
{
struct PayAbortRefundState *pars = cls;
diff --git a/src/lib/testing_api_cmd_poll_payment.c
b/src/lib/testing_api_cmd_poll_payment.c
index 954b1d4..6d8c37c 100644
--- a/src/lib/testing_api_cmd_poll_payment.c
+++ b/src/lib/testing_api_cmd_poll_payment.c
@@ -391,6 +391,7 @@ poll_payment_conclude_cleanup (void *cls,
GNUNET_SCHEDULER_cancel (cps->task);
cps->task = NULL;
}
+ GNUNET_free (cps);
}
diff --git a/src/lib/testing_api_cmd_proposal.c
b/src/lib/testing_api_cmd_proposal.c
index 1d99c1a..fd53db2 100644
--- a/src/lib/testing_api_cmd_proposal.c
+++ b/src/lib/testing_api_cmd_proposal.c
@@ -215,8 +215,9 @@ proposal_cb (void *cls,
ps->po = NULL;
if (ps->http_status != hr->http_status)
{
- TALER_LOG_ERROR ("Given vs expected: %u vs %u\n",
+ TALER_LOG_ERROR ("Given vs expected: %u(%d) vs %u\n",
hr->http_status,
+ (int) hr->ec,
ps->http_status);
TALER_TESTING_FAIL (ps->is);
}
diff --git a/src/lib/testing_api_cmd_refund_increase.c
b/src/lib/testing_api_cmd_refund_increase.c
index 153d8a7..da2c70b 100644
--- a/src/lib/testing_api_cmd_refund_increase.c
+++ b/src/lib/testing_api_cmd_refund_increase.c
@@ -114,7 +114,14 @@ refund_increase_cb (void *cls,
ris->rio = NULL;
if (ris->http_code != hr->http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected status %u, got %u(%d) for refund increase\n",
+ ris->http_code,
+ hr->http_status,
+ (int) hr->ec);
TALER_TESTING_FAIL (ris->is);
+ }
TALER_TESTING_interpreter_next (ris->is);
}
diff --git a/src/lib/testing_api_cmd_refund_lookup.c
b/src/lib/testing_api_cmd_refund_lookup.c
index c677fe5..7db933a 100644
--- a/src/lib/testing_api_cmd_refund_lookup.c
+++ b/src/lib/testing_api_cmd_refund_lookup.c
@@ -103,27 +103,6 @@ refund_lookup_cleanup (void *cls,
}
-/**
- * Callback that frees all the elements in the hashmap
- *
- * @param cls closure, NULL
- * @param key current key
- * @param value a `struct TALER_Amount`
- *
- * @return always #GNUNET_YES (continue to iterate)
- */
-static int
-hashmap_free (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
-{
- struct TALER_Amount *refund_amount = value;
-
- GNUNET_free (refund_amount);
- return GNUNET_YES;
-}
-
-
/**
* Process "GET /public/refund" (lookup) response;
* mainly checking if the refunded amount matches the
@@ -131,172 +110,203 @@ hashmap_free (void *cls,
*
* @param cls closure
* @param hr HTTP response we got
+ * @param h_contract_terms hash of the contract terms to which the refund is
applied
+ * @param merchant_pub public key of the merchant
+ * @param num_details length of the @a details array
+ * @param details details about the refund processing
*/
static void
refund_lookup_cb (void *cls,
- const struct TALER_MERCHANT_HttpResponse *hr)
+ const struct TALER_MERCHANT_HttpResponse *hr,
+ const struct GNUNET_HashCode *h_contract_terms,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ unsigned int num_details,
+ const struct TALER_MERCHANT_RefundDetail *details)
{
struct RefundLookupState *rls = cls;
struct GNUNET_CONTAINER_MultiHashMap *map;
- size_t index;
- json_t *elem;
- const char *error_name;
- unsigned int error_line;
- struct GNUNET_HashCode h_coin_pub;
const char *coin_reference;
- char *coin_reference_dup;
const char *icoin_reference;
- const struct TALER_TESTING_Command *pay_cmd;
- const struct TALER_TESTING_Command *increase_cmd;
const char *refund_amount;
struct TALER_Amount acc;
struct TALER_Amount ra;
- const json_t *arr;
rls->rlo = NULL;
+ if (MHD_HTTP_GONE == rls->http_code)
+ {
+ /* special case: GONE is not the top-level code, but expected INSIDE the
details */
+ if (MHD_HTTP_OK != hr->http_status)
+ TALER_TESTING_FAIL (rls->is);
+ for (unsigned int i = 0; i<num_details; i++)
+ if (MHD_HTTP_GONE != details[i].hr.http_status)
+ TALER_TESTING_FAIL (rls->is);
+ /* all good */
+ TALER_TESTING_interpreter_next (rls->is);
+ return;
+ }
if (rls->http_code != hr->http_status)
TALER_TESTING_FAIL (rls->is);
-
- arr = json_object_get (hr->reply,
- "refund_permissions");
- if (NULL == arr)
+ if (MHD_HTTP_OK != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Tolerating a refund permission not found\n");
TALER_TESTING_interpreter_next (rls->is);
return;
}
map = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
-
/* Put in array every refunded coin. */
- json_array_foreach (arr, index, elem)
+ for (unsigned int i = 0; i<num_details; i++)
{
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount *irefund_amount = GNUNET_new
- (struct TALER_Amount);
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("coin_pub", &coin_pub),
- TALER_JSON_spec_amount ("refund_amount", irefund_amount),
- GNUNET_JSON_spec_end ()
- };
+ struct GNUNET_HashCode h_coin_pub;
- GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (elem,
- spec,
- &error_name,
- &error_line));
- GNUNET_CRYPTO_hash (&coin_pub,
+ if (MHD_HTTP_OK != details[i].hr.http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Got unexpected status %u/%d for refunded coin %u\n",
+ details[i].hr.http_status,
+ (int) details[i].hr.ec,
+ i);
+ GNUNET_CONTAINER_multihashmap_destroy (map);
+ TALER_TESTING_FAIL (rls->is);
+ return;
+ }
+ TALER_LOG_DEBUG ("Coin %s refund is %s\n",
+ TALER_B2S (&details[i].coin_pub),
+ TALER_amount2s (&details[i].refund_amount));
+ GNUNET_CRYPTO_hash (&details[i].coin_pub,
sizeof (struct TALER_CoinSpendPublicKeyP),
&h_coin_pub);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap_put (
- map,
- &h_coin_pub, // which
- irefund_amount, // how much
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- };
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put (
+ map,
+ &h_coin_pub,
+ (void *) &details[i],
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_CONTAINER_multihashmap_destroy (map);
+ TALER_TESTING_FAIL (rls->is);
+ }
+ }
/* Compare spent coins with refunded, and if they match,
* increase an accumulator. */
- if (NULL == (pay_cmd = TALER_TESTING_interpreter_lookup_command (
- rls->is,
- rls->pay_reference)))
- TALER_TESTING_FAIL (rls->is);
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_coin_reference (
- pay_cmd,
- 0,
- &coin_reference))
- TALER_TESTING_FAIL (rls->is);
-
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_get_zero ("EUR",
- &acc));
- coin_reference_dup = GNUNET_strdup (coin_reference);
- for (icoin_reference = strtok (coin_reference_dup, ";");
- NULL != icoin_reference;
- icoin_reference = strtok (NULL, ";"))
{
- const struct TALER_CoinSpendPrivateKeyP *icoin_priv;
- struct TALER_CoinSpendPublicKeyP icoin_pub;
- struct GNUNET_HashCode h_icoin_pub;
- struct TALER_Amount *iamount;
- const struct TALER_TESTING_Command *icoin_cmd;
-
- if (NULL ==
- (icoin_cmd =
- TALER_TESTING_interpreter_lookup_command (rls->is,
- icoin_reference)) )
+ const struct TALER_TESTING_Command *pay_cmd;
+
+ if (NULL == (pay_cmd = TALER_TESTING_interpreter_lookup_command (
+ rls->is,
+ rls->pay_reference)))
{
- GNUNET_break (0);
- TALER_LOG_ERROR ("Bad reference `%s'\n",
- icoin_reference);
- TALER_TESTING_interpreter_fail (rls->is);
GNUNET_CONTAINER_multihashmap_destroy (map);
- return;
+ TALER_TESTING_FAIL (rls->is);
}
if (GNUNET_OK !=
- TALER_TESTING_get_trait_coin_priv (icoin_cmd,
- 0,
- &icoin_priv))
+ TALER_TESTING_get_trait_coin_reference (
+ pay_cmd,
+ 0,
+ &coin_reference))
{
- GNUNET_break (0);
- TALER_LOG_ERROR ("Command `%s' failed to give coin priv trait\n",
- icoin_reference);
- TALER_TESTING_interpreter_fail (rls->is);
GNUNET_CONTAINER_multihashmap_destroy (map);
- return;
+ TALER_TESTING_FAIL (rls->is);
}
- GNUNET_CRYPTO_eddsa_key_get_public (&icoin_priv->eddsa_priv,
- &icoin_pub.eddsa_pub);
- GNUNET_CRYPTO_hash (&icoin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP),
- &h_icoin_pub);
-
- iamount = GNUNET_CONTAINER_multihashmap_get (map,
- &h_icoin_pub);
-
- /* Can be NULL: not all coins are involved in refund */
- if (NULL == iamount)
- continue;
- GNUNET_assert (0 <=
- TALER_amount_add (&acc,
- &acc,
- iamount));
}
- GNUNET_free (coin_reference_dup);
-
- if (NULL !=
- (increase_cmd
- = TALER_TESTING_interpreter_lookup_command (rls->is,
- rls->increase_reference)))
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero ("EUR",
+ &acc));
{
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_string (increase_cmd,
- 0,
- &refund_amount))
- TALER_TESTING_FAIL (rls->is);
+ char *coin_reference_dup;
- if (GNUNET_OK !=
- TALER_string_to_amount (refund_amount,
- &ra))
- TALER_TESTING_FAIL (rls->is);
+ coin_reference_dup = GNUNET_strdup (coin_reference);
+ for (icoin_reference = strtok (coin_reference_dup, ";");
+ NULL != icoin_reference;
+ icoin_reference = strtok (NULL, ";"))
+ {
+ const struct TALER_CoinSpendPrivateKeyP *icoin_priv;
+ struct TALER_CoinSpendPublicKeyP icoin_pub;
+ struct GNUNET_HashCode h_icoin_pub;
+ const struct TALER_MERCHANT_RefundDetail *idetail;
+ const struct TALER_TESTING_Command *icoin_cmd;
+
+ if (NULL ==
+ (icoin_cmd =
+ TALER_TESTING_interpreter_lookup_command (rls->is,
+ icoin_reference)) )
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Bad reference `%s'\n",
+ icoin_reference);
+ TALER_TESTING_interpreter_fail (rls->is);
+ GNUNET_CONTAINER_multihashmap_destroy (map);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (icoin_cmd,
+ 0,
+ &icoin_priv))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Command `%s' failed to give coin priv trait\n",
+ icoin_reference);
+ TALER_TESTING_interpreter_fail (rls->is);
+ GNUNET_CONTAINER_multihashmap_destroy (map);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&icoin_priv->eddsa_priv,
+ &icoin_pub.eddsa_pub);
+ TALER_LOG_DEBUG ("Looking at coin %s\n",
+ TALER_B2S (&icoin_pub));
+ GNUNET_CRYPTO_hash (&icoin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP),
+ &h_icoin_pub);
+
+ idetail = GNUNET_CONTAINER_multihashmap_get (map,
+ &h_icoin_pub);
+
+ /* Can be NULL: not all coins are involved in refund */
+ if (NULL == idetail)
+ continue;
+ TALER_LOG_DEBUG ("Found coin %s refund of %s\n",
+ TALER_B2S (&idetail->coin_pub),
+ TALER_amount2s (&idetail->refund_amount));
+ GNUNET_assert (0 <=
+ TALER_amount_add (&acc,
+ &acc,
+ &idetail->refund_amount));
+ }
+ GNUNET_free (coin_reference_dup);
}
- else
+
+
{
- GNUNET_assert (NULL != rls->refund_amount);
+ const struct TALER_TESTING_Command *increase_cmd;
- if (GNUNET_OK !=
- TALER_string_to_amount (rls->refund_amount,
- &ra))
- TALER_TESTING_FAIL (rls->is);
- }
+ if (NULL !=
+ (increase_cmd
+ = TALER_TESTING_interpreter_lookup_command (rls->is,
+
rls->increase_reference)))
+ {
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_string (increase_cmd,
+ 0,
+ &refund_amount))
+ TALER_TESTING_FAIL (rls->is);
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (refund_amount,
+ &ra))
+ TALER_TESTING_FAIL (rls->is);
+ }
+ else
+ {
+ GNUNET_assert (NULL != rls->refund_amount);
- GNUNET_CONTAINER_multihashmap_iterate (map,
- &hashmap_free,
- NULL);
+ if (GNUNET_OK !=
+ TALER_string_to_amount (rls->refund_amount,
+ &ra))
+ TALER_TESTING_FAIL (rls->is);
+ }
+ }
GNUNET_CONTAINER_multihashmap_destroy (map);
/* Check that what the backend claims to have been refunded
@@ -304,10 +314,14 @@ refund_lookup_cb (void *cls,
if (0 != TALER_amount_cmp (&acc,
&ra))
{
+ char *a1;
+
+ a1 = TALER_amount_to_string (&ra);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Incomplete refund: expected '%s', got '%s'\n",
- TALER_amount_to_string (&ra),
- TALER_amount_to_string (&acc));
+ a1,
+ TALER_amount2s (&acc));
+ GNUNET_free (a1);
TALER_TESTING_interpreter_fail (rls->is);
return;
}
diff --git a/src/lib/testing_api_cmd_track_transaction.c
b/src/lib/testing_api_cmd_track_transaction.c
index e128ce5..c945050 100644
--- a/src/lib/testing_api_cmd_track_transaction.c
+++ b/src/lib/testing_api_cmd_track_transaction.c
@@ -229,12 +229,15 @@ track_transaction_traits (void *cls,
struct TrackTransactionState *tts = cls;
struct TALER_WireTransferIdentifierRawP *wtid_ptr;
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (
- tts->wtid_str,
- strlen (tts->wtid_str),
- &tts->wtid,
- sizeof (struct TALER_WireTransferIdentifierRawP)))
+ if (MHD_HTTP_OK != tts->http_status)
+ return GNUNET_SYSERR;
+ if ( (NULL != tts->wtid_str) &&
+ (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (tts->wtid_str,
+ strlen (tts->wtid_str),
+ &tts->wtid,
+ sizeof (struct
+
TALER_WireTransferIdentifierRawP))) )
wtid_ptr = NULL;
else
wtid_ptr = &tts->wtid;
--
To stop receiving notification emails like this one, please contact
address@hidden.