diff options
Diffstat (limited to 'src/auditor/taler-helper-auditor-coins.c')
-rw-r--r-- | src/auditor/taler-helper-auditor-coins.c | 1153 |
1 files changed, 731 insertions, 422 deletions
diff --git a/src/auditor/taler-helper-auditor-coins.c b/src/auditor/taler-helper-auditor-coins.c index ad9048a17..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-2021 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,7 +90,7 @@ 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; @@ -115,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. @@ -156,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. @@ -210,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; } @@ -248,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", @@ -471,15 +453,27 @@ 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; - qs = TALER_ARL_edb->get_coin_transactions (TALER_ARL_edb->cls, - coin_pub, - GNUNET_YES, - &tl); + /* 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, + coin_pub, + 0, + 0, + &etag_out, + &balance, + &h_denom_pub, + &tl); + } if (0 >= qs) return qs; - GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (value->currency, &refunded)); @@ -489,7 +483,7 @@ check_coin_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, GNUNET_assert (GNUNET_OK == 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) @@ -517,7 +511,7 @@ check_coin_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, TALER_ARL_amount_add (&spent, &spent, &pos->details.refund->refund_fee); - have_refund = GNUNET_YES; + have_refund = true; break; case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP: /* refunded += pos->value */ @@ -537,8 +531,28 @@ check_coin_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, &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) { @@ -589,33 +603,9 @@ 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. @@ -623,22 +613,22 @@ struct DenominationSummary 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; }; @@ -678,11 +668,7 @@ init_denomination (const struct TALER_DenominationHashP *denom_hash, qs = TALER_ARL_adb->get_denomination_balance (TALER_ARL_adb->cls, 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); @@ -690,28 +676,28 @@ init_denomination (const struct TALER_DenominationHashP *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_set_zero (TALER_ARL_currency, - &ds->denom_balance)); + &ds->dcd.denom_balance)); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, - &ds->denom_loss)); + &ds->dcd.denom_loss)); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, - &ds->denom_risk)); + &ds->dcd.denom_risk)); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, - &ds->denom_recoup)); + &ds->dcd.recoup_loss)); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting balance for denomination `%s' is %s (%llu)\n", GNUNET_h2s (&denom_hash->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); qs = TALER_ARL_edb->get_denomination_revocation (TALER_ARL_edb->cls, denom_hash, &msig, @@ -736,10 +722,10 @@ init_denomination (const struct TALER_DenominationHashP *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; } @@ -754,10 +740,10 @@ init_denomination (const struct TALER_DenominationHashP *denom_hash, * @return NULL on error */ static struct DenominationSummary * -get_denomination_summary (struct CoinContext *cc, - const struct - TALER_EXCHANGEDB_DenominationKeyInformation *issue, - const struct TALER_DenominationHashP *dh) +get_denomination_summary ( + struct CoinContext *cc, + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue, + const struct TALER_DenominationHashP *dh) { struct DenominationSummary *ds; @@ -826,38 +812,35 @@ sync_denomination (void *cls, 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. */ - TALER_ARL_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_master_pub, &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); @@ -874,8 +857,8 @@ 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, &denom_h); if (0 > cnt) @@ -887,39 +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, &denom_h, - &ds->denom_balance, - &ds->denom_loss, - &ds->denom_risk, - &ds->denom_recoup, - ds->num_issued); + &ds->dcd); else qs = TALER_ARL_adb->insert_denomination_balance (TALER_ARL_adb->cls, &denom_h, - &ds->denom_balance, - &ds->denom_loss, - &ds->denom_risk, - &ds->denom_recoup, - ds->num_issued); + &ds->dcd); } } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) @@ -981,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, @@ -1016,22 +992,22 @@ withdraw_cb (void *cls, "Issued coin in denomination `%s' of total value %s\n", GNUNET_h2s (&dh.hash), TALER_amount2s (&issue->value)); - ds->num_issued++; - TALER_ARL_amount_add (&ds->denom_balance, - &ds->denom_balance, - &issue->value); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New balance of denomination `%s' is %s\n", GNUNET_h2s (&dh.hash), - TALER_amount2s (&ds->denom_balance)); - TALER_ARL_amount_add (&total_escrow_balance, - &total_escrow_balance, + 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 (&total_risk, - &total_risk, + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_balance_risk), + &TALER_ARL_USE_AB (coin_balance_risk), &issue->value); - TALER_ARL_amount_add (&ds->denom_risk, - &ds->denom_risk, + 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; @@ -1134,13 +1110,13 @@ 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_EXCHANGEDB_DenominationKeyInformation *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; @@ -1185,8 +1161,8 @@ check_known_coin (const char *operation, loss_potential), GNUNET_JSON_pack_data_auto ("coin_pub", coin_pub))); - TALER_ARL_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, + 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); @@ -1195,6 +1171,65 @@ check_known_coin (const char *operation, /** + * 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; + } + 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)); +} + + +/** * Function called with details about coins that were melted, with the * goal of auditing the refresh's execution. Verifies the signature * and updates our information about coins outstanding (the old coin's @@ -1204,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 @@ -1211,7 +1247,7 @@ 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, @@ -1226,12 +1262,12 @@ refresh_session_cb (void *cls, 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, @@ -1279,6 +1315,7 @@ refresh_session_cb (void *cls, coin_pub, coin_sig)) { + GNUNET_break_op (0); TALER_ARL_report (report_bad_sig_losses, GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ("operation", @@ -1289,8 +1326,8 @@ refresh_session_cb (void *cls, amount_with_fee), GNUNET_JSON_pack_data_auto ("coin_pub", coin_pub))); - TALER_ARL_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_irregular_loss), + &TALER_ARL_USE_AB (coin_irregular_loss), amount_with_fee); } } @@ -1323,7 +1360,7 @@ 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, + TALER_ARL_report (report_refreshes_hanging, GNUNET_JSON_PACK ( GNUNET_JSON_pack_uint64 ("row", rowid), @@ -1390,11 +1427,12 @@ refresh_session_cb (void *cls, &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' */ @@ -1424,22 +1462,22 @@ refresh_session_cb (void *cls, "Created fresh coin in denomination `%s' of value %s\n", GNUNET_h2s (&ni->denom_hash.hash), TALER_amount2s (&ni->value)); - dsi->num_issued++; - TALER_ARL_amount_add (&dsi->denom_balance, - &dsi->denom_balance, + dsi->dcd.num_issued++; + TALER_ARL_amount_add (&dsi->dcd.denom_balance, + &dsi->dcd.denom_balance, &ni->value); - TALER_ARL_amount_add (&dsi->denom_risk, - &dsi->denom_risk, + 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 (&ni->denom_hash.hash), - TALER_amount2s (&dsi->denom_balance)); - TALER_ARL_amount_add (&total_escrow_balance, - &total_escrow_balance, + 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 (&total_risk, - &total_risk, + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_balance_risk), + &TALER_ARL_USE_AB (coin_balance_risk), &ni->value); } } @@ -1458,51 +1496,14 @@ refresh_session_cb (void *cls, } else { - if (TALER_ARL_SR_INVALID_NEGATIVE == - TALER_ARL_amount_subtract_neg (&tmp, - &dso->denom_balance, - amount_with_fee)) - { - TALER_ARL_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 - { - TALER_ARL_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.hash), - TALER_amount2s (&dso->denom_balance)); + reduce_denom_balance (dso, + rowid, + amount_with_fee); } /* update global melt fees */ - TALER_ARL_amount_add (&total_melt_fee_income, - &total_melt_fee_income, + 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; @@ -1537,8 +1538,9 @@ deposit_cb (void *cls, (void) done; (void) exchange_timestamp; - GNUNET_assert (rowid >= ppc.last_deposit_serial_id); /* should be monotonically increasing */ - ppc.last_deposit_serial_id = rowid + 1; + 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, @@ -1598,8 +1600,11 @@ deposit_cb (void *cls, &issue->fees.deposit, &h_wire, &deposit->h_contract_terms, + deposit->no_wallet_data_hash + ? NULL + : &deposit->wallet_data_hash, &deposit->coin.h_age_commitment, - NULL /* FIXME: h_extensions! */, + &deposit->h_policy, &h_denom_pub, deposit->timestamp, &deposit->merchant_pub, @@ -1617,8 +1622,8 @@ deposit_cb (void *cls, &deposit->amount_with_fee), GNUNET_JSON_pack_data_auto ("coin_pub", &deposit->coin.coin_pub))); - TALER_ARL_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, + 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; @@ -1643,55 +1648,14 @@ deposit_cb (void *cls, } else { - struct TALER_Amount tmp; - - if (TALER_ARL_SR_INVALID_NEGATIVE == - TALER_ARL_amount_subtract_neg (&tmp, - &ds->denom_balance, - &deposit->amount_with_fee)) - { - TALER_ARL_amount_add (&ds->denom_loss, - &ds->denom_loss, - &deposit->amount_with_fee); - ds->report_emergency = GNUNET_YES; - } - else - { - ds->denom_balance = tmp; - } - - if (-1 == TALER_amount_cmp (&total_escrow_balance, - &deposit->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, - &deposit->amount_with_fee, - 0); - } - else - { - TALER_ARL_amount_subtract (&total_escrow_balance, - &total_escrow_balance, - &deposit->amount_with_fee); - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "New balance of denomination `%s' after deposit is %s\n", - GNUNET_h2s (&issue->denom_hash.hash), - TALER_amount2s (&ds->denom_balance)); + reduce_denom_balance (ds, + rowid, + &deposit->amount_with_fee); } /* update global deposit fees */ - TALER_ARL_amount_add (&total_deposit_fee_income, - &total_deposit_fee_income, + 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; @@ -1713,6 +1677,7 @@ 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 */ @@ -1725,6 +1690,7 @@ refund_cb (void *cls, const struct TALER_MerchantSignatureP *merchant_sig, 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; @@ -1733,8 +1699,8 @@ refund_cb (void *cls, struct TALER_Amount amount_without_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, @@ -1773,8 +1739,8 @@ refund_cb (void *cls, amount_with_fee), GNUNET_JSON_pack_data_auto ("coin_pub", coin_pub))); - TALER_ARL_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, + 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; @@ -1814,27 +1780,160 @@ refund_cb (void *cls, } else { - TALER_ARL_amount_add (&ds->denom_balance, - &ds->denom_balance, + TALER_ARL_amount_add (&ds->dcd.denom_balance, + &ds->dcd.denom_balance, &amount_without_fee); - TALER_ARL_amount_add (&ds->denom_risk, - &ds->denom_risk, + TALER_ARL_amount_add (&ds->dcd.denom_risk, + &ds->dcd.denom_risk, &amount_without_fee); - TALER_ARL_amount_add (&total_escrow_balance, - &total_escrow_balance, + TALER_ARL_amount_add (&TALER_ARL_USE_AB (total_escrowed), + &TALER_ARL_USE_AB (total_escrowed), &amount_without_fee); - TALER_ARL_amount_add (&total_risk, - &total_risk, + 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.hash), - TALER_amount2s (&ds->denom_balance)); + TALER_amount2s (&ds->dcd.denom_balance)); } /* update total refund fee balance */ - TALER_ARL_amount_add (&total_refund_fee_income, - &total_refund_fee_income, + 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; @@ -1863,13 +1962,23 @@ check_recoup (struct CoinContext *cc, const struct TALER_CoinPublicInfo *coin, const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_CoinSpendSignatureP *coin_sig, - const union TALER_DenominationBlindingKeyP *coin_blind) + const union GNUNET_CRYPTO_BlindingSecretP *coin_blind) { struct DenominationSummary *ds; enum GNUNET_DB_QueryStatus qs; 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)) { @@ -1883,8 +1992,8 @@ check_recoup (struct CoinContext *cc, amount), GNUNET_JSON_pack_data_auto ("coin_pub", &coin->denom_pub_hash))); - TALER_ARL_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, + 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, @@ -1929,7 +2038,7 @@ 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, @@ -1944,15 +2053,15 @@ check_recoup (struct CoinContext *cc, amount), GNUNET_JSON_pack_data_auto ("coin_pub", &coin->coin_pub))); - TALER_ARL_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, + TALER_ARL_amount_add (&TALER_ARL_USE_AB (coin_irregular_loss), + &TALER_ARL_USE_AB (coin_irregular_loss), amount); } - TALER_ARL_amount_add (&ds->denom_recoup, - &ds->denom_recoup, + TALER_ARL_amount_add (&ds->dcd.recoup_loss, + &ds->dcd.recoup_loss, amount); - TALER_ARL_amount_add (&total_recoup_loss, - &total_recoup_loss, + TALER_ARL_amount_add (&TALER_ARL_USE_AB (total_recoup_loss), + &TALER_ARL_USE_AB (total_recoup_loss), amount); } if (TALER_ARL_do_abort ()) @@ -1984,12 +2093,12 @@ recoup_cb (void *cls, const struct TALER_CoinPublicInfo *coin, const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_CoinSpendSignatureP *coin_sig, - const union 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 != @@ -2008,8 +2117,8 @@ recoup_cb (void *cls, amount), GNUNET_JSON_pack_data_auto ("coin_pub", &coin->coin_pub))); - TALER_ARL_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, + 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; @@ -2052,7 +2161,7 @@ recoup_refresh_cb (void *cls, const struct TALER_CoinPublicInfo *coin, const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_CoinSpendSignatureP *coin_sig, - const union TALER_DenominationBlindingKeyP *coin_blind) + const union GNUNET_CRYPTO_BlindingSecretP *coin_blind) { struct CoinContext *cc = cls; const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; @@ -2060,8 +2169,8 @@ recoup_refresh_cb (void *cls, (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)); @@ -2096,13 +2205,13 @@ recoup_refresh_cb (void *cls, } else { - TALER_ARL_amount_add (&dso->denom_balance, - &dso->denom_balance, + 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.hash), - TALER_amount2s (&dso->denom_balance)); + TALER_amount2s (&dso->dcd.denom_balance)); } } @@ -2122,8 +2231,8 @@ recoup_refresh_cb (void *cls, amount), GNUNET_JSON_pack_data_auto ("coin_pub", &coin->coin_pub))); - TALER_ARL_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, + 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; @@ -2148,7 +2257,7 @@ recoup_refresh_cb (void *cls, * * @param cls closure, NULL * @param denom_pub public key, sometimes NULL (!) - * @param validity issuing information with value, fees and other info about the denomination. + * @param issue issuing information with value, fees and other info about the denomination. */ static void check_denomination ( @@ -2211,6 +2320,127 @@ check_denomination ( /** + * 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 @@ -2237,9 +2467,17 @@ analyze_coins (void *cls) } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Analyzing coins\n"); - qsp = TALER_ARL_adb->get_auditor_progress_coin (TALER_ARL_adb->cls, - &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); @@ -2252,29 +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_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); @@ -2285,7 +2533,7 @@ analyze_coins (void *cls) if (0 > (qs = TALER_ARL_edb->select_withdrawals_above_serial_id ( TALER_ARL_edb->cls, - ppc.last_withdraw_serial_id, + TALER_ARL_USE_PP (coins_withdraw_serial_id), &withdraw_cb, &cc)) ) { @@ -2299,7 +2547,7 @@ analyze_coins (void *cls) if (0 > (qs = TALER_ARL_edb->select_refunds_above_serial_id ( TALER_ARL_edb->cls, - ppc.last_refund_serial_id, + TALER_ARL_USE_PP (coins_refund_serial_id), &refund_cb, &cc))) { @@ -2309,11 +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, - ppc.last_recoup_refresh_serial_id, + TALER_ARL_USE_PP (coins_recoup_refresh_serial_id), &recoup_refresh_cb, &cc))) { @@ -2325,7 +2588,7 @@ analyze_coins (void *cls) if (0 > (qs = TALER_ARL_edb->select_recoup_above_serial_id ( TALER_ARL_edb->cls, - ppc.last_recoup_serial_id, + TALER_ARL_USE_PP (coins_recoup_serial_id), &recoup_cb, &cc))) { @@ -2335,11 +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, - ppc.last_melt_serial_id, + TALER_ARL_USE_PP (coins_melt_serial_id), &refresh_session_cb, &cc))) { @@ -2351,9 +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, - ppc.last_deposit_serial_id, + TALER_ARL_USE_PP (coins_deposit_serial_id), &deposit_cb, &cc))) { @@ -2363,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, @@ -2375,25 +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_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_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); @@ -2401,13 +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_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_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, @@ -2416,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; } @@ -2467,25 +2767,29 @@ run (void *cls, &reported_emergency_loss_by_count)); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, - &total_escrow_balance)); + &TALER_ARL_USE_AB (total_escrowed))); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, - &total_risk)); + &TALER_ARL_USE_AB ( + coin_deposit_fee_revenue))); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, - &total_recoup_loss)); + &TALER_ARL_USE_AB ( + coin_melt_fee_revenue))); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, - &total_irregular_recoups)); + &TALER_ARL_USE_AB ( + coin_refund_fee_revenue))); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, - &total_deposit_fee_income)); + &TALER_ARL_USE_AB (coin_balance_risk))); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, - &total_melt_fee_income)); + &TALER_ARL_USE_AB (total_recoup_loss))); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, - &total_refund_fee_income)); + &TALER_ARL_USE_AB ( + coin_irregular_loss))); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, &total_arithmetic_delta_plus)); @@ -2494,9 +2798,6 @@ run (void *cls, &total_arithmetic_delta_minus)); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TALER_ARL_currency, - &total_bad_sig_loss)); - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (TALER_ARL_currency, &total_refresh_hanging)); GNUNET_assert (NULL != (report_emergencies = json_array ())); @@ -2512,7 +2813,7 @@ run (void *cls, 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,27 +2826,26 @@ run (void *cls, TALER_ARL_done ( GNUNET_JSON_PACK ( TALER_JSON_pack_amount ("total_escrow_balance", - &total_escrow_balance), - TALER_JSON_pack_amount ("total_active_risk", - &total_risk), + &TALER_ARL_USE_AB (total_escrowed)), TALER_JSON_pack_amount ("total_deposit_fee_income", - &total_deposit_fee_income), + &TALER_ARL_USE_AB (coin_deposit_fee_revenue)), TALER_JSON_pack_amount ("total_melt_fee_income", - &total_melt_fee_income), + &TALER_ARL_USE_AB (coin_melt_fee_revenue)), TALER_JSON_pack_amount ("total_refund_fee_income", - &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 #4/#5/#6/#13/#26 */ - GNUNET_JSON_pack_array_steal ("bad_sig_losses", - report_bad_sig_losses), - /* Tested in test-auditor.sh #4/#5/#6/#13/#26 */ - TALER_JSON_pack_amount ("total_bad_sig_loss", - &total_bad_sig_loss), /* Tested in test-auditor.sh #31 */ GNUNET_JSON_pack_array_steal ("row_inconsistencies", report_row_inconsistencies), @@ -2558,11 +2858,11 @@ run (void *cls, &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_refreshs_hanging), - TALER_JSON_pack_amount ("total_recoup_loss", - &total_recoup_loss), + report_refreshes_hanging), /* Tested in test-auditor.sh #18 */ GNUNET_JSON_pack_array_steal ("emergencies_by_count", report_emergencies_by_count), @@ -2576,38 +2876,48 @@ run (void *cls, TALER_JSON_pack_amount ("emergencies_loss_by_count", &reported_emergency_loss_by_count), GNUNET_JSON_pack_uint64 ("start_ppc_withdraw_serial_id", - ppc_start.last_withdraw_serial_id), + 0 /* not implemented */), GNUNET_JSON_pack_uint64 ("start_ppc_deposit_serial_id", - ppc_start.last_deposit_serial_id), + 0 /* not implemented */), GNUNET_JSON_pack_uint64 ("start_ppc_melt_serial_id", - ppc_start.last_melt_serial_id), + 0 /* not implemented */), GNUNET_JSON_pack_uint64 ("start_ppc_refund_serial_id", - ppc_start.last_refund_serial_id), + 0 /* not implemented */), GNUNET_JSON_pack_uint64 ("start_ppc_recoup_serial_id", - ppc_start.last_recoup_serial_id), + 0 /* not implemented */), GNUNET_JSON_pack_uint64 ("start_ppc_recoup_refresh_serial_id", - ppc_start. - last_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", - ppc.last_withdraw_serial_id), + TALER_ARL_USE_PP (coins_withdraw_serial_id)), GNUNET_JSON_pack_uint64 ("end_ppc_deposit_serial_id", - ppc.last_deposit_serial_id), + TALER_ARL_USE_PP (coins_deposit_serial_id)), GNUNET_JSON_pack_uint64 ("end_ppc_melt_serial_id", - ppc.last_melt_serial_id), + TALER_ARL_USE_PP (coins_melt_serial_id)), GNUNET_JSON_pack_uint64 ("end_ppc_refund_serial_id", - ppc.last_refund_serial_id), + TALER_ARL_USE_PP (coins_refund_serial_id)), GNUNET_JSON_pack_uint64 ("end_ppc_recoup_serial_id", - ppc.last_recoup_serial_id), + TALER_ARL_USE_PP (coins_recoup_serial_id)), GNUNET_JSON_pack_uint64 ("end_ppc_recoup_refresh_serial_id", - ppc.last_recoup_refresh_serial_id), - TALER_JSON_pack_time_abs_human ("auditor_start_time", - start_time), + 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 ()), - TALER_JSON_pack_amount ("total_irregular_recoups", - &total_irregular_recoups), - GNUNET_JSON_pack_array_steal ("unsigned_denominations", - report_denominations_without_sigs))); + GNUNET_JSON_pack_array_steal ( + "unsigned_denominations", + report_denominations_without_sigs))); } @@ -2627,11 +2937,10 @@ main (int argc, "internal", "perform checks only applicable for exchange-internal audits", &internal_checks), - 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 ('t', + "test", + "run in test mode and exit when idle", + &test_mode), GNUNET_GETOPT_option_timetravel ('T', "timetravel"), GNUNET_GETOPT_OPTION_END |