summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-06-05 14:07:23 +0200
committerChristian Grothoff <christian@grothoff.org>2022-06-05 14:07:23 +0200
commitb9963f75255e416ca79b2f5c3081bde4ba78fab0 (patch)
tree9575e9558b6f8960798c09dec681dc277f96babc /src/lib
parent6c81796d6f39e932d58b4fc1729b472d0e46e3d1 (diff)
downloadexchange-b9963f75255e416ca79b2f5c3081bde4ba78fab0.tar.gz
exchange-b9963f75255e416ca79b2f5c3081bde4ba78fab0.tar.bz2
exchange-b9963f75255e416ca79b2f5c3081bde4ba78fab0.zip
complete P2P/W2W conflict handling, deduplicate code across handlers
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/exchange_api_common.c368
-rw-r--r--src/lib/exchange_api_common.h123
-rw-r--r--src/lib/exchange_api_deposit.c101
-rw-r--r--src/lib/exchange_api_melt.c187
-rw-r--r--src/lib/exchange_api_purse_create_with_deposit.c203
-rw-r--r--src/lib/exchange_api_purse_deposit.c172
-rw-r--r--src/lib/exchange_api_recoup.c106
-rw-r--r--src/lib/exchange_api_recoup_refresh.c117
-rw-r--r--src/lib/exchange_api_refund.c32
9 files changed, 807 insertions, 602 deletions
diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c
index 567239eed..59f5bab8a 100644
--- a/src/lib/exchange_api_common.c
+++ b/src/lib/exchange_api_common.c
@@ -22,6 +22,7 @@
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
+#include "exchange_api_common.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
@@ -685,11 +686,6 @@ struct CoinHistoryParseContext
const struct TALER_CoinSpendPublicKeyP *coin_pub;
/**
- * Hash of @e dk, set from parsing.
- */
- struct TALER_DenominationHashP *h_denom_pub;
-
- /**
* Where to sum up total refunds.
*/
struct TALER_Amount rtotal;
@@ -749,8 +745,6 @@ help_deposit (struct CoinHistoryParseContext *pc,
&h_contract_terms),
GNUNET_JSON_spec_fixed_auto ("h_wire",
&h_wire),
- GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
- pc->h_denom_pub),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
&hac),
@@ -784,7 +778,7 @@ help_deposit (struct CoinHistoryParseContext *pc,
&h_contract_terms,
no_hac ? NULL : &hac,
NULL /* h_extensions! */,
- pc->h_denom_pub,
+ &pc->dk->h_key,
wallet_timestamp,
&merchant_pub,
refund_deadline,
@@ -836,8 +830,6 @@ help_melt (struct CoinHistoryParseContext *pc,
&sig),
GNUNET_JSON_spec_fixed_auto ("rc",
&rc),
- GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
- pc->h_denom_pub),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
&h_age_commitment),
@@ -876,7 +868,7 @@ help_melt (struct CoinHistoryParseContext *pc,
amount,
&melt_fee,
&rc,
- pc->h_denom_pub,
+ &pc->dk->h_key,
no_hac
? NULL
: &h_age_commitment,
@@ -1008,8 +1000,6 @@ help_recoup (struct CoinHistoryParseContext *pc,
&coin_sig),
GNUNET_JSON_spec_fixed_auto ("coin_blind",
&coin_bks),
- GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
- pc->h_denom_pub),
GNUNET_JSON_spec_timestamp ("timestamp",
&timestamp),
GNUNET_JSON_spec_end ()
@@ -1036,7 +1026,7 @@ help_recoup (struct CoinHistoryParseContext *pc,
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
- TALER_wallet_recoup_verify (pc->h_denom_pub,
+ TALER_wallet_recoup_verify (&pc->dk->h_key,
&coin_bks,
pc->coin_pub,
&coin_sig))
@@ -1081,8 +1071,6 @@ help_recoup_refresh (struct CoinHistoryParseContext *pc,
&old_coin_pub),
GNUNET_JSON_spec_fixed_auto ("coin_blind",
&coin_bks),
- GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
- pc->h_denom_pub),
GNUNET_JSON_spec_timestamp ("timestamp",
&timestamp),
GNUNET_JSON_spec_end ()
@@ -1109,7 +1097,7 @@ help_recoup_refresh (struct CoinHistoryParseContext *pc,
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
- TALER_wallet_recoup_verify (pc->h_denom_pub,
+ TALER_wallet_recoup_verify (&pc->dk->h_key,
&coin_bks,
pc->coin_pub,
&coin_sig))
@@ -1250,12 +1238,11 @@ help_purse_deposit (struct CoinHistoryParseContext *pc,
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_verify_coin_history (
const struct TALER_EXCHANGE_DenomPublicKey *dk,
- const char *currency,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
json_t *history,
- struct TALER_DenominationHashP *h_denom_pub,
struct TALER_Amount *total)
{
+ const char *currency = dk->value.currency;
const struct
{
const char *type;
@@ -1273,8 +1260,7 @@ TALER_EXCHANGE_verify_coin_history (
struct CoinHistoryParseContext pc = {
.dk = dk,
.coin_pub = coin_pub,
- .total = total,
- .h_denom_pub = h_denom_pub
+ .total = total
};
size_t len;
@@ -1528,11 +1514,10 @@ TALER_EXCHANGE_check_purse_merge_conflict_ (
{
struct TALER_PurseMergeSignatureP merge_sig;
struct GNUNET_TIME_Timestamp merge_timestamp;
- const char *partner_url = exchange_url;
+ const char *partner_url = NULL;
struct TALER_ReservePublicKeyP reserve_pub;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_mark_optional (
- // FIXME: partner_url or partner_base_url?
GNUNET_JSON_spec_string ("partner_url",
&partner_url),
NULL),
@@ -1554,6 +1539,8 @@ TALER_EXCHANGE_check_purse_merge_conflict_ (
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
+ if (NULL == partner_url)
+ partner_url = exchange_url;
payto_uri = make_payto (partner_url,
&reserve_pub);
if (GNUNET_OK !=
@@ -1581,18 +1568,55 @@ TALER_EXCHANGE_check_purse_merge_conflict_ (
}
-/**
- * Check proof of a contract conflict.
- *
- * DESIGN-FIXME: this 'proof' doesn't really proof a conflict!
- *
- * @param ccontract_sig conflicting signature (must
- * not match the signature from the proof)
- * @param purse_pub public key of the purse
- * @param exchange_url the base URL of this exchange
- * @param proof the proof to check
- * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig
- */
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_check_purse_coin_conflict_ (
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
+ const char *exchange_url,
+ const json_t *proof,
+ struct TALER_CoinSpendPublicKeyP *coin_pub,
+ struct TALER_CoinSpendSignatureP *coin_sig)
+{
+ const char *partner_url = NULL;
+ struct TALER_Amount amount;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("coin_sig",
+ coin_sig),
+ GNUNET_JSON_spec_fixed_auto ("coin_pub",
+ coin_pub),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("partner_url",
+ &partner_url),
+ NULL),
+ TALER_JSON_spec_amount_any ("amount",
+ &amount),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (proof,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (NULL == partner_url)
+ partner_url = exchange_url;
+ if (GNUNET_OK !=
+ TALER_wallet_purse_deposit_verify (
+ partner_url,
+ purse_pub,
+ &amount,
+ coin_pub,
+ coin_sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_check_purse_econtract_conflict_ (
const struct TALER_PurseContractSignatureP *ccontract_sig,
@@ -1642,4 +1666,278 @@ TALER_EXCHANGE_check_purse_econtract_conflict_ (
}
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_check_coin_amount_conflict_ (
+ const struct TALER_EXCHANGE_Keys *keys,
+ const json_t *proof,
+ struct TALER_CoinSpendPublicKeyP *coin_pub,
+ struct TALER_Amount *remaining)
+{
+ json_t *history;
+ struct TALER_Amount total;
+ struct TALER_DenominationHashP h_denom_pub;
+ const struct TALER_EXCHANGE_DenomPublicKey *dki;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("coin_pub",
+ coin_pub),
+ GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
+ &h_denom_pub),
+ GNUNET_JSON_spec_json ("history",
+ &history),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (proof,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ dki = TALER_EXCHANGE_get_denomination_key_by_hash (
+ keys,
+ &h_denom_pub);
+ if (NULL == dki)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_verify_coin_history (dki,
+ coin_pub,
+ history,
+ &total))
+ {
+ GNUNET_break_op (0);
+ json_decref (history);
+ return GNUNET_SYSERR;
+ }
+ json_decref (history);
+ if (0 >
+ TALER_amount_subtract (remaining,
+ &dki->value,
+ &total))
+ {
+ /* Strange 'proof': coin was double-spent
+ before our transaction?! */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Verify that @a coin_sig does NOT appear in
+ * the history of @a proof and thus whatever transaction
+ * is authorized by @a coin_sig is a conflict with
+ * @a proof.
+ *
+ * @param proof a proof to check
+ * @param coin_sig signature that must not be in @a proof
+ * @return #GNUNET_OK if @a coin_sig is not in @a proof
+ */
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_check_coin_signature_conflict_ (
+ const json_t *proof,
+ const struct TALER_CoinSpendSignatureP *coin_sig)
+{
+ json_t *history;
+ size_t off;
+ json_t *entry;
+
+ history = json_object_get (proof,
+ "history");
+ if (NULL == history)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ json_array_foreach (history, off, entry)
+ {
+ struct TALER_CoinSpendSignatureP cs;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("coin_sig",
+ &cs),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (entry,
+ spec,
+ NULL, NULL))
+ continue; /* entry without coin signature */
+ if (0 ==
+ GNUNET_memcmp (&cs,
+ coin_sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_check_coin_denomination_conflict_ (
+ const json_t *proof,
+ const struct TALER_DenominationHashP *ch_denom_pub)
+{
+ struct TALER_DenominationHashP h_denom_pub;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
+ &h_denom_pub),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (proof,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (0 ==
+ GNUNET_memcmp (ch_denom_pub,
+ &h_denom_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+ /* indeed, proof with different denomination key provided */
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_check_coin_conflict_ (
+ const struct TALER_EXCHANGE_Keys *keys,
+ const json_t *proof,
+ const struct TALER_EXCHANGE_DenomPublicKey *dk,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_CoinSpendSignatureP *coin_sig,
+ const struct TALER_Amount *required)
+{
+ enum TALER_ErrorCode ec;
+
+ ec = TALER_JSON_get_error_code (proof);
+ switch (ec)
+ {
+ case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
+ {
+ struct TALER_Amount left;
+ struct TALER_CoinSpendPublicKeyP pcoin_pub;
+
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_coin_amount_conflict_ (
+ keys,
+ proof,
+ &pcoin_pub,
+ &left))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (0 !=
+ GNUNET_memcmp (&pcoin_pub,
+ coin_pub))
+ {
+ /* conflict is for a different coin! */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (-1 !=
+ TALER_amount_cmp (&left,
+ required))
+ {
+ /* Balance was sufficient after all; recoup MAY have still been possible */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_coin_signature_conflict_ (
+ proof,
+ coin_sig))
+ {
+ /* Not a conflicting transaction: ours is included! */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ break;
+ }
+ case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
+ {
+ struct TALER_Amount left;
+ struct TALER_CoinSpendPublicKeyP pcoin_pub;
+
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_coin_amount_conflict_ (
+ keys,
+ proof,
+ &pcoin_pub,
+ &left))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (0 !=
+ GNUNET_memcmp (&pcoin_pub,
+ coin_pub))
+ {
+ /* conflict is for a different coin! */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_coin_denomination_conflict_ (
+ proof,
+ &dk->h_key))
+ {
+ /* Eh, same denomination, hence no conflict */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ break;
+ }
+ default:
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_get_min_denomination_ (
+ const struct TALER_EXCHANGE_Keys *keys,
+ struct TALER_Amount *min)
+{
+ bool have_min = false;
+ for (unsigned int i = 0; i<keys->num_denom_keys; i++)
+ {
+ const struct TALER_EXCHANGE_DenomPublicKey *dk = &keys->denom_keys[i];
+
+ if (! have_min)
+ {
+ *min = dk->value;
+ have_min = true;
+ continue;
+ }
+ if (1 != TALER_amount_cmp (min,
+ &dk->value))
+ continue;
+ *min = dk->value;
+ }
+ if (! have_min)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
/* end of exchange_api_common.c */
diff --git a/src/lib/exchange_api_common.h b/src/lib/exchange_api_common.h
index 9c6d45029..9cbdf547f 100644
--- a/src/lib/exchange_api_common.h
+++ b/src/lib/exchange_api_common.h
@@ -23,6 +23,7 @@
#define EXCHANGE_API_COMMON_H
#include "taler_json_lib.h"
+#include "taler_exchange_service.h"
/**
@@ -33,7 +34,7 @@
* @param purse_pub the public key (must match
* the signature from the proof)
* @param proof the proof to check
- * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig
+ * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a cpurse_sig
*/
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_check_purse_create_conflict_ (
@@ -51,7 +52,7 @@ TALER_EXCHANGE_check_purse_create_conflict_ (
* the signature from the proof)
* @param exchange_url the base URL of this exchange
* @param proof the proof to check
- * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig
+ * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and @a merge_pub and conflicts with @a cmerge_sig
*/
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_check_purse_merge_conflict_ (
@@ -63,16 +64,38 @@ TALER_EXCHANGE_check_purse_merge_conflict_ (
/**
- * Check proof of a contract conflict.
+ * Check @a proof that claims this coin was spend
+ * differently on the same purse already. Note that
+ * the caller must still check that @a coin_pub is
+ * in the list of coins that were used, and that
+ * @a coin_sig is different from the signature the
+ * caller used.
*
- * DESIGN-FIXME: this 'proof' doesn't really proof a conflict!
+ * @param purse_pub the public key of the purse
+ * @param exchange_url base URL of our exchange
+ * @param proof the proof to check
+ * @param[out] coin_pub set to the conflicting coin
+ * @param[out] coin_sig set to the conflicting signature
+ * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and showing that @a coin_pub was spent using @a coin_sig.
+ */
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_check_purse_coin_conflict_ (
+ const struct TALER_PurseContractPublicKeyP *purse_pub,
+ const char *exchange_url,
+ const json_t *proof,
+ struct TALER_CoinSpendPublicKeyP *coin_pub,
+ struct TALER_CoinSpendSignatureP *coin_sig);
+
+
+/**
+ * Check proof of a contract conflict.
*
* @param ccontract_sig conflicting signature (must
* not match the signature from the proof)
* @param purse_pub public key of the purse
* @param exchange_url the base URL of this exchange
* @param proof the proof to check
- * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig
+ * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a ccontract_sig
*/
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_check_purse_econtract_conflict_ (
@@ -81,4 +104,94 @@ TALER_EXCHANGE_check_purse_econtract_conflict_ (
const json_t *proof);
+/**
+ * Check proof of a coin spend value conflict.
+ *
+ * @param keys exchange /keys structure
+ * @param proof the proof to check
+ * @param[out] coin_pub set to the public key of the
+ * coin that is claimed to have an insufficient
+ * balance
+ * @param[out] remaining set to the remaining balance
+ * of the coin as provided by the proof
+ * @return #GNUNET_OK if the @a proof is OK for @a purse_pub demonstrating that @a coin_pub has only @a remaining balance.
+ */
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_check_coin_amount_conflict_ (
+ const struct TALER_EXCHANGE_Keys *keys,
+ const json_t *proof,
+ struct TALER_CoinSpendPublicKeyP *coin_pub,
+ struct TALER_Amount *remaining);
+
+
+/**
+ * Verify that @a proof contains a coin history
+ * that demonstrates that @a coin_pub was previously
+ * used with a denomination key that is different
+ * from @a ch_denom_pub. Note that the coin history
+ * MUST have been checked before using
+ * #TALER_EXCHANGE_check_coin_amount_conflict_().
+ *
+ * @param proof a proof to check
+ * @param ch_denom_pub hash of the conflicting denomination
+ * @return #GNUNET_OK if @a ch_denom_pub differs from the
+ * denomination hash given by the history of the coin
+ */
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_check_coin_denomination_conflict_ (
+ const json_t *proof,
+ const struct TALER_DenominationHashP *ch_denom_pub);
+
+
+/**
+ * Verify that @a coin_sig does NOT appear in
+ * the history of @a proof and thus whatever transaction
+ * is authorized by @a coin_sig is a conflict with
+ * @a proof.
+ *
+ * @param proof a proof to check
+ * @param coin_sig signature that must not be in @a proof
+ * @return #GNUNET_OK if @a coin_sig is not in @a proof
+ */
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_check_coin_signature_conflict_ (
+ const json_t *proof,
+ const struct TALER_CoinSpendSignatureP *coin_sig);
+
+
+/**
+ * Check that the provided @a proof indeeds indicates
+ * a conflict for @a coin_pub.
+ *
+ * @param keys exchange keys
+ * @param proof provided conflict proof
+ * @param dk denomination of @a coin_pub that the client
+ * used
+ * @param coin_pub public key of the coin
+ * @param coin_sig signature over operation that conflicted
+ * @param required balance required on the coin for the operation
+ * @return #GNUNET_OK if @a proof holds
+ */
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_check_coin_conflict_ (
+ const struct TALER_EXCHANGE_Keys *keys,
+ const json_t *proof,
+ const struct TALER_EXCHANGE_DenomPublicKey *dk,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_CoinSpendSignatureP *coin_sig,
+ const struct TALER_Amount *required);
+
+
+/**
+ * Find the smallest denomination amount in @e keys.
+ *
+ * @param keys keys to search
+ * @param[out] min set to the smallest amount
+ * @return #GNUNET_SYSERR if there are no denominations in @a keys
+ */
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_get_min_denomination_ (
+ const struct TALER_EXCHANGE_Keys *keys,
+ struct TALER_Amount *min);
+
#endif
diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c
index 67f595bfb..58b1c3a4a 100644
--- a/src/lib/exchange_api_deposit.c
+++ b/src/lib/exchange_api_deposit.c
@@ -29,6 +29,7 @@
#include "taler_json_lib.h"
#include "taler_auditor_service.h"
#include "taler_exchange_service.h"
+#include "exchange_api_common.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
#include "exchange_api_curl_defaults.h"
@@ -129,6 +130,11 @@ struct TALER_EXCHANGE_DepositHandle
struct TALER_CoinSpendPublicKeyP coin_pub;
/**
+ * Our signature for the deposit operation.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
+ /**
* The Merchant's public key. Allows the merchant to later refund
* the transaction or to inquire about the wire transfer identifier.
*/
@@ -227,77 +233,6 @@ auditor_cb (void *cls,
/**
- * Verify that the signatures on the "403 FORBIDDEN" response from the
- * exchange demonstrating customer double-spending are valid.
- *
- * @param dh deposit handle
- * @param json json reply with the signature(s) and transaction history
- * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
- */
-static enum GNUNET_GenericReturnValue
-verify_deposit_signature_conflict (
- const struct TALER_EXCHANGE_DepositHandle *dh,
- const json_t *json)
-{
- json_t *history;
- struct TALER_Amount total;
- enum TALER_ErrorCode ec;
- struct TALER_DenominationHashP h_denom_pub;
-
- memset (&h_denom_pub,
- 0,
- sizeof (h_denom_pub));
- history = json_object_get (json,
- "history");
- if (GNUNET_OK !=
- TALER_EXCHANGE_verify_coin_history (&dh->dki,
- dh->dki.value.currency,
- &dh->coin_pub,
- history,
- &h_denom_pub,
- &total))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- ec = TALER_JSON_get_error_code (json);
- switch (ec)
- {
- case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
- if (0 >
- TALER_amount_add (&total,
- &total,
- &dh->amount_with_fee))
- {
- /* clearly not OK if our transaction would have caused
- the overflow... */
- return GNUNET_OK;
- }
-
- if (0 >= TALER_amount_cmp (&total,
- &dh->dki.value))
- {
- /* transaction should have still fit */
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- /* everything OK, proof of double-spending was provided */
- return GNUNET_OK;
- case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
- if (0 != GNUNET_memcmp (&dh->dki.h_key,
- &h_denom_pub))
- return GNUNET_OK; /* indeed, proof with different denomination key provided */
- /* invalid proof provided */
- return GNUNET_SYSERR;
- default:
- /* unexpected error code */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-}
-
-
-/**
* Function called when we're done processing the
* HTTP /deposit request.
*
@@ -316,8 +251,10 @@ handle_deposit_finished (void *cls,
.hr.reply = j,
.hr.http_status = (unsigned int) response_code
};
+ const struct TALER_EXCHANGE_Keys *keys;
dh->job = NULL;
+ keys = TALER_EXCHANGE_get_keys (dh->exchange);
switch (response_code)
{
case 0:
@@ -409,19 +346,21 @@ handle_deposit_finished (void *cls,
happen, we should pass the JSON reply to the application */
break;
case MHD_HTTP_CONFLICT:
- /* Double spending; check signatures on transaction history */
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
if (GNUNET_OK !=
- verify_deposit_signature_conflict (dh,
- j))
+ TALER_EXCHANGE_check_coin_conflict_ (
+ keys,
+ j,
+ &dh->dki,
+ &dh->coin_pub,
+ &dh->coin_sig,
+ &dh->amount_with_fee))
{
GNUNET_break_op (0);
dr.hr.http_status = 0;
- dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
- }
- else
- {
- dr.hr.ec = TALER_JSON_get_error_code (j);
- dr.hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ break;
}
break;
case MHD_HTTP_GONE:
@@ -692,6 +631,8 @@ TALER_EXCHANGE_deposit (
dh->exchange = exchange;
dh->cb = cb;
dh->cb_cls = cb_cls;
+ dh->coin_sig = *coin_sig;
+ dh->coin_pub = *coin_pub;
dh->url = TEAH_path_to_url (exchange,
arg_str);
if (NULL == dh->url)
diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c
index 80c759704..ff720d2ff 100644
--- a/src/lib/exchange_api_melt.c
+++ b/src/lib/exchange_api_melt.c
@@ -27,6 +27,7 @@
#include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h"
#include "taler_exchange_service.h"
+#include "exchange_api_common.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
#include "exchange_api_curl_defaults.h"
@@ -102,6 +103,11 @@ struct TALER_EXCHANGE_MeltHandle
struct TALER_CoinSpendPublicKeyP coin_pub;
/**
+ * Signature affirming the melt.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
+ /**
* @brief Public information about the coin's denomination key
*/
const struct TALER_EXCHANGE_DenomPublicKey *dki;
@@ -184,143 +190,6 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh,
/**
- * Verify that the signatures on the "409 CONFLICT" response from the
- * exchange demonstrating customer denomination key differences
- * resulting from coin private key reuse are valid.
- *
- * @param mh melt handle
- * @param json json reply with the signature(s) and transaction history
- * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
- */
-static enum GNUNET_GenericReturnValue
-verify_melt_signature_denom_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
- const json_t *json)
-
-{
- json_t *history;
- struct TALER_Amount total;
- struct TALER_DenominationHashP h_denom_pub;
-
- memset (&h_denom_pub,
- 0,
- sizeof (h_denom_pub));
- history = json_object_get (json,
- "history");
- if (GNUNET_OK !=
- TALER_EXCHANGE_verify_coin_history (mh->dki,
- mh->dki->value.currency,
- &mh->coin_pub,
- history,
- &h_denom_pub,
- &total))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (0 != GNUNET_memcmp (&mh->dki->h_key,
- &h_denom_pub))
- return GNUNET_OK; /* indeed, proof with different denomination key provided */
- /* invalid proof provided */
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Verify that the signatures on the "409 CONFLICT" response from the
- * exchange demonstrating customer double-spending are valid.
- *
- * @param mh melt handle
- * @param json json reply with the signature(s) and transaction history
- * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
- */
-static enum GNUNET_GenericReturnValue
-verify_melt_signature_spend_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
- const json_t *json)
-{
- json_t *history;
- struct TALER_Amount total;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("history",
- &history),
- GNUNET_JSON_spec_end ()
- };
- const struct MeltedCoin *mc;
- enum TALER_ErrorCode ec;
- struct TALER_DenominationHashP h_denom_pub;
-
- /* parse JSON reply */
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- /* Find out which coin was deemed problematic by the exchange */
- mc = &mh->md.melted_coin;
- /* verify coin history */
- memset (&h_denom_pub,
- 0,
- sizeof (h_denom_pub));
- history = json_object_get (json,
- "history");
- if (GNUNET_OK !=
- TALER_EXCHANGE_verify_coin_history (mh->dki,
- mc->original_value.currency,
- &mh->coin_pub,
- history,
- &h_denom_pub,
- &total))
- {
- GNUNET_break_op (0);
- json_decref (history);
- return GNUNET_SYSERR;
- }
- json_decref (history);
-
- ec = TALER_JSON_get_error_code (json);
- switch (ec)
- {
- case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
- /* check if melt operation was really too expensive given history */
- if (0 >
- TALER_amount_add (&total,
- &total,
- &mc->melt_amount_with_fee))
- {
- /* clearly not OK if our transaction would have caused
- the overflow... */
- return GNUNET_OK;
- }
-
- if (0 >= TALER_amount_cmp (&total,
- &mc->original_value))
- {
- /* transaction should have still fit */
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- /* everything OK, valid proof of double-spending was provided */
- return GNUNET_OK;
- case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
- if (0 != GNUNET_memcmp (&mh->dki->h_key,
- &h_denom_pub))
- return GNUNET_OK; /* indeed, proof with different denomination key provided */
- /* invalid proof provided */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- default:
- /* unexpected error code */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-}
-
-
-/**
* Function called when we're done processing the
* HTTP /coins/$COIN_PUB/melt request.
*
@@ -339,8 +208,10 @@ handle_melt_finished (void *cls,
.hr.reply = j,
.hr.http_status = (unsigned int) response_code
};
+ const struct TALER_EXCHANGE_Keys *keys;
mh->job = NULL;
+ keys = TALER_EXCHANGE_get_keys (mh->exchange);
switch (response_code)
{
case 0:
@@ -372,36 +243,19 @@ handle_melt_finished (void *cls,
break;
case MHD_HTTP_CONFLICT:
mr.hr.ec = TALER_JSON_get_error_code (j);
- switch (mr.hr.ec)
+ mr.hr.hint = TALER_JSON_get_error_hint (j);
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_coin_conflict_ (
+ keys,
+ j,
+ mh->dki,
+ &mh->coin_pub,
+ &mh->coin_sig,
+ &mh->md.melted_coin.melt_amount_with_fee))
{
- case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
- /* Double spending; check signatures on transaction history */
- if (GNUNET_OK !=
- verify_melt_signature_spend_conflict (mh,
- j))
- {
- GNUNET_break_op (0);
- mr.hr.http_status = 0;
- mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
- mr.hr.hint = TALER_JSON_get_error_hint (j);
- }
- break;
- case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
- if (GNUNET_OK !=
- verify_melt_signature_denom_conflict (mh,
- j))
- {
- GNUNET_break_op (0);
- mr.hr.http_status = 0;
- mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
- mr.hr.hint = TALER_JSON_get_error_hint (j);
- }
- break;
- default:
GNUNET_break_op (0);
mr.hr.http_status = 0;
- mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
- mr.hr.hint = TALER_JSON_get_error_hint (j);
+ mr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
}
break;
@@ -456,7 +310,6 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
json_t *melt_obj;
CURL *eh;
struct GNUNET_CURL_Context *ctx;
- struct TALER_CoinSpendSignatureP confirm_sig;
char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
struct TALER_DenominationHashP h_denom_pub;
struct TALER_ExchangeWithdrawValues alg_values[mh->rd->fresh_pks_len];
@@ -480,7 +333,7 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
&h_denom_pub,
mh->md.melted_coin.h_age_commitment,
&mh->md.melted_coin.coin_priv,
- &confirm_sig);
+ &mh->coin_sig);
GNUNET_CRYPTO_eddsa_key_get_public (&mh->md.melted_coin.coin_priv.eddsa_priv,
&mh->coin_pub.eddsa_pub);
melt_obj = GNUNET_JSON_PACK (
@@ -489,7 +342,7 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
TALER_JSON_pack_denom_sig ("denom_sig",
&mh->md.melted_coin.sig),
GNUNET_JSON_pack_data_auto ("confirm_sig",
- &confirm_sig),
+ &mh->coin_sig),
TALER_JSON_pack_amount ("value_with_fee",
&mh->md.melted_coin.melt_amount_with_fee),
GNUNET_JSON_pack_data_auto ("rc",
diff --git a/src/lib/exchange_api_purse_create_with_deposit.c b/src/lib/exchange_api_purse_create_with_deposit.c
index f21b7d312..f2d80b942 100644
--- a/src/lib/exchange_api_purse_create_with_deposit.c
+++ b/src/lib/exchange_api_purse_create_with_deposit.c
@@ -35,6 +35,33 @@
/**
+ * Information we track per deposited coin.
+ */
+struct Deposit
+{
+ /**
+ * Coin's public key.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Signature made with the coin.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
+ /**
+ * Coin's denomination.
+ */
+ struct TALER_DenominationHashP h_denom_pub;
+
+ /**
+ * How much did we say the coin contributed.
+ */
+ struct TALER_Amount contribution;
+};
+
+
+/**
* @brief A purse create with deposit handle
*/
struct TALER_EXCHANGE_PurseCreateDepositHandle
@@ -106,6 +133,16 @@ struct TALER_EXCHANGE_PurseCreateDepositHandle
*/
struct GNUNET_TIME_Timestamp purse_expiration;
+ /**
+ * Array of @e num_deposit deposits.
+ */
+ struct Deposit *deposits;
+
+ /**
+ * How many deposits did we make?
+ */
+ unsigned int num_deposits;
+
};
@@ -128,8 +165,10 @@ handle_purse_create_deposit_finished (void *cls,
.hr.reply = j,
.hr.http_status = (unsigned int) response_code
};
+ const struct TALER_EXCHANGE_Keys *keys;
pch->job = NULL;
+ keys = TALER_EXCHANGE_get_keys (pch->exchange);
switch (response_code)
{
case 0:
@@ -232,43 +271,151 @@ handle_purse_create_deposit_finished (void *cls,
break;
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
{
-#if FIXME
- struct TALER_Amount total;
- struct TALER_DenominationHashP h_denom_pub;
- const struct TALER_EXCHANGE_DenomPublicKey *dk = NULL;
+ struct TALER_Amount left;
+ struct TALER_CoinSpendPublicKeyP pcoin_pub;
+ bool found = false;
- // FIXME: parse coin_pub
- // FIXME: lookup dk for that coin from our deposits array!
-
- if (NULL == dk)
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_coin_amount_conflict_ (
+ keys,
+ j,
+ &pcoin_pub,
+ &left))
{
- /* not one of our coins */
GNUNET_break_op (0);
dr.hr.http_status = 0;
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
}
+ for (unsigned int i = 0; i<pch->num_deposits; i++)
+ {
+ struct Deposit *deposit = &pch->deposits[i];
+
+ if (0 != GNUNET_memcmp (&pcoin_pub,
+ &deposit->coin_pub))
+ continue;
+ if (-1 !=
+ TALER_amount_cmp (&left,
+ &deposit->contribution))
+ {
+ /* Balance was sufficient after all; recoup MAY have still been possible */
+ GNUNET_break_op (0);
+ continue;
+ }
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_coin_signature_conflict_ (
+ j,
+ &deposit->coin_sig))
+ {
+ GNUNET_break_op (0);
+ continue;
+ }
+ found = true;
+ break;
+ }
+ if (! found)
+ {
+ /* conflict is for a different coin! */
+ GNUNET_break_op (0);
+ dr.hr.http_status = 0;
+ dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ break;
+ }
+ break;
+ }
+ case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
+ {
+ struct TALER_Amount left;
+ struct TALER_CoinSpendPublicKeyP pcoin_pub;
+ bool found = false;
+
if (GNUNET_OK !=
- TALER_EXCHANGE_verify_coin_history (dk,
- pch->exchange->currency,
- &coin_pub,
- history,
- &h_denom_pub,
- &total))
+ TALER_EXCHANGE_check_coin_amount_conflict_ (
+ keys,
+ j,
+ &pcoin_pub,
+ &left))
{
GNUNET_break_op (0);
dr.hr.http_status = 0;
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
}
- // FIXME: check total is too high for the request...
-#endif
+ for (unsigned int i = 0; i<pch->num_deposits; i++)
+ {
+ struct Deposit *deposit = &pch->deposits[i];
+
+ if (0 !=
+ GNUNET_memcmp (&pcoin_pub,
+ &deposit->coin_pub))
+ continue;
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_coin_denomination_conflict_ (
+ j,
+ &deposit->h_denom_pub))
+ {
+ /* Eh, same denomination, hence no conflict */
+ GNUNET_break_op (0);
+ continue;
+ }
+ found = true;
+ }
+ if (! found)
+ {
+ /* conflict is for a different coin! */
+ GNUNET_break_op (0);
+ dr.hr.http_status = 0;
+ dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ break;
+ }
+ /* meta data conflict is real! */
break;
}
case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA:
{
- // FIXME!
- break;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_CoinSpendSignatureP coin_sig;
+ bool found = false;
+
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_purse_coin_conflict_ (
+ &pch->purse_pub,
+ pch->exchange->url,
+ j,
+ &coin_pub,
+ &coin_sig))
+ {
+ GNUNET_break_op (0);
+ dr.hr.http_status = 0;
+ dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ break;
+ }
+ for (unsigned int i = 0; i<pch->num_deposits; i++)
+ {
+ struct Deposit *deposit = &pch->deposits[i];
+
+ if (0 !=
+ GNUNET_memcmp (&coin_pub,
+ &deposit->coin_pub))
+ continue;
+ if (0 ==
+ GNUNET_memcmp (&coin_sig,
+ &deposit->coin_sig))
+ {
+ GNUNET_break_op (0);
+ continue;
+ }
+ found = true;
+ break;
+ }
+ if (! found)
+ {
+ /* conflict is for a different coin! */
+ GNUNET_break_op (0);
+ dr.hr.http_status = 0;
+ dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ break;
+ }
}
case TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA:
if (GNUNET_OK !=
@@ -408,6 +555,9 @@ TALER_EXCHANGE_purse_create_with_deposit (
GNUNET_free (pch);
return NULL;
}
+ pch->num_deposits = num_deposits;
+ pch->deposits = GNUNET_new_array (num_deposits,
+ struct Deposit);
deposit_arr = json_array ();
GNUNET_assert (NULL != deposit_arr);
url = TEAH_path_to_url (exchange,
@@ -418,9 +568,8 @@ TALER_EXCHANGE_purse_create_with_deposit (
for (unsigned int i = 0; i<num_deposits; i++)
{
const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
+ struct Deposit *d = &pch->deposits[i];
json_t *jdeposit;
- struct TALER_CoinSpendSignatureP coin_sig;
- struct TALER_CoinSpendPublicKeyP coin_pub;
#if FIXME_OEC
struct TALER_AgeCommitmentHash agh;
struct TALER_AgeCommitmentHash *aghp = NULL;
@@ -441,14 +590,16 @@ TALER_EXCHANGE_purse_create_with_deposit (
return NULL;
}
#endif
+ d->contribution = deposit->amount;
+ d->h_denom_pub = deposit->h_denom_pub;
GNUNET_CRYPTO_eddsa_key_get_public (&deposit->coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
+ &d->coin_pub.eddsa_pub);
TALER_wallet_purse_deposit_sign (
url,
&pch->purse_pub,
&deposit->amount,
&deposit->coin_priv,
- &coin_sig);
+ &d->coin_sig);
jdeposit = GNUNET_JSON_PACK (
#if FIXME_OEC
GNUNET_JSON_pack_allow_null (
@@ -465,9 +616,9 @@ TALER_EXCHANGE_purse_create_with_deposit (
TALER_JSON_pack_denom_sig ("ub_sig",
&deposit->denom_sig),
GNUNET_JSON_pack_data_auto ("coin_sig",
- &coin_sig),
+ &d->coin_sig),
GNUNET_JSON_pack_data_auto ("coin_pub",
- &coin_pub));
+ &d->coin_pub));
GNUNET_assert (0 ==
json_array_append_new (deposit_arr,
jdeposit));
@@ -529,6 +680,7 @@ TALER_EXCHANGE_purse_create_with_deposit (
curl_easy_cleanup (eh);
json_decref (create_obj);
GNUNET_free (pch->econtract.econtract);
+ GNUNET_free (pch->deposits);
GNUNET_free (pch->url);
GNUNET_free (pch);
return NULL;
@@ -558,6 +710,7 @@ TALER_EXCHANGE_purse_create_with_deposit_cancel (
}
GNUNET_free (pch->econtract.econtract);
GNUNET_free (pch->url);
+ GNUNET_free (pch->deposits);
TALER_curl_easy_post_finished (&pch->ctx);
GNUNET_free (pch);
}
diff --git a/src/lib/exchange_api_purse_deposit.c b/src/lib/exchange_api_purse_deposit.c
index 2027ca0d8..6946419dc 100644
--- a/src/lib/exchange_api_purse_deposit.c
+++ b/src/lib/exchange_api_purse_deposit.c
@@ -28,6 +28,7 @@
#include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h"
#include "taler_exchange_service.h"
+#include "exchange_api_common.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
#include "exchange_api_curl_defaults.h"
@@ -44,6 +45,11 @@ struct Coin
struct TALER_CoinSpendPublicKeyP coin_pub;
/**
+ * Signature made with the coin.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
+ /**
* Coin's denomination.
*/
struct TALER_DenominationHashP h_denom_pub;
@@ -226,30 +232,17 @@ handle_purse_deposit_finished (void *cls,
{
case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA:
{
- const char *partner_url = NULL;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_CoinSpendSignatureP coin_sig;
- struct TALER_Amount amount;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("coin_sig",
- &coin_sig),
- GNUNET_JSON_spec_fixed_auto ("coin_pub",
- &coin_pub),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("partner_url",
- &partner_url),
- NULL),
- TALER_JSON_spec_amount ("amount",
- keys->currency,
- &amount),
- GNUNET_JSON_spec_end ()
- };
bool found = false;
if (GNUNET_OK !=
- GNUNET_JSON_parse (j,
- spec,
- NULL, NULL))
+ TALER_EXCHANGE_check_purse_coin_conflict_ (
+ &pch->purse_pub,
+ pch->base_url,
+ j,
+ &coin_pub,
+ &coin_sig))
{
GNUNET_break_op (0);
dr.hr.http_status = 0;
@@ -257,29 +250,21 @@ handle_purse_deposit_finished (void *cls,
break;
}
for (unsigned int i = 0; i<pch->num_deposits; i++)
+ {
if (0 == GNUNET_memcmp (&coin_pub,
&pch->coins[i].coin_pub))
{
+ if (0 == GNUNET_memcmp (&coin_sig,
+ &pch->coins[i].coin_sig))
+ {
+ /* identical signature => not a conflict */
+ continue;
+ }
found = true;
break;
}
- if (! found)
- {
- /* proof is about a coin we did not even deposit */
- GNUNET_break_op (0);
- dr.hr.http_status = 0;
- dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- break;
}
- if (NULL == partner_url)
- partner_url = pch->base_url;
- if (GNUNET_OK !=
- TALER_wallet_purse_deposit_verify (
- partner_url,
- &pch->purse_pub,
- &amount,
- &coin_pub,
- &coin_sig))
+ if (! found)
{
GNUNET_break_op (0);
dr.hr.http_status = 0;
@@ -291,27 +276,18 @@ handle_purse_deposit_finished (void *cls,
}
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
{
- json_t *history;
- struct TALER_Amount total;
- struct TALER_DenominationHashP h_denom_pub;
- const struct TALER_EXCHANGE_DenomPublicKey *dki;
struct TALER_CoinSpendPublicKeyP coin_pub;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("coin_pub",
- &coin_pub),
- GNUNET_JSON_spec_json ("history",
- &history),
- GNUNET_JSON_spec_end ()
- };
+ struct TALER_Amount remaining;
bool found = false;
const struct Coin *my_coin;
if (GNUNET_OK !=
- GNUNET_JSON_parse (j,
- spec,
- NULL, NULL))
+ TALER_EXCHANGE_check_coin_amount_conflict_ (
+ keys,
+ j,
+ &coin_pub,
+ &remaining))
{
- GNUNET_break_op (0);
dr.hr.http_status = 0;
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
@@ -334,45 +310,22 @@ handle_purse_deposit_finished (void *cls,
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
}
- dki = TALER_EXCHANGE_get_denomination_key_by_hash (
- keys,
- &my_coin->h_denom_pub);
- if (NULL == dki)
- {
- dr.hr.http_status = 0;
- dr.hr.ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
- GNUNET_break_op (0);
- break;
- }
- if (GNUNET_OK !=
- TALER_EXCHANGE_verify_coin_history (dki,
- dki->value.currency,
- &coin_pub,
- history,
- &h_denom_pub,
- &total))
+ if (1 == TALER_amount_cmp (&remaining,
+ &my_coin->contribution))
{
+ /* transaction should have still fit */
GNUNET_break_op (0);
dr.hr.http_status = 0;
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- json_decref (history);
break;
}
- json_decref (history);
- if (0 >
- TALER_amount_add (&total,
- &total,
- &my_coin->contribution))
- {
- /* clearly not OK if our transaction would have caused
- the overflow... */
- break;
- }
- if (0 >= TALER_amount_cmp (&total,
- &dki->value))
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_coin_signature_conflict_ (
+ j,
+ &my_coin->coin_sig))
{
- /* transaction should have still fit */
- GNUNET_break (0);
+ /* THIS transaction must not be in the conflicting history */
+ GNUNET_break_op (0);
dr.hr.http_status = 0;
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
@@ -382,27 +335,18 @@ handle_purse_deposit_finished (void *cls,
}
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
{
- json_t *history;
- struct TALER_Amount total;
- struct TALER_DenominationHashP h_denom_pub;
- const struct Coin *my_coin;
- const struct TALER_EXCHANGE_DenomPublicKey *dki;
struct TALER_CoinSpendPublicKeyP coin_pub;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("coin_pub",
- &coin_pub),
- GNUNET_JSON_spec_json ("history",
- &history),
- GNUNET_JSON_spec_end ()
- };
+ struct TALER_Amount remaining;
bool found = false;
+ const struct Coin *my_coin;
if (GNUNET_OK !=
- GNUNET_JSON_parse (j,
- spec,
- NULL, NULL))
+ TALER_EXCHANGE_check_coin_amount_conflict_ (
+ keys,
+ j,
+ &coin_pub,
+ &remaining))
{
- GNUNET_break_op (0);
dr.hr.http_status = 0;
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
@@ -425,31 +369,12 @@ handle_purse_deposit_finished (void *cls,
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
}
- dki = TALER_EXCHANGE_get_denomination_key_by_hash (
- keys,
- &my_coin->h_denom_pub);
- memset (&h_denom_pub,
- 0,
- sizeof (h_denom_pub));
if (GNUNET_OK !=
- TALER_EXCHANGE_verify_coin_history (dki,
- dki->value.currency,
- &coin_pub,
- history,
- &h_denom_pub,
- &total))
- {
- GNUNET_break_op (0);
- dr.hr.http_status = 0;
- dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- json_decref (history);
- break;
- }
- json_decref (history);
- if (0 == GNUNET_memcmp (&dki->h_key,
- &h_denom_pub))
+ TALER_EXCHANGE_check_coin_denomination_conflict_ (
+ j,
+ &my_coin->h_denom_pub))
{
- /* sorry, this proves nothing */
+ /* no conflicting denomination detected */
GNUNET_break_op (0);
dr.hr.http_status = 0;
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
@@ -562,7 +487,6 @@ TALER_EXCHANGE_purse_deposit (
const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
struct Coin *coin = &pch->coins[i];
json_t *jdeposit;
- struct TALER_CoinSpendSignatureP coin_sig;
#if FIXME_OEC
struct TALER_AgeCommitmentHash agh;
struct TALER_AgeCommitmentHash *aghp = NULL;
@@ -593,7 +517,7 @@ TALER_EXCHANGE_purse_deposit (
&pch->purse_pub,
&deposit->amount,
&deposit->coin_priv,
- &coin_sig);
+ &coin->coin_sig);
jdeposit = GNUNET_JSON_PACK (
#if FIXME_OEC
GNUNET_JSON_pack_allow_null (
@@ -612,7 +536,7 @@ TALER_EXCHANGE_purse_deposit (
GNUNET_JSON_pack_data_auto ("coin_pub",
&coin->coin_pub),
GNUNET_JSON_pack_data_auto ("coin_sig",
- &coin_sig));
+ &coin->coin_sig));
GNUNET_assert (0 ==
json_array_append_new (deposit_arr,
jdeposit));
diff --git a/src/lib/exchange_api_recoup.c b/src/lib/exchange_api_recoup.c
index 5c197e2f6..49fb6fd55 100644
--- a/src/lib/exchange_api_recoup.c
+++ b/src/lib/exchange_api_recoup.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2017-2021 Taler Systems SA
+ Copyright (C) 2017-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -27,6 +27,7 @@
#include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h"
#include "taler_exchange_service.h"
+#include "exchange_api_common.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
#include "exchange_api_curl_defaults.h"
@@ -60,6 +61,11 @@ struct TALER_EXCHANGE_RecoupHandle
struct TALER_EXCHANGE_DenomPublicKey pk;
/**
+ * Our signature requesting the recoup.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
+ /**
* Handle for the request.
*/
struct GNUNET_CURL_Job *job;
@@ -139,8 +145,10 @@ handle_recoup_finished (void *cls,
.reply = j,
.http_status = (unsigned int) response_code
};
+ const struct TALER_EXCHANGE_Keys *keys;
ph->job = NULL;
+ keys = TALER_EXCHANGE_get_keys (ph->exchange);
switch (response_code)
{
case 0:
@@ -166,76 +174,34 @@ handle_recoup_finished (void *cls,
break;
case MHD_HTTP_CONFLICT:
{
- /* Insufficient funds, proof attached */
- json_t *history;
- struct TALER_Amount total;
- struct TALER_DenominationHashP h_denom_pub;
- const struct TALER_EXCHANGE_DenomPublicKey *dki;
- enum TALER_ErrorCode ec;
-
- dki = &ph->pk;
- history = json_object_get (j,
- "history");
+ struct TALER_Amount min_key;
+
+ hr.ec = TALER_JSON_get_error_code (j);
+ hr.hint = TALER_JSON_get_error_hint (j);
if (GNUNET_OK !=
- TALER_EXCHANGE_verify_coin_history (dki,
- dki->fees.deposit.currency,
- &ph->coin_pub,
- history,
- &h_denom_pub,
- &total))
+ TALER_EXCHANGE_get_min_denomination_ (keys,
+ &min_key))
{
- GNUNET_break_op (0);
- hr.http_status = 0;
+ GNUNET_break (0);
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ hr.http_status = 0;
+ break;
}
- else
- {
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
- }
- ec = TALER_JSON_get_error_code (j);
- switch (ec)
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_coin_conflict_ (
+ keys,
+ j,
+ &ph->pk,
+ &ph->coin_pub,
+ &ph->coin_sig,
+ &min_key))
{
- case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
- if (0 > TALER_amount_cmp (&total,
- &dki->value))
- {
- /* recoup MAY have still been possible */
- /* FIXME: This code may falsely complain, as we do not
- know that the smallest denomination offered by the
- exchange is here. We should look at the key
- structure of ph->exchange, and find the smallest
- _currently withdrawable_ denomination and check
- if the value remaining would suffice... */
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- break;
- }
- break;
- case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
- if (0 == GNUNET_memcmp (&ph->pk.h_key,
- &h_denom_pub))
- {
- /* invalid proof provided */
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- break;
- }
- /* valid error from exchange */
- break;
- default:
- GNUNET_break_op (0);
- hr.http_status = 0;
+ GNUNET_break (0);
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ hr.http_status = 0;
break;
}
- ph->cb (ph->cb_cls,
- &hr,
- NULL);
- TALER_EXCHANGE_recoup_cancel (ph);
- return;
+ break;
}
case MHD_HTTP_FORBIDDEN:
/* Nothing really to verify, exchange says one of the signatures is
@@ -291,8 +257,6 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
{
struct TALER_EXCHANGE_RecoupHandle *ph;
struct GNUNET_CURL_Context *ctx;
- struct TALER_CoinSpendSignatureP coin_sig;
- struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_DenominationHashP h_denom_pub;
json_t *recoup_obj;
CURL *eh;
@@ -302,7 +266,7 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_assert (GNUNET_YES ==
TEAH_handle_is_ready (exchange));
-
+ ph = GNUNET_new (struct TALER_EXCHANGE_RecoupHandle);
TALER_planchet_setup_coin_priv (ps,
exchange_vals,
&coin_priv);
@@ -310,13 +274,13 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
exchange_vals,
&bks);
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
+ &ph->coin_pub.eddsa_pub);
TALER_denom_pub_hash (&pk->key,
&h_denom_pub);
TALER_wallet_recoup_sign (&h_denom_pub,
&bks,
&coin_priv,
- &coin_sig);
+ &ph->coin_sig);
recoup_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
&h_denom_pub),
@@ -325,7 +289,7 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
TALER_JSON_pack_exchange_withdraw_values ("ewv",
exchange_vals),
GNUNET_JSON_pack_data_auto ("coin_sig",
- &coin_sig),
+ &ph->coin_sig),
GNUNET_JSON_pack_data_auto ("coin_blind_key_secret",
&bks));
if (TALER_DENOMINATION_CS == denom_sig->cipher)
@@ -352,7 +316,7 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
char *end;
end = GNUNET_STRINGS_data_to_string (
- &coin_pub,
+ &ph->coin_pub,
sizeof (struct TALER_CoinSpendPublicKeyP),
pub_str,
sizeof (pub_str));
@@ -363,8 +327,6 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
pub_str);
}
- ph = GNUNET_new (struct TALER_EXCHANGE_RecoupHandle);
- ph->coin_pub = coin_pub;
ph->exchange = exchange;
ph->pk = *pk;
memset (&ph->pk.key,
diff --git a/src/lib/exchange_api_recoup_refresh.c b/src/lib/exchange_api_recoup_refresh.c
index 8ae8f9764..d551df743 100644
--- a/src/lib/exchange_api_recoup_refresh.c
+++ b/src/lib/exchange_api_recoup_refresh.c
@@ -27,6 +27,7 @@
#include <gnunet/gnunet_curl_lib.h>
#include "taler_json_lib.h"
#include "taler_exchange_service.h"
+#include "exchange_api_common.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
#include "exchange_api_curl_defaults.h"
@@ -79,6 +80,11 @@ struct TALER_EXCHANGE_RecoupRefreshHandle
*/
struct TALER_CoinSpendPublicKeyP coin_pub;
+ /**
+ * Signature affirming the recoup-refresh operation.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
};
@@ -140,8 +146,10 @@ handle_recoup_refresh_finished (void *cls,
.reply = j,
.http_status = (unsigned int) response_code
};
+ const struct TALER_EXCHANGE_Keys *keys;
ph->job = NULL;
+ keys = TALER_EXCHANGE_get_keys (ph->exchange);
switch (response_code)
{
case 0:
@@ -180,76 +188,34 @@ handle_recoup_refresh_finished (void *cls,
break;
case MHD_HTTP_CONFLICT:
{
- /* Insufficient funds, proof attached */
- json_t *history;
- struct TALER_Amount total;
- struct TALER_DenominationHashP h_denom_pub;
- const struct TALER_EXCHANGE_DenomPublicKey *dki;
- enum TALER_ErrorCode ec;
-
- dki = &ph->pk;
- history = json_object_get (j,
- "history");
+ struct TALER_Amount min_key;
+
+ hr.ec = TALER_JSON_get_error_code (j);
+ hr.hint = TALER_JSON_get_error_hint (j);
if (GNUNET_OK !=
- TALER_EXCHANGE_verify_coin_history (dki,
- dki->fees.deposit.currency,
- &ph->coin_pub,
- history,
- &h_denom_pub,
- &total))
+ TALER_EXCHANGE_get_min_denomination_ (keys,
+ &min_key))
{
- GNUNET_break_op (0);
- hr.http_status = 0;
+ GNUNET_break (0);
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ hr.http_status = 0;
+ break;
}
- else
- {
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
- }
- ec = TALER_JSON_get_error_code (j);
- switch (ec)
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_check_coin_conflict_ (
+ keys,
+ j,
+ &ph->pk,
+ &ph->coin_pub,
+ &ph->coin_sig,
+ &min_key))
{
- case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
- if (0 > TALER_amount_cmp (&total,
- &dki->value))
- {
- /* recoup MAY have still been possible */
- /* FIXME: This code may falsely complain, as we do not
- know that the smallest denomination offered by the
- exchange is here. We should look at the key
- structure of ph->exchange, and find the smallest
- _currently withdrawable_ denomination and check
- if the value remaining would suffice... */
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- break;
- }
- break;
- case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
- if (0 == GNUNET_memcmp (&ph->pk.h_key,
- &h_denom_pub))
- {
- /* invalid proof provided */
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- break;
- }
- /* valid error from exchange */
- break;
- default:
- GNUNET_break_op (0);
- hr.http_status = 0;
+ GNUNET_break (0);
hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ hr.http_status = 0;
break;
}
- ph->cb (ph->cb_cls,
- &hr,
- NULL);
- TALER_EXCHANGE_recoup_refresh_cancel (ph);
- return;
+ break;
}
case MHD_HTTP_GONE:
/* Kind of normal: the money was already sent to the merchant
@@ -295,8 +261,6 @@ TALER_EXCHANGE_recoup_refresh (
{
struct TALER_EXCHANGE_RecoupRefreshHandle *ph;
struct GNUNET_CURL_Context *ctx;
- struct TALER_CoinSpendSignatureP coin_sig;
- struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_DenominationHashP h_denom_pub;
json_t *recoup_obj;
CURL *eh;
@@ -307,6 +271,14 @@ TALER_EXCHANGE_recoup_refresh (
GNUNET_assert (NULL != recoup_cb);
GNUNET_assert (GNUNET_YES ==
TEAH_handle_is_ready (exchange));
+ ph = GNUNET_new (struct TALER_EXCHANGE_RecoupRefreshHandle);
+ ph->exchange = exchange;
+ ph->pk = *pk;
+ memset (&ph->pk.key,
+ 0,
+ sizeof (ph->pk.key)); /* zero out, as lifetime cannot be warranted */
+ ph->cb = recoup_cb;
+ ph->cb_cls = recoup_cb_cls;
TALER_planchet_setup_coin_priv (ps,
exchange_vals,
&coin_priv);
@@ -314,13 +286,13 @@ TALER_EXCHANGE_recoup_refresh (
exchange_vals,
&bks);
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
+ &ph->coin_pub.eddsa_pub);
TALER_denom_pub_hash (&pk->key,
&h_denom_pub);
TALER_wallet_recoup_refresh_sign (&h_denom_pub,
&bks,
&coin_priv,
- &coin_sig);
+ &ph->coin_sig);
recoup_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
&h_denom_pub),
@@ -329,7 +301,7 @@ TALER_EXCHANGE_recoup_refresh (
TALER_JSON_pack_exchange_withdraw_values ("ewv",
exchange_vals),
GNUNET_JSON_pack_data_auto ("coin_sig",
- &coin_sig),
+ &ph->coin_sig),
GNUNET_JSON_pack_data_auto ("coin_blind_key_secret",
&bks));
@@ -358,7 +330,7 @@ TALER_EXCHANGE_recoup_refresh (
char *end;
end = GNUNET_STRINGS_data_to_string (
- &coin_pub,
+ &ph->coin_pub,
sizeof (struct TALER_CoinSpendPublicKeyP),
pub_str,
sizeof (pub_str));
@@ -369,15 +341,6 @@ TALER_EXCHANGE_recoup_refresh (
pub_str);
}
- ph = GNUNET_new (struct TALER_EXCHANGE_RecoupRefreshHandle);
- ph->coin_pub = coin_pub;
- ph->exchange = exchange;
- ph->pk = *pk;
- memset (&ph->pk.key,
- 0,
- sizeof (ph->pk.key)); /* zero out, as lifetime cannot be warranted */
- ph->cb = recoup_cb;
- ph->cb_cls = recoup_cb_cls;
ph->url = TEAH_path_to_url (exchange,
arg_str);
if (NULL == ph->url)
diff --git a/src/lib/exchange_api_refund.c b/src/lib/exchange_api_refund.c
index 004661b00..09a21883d 100644
--- a/src/lib/exchange_api_refund.c
+++ b/src/lib/exchange_api_refund.c
@@ -173,9 +173,12 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
const json_t *json)
{
json_t *history;
+ struct TALER_DenominationHashP h_denom_pub;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("history",
&history),
+ GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
+ &h_denom_pub),
GNUNET_JSON_spec_end ()
};
size_t len;
@@ -234,7 +237,6 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
struct TALER_AgeCommitmentHash h_age_commitment;
bool no_hac;
// struct TALER_ExtensionContractHashP h_extensions; // FIXME!
- struct TALER_DenominationHashP h_denom_pub;
struct GNUNET_TIME_Timestamp wallet_timestamp;
struct TALER_MerchantPublicKeyP merchant_pub;
struct GNUNET_TIME_Timestamp refund_deadline;
@@ -246,8 +248,6 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
&h_contract_terms),
GNUNET_JSON_spec_fixed_auto ("h_wire",
&h_wire),
- GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
- &h_denom_pub),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
&h_age_commitment),
@@ -429,24 +429,22 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
}
}
+ if (have_refund)
{
- if (have_refund)
+ if (0 >
+ TALER_amount_add (&rtotal,
+ &rtotal,
+ &rh->refund_amount))
{
- if (0 >
- TALER_amount_add (&rtotal,
- &rtotal,
- &rh->refund_amount))
- {
- GNUNET_break (0);
- GNUNET_JSON_parse_free (spec);
- return GNUNET_SYSERR;
- }
- }
- else
- {
- rtotal = rh->refund_amount;
+ GNUNET_break (0);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
}
}
+ else
+ {
+ rtotal = rh->refund_amount;
+ }
if (-1 == TALER_amount_cmp (&dtotal,
&rtotal))
{