diff options
Diffstat (limited to 'src/auditor/taler-helper-auditor-coins.c')
-rw-r--r-- | src/auditor/taler-helper-auditor-coins.c | 1639 |
1 files changed, 942 insertions, 697 deletions
diff --git a/src/auditor/taler-helper-auditor-coins.c b/src/auditor/taler-helper-auditor-coins.c index 4267cd0c2..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", @@ -276,7 +258,7 @@ 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) { @@ -284,20 +266,21 @@ report_emergency_by_amount ( "Reporting emergency on denomination `%s' over loss of %s\n", GNUNET_h2s (&issue->denom_hash.hash), TALER_amount2s (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_nbo_human ("start", - issue->start), - TALER_JSON_pack_time_abs_nbo_human ("deposit_end", - issue->expire_deposit), - TALER_JSON_pack_amount_nbo ("value", - &issue->value))); + 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); @@ -323,38 +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, - 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_nbo_human ("start", - issue->start), - TALER_JSON_pack_time_abs_nbo_human ("deposit_end", - issue->expire_deposit), - TALER_JSON_pack_amount_nbo ("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); - TALER_amount_ntoh (&denom_value, - &issue->value); for (uint64_t i = num_issued; i<num_known; i++) TALER_ARL_amount_add (&reported_emergency_loss_by_count, &reported_emergency_loss_by_count, - &denom_value); + &issue->value); } @@ -473,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; + + /* 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, - 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_set_zero (value->currency, &refunded)); @@ -491,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) @@ -519,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 */ @@ -539,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) { @@ -591,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. - */ - 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? + * Information about the circulation. */ - 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; }; @@ -671,7 +659,7 @@ struct CoinContext * @return transaction status code */ static enum GNUNET_DB_QueryStatus -init_denomination (const struct TALER_DenominationHash *denom_hash, +init_denomination (const struct TALER_DenominationHashP *denom_hash, struct DenominationSummary *ds) { enum GNUNET_DB_QueryStatus qs; @@ -680,11 +668,7 @@ init_denomination (const struct TALER_DenominationHash *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); @@ -692,28 +676,28 @@ init_denomination (const struct TALER_DenominationHash *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, @@ -738,10 +722,10 @@ init_denomination (const struct TALER_DenominationHash *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; } @@ -756,9 +740,10 @@ init_denomination (const struct TALER_DenominationHash *denom_hash, * @return NULL on error */ static struct DenominationSummary * -get_denomination_summary (struct CoinContext *cc, - const struct TALER_DenominationKeyValidityPS *issue, - const struct TALER_DenominationHash *dh) +get_denomination_summary ( + struct CoinContext *cc, + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue, + const struct TALER_DenominationHashP *dh) { struct DenominationSummary *ds; @@ -794,28 +779,30 @@ 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_DenominationHash denom_h = { + 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. */ @@ -825,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); @@ -873,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) @@ -886,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) @@ -959,18 +935,17 @@ sync_denomination (void *cls, static enum GNUNET_GenericReturnValue withdraw_cb (void *cls, uint64_t rowid, - const struct TALER_BlindedCoinHash *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 TALER_DenominationHash 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 @@ -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, @@ -1012,29 +988,27 @@ 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.hash), - TALER_amount2s (&value)); - ds->num_issued++; - TALER_ARL_amount_add (&ds->denom_balance, - &ds->denom_balance, - &value); + TALER_amount2s (&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, - &value); - TALER_ARL_amount_add (&total_risk, - &total_risk, - &value); - TALER_ARL_amount_add (&ds->denom_risk, - &ds->denom_risk, - &value); + 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; @@ -1050,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. @@ -1067,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. @@ -1082,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++) @@ -1113,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", @@ -1149,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); @@ -1203,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); @@ -1213,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 @@ -1222,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 @@ -1229,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, @@ -1240,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, @@ -1283,24 +1302,20 @@ 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_denom_pub_hash (denom_pub, - &rmc.h_denom_pub); - TALER_amount_hton (&rmc.amount_with_fee, - amount_with_fee); + &h_denom_pub); if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT, - &rmc, - &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, GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ("operation", @@ -1311,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); } } @@ -1345,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), @@ -1380,53 +1395,44 @@ refresh_session_cb (void *cls, &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); TALER_ARL_amount_add (&refresh_cost, &refresh_cost, - &fee); + &ni->fees.withdraw); TALER_ARL_amount_add (&refresh_cost, &refresh_cost, - &value); + &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 (TALER_ARL_SR_POSITIVE != - TALER_ARL_amount_subtract_neg (&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_set_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' */ @@ -1437,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", @@ -1451,29 +1458,27 @@ 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.hash), - TALER_amount2s (&value)); - dsi->num_issued++; - TALER_ARL_amount_add (&dsi->denom_balance, - &dsi->denom_balance, - &value); - TALER_ARL_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.hash), - TALER_amount2s (&dsi->denom_balance)); - TALER_ARL_amount_add (&total_escrow_balance, - &total_escrow_balance, - &value); - TALER_ARL_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 (reveal_ctx.new_issues); @@ -1491,58 +1496,15 @@ 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 */ - { - struct TALER_Amount rfee; - - TALER_amount_ntoh (&rfee, - &issue->fee_refresh); - TALER_ARL_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; @@ -1564,20 +1526,21 @@ refresh_session_cb (void *cls, static enum GNUNET_GenericReturnValue deposit_cb (void *cls, uint64_t rowid, - struct GNUNET_TIME_Absolute exchange_timestamp, + struct GNUNET_TIME_Timestamp exchange_timestamp, const struct TALER_EXCHANGEDB_Deposit *deposit, const struct TALER_DenominationPublicKey *denom_pub, 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) 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, @@ -1591,8 +1554,9 @@ deposit_cb (void *cls, return GNUNET_SYSERR; return GNUNET_OK; } - if (deposit->refund_deadline.abs_value_us > - deposit->wire_deadline.abs_value_us) + if (GNUNET_TIME_timestamp_cmp (deposit->refund_deadline, + >, + deposit->wire_deadline)) { report_row_inconsistency ("deposits", rowid, @@ -1620,26 +1584,27 @@ deposit_cb (void *cls, /* Verify deposit signature */ { - struct TALER_MerchantWireHash h_wire; - struct TALER_DenominationHash h_denom_pub; - struct TALER_Amount deposit_fee; + struct TALER_MerchantWireHashP h_wire; + struct TALER_DenominationHashP h_denom_pub; TALER_denom_pub_hash (denom_pub, &h_denom_pub); TALER_merchant_wire_signature_hash (deposit->receiver_wire_account, &deposit->wire_salt, &h_wire); - TALER_amount_ntoh (&deposit_fee, - &issue->fee_deposit); /* 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 != TALER_wallet_deposit_verify (&deposit->amount_with_fee, - &deposit_fee, + &issue->fees.deposit, &h_wire, &deposit->h_contract_terms, - NULL /* h_extensions! */, + 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, @@ -1657,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; @@ -1683,62 +1648,15 @@ 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 */ - { - struct TALER_Amount dfee; - - TALER_amount_ntoh (&dfee, - &issue->fee_deposit); - TALER_ARL_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; @@ -1759,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 */ @@ -1769,19 +1688,19 @@ refund_cb (void *cls, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_MerchantSignatureP *merchant_sig, - const struct TALER_PrivateContractHash *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, @@ -1802,54 +1721,41 @@ 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), - }; - - TALER_amount_hton (&rr.refund_amount, - amount_with_fee); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, - &rr, - &merchant_sig->eddsa_sig, - &merchant_pub->eddsa_pub)) - { - 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 (&total_bad_sig_loss, - &total_bad_sig_loss, - amount_with_fee); - if (TALER_ARL_do_abort ()) - return GNUNET_SYSERR; - 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 (TALER_ARL_SR_INVALID_NEGATIVE == TALER_ARL_amount_subtract_neg (&amount_without_fee, amount_with_fee, - &refund_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; @@ -1874,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, - &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; @@ -1915,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, @@ -1923,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_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)) { @@ -1943,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, @@ -1978,39 +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, - &coin_sig->eddsa_signature, - &coin->coin_pub.eddsa_pub)) - { - TALER_ARL_report (report_bad_sig_losses, - 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->coin_pub))); - TALER_ARL_amount_add (&total_bad_sig_loss, - &total_bad_sig_loss, - amount); - if (TALER_ARL_do_abort ()) - return GNUNET_SYSERR; - return GNUNET_OK; - } - } ds = get_denomination_summary (cc, issue, &issue->denom_hash); @@ -2022,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, @@ -2037,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 ()) @@ -2068,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 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 != + 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, @@ -2112,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 TALER_DenominationHash *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 union 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)); @@ -2166,16 +2205,39 @@ 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)); } } + 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, @@ -2195,52 +2257,37 @@ 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 ( void *cls, const struct TALER_DenominationPublicKey *denom_pub, - const struct TALER_EXCHANGEDB_DenominationKeyInformationP *validity) + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue) { - const struct TALER_DenominationKeyValidityPS *issue = &validity->properties; enum GNUNET_DB_QueryStatus qs; struct TALER_AuditorSignatureP auditor_sig; - struct TALER_Amount coin_value; - struct TALER_Amount fee_withdraw; - struct TALER_Amount fee_deposit; - struct TALER_Amount fee_refresh; - struct TALER_Amount fee_refund; - struct GNUNET_TIME_Absolute start; - struct GNUNET_TIME_Absolute end; (void) cls; (void) denom_pub; - TALER_amount_ntoh (&coin_value, - &issue->value); - TALER_amount_ntoh (&fee_withdraw, - &issue->fee_withdraw); - TALER_amount_ntoh (&fee_deposit, - &issue->fee_deposit); - TALER_amount_ntoh (&fee_refresh, - &issue->fee_refresh); - TALER_amount_ntoh (&fee_refund, - &issue->fee_refund); - start = GNUNET_TIME_absolute_ntoh (issue->start); - end = GNUNET_TIME_absolute_ntoh (issue->expire_legal); qs = TALER_ARL_edb->select_auditor_denom_sig (TALER_ARL_edb->cls, &issue->denom_hash, &TALER_ARL_auditor_pub, &auditor_sig); - if (0 >= qs) + 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 (&coin_value), - GNUNET_STRINGS_absolute_time_to_string (start), - (unsigned long long) start.abs_value_us, - (unsigned long long) end.abs_value_us); + 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 != @@ -2248,15 +2295,12 @@ check_denomination ( TALER_ARL_auditor_url, &issue->denom_hash, &TALER_ARL_master_pub, - start, - GNUNET_TIME_absolute_ntoh (issue->expire_withdraw), - GNUNET_TIME_absolute_ntoh (issue->expire_deposit), - end, - &coin_value, - &fee_withdraw, - &fee_deposit, - &fee_refresh, - &fee_refund, + issue->start, + issue->expire_withdraw, + issue->expire_deposit, + issue->expire_legal, + &issue->value, + &issue->fees, &TALER_ARL_auditor_pub, &auditor_sig)) { @@ -2265,12 +2309,134 @@ check_denomination ( GNUNET_JSON_pack_data_auto ("denomination", &issue->denom_hash), TALER_JSON_pack_amount ("value", - &coin_value), + &issue->value), TALER_JSON_pack_time_abs_human ("start_time", - start), + issue->start.abs_time), TALER_JSON_pack_time_abs_human ("end_time", - end))); + 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; } @@ -2301,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); @@ -2316,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); @@ -2349,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)) ) { @@ -2363,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))) { @@ -2373,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))) { @@ -2389,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))) { @@ -2399,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))) { @@ -2415,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))) { @@ -2427,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, @@ -2439,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); @@ -2465,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, @@ -2480,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; } @@ -2531,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)); @@ -2558,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 ())); @@ -2576,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)) @@ -2589,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), @@ -2622,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), @@ -2640,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))); } @@ -2691,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 |