diff options
Diffstat (limited to 'src/auditor/taler-helper-auditor-coins.c')
-rw-r--r-- | src/auditor/taler-helper-auditor-coins.c | 2398 |
1 files changed, 1344 insertions, 1054 deletions
diff --git a/src/auditor/taler-helper-auditor-coins.c b/src/auditor/taler-helper-auditor-coins.c index fb50c8dbf..f88f39eaf 100644 --- a/src/auditor/taler-helper-auditor-coins.c +++ b/src/auditor/taler-helper-auditor-coins.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2016-2020 Taler Systems SA + Copyright (C) 2016-2024 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero Public License as published by the Free Software @@ -17,9 +17,6 @@ * @file auditor/taler-helper-auditor-coins.c * @brief audits coins in an exchange database. * @author Christian Grothoff - * - * UNDECIDED: - * - do we care about checking the 'done' flag in deposit_cb? */ #include "platform.h" #include <gnunet/gnunet_util_lib.h> @@ -48,14 +45,37 @@ static int global_ret; /** - * Checkpointing our progress for coins. + * Run in test mode. Exit when idle instead of + * going to sleep and waiting for more work. + * + * FIXME: not yet implemented! */ -static struct TALER_AUDITORDB_ProgressPointCoin ppc; +static int test_mode; /** * Checkpointing our progress for coins. */ -static struct TALER_AUDITORDB_ProgressPointCoin ppc_start; +static TALER_ARL_DEF_PP (coins_withdraw_serial_id); +static TALER_ARL_DEF_PP (coins_deposit_serial_id); +static TALER_ARL_DEF_PP (coins_melt_serial_id); +static TALER_ARL_DEF_PP (coins_refund_serial_id); +static TALER_ARL_DEF_PP (coins_recoup_serial_id); +static TALER_ARL_DEF_PP (coins_recoup_refresh_serial_id); +static TALER_ARL_DEF_PP (coins_purse_deposits_serial_id); +static TALER_ARL_DEF_PP (coins_purse_refunds_serial_id); + + +/** + * Global coin balance sheet (for coins). + */ +static TALER_ARL_DEF_AB (coin_balance_risk); +static TALER_ARL_DEF_AB (total_escrowed); +static TALER_ARL_DEF_AB (coin_irregular_loss); +static TALER_ARL_DEF_AB (coin_melt_fee_revenue); +static TALER_ARL_DEF_AB (coin_deposit_fee_revenue); +static TALER_ARL_DEF_AB (coin_refund_fee_revenue); +static TALER_ARL_DEF_AB (total_recoup_loss); + /** * Array of reports about denomination keys with an @@ -70,11 +90,16 @@ static json_t *report_emergencies; static json_t *report_emergencies_by_count; /** - * Array of reports about row inconsitencies. + * Array of reports about row inconsistencies. */ static json_t *report_row_inconsistencies; /** + * Array of reports about denominations not counter-signed by the auditor. + */ +static json_t *report_denominations_without_sigs; + +/** * Report about amount calculation differences (causing profit * or loss at the exchange). */ @@ -110,40 +135,6 @@ static struct TALER_Amount reported_emergency_loss; */ static struct TALER_Amount reported_emergency_loss_by_count; -/** - * Expected balance in the escrow account. - */ -static struct TALER_Amount total_escrow_balance; - -/** - * Active risk exposure. - */ -static struct TALER_Amount total_risk; - -/** - * Actualized risk (= loss) from recoups. - */ -static struct TALER_Amount total_recoup_loss; - -/** - * Recoups we made on denominations that were not revoked (!?). - */ -static struct TALER_Amount total_irregular_recoups; - -/** - * Total deposit fees earned. - */ -static struct TALER_Amount total_deposit_fee_income; - -/** - * Total melt fees earned. - */ -static struct TALER_Amount total_melt_fee_income; - -/** - * Total refund fees earned. - */ -static struct TALER_Amount total_refund_fee_income; /** * Array of reports about coin operations with bad signatures. @@ -151,15 +142,10 @@ static struct TALER_Amount total_refund_fee_income; static json_t *report_bad_sig_losses; /** - * Total amount lost by operations for which signatures were invalid. - */ -static struct TALER_Amount total_bad_sig_loss; - -/** * Array of refresh transactions where the /refresh/reveal has not yet * happened (and may of course never happen). */ -static json_t *report_refreshs_hanging; +static json_t *report_refreshes_hanging; /** * Total amount lost by operations for which signatures were invalid. @@ -188,6 +174,11 @@ struct CoinHistory */ static struct CoinHistory coin_histories[MAX_COIN_HISTORIES]; +/** + * Should we run checks that only work for exchange-internal audits? + */ +static int internal_checks; + /** * Return the index we should use for @a coin_pub in #coin_histories. @@ -200,9 +191,9 @@ coin_history_index (const struct TALER_CoinSpendPublicKeyP *coin_pub) { uint32_t i; - memcpy (&i, - coin_pub, - sizeof (i)); + GNUNET_memcpy (&i, + coin_pub, + sizeof (i)); return i % MAX_COIN_HISTORIES; } @@ -238,8 +229,9 @@ get_cached_history (const struct TALER_CoinSpendPublicKeyP *coin_pub) { unsigned int i = coin_history_index (coin_pub); - if (0 == GNUNET_memcmp (coin_pub, - &coin_histories[i].coin_pub)) + if (0 == + GNUNET_memcmp (coin_pub, + &coin_histories[i].coin_pub)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found verification of %s in cache\n", @@ -266,38 +258,35 @@ get_cached_history (const struct TALER_CoinSpendPublicKeyP *coin_pub) */ static void report_emergency_by_amount ( - const struct TALER_DenominationKeyValidityPS *issue, + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue, const struct TALER_Amount *risk, const struct TALER_Amount *loss) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reporting emergency on denomination `%s' over loss of %s\n", - GNUNET_h2s (&issue->denom_hash), + GNUNET_h2s (&issue->denom_hash.hash), TALER_amount2s (loss)); - TALER_ARL_report (report_emergencies, - json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}", - "denompub_hash", - GNUNET_JSON_from_data_auto (&issue->denom_hash), - "denom_risk", - TALER_JSON_from_amount (risk), - "denom_loss", - TALER_JSON_from_amount (loss), - "start", - TALER_ARL_json_from_time_abs_nbo ( - issue->start), - "deposit_end", - TALER_ARL_json_from_time_abs_nbo ( - issue->expire_deposit), - "value", - TALER_JSON_from_amount_nbo (&issue->value))); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&reported_emergency_risk_by_amount, - &reported_emergency_risk_by_amount, - risk)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&reported_emergency_loss, - &reported_emergency_loss, - loss)); + TALER_ARL_report ( + report_emergencies, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("denompub_hash", + &issue->denom_hash), + TALER_JSON_pack_amount ("denom_risk", + risk), + TALER_JSON_pack_amount ("denom_loss", + loss), + TALER_JSON_pack_time_abs_human ("start", + issue->start.abs_time), + TALER_JSON_pack_time_abs_human ("deposit_end", + issue->expire_deposit.abs_time), + TALER_JSON_pack_amount ("value", + &issue->value))); + TALER_ARL_amount_add (&reported_emergency_risk_by_amount, + &reported_emergency_risk_by_amount, + risk); + TALER_ARL_amount_add (&reported_emergency_loss, + &reported_emergency_loss, + loss); } @@ -317,43 +306,35 @@ report_emergency_by_amount ( */ static void report_emergency_by_count ( - const struct TALER_DenominationKeyValidityPS *issue, + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue, uint64_t num_issued, uint64_t num_known, const struct TALER_Amount *risk) { - struct TALER_Amount denom_value; - - TALER_ARL_report (report_emergencies_by_count, - json_pack ("{s:o, s:I, s:I, s:o, s:o, s:o, s:o}", - "denompub_hash", - GNUNET_JSON_from_data_auto (&issue->denom_hash), - "num_issued", - (json_int_t) num_issued, - "num_known", - (json_int_t) num_known, - "denom_risk", - TALER_JSON_from_amount (risk), - "start", - TALER_ARL_json_from_time_abs_nbo ( - issue->start), - "deposit_end", - TALER_ARL_json_from_time_abs_nbo ( - issue->expire_deposit), - "value", - TALER_JSON_from_amount_nbo (&issue->value))); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&reported_emergency_risk_by_count, - &reported_emergency_risk_by_count, - risk)); - TALER_amount_ntoh (&denom_value, - &issue->value); + TALER_ARL_report ( + report_emergencies_by_count, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("denompub_hash", + &issue->denom_hash), + GNUNET_JSON_pack_uint64 ("num_issued", + num_issued), + GNUNET_JSON_pack_uint64 ("num_known", + num_known), + TALER_JSON_pack_amount ("denom_risk", + risk), + TALER_JSON_pack_time_abs_human ("start", + issue->start.abs_time), + TALER_JSON_pack_time_abs_human ("deposit_end", + issue->expire_deposit.abs_time), + TALER_JSON_pack_amount ("value", + &issue->value))); + TALER_ARL_amount_add (&reported_emergency_risk_by_count, + &reported_emergency_risk_by_count, + risk); for (uint64_t i = num_issued; i<num_known; i++) - GNUNET_assert (GNUNET_OK == - TALER_amount_add ( - &reported_emergency_loss_by_count, - &reported_emergency_loss_by_count, - &denom_value)); + TALER_ARL_amount_add (&reported_emergency_loss_by_count, + &reported_emergency_loss_by_count, + &issue->value); } @@ -363,7 +344,7 @@ report_emergency_by_count ( * respect to calculations involving amounts. * * @param operation what operation had the inconsistency - * @param rowid affected row, UINT64_MAX if row is missing + * @param rowid affected row, 0 if row is missing * @param exchange amount calculated by exchange * @param auditor amount calculated by auditor * @param profitable 1 if @a exchange being larger than @a auditor is @@ -388,36 +369,38 @@ report_amount_arithmetic_inconsistency ( auditor)) { /* exchange > auditor */ - GNUNET_assert (GNUNET_OK == - TALER_amount_subtract (&delta, - exchange, - auditor)); + TALER_ARL_amount_subtract (&delta, + exchange, + auditor); } else { /* auditor < exchange */ profitable = -profitable; - GNUNET_assert (GNUNET_OK == - TALER_amount_subtract (&delta, - auditor, - exchange)); + TALER_ARL_amount_subtract (&delta, + auditor, + exchange); } TALER_ARL_report (report_amount_arithmetic_inconsistencies, - json_pack ("{s:s, s:I, s:o, s:o, s:I}", - "operation", operation, - "rowid", (json_int_t) rowid, - "exchange", TALER_JSON_from_amount (exchange), - "auditor", TALER_JSON_from_amount (auditor), - "profitable", (json_int_t) profitable)); + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("operation", + operation), + GNUNET_JSON_pack_uint64 ("rowid", + rowid), + TALER_JSON_pack_amount ("exchange", + exchange), + TALER_JSON_pack_amount ("auditor", + auditor), + GNUNET_JSON_pack_int64 ("profitable", + profitable))); if (0 != profitable) { target = (1 == profitable) ? &total_arithmetic_delta_plus : &total_arithmetic_delta_minus; - GNUNET_assert (GNUNET_OK == - TALER_amount_add (target, - target, - &delta)); + TALER_ARL_amount_add (target, + target, + &delta); } } @@ -426,7 +409,7 @@ report_amount_arithmetic_inconsistency ( * Report a (serious) inconsistency in the exchange's database. * * @param table affected table - * @param rowid affected row, UINT64_MAX if row is missing + * @param rowid affected row, 0 if row is missing * @param diagnostic message explaining the problem */ static void @@ -435,10 +418,13 @@ report_row_inconsistency (const char *table, const char *diagnostic) { TALER_ARL_report (report_row_inconsistencies, - json_pack ("{s:s, s:I, s:s}", - "table", table, - "row", (json_int_t) rowid, - "diagnostic", diagnostic)); + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("table", + table), + GNUNET_JSON_pack_uint64 ("row", + rowid), + GNUNET_JSON_pack_string ("diagnostic", + diagnostic))); } @@ -467,26 +453,37 @@ check_coin_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, struct TALER_Amount spent; struct TALER_Amount refunded; struct TALER_Amount deposit_fee; - int have_refund; + bool have_refund; + uint64_t etag_out; + + /* TODO: could use 'etag' mechanism to only fetch transactions + we did not yet process, instead of going over them + again and again. */ + { + struct TALER_Amount balance; + struct TALER_DenominationHashP h_denom_pub; - qs = TALER_ARL_edb->get_coin_transactions (TALER_ARL_edb->cls, - TALER_ARL_esession, - coin_pub, - GNUNET_YES, - &tl); + qs = TALER_ARL_edb->get_coin_transactions (TALER_ARL_edb->cls, + coin_pub, + 0, + 0, + &etag_out, + &balance, + &h_denom_pub, + &tl); + } if (0 >= qs) return qs; - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (value->currency, + TALER_amount_set_zero (value->currency, &refunded)); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (value->currency, + TALER_amount_set_zero (value->currency, &spent)); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (value->currency, + TALER_amount_set_zero (value->currency, &deposit_fee)); - have_refund = GNUNET_NO; + have_refund = false; for (struct TALER_EXCHANGEDB_TransactionList *pos = tl; NULL != pos; pos = pos->next) @@ -495,68 +492,79 @@ check_coin_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, { case TALER_EXCHANGEDB_TT_DEPOSIT: /* spent += pos->amount_with_fee */ - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&spent, - &spent, - &pos->details.deposit->amount_with_fee)); + TALER_ARL_amount_add (&spent, + &spent, + &pos->details.deposit->amount_with_fee); deposit_fee = pos->details.deposit->deposit_fee; break; case TALER_EXCHANGEDB_TT_MELT: /* spent += pos->amount_with_fee */ - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&spent, - &spent, - &pos->details.melt->amount_with_fee)); + TALER_ARL_amount_add (&spent, + &spent, + &pos->details.melt->amount_with_fee); break; case TALER_EXCHANGEDB_TT_REFUND: /* refunded += pos->refund_amount - pos->refund_fee */ - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&refunded, - &refunded, - &pos->details.refund->refund_amount)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&spent, - &spent, - &pos->details.refund->refund_fee)); - have_refund = GNUNET_YES; + TALER_ARL_amount_add (&refunded, + &refunded, + &pos->details.refund->refund_amount); + TALER_ARL_amount_add (&spent, + &spent, + &pos->details.refund->refund_fee); + have_refund = true; break; case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP: /* refunded += pos->value */ - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&refunded, - &refunded, - &pos->details.old_coin_recoup->value)); + TALER_ARL_amount_add (&refunded, + &refunded, + &pos->details.old_coin_recoup->value); break; case TALER_EXCHANGEDB_TT_RECOUP: /* spent += pos->value */ - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&spent, - &spent, - &pos->details.recoup->value)); + TALER_ARL_amount_add (&spent, + &spent, + &pos->details.recoup->value); break; case TALER_EXCHANGEDB_TT_RECOUP_REFRESH: /* spent += pos->value */ - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&spent, - &spent, - &pos->details.recoup_refresh->value)); + TALER_ARL_amount_add (&spent, + &spent, + &pos->details.recoup_refresh->value); break; - } - } + case TALER_EXCHANGEDB_TT_PURSE_DEPOSIT: + /* spent += pos->value */ + TALER_ARL_amount_add (&spent, + &spent, + &pos->details.purse_deposit->amount); + break; + case TALER_EXCHANGEDB_TT_PURSE_REFUND: + TALER_ARL_amount_add (&refunded, + &refunded, + &tl->details.purse_refund->refund_amount); + TALER_ARL_amount_add (&spent, + &spent, + &pos->details.purse_refund->refund_fee); + have_refund = true; + break; + case TALER_EXCHANGEDB_TT_RESERVE_OPEN: + TALER_ARL_amount_add (&spent, + &spent, + &tl->details.reserve_open->coin_contribution); + break; + } /* switch (pos->type) */ + } /* for (...) */ if (have_refund) { /* If we gave any refund, also discount ONE deposit fee */ - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&refunded, - &refunded, - &deposit_fee)); + TALER_ARL_amount_add (&refunded, + &refunded, + &deposit_fee); } /* total coin value = original value plus refunds */ - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total, - &refunded, - value)); + TALER_ARL_amount_add (&total, + &refunded, + value); if (1 == TALER_amount_cmp (&spent, &total)) @@ -564,10 +572,9 @@ check_coin_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, /* spent > total: bad */ struct TALER_Amount loss; - GNUNET_assert (GNUNET_OK == - TALER_amount_subtract (&loss, - &spent, - &total)); + TALER_ARL_amount_subtract (&loss, + &spent, + &total); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loss detected for coin %s - %s\n", TALER_B2S (coin_pub), @@ -596,56 +603,32 @@ check_coin_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, struct DenominationSummary { /** - * Total value of outstanding (not deposited) coins issued with this - * denomination key. + * Information about the circulation. */ - struct TALER_Amount denom_balance; - - /** - * Total losses made (once coins deposited exceed - * coins withdrawn and thus the @e denom_balance is - * effectively negative). - */ - struct TALER_Amount denom_loss; - - /** - * Total value of coins issued with this denomination key. - */ - struct TALER_Amount denom_risk; - - /** - * Total value of coins subjected to recoup with this denomination key. - */ - struct TALER_Amount denom_recoup; - - /** - * How many coins (not their amount!) of this denomination - * did the exchange issue overall? - */ - uint64_t num_issued; + struct TALER_AUDITORDB_DenominationCirculationData dcd; /** * Denomination key information for this denomination. */ - const struct TALER_DenominationKeyValidityPS *issue; + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; /** - * #GNUNET_YES if this record already existed in the DB. + * True if this record already existed in the DB. * Used to decide between insert/update in * #sync_denomination(). */ - int in_db; + bool in_db; /** * Should we report an emergency for this denomination, causing it to be * revoked (because more coins were deposited than issued)? */ - int report_emergency; + bool report_emergency; /** - * #GNUNET_YES if this denomination was revoked. + * True if this denomination was revoked. */ - int was_revoked; + bool was_revoked; }; @@ -676,7 +659,7 @@ struct CoinContext * @return transaction status code */ static enum GNUNET_DB_QueryStatus -init_denomination (const struct GNUNET_HashCode *denom_hash, +init_denomination (const struct TALER_DenominationHashP *denom_hash, struct DenominationSummary *ds) { enum GNUNET_DB_QueryStatus qs; @@ -684,13 +667,8 @@ init_denomination (const struct GNUNET_HashCode *denom_hash, uint64_t rowid; qs = TALER_ARL_adb->get_denomination_balance (TALER_ARL_adb->cls, - TALER_ARL_asession, denom_hash, - &ds->denom_balance, - &ds->denom_loss, - &ds->denom_risk, - &ds->denom_recoup, - &ds->num_issued); + &ds->dcd); if (0 > qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -698,30 +676,29 @@ init_denomination (const struct GNUNET_HashCode *denom_hash, } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) { - ds->in_db = GNUNET_YES; + ds->in_db = true; } else { GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &ds->denom_balance)); + TALER_amount_set_zero (TALER_ARL_currency, + &ds->dcd.denom_balance)); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &ds->denom_loss)); + TALER_amount_set_zero (TALER_ARL_currency, + &ds->dcd.denom_loss)); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &ds->denom_risk)); + TALER_amount_set_zero (TALER_ARL_currency, + &ds->dcd.denom_risk)); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &ds->denom_recoup)); + TALER_amount_set_zero (TALER_ARL_currency, + &ds->dcd.recoup_loss)); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting balance for denomination `%s' is %s (%llu)\n", - GNUNET_h2s (denom_hash), - TALER_amount2s (&ds->denom_balance), - (unsigned long long) ds->num_issued); + GNUNET_h2s (&denom_hash->hash), + TALER_amount2s (&ds->dcd.denom_balance), + (unsigned long long) ds->dcd.num_issued); qs = TALER_ARL_edb->get_denomination_revocation (TALER_ARL_edb->cls, - TALER_ARL_esession, denom_hash, &msig, &rowid); @@ -733,19 +710,11 @@ init_denomination (const struct GNUNET_HashCode *denom_hash, if (0 < qs) { /* check revocation signature */ - struct TALER_MasterDenominationKeyRevocationPS rm = { - .purpose.purpose = htonl ( - TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED), - .purpose.size = htonl (sizeof (rm)), - .h_denom_pub = *denom_hash - }; - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify ( - TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED, - &rm.purpose, - &msig.eddsa_signature, - &TALER_ARL_master_pub.eddsa_pub)) + TALER_exchange_offline_denomination_revoke_verify ( + denom_hash, + &TALER_ARL_master_pub, + &msig)) { report_row_inconsistency ("denomination revocations", rowid, @@ -753,10 +722,10 @@ init_denomination (const struct GNUNET_HashCode *denom_hash, } else { - ds->was_revoked = GNUNET_YES; + ds->was_revoked = true; } } - return (GNUNET_YES == ds->in_db) + return ds->in_db ? GNUNET_DB_STATUS_SUCCESS_ONE_RESULT : GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; } @@ -771,14 +740,15 @@ init_denomination (const struct GNUNET_HashCode *denom_hash, * @return NULL on error */ static struct DenominationSummary * -get_denomination_summary (struct CoinContext *cc, - const struct TALER_DenominationKeyValidityPS *issue, - const struct GNUNET_HashCode *dh) +get_denomination_summary ( + struct CoinContext *cc, + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue, + const struct TALER_DenominationHashP *dh) { struct DenominationSummary *ds; ds = GNUNET_CONTAINER_multihashmap_get (cc->denom_summaries, - dh); + &dh->hash); if (NULL != ds) return ds; ds = GNUNET_new (struct DenominationSummary); @@ -792,7 +762,7 @@ get_denomination_summary (struct CoinContext *cc, } GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (cc->denom_summaries, - dh, + &dh->hash, ds, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); return ds; @@ -809,69 +779,68 @@ get_denomination_summary (struct CoinContext *cc, * @param value a `struct DenominationSummary` * @return #GNUNET_OK (continue to iterate) */ -static int +static enum GNUNET_GenericReturnValue sync_denomination (void *cls, const struct GNUNET_HashCode *denom_hash, void *value) { struct CoinContext *cc = cls; + struct TALER_DenominationHashP denom_h = { + .hash = *denom_hash + }; struct DenominationSummary *ds = value; - const struct TALER_DenominationKeyValidityPS *issue = ds->issue; + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue = ds->issue; struct GNUNET_TIME_Absolute now; - struct GNUNET_TIME_Absolute expire_deposit; + struct GNUNET_TIME_Timestamp expire_deposit; struct GNUNET_TIME_Absolute expire_deposit_grace; enum GNUNET_DB_QueryStatus qs; now = GNUNET_TIME_absolute_get (); - expire_deposit = GNUNET_TIME_absolute_ntoh (issue->expire_deposit); + expire_deposit = issue->expire_deposit; /* add day grace period to deal with clocks not being perfectly synchronized */ - expire_deposit_grace = GNUNET_TIME_absolute_add (expire_deposit, + expire_deposit_grace = GNUNET_TIME_absolute_add (expire_deposit.abs_time, DEPOSIT_GRACE_PERIOD); - if (now.abs_value_us > expire_deposit_grace.abs_value_us) + if (GNUNET_TIME_absolute_cmp (now, + >, + expire_deposit_grace) ) { /* Denomination key has expired, book remaining balance of outstanding coins as revenue; and reduce cc->risk exposure. */ if (ds->in_db) qs = TALER_ARL_adb->del_denomination_balance (TALER_ARL_adb->cls, - TALER_ARL_asession, - denom_hash); + &denom_h); else qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) && - ( (0 != ds->denom_risk.value) || - (0 != ds->denom_risk.fraction) ) ) + (! TALER_amount_is_zero (&ds->dcd.denom_risk)) ) { /* The denomination expired and carried a balance; we can now book the remaining balance as profit, and reduce our risk exposure by the accumulated risk of the denomination. */ - GNUNET_assert (GNUNET_SYSERR != - TALER_amount_subtract (&total_risk, - &total_risk, - &ds->denom_risk)); + TALER_ARL_amount_subtract (&TALER_ARL_USE_AB (coin_balance_risk), + &TALER_ARL_USE_AB (coin_balance_risk), + &ds->dcd.denom_risk); /* If the above fails, our risk assessment is inconsistent! This is really, really bad (auditor-internal invariant would be violated). Hence we can "safely" assert. If this assertion fails, well, good luck: there is a bug - in the auditor _or_ the auditor's database is corrupt. */// + in the auditor _or_ the auditor's database is corrupt. */ } if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) && - ( (0 != ds->denom_balance.value) || - (0 != ds->denom_balance.fraction) ) ) + (! TALER_amount_is_zero (&ds->dcd.denom_balance)) ) { /* book denom_balance coin expiration profits! */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Denomination `%s' expired, booking %s in expiration profits\n", GNUNET_h2s (denom_hash), - TALER_amount2s (&ds->denom_balance)); + TALER_amount2s (&ds->dcd.denom_balance)); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != (qs = TALER_ARL_adb->insert_historic_denom_revenue ( TALER_ARL_adb->cls, - TALER_ARL_asession, - &TALER_ARL_master_pub, - denom_hash, + &denom_h, expire_deposit, - &ds->denom_balance, - &ds->denom_recoup))) + &ds->dcd.denom_balance, + &ds->dcd.recoup_loss))) { /* Failed to store profits? Bad database */ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -888,11 +857,10 @@ sync_denomination (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Final balance for denomination `%s' is %s (%llu)\n", GNUNET_h2s (denom_hash), - TALER_amount2s (&ds->denom_balance), - (unsigned long long) ds->num_issued); + TALER_amount2s (&ds->dcd.denom_balance), + (unsigned long long) ds->dcd.num_issued); cnt = TALER_ARL_edb->count_known_coins (TALER_ARL_edb->cls, - TALER_ARL_esession, - denom_hash); + &denom_h); if (0 > cnt) { /* Failed to obtain count? Bad database */ @@ -902,41 +870,31 @@ sync_denomination (void *cls, } else { - if (ds->num_issued < (uint64_t) cnt) + if (ds->dcd.num_issued < (uint64_t) cnt) { /* more coins deposited than issued! very bad */ report_emergency_by_count (issue, - ds->num_issued, + ds->dcd.num_issued, cnt, - &ds->denom_risk); + &ds->dcd.denom_risk); } - if (GNUNET_YES == ds->report_emergency) + if (ds->report_emergency) { /* Value of coins deposited exceed value of coins issued! Also very bad! */ report_emergency_by_amount (issue, - &ds->denom_risk, - &ds->denom_loss); + &ds->dcd.denom_risk, + &ds->dcd.denom_loss); } if (ds->in_db) qs = TALER_ARL_adb->update_denomination_balance (TALER_ARL_adb->cls, - TALER_ARL_asession, - denom_hash, - &ds->denom_balance, - &ds->denom_loss, - &ds->denom_risk, - &ds->denom_recoup, - ds->num_issued); + &denom_h, + &ds->dcd); else qs = TALER_ARL_adb->insert_denomination_balance (TALER_ARL_adb->cls, - TALER_ARL_asession, - denom_hash, - &ds->denom_balance, - &ds->denom_loss, - &ds->denom_risk, - &ds->denom_recoup, - ds->num_issued); + &denom_h, + &ds->dcd); } } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) @@ -974,21 +932,20 @@ sync_denomination (void *cls, * @param amount_with_fee amount that was withdrawn * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ -static int +static enum GNUNET_GenericReturnValue withdraw_cb (void *cls, uint64_t rowid, - const struct GNUNET_HashCode *h_blind_ev, + const struct TALER_BlindedCoinHashP *h_blind_ev, const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReserveSignatureP *reserve_sig, - struct GNUNET_TIME_Absolute execution_date, + struct GNUNET_TIME_Timestamp execution_date, const struct TALER_Amount *amount_with_fee) { struct CoinContext *cc = cls; struct DenominationSummary *ds; - struct GNUNET_HashCode dh; - const struct TALER_DenominationKeyValidityPS *issue; - struct TALER_Amount value; + struct TALER_DenominationHashP dh; + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; enum GNUNET_DB_QueryStatus qs; /* Note: some optimization potential here: lots of fields we @@ -999,8 +956,9 @@ withdraw_cb (void *cls, (void) execution_date; (void) amount_with_fee; - GNUNET_assert (rowid >= ppc.last_withdraw_serial_id); /* should be monotonically increasing */ - ppc.last_withdraw_serial_id = rowid + 1; + GNUNET_assert (rowid >= + TALER_ARL_USE_PP (coins_withdraw_serial_id)); /* should be monotonically increasing */ + TALER_ARL_USE_PP (coins_withdraw_serial_id) = rowid + 1; qs = TALER_ARL_get_denomination_info (denom_pub, &issue, @@ -1010,6 +968,8 @@ withdraw_cb (void *cls, report_row_inconsistency ("withdraw", rowid, "denomination key not found"); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) @@ -1028,33 +988,29 @@ withdraw_cb (void *cls, GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == cc->qs); return GNUNET_SYSERR; } - TALER_amount_ntoh (&value, - &issue->value); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Issued coin in denomination `%s' of total value %s\n", - GNUNET_h2s (&dh), - TALER_amount2s (&value)); - ds->num_issued++; - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&ds->denom_balance, - &ds->denom_balance, - &value)); + GNUNET_h2s (&dh.hash), + TALER_amount2s (&issue->value)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New balance of denomination `%s' is %s\n", - GNUNET_h2s (&dh), - TALER_amount2s (&ds->denom_balance)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_escrow_balance, - &total_escrow_balance, - &value)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_risk, - &total_risk, - &value)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&ds->denom_risk, - &ds->denom_risk, - &value)); + GNUNET_h2s (&dh.hash), + TALER_amount2s (&ds->dcd.denom_balance)); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (total_escrowed), + &TALER_ARL_USE_AB (total_escrowed), + &issue->value); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_balance_risk), + &TALER_ARL_USE_AB (coin_balance_risk), + &issue->value); + ds->dcd.num_issued++; + TALER_ARL_amount_add (&ds->dcd.denom_balance, + &ds->dcd.denom_balance, + &issue->value); + TALER_ARL_amount_add (&ds->dcd.denom_risk, + &ds->dcd.denom_risk, + &issue->value); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } @@ -1068,7 +1024,7 @@ struct RevealContext /** * Denomination public data of the new coins. */ - const struct TALER_DenominationKeyValidityPS **new_issues; + const struct TALER_EXCHANGEDB_DenominationKeyInformation **new_issues; /** * Set to the size of the @a new_issues array. @@ -1085,7 +1041,7 @@ struct RevealContext * #GNUNET_NO if a denomination key was not found * #GNUNET_SYSERR if we had a database error. */ - int err; + enum GNUNET_GenericReturnValue err; /** * Database error, if @e err is #GNUNET_SYSERR. @@ -1100,30 +1056,18 @@ struct RevealContext * @param cls closure with a `struct RevealContext *` in it * @param num_freshcoins size of the @a rrcs array * @param rrcs array of @a num_freshcoins information about coins to be created - * @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1 - * @param tprivs array of @e num_tprivs transfer private keys - * @param tp transfer public key information */ static void reveal_data_cb (void *cls, uint32_t num_freshcoins, - const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs, - unsigned int num_tprivs, - const struct TALER_TransferPrivateKeyP *tprivs, - const struct TALER_TransferPublicKeyP *tp) + const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs) { struct RevealContext *rctx = cls; - /* Note: optimization using custom database accessor API could avoid - fetching these fields -- and we */ - (void) num_tprivs; - (void) tprivs; - (void) tp; - rctx->num_freshcoins = num_freshcoins; rctx->new_issues = GNUNET_new_array ( num_freshcoins, - const struct TALER_DenominationKeyValidityPS *); + const struct TALER_EXCHANGEDB_DenominationKeyInformation *); /* Update outstanding amounts for all new coin's denominations */ for (unsigned int i = 0; i<num_freshcoins; i++) @@ -1131,9 +1075,8 @@ reveal_data_cb (void *cls, enum GNUNET_DB_QueryStatus qs; /* lookup new coin denomination key */ - qs = TALER_ARL_get_denomination_info (&rrcs[i].denom_pub, - &rctx->new_issues[i], - NULL); + qs = TALER_ARL_get_denomination_info_by_hash (&rrcs[i].h_denom_pub, + &rctx->new_issues[i]); if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { report_row_inconsistency ("refresh_reveal", @@ -1167,26 +1110,23 @@ reveal_data_cb (void *cls, * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT */ static enum GNUNET_DB_QueryStatus -check_known_coin (const char *operation, - const struct TALER_DenominationKeyValidityPS *issue, - uint64_t rowid, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_DenominationPublicKey *denom_pub, - const struct TALER_Amount *loss_potential) +check_known_coin ( + const char *operation, + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue, + uint64_t rowid, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_DenominationPublicKey *denom_pub, + const struct TALER_Amount *loss_potential) { struct TALER_CoinPublicInfo ci; enum GNUNET_DB_QueryStatus qs; if (NULL == get_cached_history (coin_pub)) { - struct TALER_Amount value; - - TALER_amount_ntoh (&value, - &issue->value); qs = check_coin_history (coin_pub, rowid, operation, - &value); + &issue->value); if (0 > qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -1200,7 +1140,6 @@ check_known_coin (const char *operation, "Checking denomination signature on %s\n", TALER_B2S (coin_pub)); qs = TALER_ARL_edb->get_known_coin (TALER_ARL_edb->cls, - TALER_ARL_esession, coin_pub, &ci); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) @@ -1213,21 +1152,80 @@ check_known_coin (const char *operation, denom_pub)) { TALER_ARL_report (report_bad_sig_losses, - json_pack ("{s:s, s:I, s:o, s:o}", - "operation", operation, - "row", (json_int_t) rowid, - "loss", TALER_JSON_from_amount ( - loss_potential), - "coin_pub", GNUNET_JSON_from_data_auto ( - coin_pub))); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, - loss_potential)); + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("operation", + operation), + GNUNET_JSON_pack_uint64 ("row", + rowid), + TALER_JSON_pack_amount ("loss", + loss_potential), + GNUNET_JSON_pack_data_auto ("coin_pub", + coin_pub))); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_irregular_loss), + &TALER_ARL_USE_AB (coin_irregular_loss), + loss_potential); + } + TALER_denom_sig_free (&ci.denom_sig); + return qs; +} + +/** + * Update the denom balance in @a dso reducing it by + * @a amount_with_fee. If this is not possible, report + * an emergency. Also updates the balance. + * + * @param dso denomination summary to update + * @param rowid responsible row (for logging) + * @param amount_with_fee amount to subtract + */ +static void +reduce_denom_balance (struct DenominationSummary *dso, + uint64_t rowid, + const struct TALER_Amount *amount_with_fee) +{ + struct TALER_Amount tmp; + + if (TALER_ARL_SR_INVALID_NEGATIVE == + TALER_ARL_amount_subtract_neg (&tmp, + &dso->dcd.denom_balance, + amount_with_fee)) + { + TALER_ARL_amount_add (&dso->dcd.denom_loss, + &dso->dcd.denom_loss, + amount_with_fee); + dso->report_emergency = true; } - GNUNET_CRYPTO_rsa_signature_free (ci.denom_sig.rsa_signature); - return qs; + else + { + dso->dcd.denom_balance = tmp; + } + if (-1 == TALER_amount_cmp (&TALER_ARL_USE_AB (total_escrowed), + amount_with_fee)) + { + /* This can theoretically happen if for example the exchange + never issued any coins (i.e. escrow balance is zero), but + accepted a forged coin (i.e. emergency situation after + private key compromise). In that case, we cannot even + subtract the profit we make from the fee from the escrow + balance. Tested as part of test-auditor.sh, case #18 */ + report_amount_arithmetic_inconsistency ( + "subtracting amount from escrow balance", + rowid, + &TALER_ARL_USE_AB (total_escrowed), + amount_with_fee, + 0); + } + else + { + TALER_ARL_amount_subtract (&TALER_ARL_USE_AB (total_escrowed), + &TALER_ARL_USE_AB (total_escrowed), + amount_with_fee); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "New balance of denomination `%s' is %s\n", + GNUNET_h2s (&dso->issue->denom_hash.hash), + TALER_amount2s (&dso->dcd.denom_balance)); } @@ -1241,6 +1239,7 @@ check_known_coin (const char *operation, * @param cls closure * @param rowid unique serial ID for the refresh session in our DB * @param denom_pub denomination public key of @a coin_pub + * @param h_age_commitment hash of the age commitment for the coin * @param coin_pub public key of the coin * @param coin_sig signature from the coin * @param amount_with_fee amount that was deposited including fee @@ -1248,10 +1247,11 @@ check_known_coin (const char *operation, * @param rc what is the refresh commitment * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ -static int +static enum GNUNET_GenericReturnValue refresh_session_cb (void *cls, uint64_t rowid, const struct TALER_DenominationPublicKey *denom_pub, + const struct TALER_AgeCommitmentHash *h_age_commitment, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_Amount *amount_with_fee, @@ -1259,15 +1259,15 @@ refresh_session_cb (void *cls, const struct TALER_RefreshCommitmentP *rc) { struct CoinContext *cc = cls; - const struct TALER_DenominationKeyValidityPS *issue; + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; struct DenominationSummary *dso; struct TALER_Amount amount_without_fee; - struct TALER_Amount tmp; enum GNUNET_DB_QueryStatus qs; (void) noreveal_index; - GNUNET_assert (rowid >= ppc.last_melt_serial_id); /* should be monotonically increasing */ - ppc.last_melt_serial_id = rowid + 1; + GNUNET_assert (rowid >= + TALER_ARL_USE_PP (coins_melt_serial_id)); /* should be monotonically increasing */ + TALER_ARL_USE_PP (coins_melt_serial_id) = rowid + 1; qs = TALER_ARL_get_denomination_info (denom_pub, &issue, @@ -1277,6 +1277,8 @@ refresh_session_cb (void *cls, report_row_inconsistency ("melt", rowid, "denomination key not found"); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) @@ -1300,40 +1302,39 @@ refresh_session_cb (void *cls, /* verify melt signature */ { - struct TALER_RefreshMeltCoinAffirmationPS rmc = { - .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT), - .purpose.size = htonl (sizeof (rmc)), - .rc = *rc, - .melt_fee = issue->fee_refresh, - .coin_pub = *coin_pub - }; + struct TALER_DenominationHashP h_denom_pub; - TALER_amount_hton (&rmc.amount_with_fee, - amount_with_fee); + TALER_denom_pub_hash (denom_pub, + &h_denom_pub); if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT, - &rmc.purpose, - &coin_sig->eddsa_signature, - &coin_pub->eddsa_pub)) + TALER_wallet_melt_verify (amount_with_fee, + &issue->fees.refresh, + rc, + &h_denom_pub, + h_age_commitment, + coin_pub, + coin_sig)) { + GNUNET_break_op (0); TALER_ARL_report (report_bad_sig_losses, - json_pack ("{s:s, s:I, s:o, s:o}", - "operation", "melt", - "row", (json_int_t) rowid, - "loss", TALER_JSON_from_amount ( - amount_with_fee), - "coin_pub", GNUNET_JSON_from_data_auto ( - coin_pub))); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, - amount_with_fee)); + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("operation", + "melt"), + GNUNET_JSON_pack_uint64 ("row", + rowid), + TALER_JSON_pack_amount ("loss", + amount_with_fee), + GNUNET_JSON_pack_data_auto ("coin_pub", + coin_pub))); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_irregular_loss), + &TALER_ARL_USE_AB (coin_irregular_loss), + amount_with_fee); } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Melting coin %s in denomination `%s' of value %s\n", TALER_B2S (coin_pub), - GNUNET_h2s (&issue->denom_hash), + GNUNET_h2s (&issue->denom_hash.hash), TALER_amount2s (amount_with_fee)); { @@ -1344,7 +1345,6 @@ refresh_session_cb (void *cls, }; qs = TALER_ARL_edb->get_refresh_reveal (TALER_ARL_edb->cls, - TALER_ARL_esession, rc, &reveal_data_cb, &reveal_ctx); @@ -1360,17 +1360,19 @@ refresh_session_cb (void *cls, /* This can legitimately happen if reveal was not yet called or only with invalid data, even if the exchange is correctly operating. We still report it. */ - TALER_ARL_report (report_refreshs_hanging, - json_pack ("{s:I, s:o, s:o}", - "row", (json_int_t) rowid, - "amount", TALER_JSON_from_amount ( - amount_with_fee), - "coin_pub", GNUNET_JSON_from_data_auto ( - coin_pub))); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_refresh_hanging, - &total_refresh_hanging, - amount_with_fee)); + TALER_ARL_report (report_refreshes_hanging, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("row", + rowid), + TALER_JSON_pack_amount ("amount", + amount_with_fee), + GNUNET_JSON_pack_data_auto ("coin_pub", + coin_pub))); + TALER_ARL_amount_add (&total_refresh_hanging, + &total_refresh_hanging, + amount_with_fee); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } if (GNUNET_SYSERR == reveal_ctx.err) @@ -1378,66 +1380,59 @@ refresh_session_cb (void *cls, if (GNUNET_OK != reveal_ctx.err) { - GNUNET_free_non_null (reveal_ctx.new_issues); - return (GNUNET_SYSERR == reveal_ctx.err) ? GNUNET_SYSERR : GNUNET_OK; + GNUNET_free (reveal_ctx.new_issues); + if (GNUNET_SYSERR == reveal_ctx.err) + return GNUNET_SYSERR; + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; } /* Check that the resulting amounts are consistent with the value being refreshed by calculating the total refresh cost */ GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (amount_with_fee->currency, + TALER_amount_set_zero (amount_with_fee->currency, &refresh_cost)); for (unsigned int i = 0; i<reveal_ctx.num_freshcoins; i++) { + const struct TALER_EXCHANGEDB_DenominationKeyInformation *ni + = reveal_ctx.new_issues[i]; /* update cost of refresh */ - struct TALER_Amount fee; - struct TALER_Amount value; - TALER_amount_ntoh (&fee, - &reveal_ctx.new_issues[i]->fee_withdraw); - TALER_amount_ntoh (&value, - &reveal_ctx.new_issues[i]->value); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&refresh_cost, - &refresh_cost, - &fee)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&refresh_cost, - &refresh_cost, - &value)); + TALER_ARL_amount_add (&refresh_cost, + &refresh_cost, + &ni->fees.withdraw); + TALER_ARL_amount_add (&refresh_cost, + &refresh_cost, + &ni->value); } /* compute contribution of old coin */ + if (TALER_ARL_SR_POSITIVE != + TALER_ARL_amount_subtract_neg (&amount_without_fee, + amount_with_fee, + &issue->fees.refresh)) { - struct TALER_Amount melt_fee; - - TALER_amount_ntoh (&melt_fee, - &issue->fee_refresh); - if (GNUNET_OK != - TALER_amount_subtract (&amount_without_fee, - amount_with_fee, - &melt_fee)) - { - /* Melt fee higher than contribution of melted coin; this makes - no sense (exchange should never have accepted the operation) */ - report_amount_arithmetic_inconsistency ("melt contribution vs. fee", - rowid, - amount_with_fee, - &melt_fee, - -1); - /* To continue, best assumption is the melted coin contributed - nothing (=> all withdrawal amounts will be counted as losses) */ - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &amount_without_fee)); - } + /* Melt fee higher than contribution of melted coin; this makes + no sense (exchange should never have accepted the operation) */ + report_amount_arithmetic_inconsistency ("melt contribution vs. fee", + rowid, + amount_with_fee, + &issue->fees.refresh, + -1); + /* To continue, best assumption is the melted coin contributed + nothing (=> all withdrawal amounts will be counted as losses) */ + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (TALER_ARL_currency, + &amount_without_fee)); } - /* check old coin covers complete expenses (of withdraw operations) */ + /* check old coin covers complete expenses (of refresh operation) */ if (1 == TALER_amount_cmp (&refresh_cost, &amount_without_fee)) { /* refresh_cost > amount_without_fee, which is bad (exchange lost) */ + GNUNET_break_op (0); report_amount_arithmetic_inconsistency ("melt (cost)", rowid, &amount_without_fee, /* 'exchange' */ @@ -1448,12 +1443,13 @@ refresh_session_cb (void *cls, /* update outstanding denomination amounts for fresh coins withdrawn */ for (unsigned int i = 0; i<reveal_ctx.num_freshcoins; i++) { + const struct TALER_EXCHANGEDB_DenominationKeyInformation *ni + = reveal_ctx.new_issues[i]; struct DenominationSummary *dsi; - struct TALER_Amount value; dsi = get_denomination_summary (cc, - reveal_ctx.new_issues[i], - &reveal_ctx.new_issues[i]->denom_hash); + ni, + &ni->denom_hash); if (NULL == dsi) { report_row_inconsistency ("refresh_reveal", @@ -1462,36 +1458,30 @@ refresh_session_cb (void *cls, } else { - TALER_amount_ntoh (&value, - &reveal_ctx.new_issues[i]->value); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created fresh coin in denomination `%s' of value %s\n", - GNUNET_h2s (&reveal_ctx.new_issues[i]->denom_hash), - TALER_amount2s (&value)); - dsi->num_issued++; - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&dsi->denom_balance, - &dsi->denom_balance, - &value)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&dsi->denom_risk, - &dsi->denom_risk, - &value)); + GNUNET_h2s (&ni->denom_hash.hash), + TALER_amount2s (&ni->value)); + dsi->dcd.num_issued++; + TALER_ARL_amount_add (&dsi->dcd.denom_balance, + &dsi->dcd.denom_balance, + &ni->value); + TALER_ARL_amount_add (&dsi->dcd.denom_risk, + &dsi->dcd.denom_risk, + &ni->value); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New balance of denomination `%s' is %s\n", - GNUNET_h2s (&reveal_ctx.new_issues[i]->denom_hash), - TALER_amount2s (&dsi->denom_balance)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_escrow_balance, - &total_escrow_balance, - &value)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_risk, - &total_risk, - &value)); + GNUNET_h2s (&ni->denom_hash.hash), + TALER_amount2s (&dsi->dcd.denom_balance)); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (total_escrowed), + &TALER_ARL_USE_AB (total_escrowed), + &ni->value); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_balance_risk), + &TALER_ARL_USE_AB (coin_balance_risk), + &ni->value); } } - GNUNET_free_non_null (reveal_ctx.new_issues); + GNUNET_free (reveal_ctx.new_issues); } /* update old coin's denomination balance */ @@ -1506,61 +1496,17 @@ refresh_session_cb (void *cls, } else { - if (GNUNET_SYSERR == - TALER_amount_subtract (&tmp, - &dso->denom_balance, - amount_with_fee)) - { - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&dso->denom_loss, - &dso->denom_loss, - amount_with_fee)); - dso->report_emergency = GNUNET_YES; - } - else - { - dso->denom_balance = tmp; - } - if (-1 == TALER_amount_cmp (&total_escrow_balance, - amount_with_fee)) - { - /* This can theoretically happen if for example the exchange - never issued any coins (i.e. escrow balance is zero), but - accepted a forged coin (i.e. emergency situation after - private key compromise). In that case, we cannot even - subtract the profit we make from the fee from the escrow - balance. Tested as part of test-auditor.sh, case #18 */// - report_amount_arithmetic_inconsistency ( - "subtracting refresh fee from escrow balance", - rowid, - &total_escrow_balance, - amount_with_fee, - 0); - } - else - { - GNUNET_assert (GNUNET_SYSERR != - TALER_amount_subtract (&total_escrow_balance, - &total_escrow_balance, - amount_with_fee)); - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "New balance of denomination `%s' after melt is %s\n", - GNUNET_h2s (&issue->denom_hash), - TALER_amount2s (&dso->denom_balance)); + reduce_denom_balance (dso, + rowid, + amount_with_fee); } /* update global melt fees */ - { - struct TALER_Amount rfee; - - TALER_amount_ntoh (&rfee, - &issue->fee_refresh); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_melt_fee_income, - &total_melt_fee_income, - &rfee)); - } + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_melt_fee_revenue), + &TALER_ARL_USE_AB (coin_melt_fee_revenue), + &issue->fees.refresh); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } @@ -1571,45 +1517,30 @@ refresh_session_cb (void *cls, * * @param cls closure * @param rowid unique serial ID for the deposit in our DB - * @param timestamp when did the deposit happen - * @param merchant_pub public key of the merchant + * @param exchange_timestamp when did the exchange get the deposit + * @param deposit deposit details * @param denom_pub denomination public key of @a coin_pub - * @param coin_pub public key of the coin - * @param coin_sig signature from the coin - * @param amount_with_fee amount that was deposited including fee - * @param h_contract_terms hash of the proposal data known to merchant and customer - * @param refund_deadline by which the merchant advised that he might want - * to get a refund - * @param wire_deadline by which the merchant advised that he would like the - * wire transfer to be executed - * @param receiver_wire_account wire details for the merchant, NULL from iterate_matching_deposits() * @param done flag set if the deposit was already executed (or not) * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ -static int +static enum GNUNET_GenericReturnValue deposit_cb (void *cls, uint64_t rowid, - struct GNUNET_TIME_Absolute timestamp, - const struct TALER_MerchantPublicKeyP *merchant_pub, + struct GNUNET_TIME_Timestamp exchange_timestamp, + const struct TALER_EXCHANGEDB_Deposit *deposit, const struct TALER_DenominationPublicKey *denom_pub, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_CoinSpendSignatureP *coin_sig, - const struct TALER_Amount *amount_with_fee, - const struct GNUNET_HashCode *h_contract_terms, - struct GNUNET_TIME_Absolute refund_deadline, - struct GNUNET_TIME_Absolute wire_deadline, - const json_t *receiver_wire_account, - int done) + bool done) { struct CoinContext *cc = cls; - const struct TALER_DenominationKeyValidityPS *issue; + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; struct DenominationSummary *ds; enum GNUNET_DB_QueryStatus qs; - (void) wire_deadline; (void) done; - GNUNET_assert (rowid >= ppc.last_deposit_serial_id); /* should be monotonically increasing */ - ppc.last_deposit_serial_id = rowid + 1; + (void) exchange_timestamp; + GNUNET_assert (rowid >= + TALER_ARL_USE_PP (coins_deposit_serial_id)); /* should be monotonically increasing */ + TALER_ARL_USE_PP (coins_deposit_serial_id) = rowid + 1; qs = TALER_ARL_get_denomination_info (denom_pub, &issue, @@ -1619,8 +1550,18 @@ deposit_cb (void *cls, report_row_inconsistency ("deposits", rowid, "denomination key not found"); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } + if (GNUNET_TIME_timestamp_cmp (deposit->refund_deadline, + >, + deposit->wire_deadline)) + { + report_row_inconsistency ("deposits", + rowid, + "refund deadline past wire deadline"); + } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { @@ -1631,9 +1572,9 @@ deposit_cb (void *cls, qs = check_known_coin ("deposit", issue, rowid, - coin_pub, + &deposit->coin.coin_pub, denom_pub, - amount_with_fee); + &deposit->amount_with_fee); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -1643,66 +1584,57 @@ deposit_cb (void *cls, /* Verify deposit signature */ { - struct TALER_DepositRequestPS dr = { - .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT), - .purpose.size = htonl (sizeof (dr)), - .h_contract_terms = *h_contract_terms, - .timestamp = GNUNET_TIME_absolute_hton (timestamp), - .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline), - .deposit_fee = issue->fee_deposit, - .merchant = *merchant_pub, - .coin_pub = *coin_pub - }; + struct TALER_MerchantWireHashP h_wire; + struct TALER_DenominationHashP h_denom_pub; - if (GNUNET_OK != - TALER_JSON_merchant_wire_signature_hash (receiver_wire_account, - &dr.h_wire)) - { - TALER_ARL_report (report_bad_sig_losses, - json_pack ("{s:s, s:I, s:o, s:o}", - "operation", "deposit", - "row", (json_int_t) rowid, - "loss", TALER_JSON_from_amount ( - amount_with_fee), - "coin_pub", GNUNET_JSON_from_data_auto ( - coin_pub))); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, - amount_with_fee)); - return GNUNET_OK; - } - TALER_amount_hton (&dr.amount_with_fee, - amount_with_fee); + TALER_denom_pub_hash (denom_pub, + &h_denom_pub); + TALER_merchant_wire_signature_hash (deposit->receiver_wire_account, + &deposit->wire_salt, + &h_wire); /* NOTE: This is one of the operations we might eventually want to do in parallel in the background to improve auditor performance! */ if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, - &dr.purpose, - &coin_sig->eddsa_signature, - &coin_pub->eddsa_pub)) + TALER_wallet_deposit_verify (&deposit->amount_with_fee, + &issue->fees.deposit, + &h_wire, + &deposit->h_contract_terms, + deposit->no_wallet_data_hash + ? NULL + : &deposit->wallet_data_hash, + &deposit->coin.h_age_commitment, + &deposit->h_policy, + &h_denom_pub, + deposit->timestamp, + &deposit->merchant_pub, + deposit->refund_deadline, + &deposit->coin.coin_pub, + &deposit->csig)) { TALER_ARL_report (report_bad_sig_losses, - json_pack ("{s:s, s:I, s:o, s:o}", - "operation", "deposit", - "row", (json_int_t) rowid, - "loss", TALER_JSON_from_amount ( - amount_with_fee), - "coin_pub", GNUNET_JSON_from_data_auto ( - coin_pub))); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, - amount_with_fee)); + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("operation", + "deposit"), + GNUNET_JSON_pack_uint64 ("row", + rowid), + TALER_JSON_pack_amount ("loss", + &deposit->amount_with_fee), + GNUNET_JSON_pack_data_auto ("coin_pub", + &deposit->coin.coin_pub))); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_irregular_loss), + &TALER_ARL_USE_AB (coin_irregular_loss), + &deposit->amount_with_fee); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deposited coin %s in denomination `%s' of value %s\n", - TALER_B2S (coin_pub), - GNUNET_h2s (&issue->denom_hash), - TALER_amount2s (amount_with_fee)); + TALER_B2S (&deposit->coin.coin_pub), + GNUNET_h2s (&issue->denom_hash.hash), + TALER_amount2s (&deposit->amount_with_fee)); /* update old coin's denomination balance */ ds = get_denomination_summary (cc, @@ -1716,66 +1648,17 @@ deposit_cb (void *cls, } else { - struct TALER_Amount tmp; - - if (GNUNET_SYSERR == - TALER_amount_subtract (&tmp, - &ds->denom_balance, - amount_with_fee)) - { - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&ds->denom_loss, - &ds->denom_loss, - amount_with_fee)); - ds->report_emergency = GNUNET_YES; - } - else - { - ds->denom_balance = tmp; - } - - if (-1 == TALER_amount_cmp (&total_escrow_balance, - amount_with_fee)) - { - /* This can theoretically happen if for example the exchange - never issued any coins (i.e. escrow balance is zero), but - accepted a forged coin (i.e. emergency situation after - private key compromise). In that case, we cannot even - subtract the profit we make from the fee from the escrow - balance. Tested as part of test-auditor.sh, case #18 */// - report_amount_arithmetic_inconsistency ( - "subtracting deposit fee from escrow balance", - rowid, - &total_escrow_balance, - amount_with_fee, - 0); - } - else - { - GNUNET_assert (GNUNET_SYSERR != - TALER_amount_subtract (&total_escrow_balance, - &total_escrow_balance, - amount_with_fee)); - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "New balance of denomination `%s' after deposit is %s\n", - GNUNET_h2s (&issue->denom_hash), - TALER_amount2s (&ds->denom_balance)); + reduce_denom_balance (ds, + rowid, + &deposit->amount_with_fee); } /* update global deposit fees */ - { - struct TALER_Amount dfee; - - TALER_amount_ntoh (&dfee, - &issue->fee_deposit); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_deposit_fee_income, - &total_deposit_fee_income, - &dfee)); - } - + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_deposit_fee_revenue), + &TALER_ARL_USE_AB (coin_deposit_fee_revenue), + &issue->fees.deposit); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } @@ -1794,29 +1677,30 @@ deposit_cb (void *cls, * @param merchant_sig signature of the merchant * @param h_contract_terms hash of the proposal data known to merchant and customer * @param rtransaction_id refund transaction ID chosen by the merchant + * @param full_refund true if the refunds total up to the entire deposited value * @param amount_with_fee amount that was deposited including fee * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ -static int +static enum GNUNET_GenericReturnValue refund_cb (void *cls, uint64_t rowid, const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_MerchantSignatureP *merchant_sig, - const struct GNUNET_HashCode *h_contract_terms, + const struct TALER_PrivateContractHashP *h_contract_terms, uint64_t rtransaction_id, + bool full_refund, const struct TALER_Amount *amount_with_fee) { struct CoinContext *cc = cls; - const struct TALER_DenominationKeyValidityPS *issue; + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; struct DenominationSummary *ds; struct TALER_Amount amount_without_fee; - struct TALER_Amount refund_fee; enum GNUNET_DB_QueryStatus qs; - GNUNET_assert (rowid >= ppc.last_refund_serial_id); /* should be monotonically increasing */ - ppc.last_refund_serial_id = rowid + 1; + GNUNET_assert (rowid >= TALER_ARL_USE_PP (coins_refund_serial_id)); /* should be monotonically increasing */ + TALER_ARL_USE_PP (coins_refund_serial_id) = rowid + 1; qs = TALER_ARL_get_denomination_info (denom_pub, &issue, @@ -1826,7 +1710,9 @@ refund_cb (void *cls, report_row_inconsistency ("refunds", rowid, "denomination key not found"); - return GNUNET_SYSERR; + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { @@ -1835,60 +1721,51 @@ refund_cb (void *cls, } /* verify refund signature */ + if (GNUNET_OK != + TALER_merchant_refund_verify (coin_pub, + h_contract_terms, + rtransaction_id, + amount_with_fee, + merchant_pub, + merchant_sig)) { - struct TALER_RefundRequestPS rr = { - .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND), - .purpose.size = htonl (sizeof (rr)), - .h_contract_terms = *h_contract_terms, - .coin_pub = *coin_pub, - .merchant = *merchant_pub, - .rtransaction_id = GNUNET_htonll (rtransaction_id), - .refund_fee = issue->fee_refund - }; - - TALER_amount_hton (&rr.refund_amount, - amount_with_fee); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, - &rr.purpose, - &merchant_sig->eddsa_sig, - &merchant_pub->eddsa_pub)) - { - TALER_ARL_report (report_bad_sig_losses, - json_pack ("{s:s, s:I, s:o, s:o}", - "operation", "refund", - "row", (json_int_t) rowid, - "loss", TALER_JSON_from_amount ( - amount_with_fee), - "coin_pub", GNUNET_JSON_from_data_auto ( - coin_pub))); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, - amount_with_fee)); - return GNUNET_OK; - } + TALER_ARL_report (report_bad_sig_losses, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("operation", + "refund"), + GNUNET_JSON_pack_uint64 ("row", + rowid), + TALER_JSON_pack_amount ("loss", + amount_with_fee), + GNUNET_JSON_pack_data_auto ("coin_pub", + coin_pub))); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_irregular_loss), + &TALER_ARL_USE_AB (coin_irregular_loss), + amount_with_fee); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; } - TALER_amount_ntoh (&refund_fee, - &issue->fee_refund); - if (GNUNET_OK != - TALER_amount_subtract (&amount_without_fee, - amount_with_fee, - &refund_fee)) + if (TALER_ARL_SR_INVALID_NEGATIVE == + TALER_ARL_amount_subtract_neg (&amount_without_fee, + amount_with_fee, + &issue->fees.refund)) { report_amount_arithmetic_inconsistency ("refund (fee)", rowid, &amount_without_fee, - &refund_fee, + &issue->fees.refund, -1); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Refunding coin %s in denomination `%s' value %s\n", TALER_B2S (coin_pub), - GNUNET_h2s (&issue->denom_hash), + GNUNET_h2s (&issue->denom_hash.hash), TALER_amount2s (amount_with_fee)); /* update coin's denomination balance */ @@ -1903,32 +1780,162 @@ refund_cb (void *cls, } else { - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&ds->denom_balance, - &ds->denom_balance, - &amount_without_fee)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&ds->denom_risk, - &ds->denom_risk, - &amount_without_fee)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_escrow_balance, - &total_escrow_balance, - &amount_without_fee)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_risk, - &total_risk, - &amount_without_fee)); + TALER_ARL_amount_add (&ds->dcd.denom_balance, + &ds->dcd.denom_balance, + &amount_without_fee); + TALER_ARL_amount_add (&ds->dcd.denom_risk, + &ds->dcd.denom_risk, + &amount_without_fee); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (total_escrowed), + &TALER_ARL_USE_AB (total_escrowed), + &amount_without_fee); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_balance_risk), + &TALER_ARL_USE_AB (coin_balance_risk), + &amount_without_fee); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New balance of denomination `%s' after refund is %s\n", - GNUNET_h2s (&issue->denom_hash), - TALER_amount2s (&ds->denom_balance)); + GNUNET_h2s (&issue->denom_hash.hash), + TALER_amount2s (&ds->dcd.denom_balance)); } /* update total refund fee balance */ - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_refund_fee_income, - &total_refund_fee_income, - &refund_fee)); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_refund_fee_revenue), + &TALER_ARL_USE_AB (coin_refund_fee_revenue), + &issue->fees.refund); + if (full_refund) + { + TALER_ARL_amount_subtract (&TALER_ARL_USE_AB (coin_deposit_fee_revenue), + &TALER_ARL_USE_AB (coin_deposit_fee_revenue), + &issue->fees.deposit); + } + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * Function called with details about purse refunds that have been made, with + * the goal of auditing the purse refund's execution. + * + * @param cls closure + * @param rowid row of the purse-refund + * @param amount_with_fee amount of the deposit into the purse + * @param coin_pub coin that is to be refunded the @a given amount_with_fee + * @param denom_pub denomination of @a coin_pub + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +static enum GNUNET_GenericReturnValue +purse_refund_coin_cb ( + void *cls, + uint64_t rowid, + const struct TALER_Amount *amount_with_fee, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_DenominationPublicKey *denom_pub) +{ + struct CoinContext *cc = cls; + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; + struct DenominationSummary *ds; + enum GNUNET_DB_QueryStatus qs; + + qs = TALER_ARL_get_denomination_info (denom_pub, + &issue, + NULL); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + report_row_inconsistency ("purse-refunds", + rowid, + "denomination key not found"); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; + } + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Aborted purse-deposit of coin %s in denomination `%s' value %s\n", + TALER_B2S (coin_pub), + GNUNET_h2s (&issue->denom_hash.hash), + TALER_amount2s (amount_with_fee)); + + /* update coin's denomination balance */ + ds = get_denomination_summary (cc, + issue, + &issue->denom_hash); + if (NULL == ds) + { + report_row_inconsistency ("purse-refund", + rowid, + "denomination key for purse-refunded coin unknown to auditor"); + } + else + { + TALER_ARL_amount_add (&ds->dcd.denom_balance, + &ds->dcd.denom_balance, + amount_with_fee); + TALER_ARL_amount_add (&ds->dcd.denom_risk, + &ds->dcd.denom_risk, + amount_with_fee); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (total_escrowed), + &TALER_ARL_USE_AB (total_escrowed), + amount_with_fee); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_balance_risk), + &TALER_ARL_USE_AB (coin_balance_risk), + amount_with_fee); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "New balance of denomination `%s' after purse-refund is %s\n", + GNUNET_h2s (&issue->denom_hash.hash), + TALER_amount2s (&ds->dcd.denom_balance)); + } + /* update total deposit fee balance */ + TALER_ARL_amount_subtract (&TALER_ARL_USE_AB (coin_deposit_fee_revenue), + &TALER_ARL_USE_AB (coin_deposit_fee_revenue), + &issue->fees.deposit); + + return GNUNET_OK; +} + + +/** + * Function called with details about a purse that was refunded. Adds the + * refunded amounts back to the outstanding balance of the respective + * denominations. + * + * @param cls closure + * @param rowid unique serial ID for the refund in our DB + * @param purse_pub public key of the purse + * @param reserve_pub public key of the targeted reserve (ignored) + * @param val targeted amount to be in the reserve (ignored) + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +static enum GNUNET_GenericReturnValue +purse_refund_cb (void *cls, + uint64_t rowid, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *val) +{ + struct CoinContext *cc = cls; + enum GNUNET_DB_QueryStatus qs; + + (void) val; /* irrelevant on refund */ + (void) reserve_pub; /* irrelevant, may even be NULL */ + GNUNET_assert (rowid >= + TALER_ARL_USE_PP (coins_purse_refunds_serial_id)); /* should be monotonically increasing */ + TALER_ARL_USE_PP (coins_purse_refunds_serial_id) = rowid + 1; + qs = TALER_ARL_edb->select_purse_deposits_by_purse (TALER_ARL_edb->cls, + purse_pub, + &purse_refund_coin_cb, + cc); + if (qs < 0) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + return GNUNET_SYSERR; + } + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } @@ -1947,7 +1954,7 @@ refund_cb (void *cls, * @param coin_blind blinding factor used to blind the coin * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ -static int +static enum GNUNET_GenericReturnValue check_recoup (struct CoinContext *cc, const char *operation, uint64_t rowid, @@ -1955,27 +1962,39 @@ check_recoup (struct CoinContext *cc, const struct TALER_CoinPublicInfo *coin, const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_CoinSpendSignatureP *coin_sig, - const struct TALER_DenominationBlindingKeyP *coin_blind) + const union GNUNET_CRYPTO_BlindingSecretP *coin_blind) { struct DenominationSummary *ds; enum GNUNET_DB_QueryStatus qs; - const struct TALER_DenominationKeyValidityPS *issue; + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; if (GNUNET_OK != + TALER_wallet_recoup_verify (&coin->denom_pub_hash, + coin_blind, + &coin->coin_pub, + coin_sig)) + { + report_row_inconsistency (operation, + rowid, + "recoup signature invalid"); + } + if (GNUNET_OK != TALER_test_coin_valid (coin, denom_pub)) { TALER_ARL_report (report_bad_sig_losses, - json_pack ("{s:s, s:I, s:o, s:o}", - "operation", operation, - "row", (json_int_t) rowid, - "loss", TALER_JSON_from_amount (amount), - "coin_pub", GNUNET_JSON_from_data_auto ( - &coin->denom_pub_hash))); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, - amount)); + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("operation", + operation), + GNUNET_JSON_pack_uint64 ("row", + rowid), + TALER_JSON_pack_amount ("loss", + amount), + GNUNET_JSON_pack_data_auto ("coin_pub", + &coin->denom_pub_hash))); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_irregular_loss), + &TALER_ARL_USE_AB (coin_irregular_loss), + amount); } qs = TALER_ARL_get_denomination_info_by_hash (&coin->denom_pub_hash, &issue); @@ -1984,6 +2003,8 @@ check_recoup (struct CoinContext *cc, report_row_inconsistency (operation, rowid, "denomination key not found"); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) @@ -2006,35 +2027,6 @@ check_recoup (struct CoinContext *cc, cc->qs = qs; return GNUNET_SYSERR; } - { - struct TALER_RecoupRequestPS pr = { - .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP), - .purpose.size = htonl (sizeof (pr)), - .coin_pub = coin->coin_pub, - .coin_blind = *coin_blind, - .h_denom_pub = coin->denom_pub_hash - }; - - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, - &pr.purpose, - &coin_sig->eddsa_signature, - &coin->coin_pub.eddsa_pub)) - { - TALER_ARL_report (report_bad_sig_losses, - json_pack ("{s:s, s:I, s:o, s:o}", - "operation", operation, - "row", (json_int_t) rowid, - "loss", TALER_JSON_from_amount (amount), - "coin_pub", GNUNET_JSON_from_data_auto ( - &coin->coin_pub))); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, - amount)); - return GNUNET_OK; - } - } ds = get_denomination_summary (cc, issue, &issue->denom_hash); @@ -2046,33 +2038,34 @@ check_recoup (struct CoinContext *cc, } else { - if (GNUNET_NO == ds->was_revoked) + if (! ds->was_revoked) { /* Woopsie, we allowed recoup on non-revoked denomination!? */ TALER_ARL_report (report_bad_sig_losses, - json_pack ("{s:s, s:s, s:I, s:o, s:o}", - "operation", - operation, - "hint", - "denomination not revoked", - "row", (json_int_t) rowid, - "loss", TALER_JSON_from_amount (amount), - "coin_pub", GNUNET_JSON_from_data_auto ( - &coin->coin_pub))); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, - amount)); + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("operation", + operation), + GNUNET_JSON_pack_string ("hint", + "denomination not revoked"), + GNUNET_JSON_pack_uint64 ("row", + rowid), + TALER_JSON_pack_amount ("loss", + amount), + GNUNET_JSON_pack_data_auto ("coin_pub", + &coin->coin_pub))); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_irregular_loss), + &TALER_ARL_USE_AB (coin_irregular_loss), + amount); } - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&ds->denom_recoup, - &ds->denom_recoup, - amount)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&total_recoup_loss, - &total_recoup_loss, - amount)); - } + TALER_ARL_amount_add (&ds->dcd.recoup_loss, + &ds->dcd.recoup_loss, + amount); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (total_recoup_loss), + &TALER_ARL_USE_AB (total_recoup_loss), + amount); + } + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; return GNUNET_OK; } @@ -2091,23 +2084,46 @@ check_recoup (struct CoinContext *cc, * @param coin_blind blinding factor used to blind the coin * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ -static int +static enum GNUNET_GenericReturnValue recoup_cb (void *cls, uint64_t rowid, - struct GNUNET_TIME_Absolute timestamp, + struct GNUNET_TIME_Timestamp timestamp, const struct TALER_Amount *amount, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_CoinPublicInfo *coin, const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_CoinSpendSignatureP *coin_sig, - const struct TALER_DenominationBlindingKeyP *coin_blind) + const union GNUNET_CRYPTO_BlindingSecretP *coin_blind) { struct CoinContext *cc = cls; - GNUNET_assert (rowid >= ppc.last_recoup_serial_id); /* should be monotonically increasing */ - ppc.last_recoup_serial_id = rowid + 1; + GNUNET_assert (rowid >= TALER_ARL_USE_PP (coins_recoup_serial_id)); /* should be monotonically increasing */ + TALER_ARL_USE_PP (coins_recoup_serial_id) = rowid + 1; (void) timestamp; (void) reserve_pub; + if (GNUNET_OK != + TALER_wallet_recoup_verify (&coin->denom_pub_hash, + coin_blind, + &coin->coin_pub, + coin_sig)) + { + TALER_ARL_report (report_bad_sig_losses, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("operation", + "recoup"), + GNUNET_JSON_pack_uint64 ("row", + rowid), + TALER_JSON_pack_amount ("loss", + amount), + GNUNET_JSON_pack_data_auto ("coin_pub", + &coin->coin_pub))); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_irregular_loss), + &TALER_ARL_USE_AB (coin_irregular_loss), + amount); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; + } return check_recoup (cc, "recoup", rowid, @@ -2135,26 +2151,26 @@ recoup_cb (void *cls, * @param coin_blind blinding factor used to blind the coin * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ -static int +static enum GNUNET_GenericReturnValue recoup_refresh_cb (void *cls, uint64_t rowid, - struct GNUNET_TIME_Absolute timestamp, + struct GNUNET_TIME_Timestamp timestamp, const struct TALER_Amount *amount, const struct TALER_CoinSpendPublicKeyP *old_coin_pub, - const struct GNUNET_HashCode *old_denom_pub_hash, + const struct TALER_DenominationHashP *old_denom_pub_hash, const struct TALER_CoinPublicInfo *coin, const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_CoinSpendSignatureP *coin_sig, - const struct TALER_DenominationBlindingKeyP *coin_blind) + const union GNUNET_CRYPTO_BlindingSecretP *coin_blind) { struct CoinContext *cc = cls; - const struct TALER_DenominationKeyValidityPS *issue; + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; enum GNUNET_DB_QueryStatus qs; (void) timestamp; (void) old_coin_pub; - GNUNET_assert (rowid >= ppc.last_recoup_refresh_serial_id); /* should be monotonically increasing */ - ppc.last_recoup_refresh_serial_id = rowid + 1; + GNUNET_assert (rowid >= TALER_ARL_USE_PP (coins_recoup_refresh_serial_id)); /* should be monotonically increasing */ + TALER_ARL_USE_PP (coins_recoup_refresh_serial_id) = rowid + 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recoup-refresh amount is %s\n", TALER_amount2s (amount)); @@ -2189,17 +2205,39 @@ recoup_refresh_cb (void *cls, } else { - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&dso->denom_balance, - &dso->denom_balance, - amount)); + TALER_ARL_amount_add (&dso->dcd.denom_balance, + &dso->dcd.denom_balance, + amount); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New balance of denomination `%s' after refresh-recoup is %s\n", - GNUNET_h2s (&issue->denom_hash), - TALER_amount2s (&dso->denom_balance)); + GNUNET_h2s (&issue->denom_hash.hash), + TALER_amount2s (&dso->dcd.denom_balance)); } } + if (GNUNET_OK != + TALER_wallet_recoup_refresh_verify (&coin->denom_pub_hash, + coin_blind, + &coin->coin_pub, + coin_sig)) + { + TALER_ARL_report (report_bad_sig_losses, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("operation", + "recoup-refresh"), + GNUNET_JSON_pack_uint64 ("row", + rowid), + TALER_JSON_pack_amount ("loss", + amount), + GNUNET_JSON_pack_data_auto ("coin_pub", + &coin->coin_pub))); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_irregular_loss), + &TALER_ARL_USE_AB (coin_irregular_loss), + amount); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; + } return check_recoup (cc, "recoup-refresh", rowid, @@ -2212,6 +2250,197 @@ recoup_refresh_cb (void *cls, /** + * Function called with the results of iterate_denomination_info(), + * or directly (!). Used to check that we correctly signed the + * denomination and to warn if there are denominations not approved + * by this auditor. + * + * @param cls closure, NULL + * @param denom_pub public key, sometimes NULL (!) + * @param issue issuing information with value, fees and other info about the denomination. + */ +static void +check_denomination ( + void *cls, + const struct TALER_DenominationPublicKey *denom_pub, + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue) +{ + enum GNUNET_DB_QueryStatus qs; + struct TALER_AuditorSignatureP auditor_sig; + + (void) cls; + (void) denom_pub; + qs = TALER_ARL_edb->select_auditor_denom_sig (TALER_ARL_edb->cls, + &issue->denom_hash, + &TALER_ARL_auditor_pub, + &auditor_sig); + if (0 > qs) + { + GNUNET_break (0); + return; /* skip! */ + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Encountered denomination `%s' (%s) valid from %s (%llu-%llu) that this auditor is not auditing!\n", + GNUNET_h2s (&issue->denom_hash.hash), + TALER_amount2s (&issue->value), + GNUNET_TIME_timestamp2s (issue->start), + (unsigned long long) issue->start.abs_time.abs_value_us, + (unsigned long long) issue->expire_legal.abs_time.abs_value_us); + return; /* skip! */ + } + if (GNUNET_OK != + TALER_auditor_denom_validity_verify ( + TALER_ARL_auditor_url, + &issue->denom_hash, + &TALER_ARL_master_pub, + issue->start, + issue->expire_withdraw, + issue->expire_deposit, + issue->expire_legal, + &issue->value, + &issue->fees, + &TALER_ARL_auditor_pub, + &auditor_sig)) + { + TALER_ARL_report (report_denominations_without_sigs, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("denomination", + &issue->denom_hash), + TALER_JSON_pack_amount ("value", + &issue->value), + TALER_JSON_pack_time_abs_human ("start_time", + issue->start.abs_time), + TALER_JSON_pack_time_abs_human ("end_time", + issue->expire_legal. + abs_time))); + } +} + + +/** + * Function called with details about purse deposits that have been made, with + * the goal of auditing the deposit's execution. + * + * @param cls closure + * @param rowid unique serial ID for the deposit in our DB + * @param deposit deposit details + * @param reserve_pub which reserve is the purse merged into, NULL if unknown + * @param flags purse flags + * @param auditor_balance purse balance (according to the + * auditor during auditing) + * @param purse_total target amount the purse should reach + * @param denom_pub denomination public key of @a coin_pub + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +static enum GNUNET_GenericReturnValue +purse_deposit_cb ( + void *cls, + uint64_t rowid, + const struct TALER_EXCHANGEDB_PurseDeposit *deposit, + const struct TALER_ReservePublicKeyP *reserve_pub, + enum TALER_WalletAccountMergeFlags flags, + const struct TALER_Amount *auditor_balance, + const struct TALER_Amount *purse_total, + const struct TALER_DenominationPublicKey *denom_pub) +{ + struct CoinContext *cc = cls; + enum GNUNET_DB_QueryStatus qs; + struct TALER_DenominationHashP dh; + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; + struct DenominationSummary *ds; + + (void) flags; + (void) auditor_balance; + (void) purse_total; + (void) reserve_pub; + GNUNET_assert (rowid >= + TALER_ARL_USE_PP (coins_purse_deposits_serial_id)); + TALER_ARL_USE_PP (coins_purse_deposits_serial_id) = rowid + 1; + qs = TALER_ARL_get_denomination_info (denom_pub, + &issue, + &dh); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + report_row_inconsistency ("purse-deposits", + rowid, + "denomination key not found"); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; + } + qs = check_known_coin ("purse-deposit", + issue, + rowid, + &deposit->coin_pub, + denom_pub, + &deposit->amount); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + cc->qs = qs; + return GNUNET_SYSERR; + } + + if (GNUNET_OK != + TALER_wallet_purse_deposit_verify ( + NULL != deposit->exchange_base_url + ? deposit->exchange_base_url + : TALER_ARL_exchange_url, + &deposit->purse_pub, + &deposit->amount, + &dh, + &deposit->h_age_commitment, + &deposit->coin_pub, + &deposit->coin_sig)) + { + TALER_ARL_report (report_bad_sig_losses, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("operation", + "purse-deposit"), + GNUNET_JSON_pack_uint64 ("row", + rowid), + TALER_JSON_pack_amount ("loss", + &deposit->amount), + GNUNET_JSON_pack_data_auto ("coin_pub", + &deposit->coin_pub))); + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_irregular_loss), + &TALER_ARL_USE_AB (coin_irregular_loss), + &deposit->amount); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; + } + + /* update coin's denomination balance */ + ds = get_denomination_summary (cc, + issue, + &issue->denom_hash); + if (NULL == ds) + { + report_row_inconsistency ("purse-deposit", + rowid, + "denomination key for purse-deposited coin unknown to auditor"); + } + else + { + reduce_denom_balance (ds, + rowid, + &deposit->amount); + } + + /* update global deposit fees */ + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_deposit_fee_revenue), + &TALER_ARL_USE_AB (coin_deposit_fee_revenue), + &issue->fees.deposit); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** * Analyze the exchange's processing of coins. * * @param cls closure @@ -2227,11 +2456,28 @@ analyze_coins (void *cls) (void) cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Checking denominations...\n"); + qs = TALER_ARL_edb->iterate_denomination_info (TALER_ARL_edb->cls, + &check_denomination, + NULL); + if (0 > qs) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + return qs; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Analyzing coins\n"); - qsp = TALER_ARL_adb->get_auditor_progress_coin (TALER_ARL_adb->cls, - TALER_ARL_asession, - &TALER_ARL_master_pub, - &ppc); + qsp = TALER_ARL_adb->get_auditor_progress ( + TALER_ARL_adb->cls, + TALER_ARL_GET_PP (coins_withdraw_serial_id), + TALER_ARL_GET_PP (coins_deposit_serial_id), + TALER_ARL_GET_PP (coins_melt_serial_id), + TALER_ARL_GET_PP (coins_refund_serial_id), + TALER_ARL_GET_PP (coins_recoup_serial_id), + TALER_ARL_GET_PP (coins_recoup_refresh_serial_id), + TALER_ARL_GET_PP (coins_purse_deposits_serial_id), + TALER_ARL_GET_PP (coins_purse_refunds_serial_id), + NULL); if (0 > qsp) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsp); @@ -2244,30 +2490,39 @@ analyze_coins (void *cls) } else { - ppc_start = ppc; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Resuming coin audit at %llu/%llu/%llu/%llu/%llu\n", - (unsigned long long) ppc.last_deposit_serial_id, - (unsigned long long) ppc.last_melt_serial_id, - (unsigned long long) ppc.last_refund_serial_id, - (unsigned long long) ppc.last_withdraw_serial_id, - (unsigned long long) ppc.last_recoup_refresh_serial_id); + GNUNET_log ( + GNUNET_ERROR_TYPE_INFO, + "Resuming coin audit at %llu/%llu/%llu/%llu/%llu/%llu/%llu\n", + (unsigned long long) TALER_ARL_USE_PP ( + coins_deposit_serial_id), + (unsigned long long) TALER_ARL_USE_PP ( + coins_melt_serial_id), + (unsigned long long) TALER_ARL_USE_PP ( + coins_refund_serial_id), + (unsigned long long) TALER_ARL_USE_PP ( + coins_withdraw_serial_id), + (unsigned long long) TALER_ARL_USE_PP ( + coins_recoup_refresh_serial_id), + (unsigned long long) TALER_ARL_USE_PP ( + coins_purse_deposits_serial_id), + (unsigned long long) TALER_ARL_USE_PP ( + coins_purse_refunds_serial_id)); } /* setup 'cc' */ cc.qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; cc.denom_summaries = GNUNET_CONTAINER_multihashmap_create (256, GNUNET_NO); - qsx = TALER_ARL_adb->get_balance_summary (TALER_ARL_adb->cls, - TALER_ARL_asession, - &TALER_ARL_master_pub, - &total_escrow_balance, - &total_deposit_fee_income, - &total_melt_fee_income, - &total_refund_fee_income, - &total_risk, - &total_recoup_loss, - &total_irregular_recoups); + qsx = TALER_ARL_adb->get_balance ( + TALER_ARL_adb->cls, + TALER_ARL_GET_AB (coin_balance_risk), + TALER_ARL_GET_AB (total_escrowed), + TALER_ARL_GET_AB (coin_irregular_loss), + TALER_ARL_GET_AB (coin_melt_fee_revenue), + TALER_ARL_GET_AB (coin_deposit_fee_revenue), + TALER_ARL_GET_AB (coin_refund_fee_revenue), + TALER_ARL_GET_AB (total_recoup_loss), + NULL); if (0 > qsx) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx); @@ -2278,8 +2533,7 @@ analyze_coins (void *cls) if (0 > (qs = TALER_ARL_edb->select_withdrawals_above_serial_id ( TALER_ARL_edb->cls, - TALER_ARL_esession, - ppc.last_withdraw_serial_id, + TALER_ARL_USE_PP (coins_withdraw_serial_id), &withdraw_cb, &cc)) ) { @@ -2293,8 +2547,7 @@ analyze_coins (void *cls) if (0 > (qs = TALER_ARL_edb->select_refunds_above_serial_id ( TALER_ARL_edb->cls, - TALER_ARL_esession, - ppc.last_refund_serial_id, + TALER_ARL_USE_PP (coins_refund_serial_id), &refund_cb, &cc))) { @@ -2304,12 +2557,26 @@ analyze_coins (void *cls) if (0 > cc.qs) return cc.qs; + /* process purse_refunds */ + if (0 > + (qs = TALER_ARL_edb->select_purse_decisions_above_serial_id ( + TALER_ARL_edb->cls, + TALER_ARL_USE_PP (coins_purse_refunds_serial_id), + true, /* only go for refunds! */ + &purse_refund_cb, + &cc))) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + return qs; + } + if (0 > cc.qs) + return cc.qs; + /* process recoups */ if (0 > (qs = TALER_ARL_edb->select_recoup_refresh_above_serial_id ( TALER_ARL_edb->cls, - TALER_ARL_esession, - ppc.last_recoup_refresh_serial_id, + TALER_ARL_USE_PP (coins_recoup_refresh_serial_id), &recoup_refresh_cb, &cc))) { @@ -2321,8 +2588,7 @@ analyze_coins (void *cls) if (0 > (qs = TALER_ARL_edb->select_recoup_above_serial_id ( TALER_ARL_edb->cls, - TALER_ARL_esession, - ppc.last_recoup_serial_id, + TALER_ARL_USE_PP (coins_recoup_serial_id), &recoup_cb, &cc))) { @@ -2332,12 +2598,11 @@ analyze_coins (void *cls) if (0 > cc.qs) return cc.qs; - /* process refreshs */ + /* process refreshes */ if (0 > (qs = TALER_ARL_edb->select_refreshes_above_serial_id ( TALER_ARL_edb->cls, - TALER_ARL_esession, - ppc.last_melt_serial_id, + TALER_ARL_USE_PP (coins_melt_serial_id), &refresh_session_cb, &cc))) { @@ -2349,10 +2614,9 @@ analyze_coins (void *cls) /* process deposits */ if (0 > - (qs = TALER_ARL_edb->select_deposits_above_serial_id ( + (qs = TALER_ARL_edb->select_coin_deposits_above_serial_id ( TALER_ARL_edb->cls, - TALER_ARL_esession, - ppc.last_deposit_serial_id, + TALER_ARL_USE_PP (coins_deposit_serial_id), &deposit_cb, &cc))) { @@ -2362,6 +2626,20 @@ analyze_coins (void *cls) if (0 > cc.qs) return cc.qs; + /* process purse_deposits */ + if (0 > + (qs = TALER_ARL_edb->select_purse_deposits_above_serial_id ( + TALER_ARL_edb->cls, + TALER_ARL_USE_PP (coins_purse_deposits_serial_id), + &purse_deposit_cb, + &cc))) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + return qs; + } + if (0 > cc.qs) + return cc.qs; + /* sync 'cc' back to disk */ cc.qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; GNUNET_CONTAINER_multihashmap_iterate (cc.denom_summaries, @@ -2374,27 +2652,27 @@ analyze_coins (void *cls) return cc.qs; } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qsx) - qs = TALER_ARL_adb->update_balance_summary (TALER_ARL_adb->cls, - TALER_ARL_asession, - &TALER_ARL_master_pub, - &total_escrow_balance, - &total_deposit_fee_income, - &total_melt_fee_income, - &total_refund_fee_income, - &total_risk, - &total_recoup_loss, - &total_irregular_recoups); + qs = TALER_ARL_adb->update_balance ( + TALER_ARL_adb->cls, + TALER_ARL_SET_AB (coin_balance_risk), + TALER_ARL_SET_AB (total_escrowed), + TALER_ARL_SET_AB (coin_irregular_loss), + TALER_ARL_SET_AB (coin_melt_fee_revenue), + TALER_ARL_SET_AB (coin_deposit_fee_revenue), + TALER_ARL_SET_AB (coin_refund_fee_revenue), + TALER_ARL_SET_AB (total_recoup_loss), + NULL); else - qs = TALER_ARL_adb->insert_balance_summary (TALER_ARL_adb->cls, - TALER_ARL_asession, - &TALER_ARL_master_pub, - &total_escrow_balance, - &total_deposit_fee_income, - &total_melt_fee_income, - &total_refund_fee_income, - &total_risk, - &total_recoup_loss, - &total_irregular_recoups); + qs = TALER_ARL_adb->insert_balance ( + TALER_ARL_adb->cls, + TALER_ARL_SET_AB (coin_balance_risk), + TALER_ARL_SET_AB (total_escrowed), + TALER_ARL_SET_AB (coin_irregular_loss), + TALER_ARL_SET_AB (coin_melt_fee_revenue), + TALER_ARL_SET_AB (coin_deposit_fee_revenue), + TALER_ARL_SET_AB (coin_refund_fee_revenue), + TALER_ARL_SET_AB (total_recoup_loss), + NULL); if (0 >= qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -2402,15 +2680,29 @@ analyze_coins (void *cls) } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qsp) - qs = TALER_ARL_adb->update_auditor_progress_coin (TALER_ARL_adb->cls, - TALER_ARL_asession, - &TALER_ARL_master_pub, - &ppc); + qs = TALER_ARL_adb->update_auditor_progress ( + TALER_ARL_adb->cls, + TALER_ARL_SET_PP (coins_withdraw_serial_id), + TALER_ARL_SET_PP (coins_deposit_serial_id), + TALER_ARL_SET_PP (coins_melt_serial_id), + TALER_ARL_SET_PP (coins_refund_serial_id), + TALER_ARL_SET_PP (coins_recoup_serial_id), + TALER_ARL_SET_PP (coins_recoup_refresh_serial_id), + TALER_ARL_SET_PP (coins_purse_deposits_serial_id), + TALER_ARL_SET_PP (coins_purse_refunds_serial_id), + NULL); else - qs = TALER_ARL_adb->insert_auditor_progress_coin (TALER_ARL_adb->cls, - TALER_ARL_asession, - &TALER_ARL_master_pub, - &ppc); + qs = TALER_ARL_adb->insert_auditor_progress ( + TALER_ARL_adb->cls, + TALER_ARL_SET_PP (coins_withdraw_serial_id), + TALER_ARL_SET_PP (coins_deposit_serial_id), + TALER_ARL_SET_PP (coins_melt_serial_id), + TALER_ARL_SET_PP (coins_refund_serial_id), + TALER_ARL_SET_PP (coins_recoup_serial_id), + TALER_ARL_SET_PP (coins_recoup_refresh_serial_id), + TALER_ARL_SET_PP (coins_purse_deposits_serial_id), + TALER_ARL_SET_PP (coins_purse_refunds_serial_id), + NULL); if (0 >= qs) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -2419,12 +2711,17 @@ analyze_coins (void *cls) return qs; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Concluded coin audit step at %llu/%llu/%llu/%llu/%llu\n", - (unsigned long long) ppc.last_deposit_serial_id, - (unsigned long long) ppc.last_melt_serial_id, - (unsigned long long) ppc.last_refund_serial_id, - (unsigned long long) ppc.last_withdraw_serial_id, - (unsigned long long) ppc.last_recoup_refresh_serial_id); + "Concluded coin audit step at %llu/%llu/%llu/%llu/%llu/%llu/%llu\n", + (unsigned long long) TALER_ARL_USE_PP (coins_deposit_serial_id), + (unsigned long long) TALER_ARL_USE_PP (coins_melt_serial_id), + (unsigned long long) TALER_ARL_USE_PP (coins_refund_serial_id), + (unsigned long long) TALER_ARL_USE_PP (coins_withdraw_serial_id), + (unsigned long long) TALER_ARL_USE_PP ( + coins_recoup_refresh_serial_id), + (unsigned long long) TALER_ARL_USE_PP ( + coins_purse_deposits_serial_id), + (unsigned long long) TALER_ARL_USE_PP ( + coins_purse_refunds_serial_id)); return qs; } @@ -2443,8 +2740,6 @@ run (void *cls, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { - json_t *report; - (void) cls; (void) args; (void) cfgfile; @@ -2453,55 +2748,56 @@ run (void *cls, if (GNUNET_OK != TALER_ARL_init (c)) { - global_ret = 1; + global_ret = EXIT_FAILURE; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting audit\n"); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, + TALER_amount_set_zero (TALER_ARL_currency, &reported_emergency_loss)); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, + TALER_amount_set_zero (TALER_ARL_currency, &reported_emergency_risk_by_amount)); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, + TALER_amount_set_zero (TALER_ARL_currency, &reported_emergency_risk_by_count)); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, + TALER_amount_set_zero (TALER_ARL_currency, &reported_emergency_loss_by_count)); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &total_escrow_balance)); + TALER_amount_set_zero (TALER_ARL_currency, + &TALER_ARL_USE_AB (total_escrowed))); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &total_risk)); + TALER_amount_set_zero (TALER_ARL_currency, + &TALER_ARL_USE_AB ( + coin_deposit_fee_revenue))); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &total_recoup_loss)); + TALER_amount_set_zero (TALER_ARL_currency, + &TALER_ARL_USE_AB ( + coin_melt_fee_revenue))); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &total_irregular_recoups)); + TALER_amount_set_zero (TALER_ARL_currency, + &TALER_ARL_USE_AB ( + coin_refund_fee_revenue))); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &total_deposit_fee_income)); + TALER_amount_set_zero (TALER_ARL_currency, + &TALER_ARL_USE_AB (coin_balance_risk))); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &total_melt_fee_income)); + TALER_amount_set_zero (TALER_ARL_currency, + &TALER_ARL_USE_AB (total_recoup_loss))); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &total_refund_fee_income)); + TALER_amount_set_zero (TALER_ARL_currency, + &TALER_ARL_USE_AB ( + coin_irregular_loss))); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, + TALER_amount_set_zero (TALER_ARL_currency, &total_arithmetic_delta_plus)); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, + TALER_amount_set_zero (TALER_ARL_currency, &total_arithmetic_delta_minus)); GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, - &total_bad_sig_loss)); - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TALER_ARL_currency, + TALER_amount_set_zero (TALER_ARL_currency, &total_refresh_hanging)); GNUNET_assert (NULL != (report_emergencies = json_array ())); @@ -2510,12 +2806,14 @@ run (void *cls, GNUNET_assert (NULL != (report_row_inconsistencies = json_array ())); GNUNET_assert (NULL != + (report_denominations_without_sigs = json_array ())); + GNUNET_assert (NULL != (report_amount_arithmetic_inconsistencies = json_array ())); GNUNET_assert (NULL != (report_bad_sig_losses = json_array ())); GNUNET_assert (NULL != - (report_refreshs_hanging = json_array ())); + (report_refreshes_hanging = json_array ())); if (GNUNET_OK != TALER_ARL_setup_sessions_and_run (&analyze_coins, NULL)) @@ -2525,117 +2823,101 @@ run (void *cls, } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audit complete\n"); - report = json_pack ("{s:o, s:o, s:o, s:o, s:o," - " s:o, s:o, s:o, s:o, s:o," - " s:o, s:o, s:o, s:o, s:o," - " s:o, s:o, s:o, s:o, s:o," - " s:I, s:I, s:I, s:I, s:I," - " s:I, s:I, s:I, s:I, s:I," - " s:I, s:I, s:o, s:o, s:o}", - /* Block #1 */ - "total_escrow_balance", - TALER_JSON_from_amount (&total_escrow_balance), - "total_active_risk", - TALER_JSON_from_amount (&total_risk), - "total_deposit_fee_income", - TALER_JSON_from_amount ( - &total_deposit_fee_income), - "total_melt_fee_income", - TALER_JSON_from_amount (&total_melt_fee_income), - "total_refund_fee_income", - TALER_JSON_from_amount ( - &total_refund_fee_income), - /* Block #2 */ - /* Tested in test-auditor.sh #18 */ - "emergencies", - report_emergencies, - /* Tested in test-auditor.sh #18 */ - "emergencies_risk_by_amount", - TALER_JSON_from_amount ( - &reported_emergency_risk_by_amount), - /* Tested in test-auditor.sh #4/#5/#6/#13/#26 */ - "bad_sig_losses", - report_bad_sig_losses, - /* Tested in test-auditor.sh #4/#5/#6/#13/#26 */ - "total_bad_sig_loss", - TALER_JSON_from_amount (&total_bad_sig_loss), - /* Tested in test-auditor.sh #31 */ - "row_inconsistencies", - report_row_inconsistencies, - /* Block #3 */ - /* Tested in test-auditor.sh #18 */ - "amount_arithmetic_inconsistencies", - report_amount_arithmetic_inconsistencies, - "total_arithmetic_delta_plus", - TALER_JSON_from_amount ( - &total_arithmetic_delta_plus), - "total_arithmetic_delta_minus", - TALER_JSON_from_amount ( - &total_arithmetic_delta_minus), - /* Tested in test-auditor.sh #12 */ - "total_refresh_hanging", - TALER_JSON_from_amount (&total_refresh_hanging), - /* Tested in test-auditor.sh #12 */ - "refresh_hanging", - report_refreshs_hanging, - /* Block #4 */ - "total_recoup_loss", - TALER_JSON_from_amount (&total_recoup_loss), - /* Tested in test-auditor.sh #18 */ - "emergencies_by_count", - report_emergencies_by_count, - /* Tested in test-auditor.sh #18 */ - "emergencies_risk_by_count", - TALER_JSON_from_amount ( - &reported_emergency_risk_by_count), - /* Tested in test-auditor.sh #18 */ - "emergencies_loss", - TALER_JSON_from_amount ( - &reported_emergency_loss), - /* Tested in test-auditor.sh #18 */ - "emergencies_loss_by_count", - TALER_JSON_from_amount ( - &reported_emergency_loss_by_count), - /* Block #5 */ - "start_ppc_withdraw_serial_id", - (json_int_t) ppc_start.last_withdraw_serial_id, - "start_ppc_deposit_serial_id", - (json_int_t) ppc_start.last_deposit_serial_id, - "start_ppc_melt_serial_id", - (json_int_t) ppc_start.last_melt_serial_id, - "start_ppc_refund_serial_id", - (json_int_t) ppc_start.last_refund_serial_id, - "start_ppc_recoup_serial_id", - (json_int_t) ppc_start.last_recoup_serial_id, - /* Block #6 */ - "start_ppc_recoup_refresh_serial_id", - (json_int_t) ppc_start. - last_recoup_refresh_serial_id, - "end_ppc_withdraw_serial_id", - (json_int_t) ppc.last_withdraw_serial_id, - "end_ppc_deposit_serial_id", - (json_int_t) ppc.last_deposit_serial_id, - "end_ppc_melt_serial_id", - (json_int_t) ppc.last_melt_serial_id, - "end_ppc_refund_serial_id", - (json_int_t) ppc.last_refund_serial_id, - /* Block #7 */ - "end_ppc_recoup_serial_id", - (json_int_t) ppc.last_recoup_serial_id, - "end_ppc_recoup_refresh_serial_id", - (json_int_t) ppc.last_recoup_refresh_serial_id, - "auditor_start_time", - TALER_ARL_json_from_time_abs ( - start_time), - "auditor_end_time", - TALER_ARL_json_from_time_abs ( - GNUNET_TIME_absolute_get ()), - "total_irregular_recoups", - TALER_JSON_from_amount ( - &total_irregular_recoups) - ); - GNUNET_break (NULL != report); - TALER_ARL_done (report); + TALER_ARL_done ( + GNUNET_JSON_PACK ( + TALER_JSON_pack_amount ("total_escrow_balance", + &TALER_ARL_USE_AB (total_escrowed)), + TALER_JSON_pack_amount ("total_deposit_fee_income", + &TALER_ARL_USE_AB (coin_deposit_fee_revenue)), + TALER_JSON_pack_amount ("total_melt_fee_income", + &TALER_ARL_USE_AB (coin_melt_fee_revenue)), + TALER_JSON_pack_amount ("total_refund_fee_income", + &TALER_ARL_USE_AB (coin_refund_fee_revenue)), + TALER_JSON_pack_amount ("total_active_risk", + &TALER_ARL_USE_AB (coin_balance_risk)), + TALER_JSON_pack_amount ("total_recoup_loss", + &TALER_ARL_USE_AB (total_recoup_loss)), + /* Tested in test-auditor.sh #4/#5/#6/#13/#26 */ + TALER_JSON_pack_amount ("irregular_loss", + &TALER_ARL_USE_AB (coin_irregular_loss)), + /* Tested in test-auditor.sh #18 */ + GNUNET_JSON_pack_array_steal ("emergencies", + report_emergencies), + /* Tested in test-auditor.sh #18 */ + TALER_JSON_pack_amount ("emergencies_risk_by_amount", + &reported_emergency_risk_by_amount), + /* Tested in test-auditor.sh #31 */ + GNUNET_JSON_pack_array_steal ("row_inconsistencies", + report_row_inconsistencies), + /* Tested in test-auditor.sh #18 */ + GNUNET_JSON_pack_array_steal ("amount_arithmetic_inconsistencies", + report_amount_arithmetic_inconsistencies), + TALER_JSON_pack_amount ("total_arithmetic_delta_plus", + &total_arithmetic_delta_plus), + TALER_JSON_pack_amount ("total_arithmetic_delta_minus", + &total_arithmetic_delta_minus), + TALER_JSON_pack_amount ("total_refresh_hanging", + &total_refresh_hanging), + GNUNET_JSON_pack_array_steal ("bad_sig_losses", + report_bad_sig_losses), + /* Tested in test-auditor.sh #12 */ + GNUNET_JSON_pack_array_steal ("refresh_hanging", + report_refreshes_hanging), + /* Tested in test-auditor.sh #18 */ + GNUNET_JSON_pack_array_steal ("emergencies_by_count", + report_emergencies_by_count), + /* Tested in test-auditor.sh #18 */ + TALER_JSON_pack_amount ("emergencies_risk_by_count", + &reported_emergency_risk_by_count), + /* Tested in test-auditor.sh #18 */ + TALER_JSON_pack_amount ("emergencies_loss", + &reported_emergency_loss), + /* Tested in test-auditor.sh #18 */ + TALER_JSON_pack_amount ("emergencies_loss_by_count", + &reported_emergency_loss_by_count), + GNUNET_JSON_pack_uint64 ("start_ppc_withdraw_serial_id", + 0 /* not implemented */), + GNUNET_JSON_pack_uint64 ("start_ppc_deposit_serial_id", + 0 /* not implemented */), + GNUNET_JSON_pack_uint64 ("start_ppc_melt_serial_id", + 0 /* not implemented */), + GNUNET_JSON_pack_uint64 ("start_ppc_refund_serial_id", + 0 /* not implemented */), + GNUNET_JSON_pack_uint64 ("start_ppc_recoup_serial_id", + 0 /* not implemented */), + GNUNET_JSON_pack_uint64 ("start_ppc_recoup_refresh_serial_id", + 0 /* not implemented */), + GNUNET_JSON_pack_uint64 ("start_ppc_purse_deposits_serial_id", + 0 /* not implemented */), + GNUNET_JSON_pack_uint64 ("start_ppc_purse_refunds_serial_id", + 0 /* not implemented */), + GNUNET_JSON_pack_uint64 ("end_ppc_withdraw_serial_id", + TALER_ARL_USE_PP (coins_withdraw_serial_id)), + GNUNET_JSON_pack_uint64 ("end_ppc_deposit_serial_id", + TALER_ARL_USE_PP (coins_deposit_serial_id)), + GNUNET_JSON_pack_uint64 ("end_ppc_melt_serial_id", + TALER_ARL_USE_PP (coins_melt_serial_id)), + GNUNET_JSON_pack_uint64 ("end_ppc_refund_serial_id", + TALER_ARL_USE_PP (coins_refund_serial_id)), + GNUNET_JSON_pack_uint64 ("end_ppc_recoup_serial_id", + TALER_ARL_USE_PP (coins_recoup_serial_id)), + GNUNET_JSON_pack_uint64 ("end_ppc_recoup_refresh_serial_id", + TALER_ARL_USE_PP ( + coins_recoup_refresh_serial_id)), + GNUNET_JSON_pack_uint64 ("end_ppc_purse_deposits_serial_id", + TALER_ARL_USE_PP ( + coins_purse_deposits_serial_id)), + GNUNET_JSON_pack_uint64 ("end_ppc_purse_refunds_serial_id", + TALER_ARL_USE_PP ( + coins_purse_refunds_serial_id)), + TALER_JSON_pack_time_abs_human ( + "auditor_start_time", + start_time), + TALER_JSON_pack_time_abs_human ("auditor_end_time", + GNUNET_TIME_absolute_get ()), + GNUNET_JSON_pack_array_steal ( + "unsigned_denominations", + report_denominations_without_sigs))); } @@ -2651,33 +2933,41 @@ main (int argc, char *const *argv) { const struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_option_base32_auto ('m', - "exchange-key", - "KEY", - "public key of the exchange (Crockford base32 encoded)", - &TALER_ARL_master_pub), + GNUNET_GETOPT_option_flag ('i', + "internal", + "perform checks only applicable for exchange-internal audits", + &internal_checks), + GNUNET_GETOPT_option_flag ('t', + "test", + "run in test mode and exit when idle", + &test_mode), GNUNET_GETOPT_option_timetravel ('T', "timetravel"), GNUNET_GETOPT_OPTION_END }; + enum GNUNET_GenericReturnValue ret; /* force linker to link against libtalerutil; if we do not do this, the linker may "optimize" libtalerutil away and skip #TALER_OS_init(), which we do need */ (void) TALER_project_data_default (); - GNUNET_assert (GNUNET_OK == - GNUNET_log_setup ("taler-helper-auditor-coins", - "MESSAGE", - NULL)); if (GNUNET_OK != - GNUNET_PROGRAM_run (argc, - argv, - "taler-helper-auditor-coins", - "Audit Taler coin processing", - options, - &run, - NULL)) - return 1; + GNUNET_STRINGS_get_utf8_args (argc, argv, + &argc, &argv)) + return EXIT_INVALIDARGUMENT; + ret = GNUNET_PROGRAM_run ( + argc, + argv, + "taler-helper-auditor-coins", + gettext_noop ("Audit Taler coin processing"), + options, + &run, + NULL); + GNUNET_free_nz ((void *) argv); + if (GNUNET_SYSERR == ret) + return EXIT_INVALIDARGUMENT; + if (GNUNET_NO == ret) + return EXIT_SUCCESS; return global_ret; } |