more work on auditor, listing open TODOs

This commit is contained in:
Christian Grothoff 2017-03-14 18:00:17 +01:00
parent 6d798cecba
commit 296f919ce4
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
3 changed files with 578 additions and 40 deletions

View File

@ -22,7 +22,22 @@
* - This auditor does not verify that 'reserves_in' actually matches * - This auditor does not verify that 'reserves_in' actually matches
* the wire transfers from the bank. This needs to be checked separately! * the wire transfers from the bank. This needs to be checked separately!
* - Similarly, we do not check that the outgoing wire transfers match those * - 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 "platform.h"
#include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_util_lib.h>
@ -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. * 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 ************************ */ /* ************************* Transaction-global state ************************ */
/** /**
@ -236,6 +310,7 @@ clear_transaction_state_cache ()
/* ***************************** Analyze reserves ************************ */ /* ***************************** Analyze reserves ************************ */
/* This logic checks the reserves_in, reserves_out and reserves-tables */
/** /**
* Summary data we keep per reserve. * Summary data we keep per reserve.
@ -244,46 +319,62 @@ struct ReserveSummary
{ {
/** /**
* Public key of the reserve. * Public key of the reserve.
* Always set when the struct is first initialized.
*/ */
struct TALER_ReservePublicKeyP reserve_pub; 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; 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; 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. * 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; struct TALER_Amount a_balance;
/** /**
* Previous withdraw fee balance of the reserve, as remembered by the auditor. * 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; struct TALER_Amount a_withdraw_fee_balance;
/** /**
* Previous reserve expiration data, as remembered by the auditor. * Previous reserve expiration data, as remembered by the auditor.
* (updated on-the-fly in #handle_reserve_in()).
*/ */
struct GNUNET_TIME_Absolute a_expiration_date; struct GNUNET_TIME_Absolute a_expiration_date;
/** /**
* Previous last processed reserve_in serial ID, as remembered by the auditor. * 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; uint64_t a_last_reserve_in_serial_id;
/** /**
* Previous last processed reserve_out serial ID, as remembered by the auditor. * 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; 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; int had_ri;
@ -292,6 +383,8 @@ struct ReserveSummary
/** /**
* Load the auditor's remembered state about the reserve into @a rs. * 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 * @param[in|out] rs reserve summary to (fully) initialize
* @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors * @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) if (GNUNET_NO == ret)
{ {
rs->had_ri = GNUNET_NO; 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; return GNUNET_OK;
} }
rs->had_ri = GNUNET_YES; 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; 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. * 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 rowid unique serial ID for the refresh session in our DB
* @param reserve_pub public key of the reserve (also the WTID) * @param reserve_pub public key of the reserve (also the WTID)
* @param credit amount that was received * @param credit amount that was received
@ -348,16 +482,17 @@ handle_reserve_in (void *cls,
const json_t *transfer_details, const json_t *transfer_details,
struct GNUNET_TIME_Absolute execution_date) struct GNUNET_TIME_Absolute execution_date)
{ {
struct GNUNET_CONTAINER_MultiHashMap *reserves = cls; struct ReserveContext *rc = cls;
struct GNUNET_HashCode key; struct GNUNET_HashCode key;
struct ReserveSummary *rs; struct ReserveSummary *rs;
struct GNUNET_TIME_Absolute expiry;
GNUNET_assert (rowid >= reserve_in_serial_id); /* should be monotonically increasing */ GNUNET_assert (rowid >= reserve_in_serial_id); /* should be monotonically increasing */
reserve_in_serial_id = rowid + 1; reserve_in_serial_id = rowid + 1;
GNUNET_CRYPTO_hash (reserve_pub, GNUNET_CRYPTO_hash (reserve_pub,
sizeof (*reserve_pub), sizeof (*reserve_pub),
&key); &key);
rs = GNUNET_CONTAINER_multihashmap_get (reserves, rs = GNUNET_CONTAINER_multihashmap_get (rc->reserves,
&key); &key);
if (NULL == rs) if (NULL == rs)
{ {
@ -367,6 +502,9 @@ handle_reserve_in (void *cls,
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (credit->currency, TALER_amount_get_zero (credit->currency,
&rs->total_out)); &rs->total_out));
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (credit->currency,
&rs->total_fee));
if (GNUNET_OK != if (GNUNET_OK !=
load_auditor_reserve_summary (rs)) load_auditor_reserve_summary (rs))
{ {
@ -375,7 +513,7 @@ handle_reserve_in (void *cls,
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (reserves, GNUNET_CONTAINER_multihashmap_put (rc->reserves,
&key, &key,
rs, rs,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
@ -387,6 +525,12 @@ handle_reserve_in (void *cls,
&rs->total_in, &rs->total_in,
credit)); 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; return GNUNET_OK;
} }
@ -394,7 +538,7 @@ handle_reserve_in (void *cls,
/** /**
* Function called with details about withdraw operations. * 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 rowid unique serial ID for the refresh session in our DB
* @param h_blind_ev blinded hash of the coin's public key * @param h_blind_ev blinded hash of the coin's public key
* @param denom_pub public denomination key of the deposited coin * @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, struct GNUNET_TIME_Absolute execution_date,
const struct TALER_Amount *amount_with_fee) const struct TALER_Amount *amount_with_fee)
{ {
struct GNUNET_CONTAINER_MultiHashMap *reserves = cls; struct ReserveContext *rc = cls;
struct TALER_WithdrawRequestPS wsrd; struct TALER_WithdrawRequestPS wsrd;
struct GNUNET_HashCode key; struct GNUNET_HashCode key;
struct ReserveSummary *rs; struct ReserveSummary *rs;
const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki; 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; int ret;
/* should be monotonically increasing */ /* should be monotonically increasing */
@ -444,7 +591,16 @@ handle_reserve_out (void *cls,
return GNUNET_OK; 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 */ /* check reserve_sig */
wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
@ -468,7 +624,7 @@ handle_reserve_out (void *cls,
GNUNET_CRYPTO_hash (reserve_pub, GNUNET_CRYPTO_hash (reserve_pub,
sizeof (*reserve_pub), sizeof (*reserve_pub),
&key); &key);
rs = GNUNET_CONTAINER_multihashmap_get (reserves, rs = GNUNET_CONTAINER_multihashmap_get (rc->reserves,
&key); &key);
if (NULL == rs) if (NULL == rs)
{ {
@ -478,6 +634,9 @@ handle_reserve_out (void *cls,
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (amount_with_fee->currency, TALER_amount_get_zero (amount_with_fee->currency,
&rs->total_in)); &rs->total_in));
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (amount_with_fee->currency,
&rs->total_fee));
if (GNUNET_OK != if (GNUNET_OK !=
load_auditor_reserve_summary (rs)) load_auditor_reserve_summary (rs))
{ {
@ -486,7 +645,7 @@ handle_reserve_out (void *cls,
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (reserves, GNUNET_CONTAINER_multihashmap_put (rc->reserves,
&key, &key,
rs, rs,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
@ -498,6 +657,16 @@ handle_reserve_out (void *cls,
&rs->total_out, &rs->total_out,
amount_with_fee)); 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; return GNUNET_OK;
} }
@ -508,7 +677,7 @@ handle_reserve_out (void *cls,
* *
* Remove all reserves that we are happy with from the DB. * 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 key hash of the reserve public key
* @param value a `struct ReserveSummary` * @param value a `struct ReserveSummary`
* @return #GNUNET_OK to process more entries * @return #GNUNET_OK to process more entries
@ -518,7 +687,7 @@ verify_reserve_balance (void *cls,
const struct GNUNET_HashCode *key, const struct GNUNET_HashCode *key,
void *value) void *value)
{ {
struct GNUNET_CONTAINER_MultiHashMap *reserves = cls; struct ReserveContext *rc = cls;
struct ReserveSummary *rs = value; struct ReserveSummary *rs = value;
struct TALER_EXCHANGEDB_Reserve reserve; struct TALER_EXCHANGEDB_Reserve reserve;
struct TALER_Amount balance; struct TALER_Amount balance;
@ -542,13 +711,22 @@ verify_reserve_balance (void *cls,
GNUNET_free (diag); GNUNET_free (diag);
return GNUNET_OK; return GNUNET_OK;
} }
/* TODO: check reserve.expiry */
/* FIXME: simplified computation as we have no previous reserve state yet */ if (GNUNET_OK !=
/* FIXME: actually update withdraw fee balance, expiration data and serial IDs! */ 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 == if (GNUNET_SYSERR ==
TALER_amount_subtract (&balance, TALER_amount_subtract (&balance,
&rs->total_in, &balance,
&rs->total_out)) &rs->total_out))
{ {
report_reserve_inconsistency (&rs->reserve_pub, report_reserve_inconsistency (&rs->reserve_pub,
@ -567,12 +745,55 @@ verify_reserve_balance (void *cls,
goto cleanup; 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, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Reserve balance `%s' OK\n", "Reserve balance `%s' OK\n",
TALER_B2S (&rs->reserve_pub)); 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) if (rs->had_ri)
ret = adb->update_reserve_info (adb->cls, ret = adb->update_reserve_info (adb->cls,
asession, asession,
@ -594,10 +815,28 @@ verify_reserve_balance (void *cls,
rs->a_last_reserve_in_serial_id, rs->a_last_reserve_in_serial_id,
rs->a_last_reserve_out_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: cleanup:
GNUNET_assert (GNUNET_YES == GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multihashmap_remove (reserves, GNUNET_CONTAINER_multihashmap_remove (rc->reserves,
key, key,
rs)); rs));
GNUNET_free (rs); GNUNET_free (rs);
@ -614,18 +853,29 @@ verify_reserve_balance (void *cls,
static int static int
analyze_reserves (void *cls) analyze_reserves (void *cls)
{ {
/* Map from hash of reserve's public key to a `struct ReserveSummary`. */ struct ReserveContext rc;
struct GNUNET_CONTAINER_MultiHashMap *reserves; int ret;
reserves = GNUNET_CONTAINER_multihashmap_create (512, ret = adb->get_reserve_summary (adb->cls,
GNUNET_NO); asession,
&master_pub,
&rc.total_balance,
&rc.total_fee_balance);
if (GNUNET_SYSERR == ret)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
rc.reserves = GNUNET_CONTAINER_multihashmap_create (512,
GNUNET_NO);
if (GNUNET_OK != if (GNUNET_OK !=
edb->select_reserves_in_above_serial_id (edb->cls, edb->select_reserves_in_above_serial_id (edb->cls,
esession, esession,
reserve_in_serial_id, reserve_in_serial_id,
&handle_reserve_in, &handle_reserve_in,
reserves)) &rc))
{ {
GNUNET_break (0); GNUNET_break (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -635,18 +885,234 @@ analyze_reserves (void *cls)
esession, esession,
reserve_out_serial_id, reserve_out_serial_id,
&handle_reserve_out, &handle_reserve_out,
reserves)) &rc))
{ {
GNUNET_break (0); GNUNET_break (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
GNUNET_CONTAINER_multihashmap_iterate (reserves, /* TODO: iterate over table for reserve expiration refunds! (#4956) */
&verify_reserve_balance,
reserves);
GNUNET_break (0 ==
GNUNET_CONTAINER_multihashmap_size (reserves));
GNUNET_CONTAINER_multihashmap_destroy (reserves);
GNUNET_CONTAINER_multihashmap_iterate (rc.reserves,
&verify_reserve_balance,
&rc);
GNUNET_break (0 ==
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; return GNUNET_OK;
} }
@ -835,7 +1301,10 @@ setup_sessions_and_run ()
transact (&analyze_reserves, transact (&analyze_reserves,
NULL); NULL);
// NOTE: add other 'transact (&analyze_*)'-calls here as they are implemented. transact (&analyze_coins,
NULL);
transact (&analyze_merchants,
NULL);
} }

View File

@ -649,6 +649,13 @@ postgres_prepare (PGconn *db_conn)
" WHERE reserve_pub=$1 AND master_pub=$2;", " WHERE reserve_pub=$1 AND master_pub=$2;",
2, NULL); 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() */ /* Used in #postgres_insert_reserve_summary() */
PREPARE ("auditor_reserve_balance_insert", PREPARE ("auditor_reserve_balance_insert",
"INSERT INTO auditor_reserve_balance" "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. * 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->update_auditor_progress = &postgres_update_auditor_progress;
plugin->insert_auditor_progress = &postgres_insert_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->get_reserve_info = &postgres_get_reserve_info;
plugin->update_reserve_info = &postgres_update_reserve_info; plugin->update_reserve_info = &postgres_update_reserve_info;
plugin->insert_reserve_info = &postgres_insert_reserve_info; plugin->insert_reserve_info = &postgres_insert_reserve_info;

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER 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 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 terms of the GNU General Public License as published by the Free Software
@ -252,6 +252,10 @@ struct TALER_AUDITORDB_Plugin
void *cb_cls); 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 * Insert information about the auditor's progress with an exchange's
* data. * data.
@ -420,6 +424,22 @@ struct TALER_AUDITORDB_Plugin
uint64_t *last_reserve_out_serial_id); 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 * 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 cls the @e cls of this struct with the plugin-specific state
* @param session connection to use * @param session connection to use
* @param denom_pub_hash hash of the denomination public key * @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 deposit_fee_balance total deposit fees collected for this DK
* @param melt_fee_balance total melt 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 * @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 cls the @e cls of this struct with the plugin-specific state
* @param session connection to use * @param session connection to use
* @param denom_pub_hash hash of the denomination public key * @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 deposit_fee_balance total deposit fees collected for this DK
* @param melt_fee_balance total melt 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 * @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 cls the @e cls of this struct with the plugin-specific state
* @param session connection to use * @param session connection to use
* @param denom_pub_hash hash of the denomination public key * @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] deposit_fee_balance total deposit fees collected for this DK
* @param[out] melt_fee_balance total melt 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 * @param[out] refund_fee_balance total refund fees collected for this DK