From 296f919ce4dcd9123c402d52d18afae7e353b11a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 14 Mar 2017 18:00:17 +0100 Subject: more work on auditor, listing open TODOs --- src/auditor/taler-auditor.c | 537 ++++++++++++++++++++++++++++-- src/auditordb/plugin_auditordb_postgres.c | 49 +++ src/include/taler_auditordb_plugin.h | 28 +- 3 files changed, 576 insertions(+), 38 deletions(-) diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c index 51a4eda46..cab44e4dc 100644 --- a/src/auditor/taler-auditor.c +++ b/src/auditor/taler-auditor.c @@ -22,7 +22,22 @@ * - This auditor does not verify that 'reserves_in' actually matches * the wire transfers from the bank. This needs to be checked separately! * - Similarly, we do not check that the outgoing wire transfers match those - * given in the XXX table. This needs to be checked separately! + * given in the aggregation_tracking table. This needs to be checked separately! + * + * TODO: + * - initialize master_pub via command-line argument (URGENT!) + * - modify auditordb to allow multiple last serial IDs per table in progress tracking + * - modify auditordb to return row ID where we need it for diagnostics + * - implement coin/denomination audit + * - implement merchant deposit audit + * - see if we need more tables there + * - write reporting logic to output nice report beyond GNUNET_log() + * + * EXTERNAL: + * - add tool to pay-back expired reserves (#4956), and support here + * - add tool to verify 'reserves_in' from wire transfer inspection + * - add tool to trigger computation of historic revenues + * (move balances from 'current' revenue/profits to 'historic' tables) */ #include "platform.h" #include @@ -115,6 +130,28 @@ report_row_inconsistency (const char *table, } +/** + * Report a minor inconsistency in the exchange's database (i.e. something + * relating to timestamps that should have no financial implications). + * + * @param table affected table + * @param rowid affected row, UINT64_MAX if row is missing + * @param diagnostic message explaining the problem + */ +static void +report_row_minor_inconsistency (const char *table, + uint64_t rowid, + const char *diagnostic) +{ + // TODO: implement proper reporting logic writing to file. + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Minor inconsistency detected in table %s at row %llu: %s\n", + table, + (unsigned long long) rowid, + diagnostic); +} + + /** * Report a global inconsistency with respect to a reserve. * @@ -137,6 +174,43 @@ report_reserve_inconsistency (const struct TALER_ReservePublicKeyP *reserve_pub, } +/** + * Report the final result on the reserve balances of the exchange. + * The reserve must have @a total_balance in its escrow account just + * to cover outstanding reserve funds (outstanding coins are on top). + * The reserve has made @a total_fee_balance in profit from withdrawal + * operations alone. + * + * Note that this is for the "ongoing" reporting period. Historic + * revenue (as stored via the "insert_historic_reserve_revenue") + * is not included in the @a total_fee_balance. + * + * @param total_balance how much money (in total) is left in all of the + * reserves (that has not been withdrawn) + * @param total_fee_balance how much money (in total) did the reserve + * make from withdrawal fees + */ +static void +report_reserve_balance (const struct TALER_Amount *total_balance, + const struct TALER_Amount *total_fee_balance) +{ + char *balance; + char *fees; + + balance = TALER_amount_to_string (total_balance); + fees = TALER_amount_to_string (total_fee_balance); + // TODO: implement proper reporting logic writing to file. + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Total escrow balance to be held for reserves: %s\n", + balance); + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Total profits made from reserves: %s\n", + fees); + GNUNET_free (fees); + GNUNET_free (balance); +} + + /* ************************* Transaction-global state ************************ */ /** @@ -236,6 +310,7 @@ clear_transaction_state_cache () /* ***************************** Analyze reserves ************************ */ +/* This logic checks the reserves_in, reserves_out and reserves-tables */ /** * Summary data we keep per reserve. @@ -244,46 +319,62 @@ struct ReserveSummary { /** * Public key of the reserve. + * Always set when the struct is first initialized. */ struct TALER_ReservePublicKeyP reserve_pub; /** - * Sum of all incoming transfers. + * Sum of all incoming transfers during this transaction. + * Updated only in #handle_reserve_in(). */ struct TALER_Amount total_in; /** - * Sum of all outgoing transfers. + * Sum of all outgoing transfers during this transaction (includes fees). + * Updated only in #handle_reserve_out(). */ struct TALER_Amount total_out; + /** + * Sum of withdraw fees encountered during this transaction. + */ + struct TALER_Amount total_fee; + /** * Previous balance of the reserve as remembered by the auditor. + * (updated based on @e total_in and @e total_out at the end). */ struct TALER_Amount a_balance; /** * Previous withdraw fee balance of the reserve, as remembered by the auditor. + * (updated based on @e total_fee at the end). */ struct TALER_Amount a_withdraw_fee_balance; /** * Previous reserve expiration data, as remembered by the auditor. + * (updated on-the-fly in #handle_reserve_in()). */ struct GNUNET_TIME_Absolute a_expiration_date; /** * Previous last processed reserve_in serial ID, as remembered by the auditor. + * (updated on-the-fly in #handle_reserve_in()). */ uint64_t a_last_reserve_in_serial_id; /** * Previous last processed reserve_out serial ID, as remembered by the auditor. + * (updated on-the-fly in #handle_reserve_out()). */ uint64_t a_last_reserve_out_serial_id; /** - * Did we have a previous reserve info? + * Did we have a previous reserve info? Used to decide between + * UPDATE and INSERT later. Initialized in + * #load_auditor_reserve_summary() together with the a-* values + * (if available). */ int had_ri; @@ -292,6 +383,8 @@ struct ReserveSummary /** * Load the auditor's remembered state about the reserve into @a rs. + * The "total_in" and "total_out" amounts of @a rs must already be + * initialized (so we can determine the currency). * * @param[in|out] rs reserve summary to (fully) initialize * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors @@ -318,19 +411,60 @@ load_auditor_reserve_summary (struct ReserveSummary *rs) if (GNUNET_NO == ret) { rs->had_ri = GNUNET_NO; - // FIXME: set rs->a-values to sane defaults! + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (rs->total_in.currency, + &rs->a_balance)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (rs->total_in.currency, + &rs->a_withdraw_fee_balance)); return GNUNET_OK; } rs->had_ri = GNUNET_YES; - /* TODO: check values we got are sane? */ + if ( (GNUNET_YES != + TALER_amount_cmp_currency (&rs->a_balance, + &rs->a_withdraw_fee_balance)) || + (GNUNET_YES != + TALER_amount_cmp_currency (&rs->total_in, + &rs->a_balance)) ) + { + report_row_inconsistency ("auditor-reserve-info", + UINT64_MAX, /* FIXME: modify API to get rowid! */ + "currencies for reserve differ"); + /* TODO: find a sane way to continue... */ + GNUNET_break (0); + return GNUNET_SYSERR; + } return GNUNET_OK; } +/** + * Closure to the various callbacks we make while checking a reserve. + */ +struct ReserveContext +{ + /** + * Map from hash of reserve's public key to a `struct ReserveSummary`. + */ + struct GNUNET_CONTAINER_MultiHashMap *reserves; + + /** + * Total balance in all reserves (updated). + */ + struct TALER_Amount total_balance; + + /** + * Total withdraw fees gotten in all reserves (updated). + */ + struct TALER_Amount total_fee_balance; + +}; + + /** * Function called with details about incoming wire transfers. * - * @param cls our `struct GNUNET_CONTAINER_MultiHashMap` with the reserves + * @param cls our `struct ReserveContext` * @param rowid unique serial ID for the refresh session in our DB * @param reserve_pub public key of the reserve (also the WTID) * @param credit amount that was received @@ -348,16 +482,17 @@ handle_reserve_in (void *cls, const json_t *transfer_details, struct GNUNET_TIME_Absolute execution_date) { - struct GNUNET_CONTAINER_MultiHashMap *reserves = cls; + struct ReserveContext *rc = cls; struct GNUNET_HashCode key; struct ReserveSummary *rs; + struct GNUNET_TIME_Absolute expiry; GNUNET_assert (rowid >= reserve_in_serial_id); /* should be monotonically increasing */ reserve_in_serial_id = rowid + 1; GNUNET_CRYPTO_hash (reserve_pub, sizeof (*reserve_pub), &key); - rs = GNUNET_CONTAINER_multihashmap_get (reserves, + rs = GNUNET_CONTAINER_multihashmap_get (rc->reserves, &key); if (NULL == rs) { @@ -367,6 +502,9 @@ handle_reserve_in (void *cls, GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (credit->currency, &rs->total_out)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (credit->currency, + &rs->total_fee)); if (GNUNET_OK != load_auditor_reserve_summary (rs)) { @@ -375,7 +513,7 @@ handle_reserve_in (void *cls, return GNUNET_SYSERR; } GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (reserves, + GNUNET_CONTAINER_multihashmap_put (rc->reserves, &key, rs, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); @@ -387,6 +525,12 @@ handle_reserve_in (void *cls, &rs->total_in, credit)); } + GNUNET_assert (rowid >= rs->a_last_reserve_in_serial_id); + rs->a_last_reserve_in_serial_id = rowid + 1; + expiry = GNUNET_TIME_absolute_add (execution_date, + TALER_IDLE_RESERVE_EXPIRATION_TIME); + rs->a_expiration_date = GNUNET_TIME_absolute_max (rs->a_expiration_date, + expiry); return GNUNET_OK; } @@ -394,7 +538,7 @@ handle_reserve_in (void *cls, /** * Function called with details about withdraw operations. * - * @param cls our `struct GNUNET_CONTAINER_MultiHashMap` with the reserves + * @param cls our `struct ReserveContext` * @param rowid unique serial ID for the refresh session in our DB * @param h_blind_ev blinded hash of the coin's public key * @param denom_pub public denomination key of the deposited coin @@ -416,11 +560,14 @@ handle_reserve_out (void *cls, struct GNUNET_TIME_Absolute execution_date, const struct TALER_Amount *amount_with_fee) { - struct GNUNET_CONTAINER_MultiHashMap *reserves = cls; + struct ReserveContext *rc = cls; struct TALER_WithdrawRequestPS wsrd; struct GNUNET_HashCode key; struct ReserveSummary *rs; const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki; + struct TALER_Amount withdraw_fee; + struct GNUNET_TIME_Absolute valid_start; + struct GNUNET_TIME_Absolute expire_withdraw; int ret; /* should be monotonically increasing */ @@ -444,7 +591,16 @@ handle_reserve_out (void *cls, return GNUNET_OK; } - /* check that execution date is within withdraw range for denom_pub (?) */ + /* check that execution date is within withdraw range for denom_pub */ + valid_start = GNUNET_TIME_absolute_ntoh (dki->properties.start); + expire_withdraw = GNUNET_TIME_absolute_ntoh (dki->properties.expire_withdraw); + if ( (valid_start.abs_value_us > execution_date.abs_value_us) || + (expire_withdraw.abs_value_us < execution_date.abs_value_us) ) + { + report_row_minor_inconsistency ("reserve_out", + rowid, + "denomination key not valid at time of withdrawal"); + } /* check reserve_sig */ wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); @@ -468,7 +624,7 @@ handle_reserve_out (void *cls, GNUNET_CRYPTO_hash (reserve_pub, sizeof (*reserve_pub), &key); - rs = GNUNET_CONTAINER_multihashmap_get (reserves, + rs = GNUNET_CONTAINER_multihashmap_get (rc->reserves, &key); if (NULL == rs) { @@ -478,6 +634,9 @@ handle_reserve_out (void *cls, GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (amount_with_fee->currency, &rs->total_in)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (amount_with_fee->currency, + &rs->total_fee)); if (GNUNET_OK != load_auditor_reserve_summary (rs)) { @@ -486,7 +645,7 @@ handle_reserve_out (void *cls, return GNUNET_SYSERR; } GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (reserves, + GNUNET_CONTAINER_multihashmap_put (rc->reserves, &key, rs, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); @@ -498,6 +657,16 @@ handle_reserve_out (void *cls, &rs->total_out, amount_with_fee)); } + GNUNET_assert (rowid >= rs->a_last_reserve_out_serial_id); + rs->a_last_reserve_out_serial_id = rowid + 1; + + TALER_amount_ntoh (&withdraw_fee, + &dki->properties.fee_withdraw); + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&rs->total_fee, + &rs->total_fee, + &withdraw_fee)); + return GNUNET_OK; } @@ -508,7 +677,7 @@ handle_reserve_out (void *cls, * * Remove all reserves that we are happy with from the DB. * - * @param cls our `struct GNUNET_CONTAINER_MultiHashMap` with the reserves + * @param cls our `struct ReserveContext` * @param key hash of the reserve public key * @param value a `struct ReserveSummary` * @return #GNUNET_OK to process more entries @@ -518,7 +687,7 @@ verify_reserve_balance (void *cls, const struct GNUNET_HashCode *key, void *value) { - struct GNUNET_CONTAINER_MultiHashMap *reserves = cls; + struct ReserveContext *rc = cls; struct ReserveSummary *rs = value; struct TALER_EXCHANGEDB_Reserve reserve; struct TALER_Amount balance; @@ -542,13 +711,22 @@ verify_reserve_balance (void *cls, GNUNET_free (diag); return GNUNET_OK; } - /* TODO: check reserve.expiry */ - /* FIXME: simplified computation as we have no previous reserve state yet */ - /* FIXME: actually update withdraw fee balance, expiration data and serial IDs! */ + if (GNUNET_OK != + TALER_amount_add (&balance, + &rs->total_in, + &rs->a_balance)) + { + report_reserve_inconsistency (&rs->reserve_pub, + &rs->total_in, + &rs->a_balance, + "could not add old balance to new balance"); + goto cleanup; + } + if (GNUNET_SYSERR == TALER_amount_subtract (&balance, - &rs->total_in, + &balance, &rs->total_out)) { report_reserve_inconsistency (&rs->reserve_pub, @@ -567,12 +745,55 @@ verify_reserve_balance (void *cls, goto cleanup; } - /* FIXME: if balance is zero, create reserve summary and drop reserve details! */ + if (0 == GNUNET_TIME_absolute_get_remaining (rs->a_expiration_date).rel_value_us) + { + /* TODO: handle case where reserve is expired! (#4956) */ + /* NOTE: we may or may not have seen the wire-back transfer at this time, + as the expiration may have just now happened. + (That is, after we add the table structures and the logic to track + such transfers...) */ + } + + if ( (0ULL == balance.value) && + (0U == balance.fraction) ) + { + /* TODO: balance is zero, drop reserve details (and then do not update/insert) */ + if (rs->had_ri) + { + ret = adb->del_reserve_info (adb->cls, + asession, + &rs->reserve_pub, + &master_pub); + if (GNUNET_SYSERR == ret) + { + GNUNET_break (0); + goto cleanup; + } + if (GNUNET_NO == ret) + { + GNUNET_break (0); + ret = GNUNET_SYSERR; + goto cleanup; + } + } + ret = GNUNET_OK; + goto cleanup; + } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reserve balance `%s' OK\n", TALER_B2S (&rs->reserve_pub)); + /* Add withdraw fees we encountered to totals */ + if (GNUNET_YES != + TALER_amount_add (&rs->a_withdraw_fee_balance, + &rs->a_withdraw_fee_balance, + &rs->total_fee)) + { + GNUNET_break (0); + ret = GNUNET_SYSERR; + goto cleanup; + } if (rs->had_ri) ret = adb->update_reserve_info (adb->cls, asession, @@ -594,10 +815,28 @@ verify_reserve_balance (void *cls, rs->a_last_reserve_in_serial_id, rs->a_last_reserve_out_serial_id); + if ( (GNUNET_YES != + TALER_amount_add (&rc->total_balance, + &rc->total_balance, + &rs->total_in)) || + (GNUNET_SYSERR == + TALER_amount_subtract (&rc->total_balance, + &rc->total_balance, + &rs->total_out)) || + (GNUNET_YES != + TALER_amount_add (&rc->total_fee_balance, + &rc->total_fee_balance, + &rs->total_fee)) ) + { + GNUNET_break (0); + ret = GNUNET_SYSERR; + goto cleanup; + } + cleanup: GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (reserves, + GNUNET_CONTAINER_multihashmap_remove (rc->reserves, key, rs)); GNUNET_free (rs); @@ -614,18 +853,29 @@ verify_reserve_balance (void *cls, static int analyze_reserves (void *cls) { - /* Map from hash of reserve's public key to a `struct ReserveSummary`. */ - struct GNUNET_CONTAINER_MultiHashMap *reserves; + struct ReserveContext rc; + int ret; + + ret = adb->get_reserve_summary (adb->cls, + asession, + &master_pub, + &rc.total_balance, + &rc.total_fee_balance); + if (GNUNET_SYSERR == ret) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } - reserves = GNUNET_CONTAINER_multihashmap_create (512, - GNUNET_NO); + rc.reserves = GNUNET_CONTAINER_multihashmap_create (512, + GNUNET_NO); if (GNUNET_OK != edb->select_reserves_in_above_serial_id (edb->cls, esession, reserve_in_serial_id, &handle_reserve_in, - reserves)) + &rc)) { GNUNET_break (0); return GNUNET_SYSERR; @@ -635,18 +885,234 @@ analyze_reserves (void *cls) esession, reserve_out_serial_id, &handle_reserve_out, - reserves)) + &rc)) { GNUNET_break (0); return GNUNET_SYSERR; } - GNUNET_CONTAINER_multihashmap_iterate (reserves, + /* TODO: iterate over table for reserve expiration refunds! (#4956) */ + + GNUNET_CONTAINER_multihashmap_iterate (rc.reserves, &verify_reserve_balance, - reserves); + &rc); GNUNET_break (0 == - GNUNET_CONTAINER_multihashmap_size (reserves)); - GNUNET_CONTAINER_multihashmap_destroy (reserves); + GNUNET_CONTAINER_multihashmap_size (rc.reserves)); + GNUNET_CONTAINER_multihashmap_destroy (rc.reserves); + + if (GNUNET_NO == ret) + { + ret = adb->insert_reserve_summary (adb->cls, + asession, + &master_pub, + &rc.total_balance, + &rc.total_fee_balance); + } + else + { + ret = adb->update_reserve_summary (adb->cls, + asession, + &master_pub, + &rc.total_balance, + &rc.total_fee_balance); + } + report_reserve_balance (&rc.total_balance, + &rc.total_fee_balance); + return GNUNET_OK; +} + + +/* ************************* Analyze coins ******************** */ +/* This logic checks that the exchange did the right thing for each + coin, checking deposits, refunds, refresh* and known_coins + tables */ + +/* TODO! */ +/** + * Summary data we keep per coin. + */ +struct CoinSummary +{ + /** + * Denomination of the coin with fee structure. + */ + struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki; + + /** + * Public key of the coin. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * Total value lost of the coin (deposits, refreshs and fees minus refunds). + * Must be smaller than the coin's total (origional) value. + */ + struct TALER_Amount spent; + +}; + + +/** + * Summary data we keep per denomination. + */ +struct DenominationSummary +{ + /** + * Total value of coins issued with this denomination key. + */ + struct TALER_Amount denom_balance; + + /** + * Total amount of deposit fees made. + */ + struct TALER_Amount deposit_fee_balance; + + /** + * Total amount of melt fees made. + */ + struct TALER_Amount melt_fee_balance; + + /** + * Total amount of refund fees made. + */ + struct TALER_Amount refund_fee_balance; + + /** + * Up to which point have we processed reserves_out? + */ + uint64_t last_reserve_out_serial_id; + + /** + * Up to which point have we processed deposits? + */ + uint64_t last_deposit_serial_id; + + /** + * Up to which point have we processed melts? + */ + uint64_t last_melt_serial_id; + + /** + * Up to which point have we processed refunds? + */ + uint64_t last_refund_serial_id; +}; + + +/** + * Closure for callbacks during #analyze_coins(). + */ +struct CoinContext +{ + + /** + * Map for tracking information about coins. + */ + struct GNUNET_CONTAINER_MultiHashMap *coins; + + /** + * Map for tracking information about denominations. + */ + struct GNUNET_CONTAINER_MultiHashMap *denominations; + +}; + + +/** + * Analyze the exchange's processing of coins. + * + * @param cls closure + * @param int #GNUNET_OK on success, #GNUNET_SYSERR on hard errors + */ +static int +analyze_coins (void *cls) +{ + struct CoinContext cc; + + cc.coins = GNUNET_CONTAINER_multihashmap_create (1024, + GNUNET_YES); + cc.denominations = GNUNET_CONTAINER_multihashmap_create (256, + GNUNET_YES); + + + GNUNET_CONTAINER_multihashmap_destroy (cc.denominations); + GNUNET_CONTAINER_multihashmap_destroy (cc.coins); + + return GNUNET_OK; +} + + +/* ************************* Analyze merchants ******************** */ +/* This logic checks that the aggregator did the right thing + paying each merchant what they were due (and on time). */ + + +/** + * Summary data we keep per merchant. + */ +struct MerchantSummary +{ + + /** + * Which account were we supposed to pay? + */ + struct GNUNET_HashCode h_wire; + + /** + * Total due to be paid to @e h_wire. + */ + struct TALER_Amount total_due; + + /** + * Total paid to @e h_wire. + */ + struct TALER_Amount total_paid; + + /** + * Total wire fees charged. + */ + struct TALER_Amount total_fees; + + /** + * Last (expired) refund deadline of all the transactions totaled + * up in @e due. + */ + struct GNUNET_TIME_Absolute last_refund_deadline; + +}; + + +/** + * Closure for callbacks during #analyze_merchants(). + */ +struct MerchantContext +{ + + /** + * Map for tracking information about merchants. + */ + struct GNUNET_CONTAINER_MultiHashMap *merchants; + +}; + + +/** + * Analyze the exchange aggregator's payment processing. + * + * @param cls closure + * @param int #GNUNET_OK on success, #GNUNET_SYSERR on hard errors + */ +static int +analyze_merchants (void *cls) +{ + struct MerchantContext mc; + + mc.merchants = GNUNET_CONTAINER_multihashmap_create (1024, + GNUNET_YES); + + // TODO + + GNUNET_CONTAINER_multihashmap_destroy (mc.merchants); return GNUNET_OK; } @@ -835,7 +1301,10 @@ setup_sessions_and_run () transact (&analyze_reserves, NULL); - // NOTE: add other 'transact (&analyze_*)'-calls here as they are implemented. + transact (&analyze_coins, + NULL); + transact (&analyze_merchants, + NULL); } diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c index 81c1b4369..65da0bf18 100644 --- a/src/auditordb/plugin_auditordb_postgres.c +++ b/src/auditordb/plugin_auditordb_postgres.c @@ -649,6 +649,13 @@ postgres_prepare (PGconn *db_conn) " WHERE reserve_pub=$1 AND master_pub=$2;", 2, NULL); + /* Used in #postgres_del_reserve_info() */ + PREPARE ("auditor_reserves_delete", + "DELETE" + " FROM auditor_reserves" + " WHERE reserve_pub=$1 AND master_pub=$2;", + 2, NULL); + /* Used in #postgres_insert_reserve_summary() */ PREPARE ("auditor_reserve_balance_insert", "INSERT INTO auditor_reserve_balance" @@ -1650,6 +1657,47 @@ postgres_update_reserve_info (void *cls, } +/** + * Delete information about a reserve. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param reserve_pub public key of the reserve + * @param master_pub master public key of the exchange + * @return #GNUNET_OK on success; #GNUNET_NO if there is no known + * record about this reserve; #GNUNET_SYSERR on failure + */ +static int +postgres_del_reserve_info (void *cls, + struct TALER_AUDITORDB_Session *session, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_MasterPublicKeyP *master_pub) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_auto_from_type (master_pub), + GNUNET_PQ_query_param_end + }; + PGresult *result; + int ret; + + result = GNUNET_PQ_exec_prepared (session->conn, + "auditor_reserves_delete", + params); + ret = PQresultStatus (result); + if (PGRES_COMMAND_OK != ret) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 == strcmp ("0", + PQcmdTuples (result))) + return GNUNET_NO; + return GNUNET_OK; +} + + /** * Get information about a reserve. * @@ -3110,6 +3158,7 @@ libtaler_plugin_auditordb_postgres_init (void *cls) plugin->update_auditor_progress = &postgres_update_auditor_progress; plugin->insert_auditor_progress = &postgres_insert_auditor_progress; + plugin->del_reserve_info = &postgres_del_reserve_info; plugin->get_reserve_info = &postgres_get_reserve_info; plugin->update_reserve_info = &postgres_update_reserve_info; plugin->insert_reserve_info = &postgres_insert_reserve_info; diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h index c27295a08..fa5f9e816 100644 --- a/src/include/taler_auditordb_plugin.h +++ b/src/include/taler_auditordb_plugin.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2016 GNUnet e.V. + Copyright (C) 2014-2017 Inria and GNUnet e.V. TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -252,6 +252,10 @@ struct TALER_AUDITORDB_Plugin void *cb_cls); + // FIXME: this does not quite work, as independent transactions + // touch certain tables (i.e. reserves_out), so we need some of + // these counters more than once! + // ALSO: put all of these counters into a struct, this is very ugly... /** * Insert information about the auditor's progress with an exchange's * data. @@ -420,6 +424,22 @@ struct TALER_AUDITORDB_Plugin uint64_t *last_reserve_out_serial_id); + /** + * Delete information about a reserve. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param reserve_pub public key of the reserve + * @param master_pub master public key of the exchange + * @return #GNUNET_OK on success; #GNUNET_NO if there is no known + * record about this reserve; #GNUNET_SYSERR on failure + */ + int + (*del_reserve_info)(void *cls, + struct TALER_AUDITORDB_Session *session, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_MasterPublicKeyP *master_pub); + /** * Insert information about all reserves. There must not be an @@ -488,7 +508,7 @@ struct TALER_AUDITORDB_Plugin * @param cls the @e cls of this struct with the plugin-specific state * @param session connection to use * @param denom_pub_hash hash of the denomination public key - * @param denom_balance value of coins outstanding with this denomination key + * @param denom_balance value of coins outstanding (or issued?) with this denomination key * @param deposit_fee_balance total deposit fees collected for this DK * @param melt_fee_balance total melt fees collected for this DK * @param refund_fee_balance total refund fees collected for this DK @@ -523,7 +543,7 @@ struct TALER_AUDITORDB_Plugin * @param cls the @e cls of this struct with the plugin-specific state * @param session connection to use * @param denom_pub_hash hash of the denomination public key - * @param denom_balance value of coins outstanding with this denomination key + * @param denom_balance value of coins outstanding (or issued?) with this denomination key * @param deposit_fee_balance total deposit fees collected for this DK * @param melt_fee_balance total melt fees collected for this DK * @param refund_fee_balance total refund fees collected for this DK @@ -557,7 +577,7 @@ struct TALER_AUDITORDB_Plugin * @param cls the @e cls of this struct with the plugin-specific state * @param session connection to use * @param denom_pub_hash hash of the denomination public key - * @param[out] denom_balance value of coins outstanding with this denomination key + * @param[out] denom_balance value of coins outstanding (or issued?) with this denomination key * @param[out] deposit_fee_balance total deposit fees collected for this DK * @param[out] melt_fee_balance total melt fees collected for this DK * @param[out] refund_fee_balance total refund fees collected for this DK -- cgit v1.2.3