summaryrefslogtreecommitdiff
path: root/src/lib/exchange_api_common.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-05-23 00:19:57 +0200
committerChristian Grothoff <christian@grothoff.org>2022-05-23 00:19:57 +0200
commit3ee8879ada5adb056884a80cdcab49ba0e233b0a (patch)
tree1b0fea370990c233220acc18eddf3c6ea49cd96c /src/lib/exchange_api_common.c
parent3599ac0ac2452fb3a9017b7aa38ef7c1122ce3bc (diff)
downloadexchange-3ee8879ada5adb056884a80cdcab49ba0e233b0a.tar.gz
exchange-3ee8879ada5adb056884a80cdcab49ba0e233b0a.tar.bz2
exchange-3ee8879ada5adb056884a80cdcab49ba0e233b0a.zip
-refactor coin history checker
Diffstat (limited to 'src/lib/exchange_api_common.c')
-rw-r--r--src/lib/exchange_api_common.c984
1 files changed, 572 insertions, 412 deletions
diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c
index 5e76bca3b..a517d844a 100644
--- a/src/lib/exchange_api_common.c
+++ b/src/lib/exchange_api_common.c
@@ -27,7 +27,7 @@
/**
- * UUID array for duplicate detection.
+ * Context for history entry helpers.
*/
struct HistoryParseContext
{
@@ -543,7 +543,7 @@ TALER_EXCHANGE_parse_reserve_history (
.reserve_pub = reserve_pub,
.uuids = uuid,
.total_in = total_in,
- .total_in = total_out
+ .total_out = total_out
};
GNUNET_assert (GNUNET_OK ==
@@ -642,7 +642,537 @@ TALER_EXCHANGE_free_reserve_history (
}
-// FIMXE: also transform with helpers...
+/**
+ * Context for coin helpers.
+ */
+struct CoinHistoryParseContext
+{
+
+ /**
+ * Denomination of the coin.
+ */
+ const struct TALER_EXCHANGE_DenomPublicKey *dk;
+
+ /**
+ * Our coin public key.
+ */
+ 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;
+
+ /**
+ * Where to sum up fees.
+ */
+ struct TALER_Amount fee;
+
+ /**
+ * Total amount encountered.
+ */
+ struct TALER_Amount *total;
+
+};
+
+
+/**
+ * Signature of functions that operate on one of
+ * the coin's history entries.
+ *
+ * @param[in,out] pc overall context
+ * @param amount main amount of this operation
+ * @param transaction JSON details for the operation
+ * @return #GNUNET_SYSERR on error,
+ * #GNUNET_OK to add, #GNUNET_NO to subtract
+ */
+typedef enum GNUNET_GenericReturnValue
+(*CoinCheckHelper)(struct CoinHistoryParseContext *pc,
+ const struct TALER_Amount *amount,
+ json_t *transaction);
+
+
+/**
+ * Handle deposit entry in the coin's history.
+ *
+ * @param[in,out] pc overall context
+ * @param amount main amount of this operation
+ * @param transaction JSON details for the operation
+ * @return #GNUNET_SYSERR on error,
+ * #GNUNET_OK to add, #GNUNET_NO to subtract
+ */
+static enum GNUNET_GenericReturnValue
+help_deposit (struct CoinHistoryParseContext *pc,
+ const struct TALER_Amount *amount,
+ json_t *transaction)
+{
+ struct TALER_MerchantWireHashP h_wire;
+ struct TALER_PrivateContractHashP h_contract_terms;
+ // struct TALER_ExtensionContractHashP h_extensions; // FIXME!
+ struct GNUNET_TIME_Timestamp wallet_timestamp;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ struct GNUNET_TIME_Timestamp refund_deadline = {0};
+ struct TALER_CoinSpendSignatureP sig;
+ struct TALER_AgeCommitmentHash hac;
+ bool no_hac;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("coin_sig",
+ &sig),
+ GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
+ &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),
+ &no_hac),
+ GNUNET_JSON_spec_timestamp ("timestamp",
+ &wallet_timestamp),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_timestamp ("refund_deadline",
+ &refund_deadline),
+ NULL),
+ TALER_JSON_spec_amount_any ("deposit_fee",
+ &pc->fee),
+ GNUNET_JSON_spec_fixed_auto ("merchant_pub",
+ &merchant_pub),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_wallet_deposit_verify (
+ amount,
+ &pc->fee,
+ &h_wire,
+ &h_contract_terms,
+ no_hac ? NULL : &hac,
+ NULL /* h_extensions! */,
+ pc->h_denom_pub,
+ wallet_timestamp,
+ &merchant_pub,
+ refund_deadline,
+ pc->coin_pub,
+ &sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (NULL != pc->dk)
+ {
+ /* check that deposit fee matches our expectations from /keys! */
+ if ( (GNUNET_YES !=
+ TALER_amount_cmp_currency (&pc->fee,
+ &pc->dk->fees.deposit)) ||
+ (0 !=
+ TALER_amount_cmp (&pc->fee,
+ &pc->dk->fees.deposit)) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handle melt entry in the coin's history.
+ *
+ * @param[in,out] pc overall context
+ * @param amount main amount of this operation
+ * @param transaction JSON details for the operation
+ * @return #GNUNET_SYSERR on error,
+ * #GNUNET_OK to add, #GNUNET_NO to subtract
+ */
+static enum GNUNET_GenericReturnValue
+help_melt (struct CoinHistoryParseContext *pc,
+ const struct TALER_Amount *amount,
+ json_t *transaction)
+{
+ struct TALER_CoinSpendSignatureP sig;
+ struct TALER_RefreshCommitmentP rc;
+ struct TALER_AgeCommitmentHash h_age_commitment;
+ bool no_hac;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("coin_sig",
+ &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),
+ &no_hac),
+ TALER_JSON_spec_amount_any ("melt_fee",
+ &pc->fee),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ if (NULL != pc->dk)
+ {
+ /* check that melt fee matches our expectations from /keys! */
+ if ( (GNUNET_YES !=
+ TALER_amount_cmp_currency (&pc->fee,
+ &pc->dk->fees.refresh)) ||
+ (0 !=
+ TALER_amount_cmp (&pc->fee,
+ &pc->dk->fees.refresh)) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+
+ if (GNUNET_OK !=
+ TALER_wallet_melt_verify (
+ amount,
+ &pc->fee,
+ &rc,
+ pc->h_denom_pub,
+ no_hac
+ ? NULL
+ : &h_age_commitment,
+ pc->coin_pub,
+ &sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handle refund entry in the coin's history.
+ *
+ * @param[in,out] pc overall context
+ * @param amount main amount of this operation
+ * @param transaction JSON details for the operation
+ * @return #GNUNET_SYSERR on error,
+ * #GNUNET_OK to add, #GNUNET_NO to subtract
+ */
+static enum GNUNET_GenericReturnValue
+help_refund (struct CoinHistoryParseContext *pc,
+ const struct TALER_Amount *amount,
+ json_t *transaction)
+{
+ struct TALER_PrivateContractHashP h_contract_terms;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ struct TALER_MerchantSignatureP sig;
+ struct TALER_Amount refund_fee;
+ struct TALER_Amount sig_amount;
+ uint64_t rtransaction_id;
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount_any ("refund_fee",
+ &refund_fee),
+ GNUNET_JSON_spec_fixed_auto ("merchant_sig",
+ &sig),
+ GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
+ &h_contract_terms),
+ GNUNET_JSON_spec_fixed_auto ("merchant_pub",
+ &merchant_pub),
+ GNUNET_JSON_spec_uint64 ("rtransaction_id",
+ &rtransaction_id),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (0 >
+ TALER_amount_add (&sig_amount,
+ &refund_fee,
+ amount))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_merchant_refund_verify (pc->coin_pub,
+ &h_contract_terms,
+ rtransaction_id,
+ &sig_amount,
+ &merchant_pub,
+ &sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ /* NOTE: theoretically, we could also check that the given
+ merchant_pub and h_contract_terms appear in the
+ history under deposits. However, there is really no benefit
+ for the exchange to lie here, so not checking is probably OK
+ (an auditor ought to check, though). Then again, we similarly
+ had no reason to check the merchant's signature (other than a
+ well-formendess check). */
+
+ /* check that refund fee matches our expectations from /keys! */
+ if (NULL != pc->dk)
+ {
+ if ( (GNUNET_YES !=
+ TALER_amount_cmp_currency (&refund_fee,
+ &pc->dk->fees.refund)) ||
+ (0 !=
+ TALER_amount_cmp (&refund_fee,
+ &pc->dk->fees.refund)) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * Handle recoup entry in the coin's history.
+ *
+ * @param[in,out] pc overall context
+ * @param amount main amount of this operation
+ * @param transaction JSON details for the operation
+ * @return #GNUNET_SYSERR on error,
+ * #GNUNET_OK to add, #GNUNET_NO to subtract
+ */
+static enum GNUNET_GenericReturnValue
+help_recoup (struct CoinHistoryParseContext *pc,
+ const struct TALER_Amount *amount,
+ json_t *transaction)
+{
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct GNUNET_TIME_Timestamp timestamp;
+ union TALER_DenominationBlindingKeyP coin_bks;
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct TALER_CoinSpendSignatureP coin_sig;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &exchange_pub),
+ GNUNET_JSON_spec_fixed_auto ("reserve_pub",
+ &reserve_pub),
+ GNUNET_JSON_spec_fixed_auto ("coin_sig",
+ &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 ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_exchange_online_confirm_recoup_verify (
+ timestamp,
+ amount,
+ pc->coin_pub,
+ &reserve_pub,
+ &exchange_pub,
+ &exchange_sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_wallet_recoup_verify (pc->h_denom_pub,
+ &coin_bks,
+ pc->coin_pub,
+ &coin_sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handle recoup-refresh entry in the coin's history.
+ *
+ * @param[in,out] pc overall context
+ * @param amount main amount of this operation
+ * @param transaction JSON details for the operation
+ * @return #GNUNET_SYSERR on error,
+ * #GNUNET_OK to add, #GNUNET_NO to subtract
+ */
+static enum GNUNET_GenericReturnValue
+help_recoup_refresh (struct CoinHistoryParseContext *pc,
+ const struct TALER_Amount *amount,
+ json_t *transaction)
+{
+ /* This is the coin that was subjected to a recoup,
+ the value being credited to the old coin. */
+ struct TALER_CoinSpendPublicKeyP old_coin_pub;
+ union TALER_DenominationBlindingKeyP coin_bks;
+ struct GNUNET_TIME_Timestamp timestamp;
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct TALER_CoinSpendSignatureP coin_sig;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &exchange_pub),
+ GNUNET_JSON_spec_fixed_auto ("coin_sig",
+ &coin_sig),
+ GNUNET_JSON_spec_fixed_auto ("old_coin_pub",
+ &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 ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_exchange_online_confirm_recoup_refresh_verify (
+ timestamp,
+ amount,
+ pc->coin_pub,
+ &old_coin_pub,
+ &exchange_pub,
+ &exchange_sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_wallet_recoup_verify (pc->h_denom_pub,
+ &coin_bks,
+ pc->coin_pub,
+ &coin_sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handle old coin recoup entry in the coin's history.
+ *
+ * @param[in,out] pc overall context
+ * @param amount main amount of this operation
+ * @param transaction JSON details for the operation
+ * @return #GNUNET_SYSERR on error,
+ * #GNUNET_OK to add, #GNUNET_NO to subtract
+ */
+static enum GNUNET_GenericReturnValue
+help_old_coin_recoup (struct CoinHistoryParseContext *pc,
+ const struct TALER_Amount *amount,
+ json_t *transaction)
+{
+ /* This is the coin that was credited in a recoup,
+ the value being credited to the this coin. */
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct TALER_CoinSpendPublicKeyP new_coin_pub;
+ struct GNUNET_TIME_Timestamp timestamp;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &exchange_pub),
+ GNUNET_JSON_spec_fixed_auto ("coin_pub",
+ &new_coin_pub),
+ GNUNET_JSON_spec_timestamp ("timestamp",
+ &timestamp),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_exchange_online_confirm_recoup_refresh_verify (
+ timestamp,
+ amount,
+ &new_coin_pub,
+ pc->coin_pub,
+ &exchange_pub,
+ &exchange_sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * Handle purse deposit entry in the coin's history.
+ *
+ * @param[in,out] pc overall context
+ * @param amount main amount of this operation
+ * @param transaction JSON details for the operation
+ * @return #GNUNET_SYSERR on error,
+ * #GNUNET_OK to add, #GNUNET_NO to subtract
+ */
+static enum GNUNET_GenericReturnValue
+help_purse_deposit (struct CoinHistoryParseContext *pc,
+ const struct TALER_Amount *amount,
+ json_t *transaction)
+{
+ GNUNET_break (0); // FIXME: implement!
+ return GNUNET_SYSERR;
+}
+
+
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_verify_coin_history (
const struct TALER_EXCHANGE_DenomPublicKey *dk,
@@ -652,9 +1182,27 @@ TALER_EXCHANGE_verify_coin_history (
struct TALER_DenominationHashP *h_denom_pub,
struct TALER_Amount *total)
{
+ const struct
+ {
+ const char *type;
+ CoinCheckHelper helper;
+ } map[] = {
+ { "DEPOSIT", &help_deposit },
+ { "MELT", &help_melt },
+ { "REFUND", &help_refund },
+ { "RECOUP", &help_recoup },
+ { "RECOUP-REFRESH", &help_recoup_refresh },
+ { "OLD-COIN-RECOUP", &help_old_coin_recoup },
+ { "PURSE_DEPOSIT", &help_purse_deposit },
+ { NULL, NULL }
+ };
+ struct CoinHistoryParseContext pc = {
+ .dk = dk,
+ .coin_pub = coin_pub,
+ .total = total,
+ .h_denom_pub = h_denom_pub
+ };
size_t len;
- struct TALER_Amount rtotal;
- struct TALER_Amount fee;
if (NULL == history)
{
@@ -672,10 +1220,10 @@ TALER_EXCHANGE_verify_coin_history (
total));
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (currency,
- &rtotal));
+ &pc.rtotal));
for (size_t off = 0; off<len; off++)
{
- int add;
+ enum GNUNET_GenericReturnValue add;
json_t *transaction;
struct TALER_Amount amount;
const char *type;
@@ -699,416 +1247,33 @@ TALER_EXCHANGE_verify_coin_history (
}
if (GNUNET_YES !=
TALER_amount_cmp_currency (&amount,
- &rtotal))
+ &pc.rtotal))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
add = GNUNET_SYSERR;
- if (0 == strcasecmp (type,
- "DEPOSIT"))
- {
- struct TALER_MerchantWireHashP h_wire;
- struct TALER_PrivateContractHashP h_contract_terms;
- // struct TALER_ExtensionContractHashP h_extensions; // FIXME!
- struct GNUNET_TIME_Timestamp wallet_timestamp;
- struct TALER_MerchantPublicKeyP merchant_pub;
- struct GNUNET_TIME_Timestamp refund_deadline = {0};
- struct TALER_CoinSpendSignatureP sig;
- struct TALER_AgeCommitmentHash hac;
- bool no_hac;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("coin_sig",
- &sig),
- GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
- &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",
- &hac),
- &no_hac),
- GNUNET_JSON_spec_timestamp ("timestamp",
- &wallet_timestamp),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_timestamp ("refund_deadline",
- &refund_deadline),
- NULL),
- TALER_JSON_spec_amount_any ("deposit_fee",
- &fee),
- GNUNET_JSON_spec_fixed_auto ("merchant_pub",
- &merchant_pub),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (transaction,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_wallet_deposit_verify (
- &amount,
- &fee,
- &h_wire,
- &h_contract_terms,
- no_hac ? NULL : &hac,
- NULL /* h_extensions! */,
- h_denom_pub,
- wallet_timestamp,
- &merchant_pub,
- refund_deadline,
- coin_pub,
- &sig))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (NULL != dk)
- {
- /* check that deposit fee matches our expectations from /keys! */
- if ( (GNUNET_YES !=
- TALER_amount_cmp_currency (&fee,
- &dk->fees.deposit)) ||
- (0 !=
- TALER_amount_cmp (&fee,
- &dk->fees.deposit)) )
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- }
- add = GNUNET_YES;
- }
- else if (0 == strcasecmp (type,
- "MELT"))
- {
- struct TALER_CoinSpendSignatureP sig;
- struct TALER_RefreshCommitmentP rc;
- struct TALER_AgeCommitmentHash h_age_commitment;
- bool no_hac;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("coin_sig",
- &sig),
- GNUNET_JSON_spec_fixed_auto ("rc",
- &rc),
- 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),
- &no_hac),
- TALER_JSON_spec_amount_any ("melt_fee",
- &fee),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (transaction,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- if (NULL != dk)
- {
- /* check that melt fee matches our expectations from /keys! */
- if ( (GNUNET_YES !=
- TALER_amount_cmp_currency (&fee,
- &dk->fees.refresh)) ||
- (0 !=
- TALER_amount_cmp (&fee,
- &dk->fees.refresh)) )
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- }
-
- if (GNUNET_OK !=
- TALER_wallet_melt_verify (
- &amount,
- &fee,
- &rc,
- h_denom_pub,
- no_hac
- ? NULL
- : &h_age_commitment,
- coin_pub,
- &sig))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- add = GNUNET_YES;
- }
- else if (0 == strcasecmp (type,
- "REFUND"))
- {
- struct TALER_PrivateContractHashP h_contract_terms;
- struct TALER_MerchantPublicKeyP merchant_pub;
- struct TALER_MerchantSignatureP sig;
- struct TALER_Amount refund_fee;
- struct TALER_Amount sig_amount;
- uint64_t rtransaction_id;
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount_any ("refund_fee",
- &refund_fee),
- GNUNET_JSON_spec_fixed_auto ("merchant_sig",
- &sig),
- GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
- &h_contract_terms),
- GNUNET_JSON_spec_fixed_auto ("merchant_pub",
- &merchant_pub),
- GNUNET_JSON_spec_uint64 ("rtransaction_id",
- &rtransaction_id),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (transaction,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (0 >
- TALER_amount_add (&sig_amount,
- &refund_fee,
- &amount))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_merchant_refund_verify (coin_pub,
- &h_contract_terms,
- rtransaction_id,
- &sig_amount,
- &merchant_pub,
- &sig))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- /* NOTE: theoretically, we could also check that the given
- merchant_pub and h_contract_terms appear in the
- history under deposits. However, there is really no benefit
- for the exchange to lie here, so not checking is probably OK
- (an auditor ought to check, though). Then again, we similarly
- had no reason to check the merchant's signature (other than a
- well-formendess check). */
-
- /* check that refund fee matches our expectations from /keys! */
- if (NULL != dk)
- {
- if ( (GNUNET_YES !=
- TALER_amount_cmp_currency (&refund_fee,
- &dk->fees.refund)) ||
- (0 !=
- TALER_amount_cmp (&refund_fee,
- &dk->fees.refund)) )
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- }
- add = GNUNET_NO;
- }
- else if (0 == strcasecmp (type,
- "RECOUP"))
- {
- struct TALER_ReservePublicKeyP reserve_pub;
- struct GNUNET_TIME_Timestamp timestamp;
- union TALER_DenominationBlindingKeyP coin_bks;
- struct TALER_ExchangePublicKeyP exchange_pub;
- struct TALER_ExchangeSignatureP exchange_sig;
- struct TALER_CoinSpendSignatureP coin_sig;
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount_any ("amount",
- &amount),
- GNUNET_JSON_spec_fixed_auto ("exchange_sig",
- &exchange_sig),
- GNUNET_JSON_spec_fixed_auto ("exchange_pub",
- &exchange_pub),
- GNUNET_JSON_spec_fixed_auto ("reserve_pub",
- &reserve_pub),
- GNUNET_JSON_spec_fixed_auto ("coin_sig",
- &coin_sig),
- GNUNET_JSON_spec_fixed_auto ("coin_blind",
- &coin_bks),
- GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
- h_denom_pub),
- GNUNET_JSON_spec_timestamp ("timestamp",
- &timestamp),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (transaction,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_exchange_online_confirm_recoup_verify (
- timestamp,
- &amount,
- coin_pub,
- &reserve_pub,
- &exchange_pub,
- &exchange_sig))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_wallet_recoup_verify (h_denom_pub,
- &coin_bks,
- coin_pub,
- &coin_sig))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- add = GNUNET_YES;
- }
- else if (0 == strcasecmp (type,
- "RECOUP-REFRESH"))
- {
- /* This is the coin that was subjected to a recoup,
- the value being credited to the old coin. */
- struct TALER_CoinSpendPublicKeyP old_coin_pub;
- union TALER_DenominationBlindingKeyP coin_bks;
- struct TALER_Amount amount;
- struct GNUNET_TIME_Timestamp timestamp;
- struct TALER_ExchangePublicKeyP exchange_pub;
- struct TALER_ExchangeSignatureP exchange_sig;
- struct TALER_CoinSpendSignatureP coin_sig;
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount_any ("amount",
- &amount),
- GNUNET_JSON_spec_fixed_auto ("exchange_sig",
- &exchange_sig),
- GNUNET_JSON_spec_fixed_auto ("exchange_pub",
- &exchange_pub),
- GNUNET_JSON_spec_fixed_auto ("coin_sig",
- &coin_sig),
- GNUNET_JSON_spec_fixed_auto ("old_coin_pub",
- &old_coin_pub),
- GNUNET_JSON_spec_fixed_auto ("coin_blind",
- &coin_bks),
- GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
- h_denom_pub),
- GNUNET_JSON_spec_timestamp ("timestamp",
- &timestamp),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (transaction,
- spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_exchange_online_confirm_recoup_refresh_verify (
- timestamp,
- &amount,
- coin_pub,
- &old_coin_pub,
- &exchange_pub,
- &exchange_sig))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_wallet_recoup_verify (h_denom_pub,
- &coin_bks,
- coin_pub,
- &coin_sig))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- add = GNUNET_YES;
- }
- else if (0 == strcasecmp (type,
- "OLD-COIN-RECOUP"))
+ for (unsigned int i = 0; NULL != map[i].type; i++)
{
- /* This is the coin that was credited in a recoup,
- the value being credited to the this coin. */
- struct TALER_ExchangePublicKeyP exchange_pub;
- struct TALER_ExchangeSignatureP exchange_sig;
- struct TALER_CoinSpendPublicKeyP new_coin_pub;
- struct GNUNET_TIME_Timestamp timestamp;
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount_any ("amount",
- &amount),
- GNUNET_JSON_spec_fixed_auto ("exchange_sig",
- &exchange_sig),
- GNUNET_JSON_spec_fixed_auto ("exchange_pub",
- &exchange_pub),
- GNUNET_JSON_spec_fixed_auto ("coin_pub",
- &new_coin_pub),
- GNUNET_JSON_spec_timestamp ("timestamp",
- &timestamp),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (transaction,
- spec,
- NULL, NULL))
+ if (0 == strcasecmp (type,
+ map[i].type))
{
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_exchange_online_confirm_recoup_refresh_verify (
- timestamp,
- &amount,
- &new_coin_pub,
- coin_pub,
- &exchange_pub,
- &exchange_sig))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
+ add = map[i].helper (&pc,
+ &amount,
+ transaction);
+ break;
}
- add = GNUNET_NO;
- }
- else if (0 == strcasecmp (type,
- "LOCK_NONCE"))
- {
- GNUNET_break (0); // FIXME: implement!
}
- else
+ switch (add)
{
- /* signature not supported, new version on server? */
+ case GNUNET_SYSERR:
+ /* entry type not supported, new version on server? */
GNUNET_break_op (0);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected type `%s' in response\n",
type);
- GNUNET_assert (GNUNET_SYSERR == add);
return GNUNET_SYSERR;
- }
-
- if (GNUNET_YES == add)
- {
+ case GNUNET_YES:
/* This amount should be added to the total */
if (0 >
TALER_amount_add (total,
@@ -1119,35 +1284,30 @@ TALER_EXCHANGE_verify_coin_history (
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- }
- else
- {
+ case GNUNET_NO:
/* This amount should be subtracted from the total.
However, for the implementation, we first *add* up all of
these negative amounts, as we might get refunds before
deposits from a semi-evil exchange. Then, at the end, we do
the subtraction by calculating "total = total - rtotal" */
- GNUNET_assert (GNUNET_NO == add);
if (0 >
- TALER_amount_add (&rtotal,
- &rtotal,
+ TALER_amount_add (&pc.rtotal,
+ &pc.rtotal,
&amount))
{
/* overflow in refund history? inconceivable! Bad exchange! */
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
-
- }
+ } /* end of switch(add) */
}
-
/* Finally, subtract 'rtotal' from total to handle the subtractions */
if (0 >
TALER_amount_subtract (total,
total,
- &rtotal))
+ &pc.rtotal))
{
/* underflow in history? inconceivable! Bad exchange! */
GNUNET_break_op (0);