aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/exchange-lib/test_exchange_api.c229
-rw-r--r--src/include/taler_exchange_service.h2
2 files changed, 200 insertions, 31 deletions
diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c
index a87141fce..8e0d9d2aa 100644
--- a/src/exchange-lib/test_exchange_api.c
+++ b/src/exchange-lib/test_exchange_api.c
@@ -144,7 +144,12 @@ enum OpCode
/**
* Check that the fakebank has not received any other transactions.
*/
- OC_CHECK_BANK_TRANSFERS_EMPTY
+ OC_CHECK_BANK_TRANSFERS_EMPTY,
+
+ /**
+ * Refund some deposit.
+ */
+ OC_REFUND
};
@@ -601,6 +606,37 @@ struct Command
} check_bank_transfer;
+ struct {
+
+ /**
+ * Amount that should be refunded.
+ */
+ const char *amount;
+
+ /**
+ * Expected refund fee.
+ */
+ const char *fee;
+
+ /**
+ * Reference to the corresponding deposit operation.
+ * Used to obtain contract details, merchant keys,
+ * fee structure, etc.
+ */
+ const char *deposit_ref;
+
+ /**
+ * Refund transaction identifier.
+ */
+ uint64_t rtransaction_id;
+
+ /**
+ * Handle to the refund operation (while it is ongoing).
+ */
+ struct TALER_EXCHANGE_RefundHandle *rh;
+
+ } refund;
+
} details;
};
@@ -1534,6 +1570,82 @@ deposit_wtid_cb (void *cls,
/**
+ * Check the result for the refund request.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
+ * 0 if the exchange's reply is bogus (fails to follow the protocol)
+ * @param obj the received JSON reply, should be kept as proof (and, in particular,
+ * be forwarded to the customer)
+ */
+static void
+refund_cb (void *cls,
+ unsigned int http_status,
+ const json_t *obj)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+
+ cmd->details.refund.rh = NULL;
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (obj, stderr, 0);
+ fail (is);
+ return;
+ }
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ break;
+ default:
+ break;
+ }
+ next_command (is);
+}
+
+
+
+/**
+ * Given a command that is used to withdraw coins,
+ * extract the corresponding public key of the coin.
+ *
+ * @param coin command relating to coin withdrawal or refresh
+ * @param idx index to use if we got multiple coins from the @a coin command
+ * @param[out] coin_pub where to store the public key of the coin
+ */
+static void
+get_public_key_from_coin_command (const struct Command *coin,
+ unsigned int idx,
+ struct TALER_CoinSpendPublicKeyP *coin_pub)
+{
+ switch (coin->oc)
+ {
+ case OC_WITHDRAW_SIGN:
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.coin_priv.eddsa_priv,
+ &coin_pub->eddsa_pub);
+ break;
+ case OC_REFRESH_REVEAL:
+ {
+ const struct FreshCoin *fc;
+
+ GNUNET_assert (idx < coin->details.refresh_reveal.num_fresh_coins);
+ fc = &coin->details.refresh_reveal.fresh_coins[idx];
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
+ &coin_pub->eddsa_pub);
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
+/**
* Run the main interpreter loop that performs exchange operations.
*
* @param cls contains the `struct InterpreterState`
@@ -1614,12 +1726,12 @@ interpreter_run (void *cls)
GNUNET_TIME_round_abs (&execution_date);
cmd->details.admin_add_incoming.aih
= TALER_EXCHANGE_admin_add_incoming (exchange,
- &reserve_pub,
- &amount,
- execution_date,
- wire,
- &add_incoming_cb,
- is);
+ &reserve_pub,
+ &amount,
+ execution_date,
+ wire,
+ &add_incoming_cb,
+ is);
if (NULL == cmd->details.admin_add_incoming.aih)
{
GNUNET_break (0);
@@ -2038,29 +2150,9 @@ interpreter_run (void *cls)
coin = find_command (is,
ref->details.deposit.coin_ref);
GNUNET_assert (NULL != coin);
- switch (coin->oc)
- {
- case OC_WITHDRAW_SIGN:
- GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- break;
- case OC_REFRESH_REVEAL:
- {
- const struct FreshCoin *fc;
- unsigned int idx;
-
- idx = ref->details.deposit.coin_idx;
- GNUNET_assert (idx < coin->details.refresh_reveal.num_fresh_coins);
- fc = &coin->details.refresh_reveal.fresh_coins[idx];
-
- GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- }
- break;
- default:
- GNUNET_assert (0);
- }
-
+ get_public_key_from_coin_command (coin,
+ ref->details.deposit.coin_idx,
+ &coin_pub);
wire = json_loads (ref->details.deposit.wire_details,
JSON_REJECT_DUPLICATES,
NULL);
@@ -2150,6 +2242,72 @@ interpreter_run (void *cls)
next_command (is);
return;
}
+ case OC_REFUND:
+ {
+ const struct Command *coin;
+ struct GNUNET_HashCode h_contract;
+ json_t *contract;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_Amount refund_fee;
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (cmd->details.refund.amount,
+ &amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %u\n",
+ cmd->details.refund.amount,
+ is->ip);
+ fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_string_to_amount (cmd->details.refund.fee,
+ &refund_fee))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %u\n",
+ cmd->details.refund.fee,
+ is->ip);
+ fail (is);
+ return;
+ }
+ ref = find_command (is,
+ cmd->details.refund.deposit_ref);
+ GNUNET_assert (NULL != ref);
+ contract = json_loads (cmd->details.deposit.contract,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ GNUNET_assert (NULL != contract);
+ TALER_JSON_hash (contract,
+ &h_contract);
+ json_decref (contract);
+
+ coin = find_command (is,
+ ref->details.deposit.coin_ref);
+ GNUNET_assert (NULL != coin);
+ get_public_key_from_coin_command (coin,
+ ref->details.deposit.coin_idx,
+ &coin_pub);
+ cmd->details.refund.rh
+ = TALER_EXCHANGE_refund (exchange,
+ &amount,
+ &refund_fee,
+ &h_contract,
+ ref->details.deposit.transaction_id,
+ &coin_pub,
+ cmd->details.refund.rtransaction_id,
+ &ref->details.deposit.merchant_priv,
+ &refund_cb,
+ is);
+ if (NULL == cmd->details.refund.rh)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ return;
+ }
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unknown instruction %d at %u (%s)\n",
@@ -2364,6 +2522,17 @@ do_shutdown (void *cls)
break;
case OC_CHECK_BANK_TRANSFERS_EMPTY:
break;
+ case OC_REFUND:
+ if (NULL != cmd->details.refund.rh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_EXCHANGE_refund_cancel (cmd->details.refund.rh);
+ cmd->details.refund.rh = NULL;
+ }
+ break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unknown instruction %d at %u (%s)\n",
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index 4f3211309..57ab51253 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -475,7 +475,7 @@ struct TALER_EXCHANGE_RefundHandle;
/**
* Callbacks of this type are used to serve the result of submitting a
- * deposit permission request to a exchange.
+ * refund request to an exchange.
*
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;