more work on auditor

This commit is contained in:
Christian Grothoff 2017-03-18 17:47:44 +01:00
parent 9a5cef0eb1
commit 9cfe47493c
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
5 changed files with 131 additions and 36 deletions

View File

@ -25,16 +25,16 @@
* given in the 'wire_out' table. This needs to be checked separately!
*
* TODO:
* - implement merchant deposit audit starting with 'wire_out'
* - modify auditordb to allow multiple last serial IDs per table in progress tracking (needed?)
* - modify auditordb to track risk with balances and fees (and rename callback
* - COMPLETE: implement misc. FIXMEs
* - COMPLETE: deal with risk / expired denomination keys in #sync_denomination
* - SANITY: modify auditordb to track risk with balances and fees (and rename callback
* to clarify what it is)
* - modify auditordb to return DK when we inquire about deposit/refresh/refund,
* - SANITY: rename operations to better describe what they do!
* - OPTIMIZE/SIMPLIFY: modify auditordb to return DK when we inquire about deposit/refresh/refund,
* so we can avoid the costly #get_coin_summary with the transaction history building
* (at least during #analyze_coins); the logic may be partially useful in
* #analyze_merchants (but we won't need the cache!)
* - deal with risk / expired denomination keys in #sync_denomination
* - write reporting logic to output nice report beyond GNUNET_log()
* - BEAUTIFY: write reporting logic to output nice report beyond GNUNET_log()
* - write logic to deal with emergency (#3887) -- and emergency-related tables!
*/
#include "platform.h"
@ -191,6 +191,49 @@ report_reserve_inconsistency (const struct TALER_ReservePublicKeyP *reserve_pub,
}
/**
* Report a global inconsistency with respect to a wire transfer.
*
* @param reserve_pub the affected reserve
* @param expected expected amount
* @param observed observed amount
* @param diagnostic message explaining what @a expected and @a observed refer to
*/
static void
report_wire_out_inconsistency (const json_t *destination,
uint64_t rowid,
const struct TALER_Amount *expected,
const struct TALER_Amount *observed,
const char *diagnostic)
{
// TODO: implement proper reporting logic writing to file, include amounts.
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire out inconsistency detected: %s\n",
diagnostic);
}
/**
* Report a global inconsistency with respect to a coin's history.
*
* @param coin_pub the affected coin
* @param expected expected amount
* @param observed observed amount
* @param diagnostic message explaining what @a expected and @a observed refer to
*/
static void
report_coin_inconsistency (const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_Amount *expected,
const struct TALER_Amount *observed,
const char *diagnostic)
{
// TODO: implement proper reporting logic writing to file, include amounts.
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Coin inconsistency detected: %s\n",
diagnostic);
}
/**
* Report the final result on the reserve balances of the exchange.
* The reserve must have @a total_balance in its escrow account just
@ -1714,9 +1757,9 @@ deposit_cb (void *cls,
}
}
/* TODO: *if* past pay_deadline, check that
aggregation record exists for the deposit;
if NOT, check that full _refund_ exists. */
/* TODO: *if* past pay_deadline, check that aggregation record
exists for the deposit, and if NOT, check that full _refund_
exists. */
return GNUNET_OK;
}
@ -2113,11 +2156,6 @@ struct WireCheckContext
*/
struct GNUNET_TIME_Absolute date;
/**
* Set to error message of @e ok is #GNUNET_SYSERR.
*/
const char *emsg;
/**
* Wire method used for the transfer.
*/
@ -2209,7 +2247,10 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
{
/* overflow in history already!? inconceivable! Bad DB! */
GNUNET_break (0);
// FIXME: report!
report_coin_inconsistency (coin_pub,
add_to,
amount_with_fee,
"could not add coin's contribution to total");
return GNUNET_SYSERR;
}
TALER_amount_ntoh (&tmp,
@ -2220,7 +2261,10 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
{
/* Disagreement in fee structure within DB! */
GNUNET_break (0);
// FIXME: report!
report_coin_inconsistency (coin_pub,
&tmp,
fee,
"coin's fee in transaction and in denomination data differ");
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
@ -2230,20 +2274,26 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
{
/* overflow in fee total? inconceivable! Bad DB! */
GNUNET_break (0);
// FIXME: report!
report_coin_inconsistency (coin_pub,
fee,
&fees,
"could not add coin's fee to total fees");
return GNUNET_SYSERR;
}
} /* for 'tl' */
/* Finally, calculate total balance change, i.e. expenditures minus refunds */
if (GNUNET_OK !=
if (GNUNET_SYSERR ==
TALER_amount_subtract (final_expenditures,
&expenditures,
&refunds))
{
/* refunds above expenditures? inconceivable! Bad DB! */
GNUNET_break (0);
// FIXME: report!
report_coin_inconsistency (coin_pub,
&expenditures,
&refunds,
"could not subtract refunded amount from expenditures");
return GNUNET_SYSERR;
}
return GNUNET_OK;
@ -2255,6 +2305,7 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
* transaction data associated with a wire transfer identifier.
*
* @param cls a `struct WireCheckContext`
* @param rowid which row in the table is the information from (for diagnostics)
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
* @param wire_method which wire plugin was used for the transfer?
* @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
@ -2264,9 +2315,9 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
* @param coin_value amount contributed by this coin in total (with fee)
* @param coin_fee applicable fee for this coin
*/
// TODO: modify to have rowid to log errors in a more fine-grained way?
static void
wire_transfer_information_cb (void *cls,
uint64_t rowid,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const char *wire_method,
const struct GNUNET_HashCode *h_wire,
@ -2291,7 +2342,9 @@ wire_transfer_information_cb (void *cls,
if (NULL == tl)
{
wcc->ok = GNUNET_SYSERR;
wcc->emsg = "no transaction history for coin claimed in aggregation";
report_row_inconsistency ("aggregation",
rowid,
"no transaction history for coin claimed in aggregation");
return;
}
@ -2315,11 +2368,14 @@ wire_transfer_information_cb (void *cls,
&dki,
NULL))
{
/* This should be impossible from database constraints */
GNUNET_break (0);
edb->free_coin_transaction_list (edb->cls,
tl);
wcc->ok = GNUNET_SYSERR;
wcc->emsg = "could not find denomination key for coin claimed in aggregation";
report_row_inconsistency ("aggregation",
rowid,
"could not find denomination key for coin claimed in aggregation");
return;
}
@ -2336,14 +2392,18 @@ wire_transfer_information_cb (void *cls,
coin_value))
{
wcc->ok = GNUNET_SYSERR;
wcc->emsg = "coin transaction history and aggregation disagree about coin's contribution";
report_row_inconsistency ("aggregation",
rowid,
"coin transaction history and aggregation disagree about coin's contribution");
}
if (0 !=
TALER_amount_cmp (&computed_fees,
coin_fee))
{
wcc->ok = GNUNET_SYSERR;
wcc->emsg = "coin transaction history and aggregation disagree about applicable fees";
report_row_inconsistency ("aggregation",
rowid,
"coin transaction history and aggregation disagree about applicable fees");
}
edb->free_coin_transaction_list (edb->cls,
tl);
@ -2353,21 +2413,28 @@ wire_transfer_information_cb (void *cls,
wcc->method))
{
wcc->ok = GNUNET_SYSERR;
wcc->emsg = "wire method of aggregate do not match wire transfer";
return;
report_row_inconsistency ("aggregation",
rowid,
"wire method of aggregate do not match wire transfer");
}
if (0 != memcmp (h_wire,
&wcc->h_wire,
sizeof (struct GNUNET_HashCode)))
{
wcc->ok = GNUNET_SYSERR;
wcc->emsg = "account details of aggregate do not match account details of wire transfer";
report_row_inconsistency ("aggregation",
rowid,
"account details of aggregate do not match account details of wire transfer");
return;
}
if (exec_time.abs_value_us != wcc->date.abs_value_us)
{
/* This should be impossible from database constraints */
GNUNET_break (0);
wcc->ok = GNUNET_SYSERR;
wcc->emsg = "date given in aggregate does not match wire transfer date";
report_row_inconsistency ("aggregation",
rowid,
"date given in aggregate does not match wire transfer date");
return;
}
if (GNUNET_SYSERR ==
@ -2376,7 +2443,9 @@ wire_transfer_information_cb (void *cls,
coin_fee))
{
wcc->ok = GNUNET_SYSERR;
wcc->emsg = "could not calculate contribution of coin";
report_row_inconsistency ("aggregation",
rowid,
"could not calculate contribution of coin");
return;
}
@ -2418,7 +2487,10 @@ check_wire_out_cb (void *cls,
if ( (NULL == method) ||
(! json_is_string (method)) )
{
// TODO: bitch
report_row_inconsistency ("wire_out",
rowid,
"specified wire address lacks type");
return;
}
wcc.method = json_string_value (method);
wcc.ok = GNUNET_OK;
@ -2434,24 +2506,35 @@ check_wire_out_cb (void *cls,
&wcc);
if (GNUNET_OK != wcc.ok)
{
// TODO: bitch
report_row_inconsistency ("wire_out",
rowid,
"audit of associated transactions failed");
}
plugin = get_wire_plugin (mc,
wcc.method);
if (NULL == plugin)
{
// TODO: bitch
report_row_inconsistency ("wire_out",
rowid,
"could not load required wire plugin to validate");
return;
}
if (GNUNET_OK !=
plugin->amount_round (plugin->cls,
&wcc.total_deposits))
{
// TODO: bitch
report_row_minor_inconsistency ("wire_out",
rowid,
"wire plugin failed to round given amount");
}
if (0 != TALER_amount_cmp (amount,
&wcc.total_deposits))
{
// TODO: bitch!
report_wire_out_inconsistency (wire,
rowid,
&wcc.total_deposits,
amount,
"computed amount inconsistent with wire amount");
}
}

View File

@ -1912,6 +1912,7 @@ struct WtidTransactionContext
* transaction data for the given wire transfer identifier.
*
* @param cls our context for transmission
* @param rowid which row in the DB is the information from (for diagnostics)
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
* @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
* @param exec_time execution time of the wire transfer (should be same for all callbacks with the same @e cls)
@ -1922,6 +1923,7 @@ struct WtidTransactionContext
*/
static void
handle_transaction_data (void *cls,
uint64_t rowid,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const char *wire_method,
const struct GNUNET_HashCode *h_wire,

View File

@ -490,7 +490,8 @@ postgres_create_tables (void *cls)
/* Table for the tracking API, mapping from wire transfer identifiers
to transactions and back */
SQLEXEC("CREATE TABLE IF NOT EXISTS aggregation_tracking "
"(deposit_serial_id INT8 PRIMARY KEY REFERENCES deposits (deposit_serial_id) ON DELETE CASCADE"
"(aggregation_serial_id BIGSERIAL"
",deposit_serial_id INT8 PRIMARY KEY REFERENCES deposits (deposit_serial_id) ON DELETE CASCADE"
",wtid_raw BYTEA CONSTRAINT wire_out_ref REFERENCES wire_out(wtid_raw) ON DELETE CASCADE DEFERRABLE"
",execution_time INT8 NOT NULL"
")");
@ -1235,7 +1236,8 @@ postgres_prepare (PGconn *db_conn)
/* Used in #postgres_lookup_wire_transfer */
PREPARE ("lookup_transactions",
"SELECT"
" deposits.h_proposal_data"
" aggregation_serial_id"
",deposits.h_proposal_data"
",deposits.wire"
",deposits.h_wire"
",deposits.coin_pub"
@ -4067,6 +4069,7 @@ postgres_lookup_wire_transfer (void *cls,
}
for (i=0;i<nrows;i++)
{
uint64_t rowid;
struct GNUNET_HashCode h_proposal_data;
struct GNUNET_HashCode h_wire;
struct TALER_CoinSpendPublicKeyP coin_pub;
@ -4078,6 +4081,7 @@ postgres_lookup_wire_transfer (void *cls,
json_t *t;
const char *wire_method;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("aggregation_serial_id", &rowid),
GNUNET_PQ_result_spec_auto_from_type ("h_proposal_data", &h_proposal_data),
TALER_PQ_result_spec_json ("wire", &wire),
GNUNET_PQ_result_spec_auto_from_type ("h_wire", &h_wire),
@ -4088,6 +4092,7 @@ postgres_lookup_wire_transfer (void *cls,
TALER_PQ_result_spec_amount ("fee_deposit", &deposit_fee),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
@ -4112,6 +4117,7 @@ postgres_lookup_wire_transfer (void *cls,
return GNUNET_SYSERR;
}
cb (cb_cls,
rowid,
&merchant_pub,
wire_method,
&h_wire,

View File

@ -752,6 +752,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
*/
static void
cb_wt_never (void *cls,
uint64_t serial_id,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const char *wire_method,
const struct GNUNET_HashCode *h_wire,
@ -795,6 +796,7 @@ static struct TALER_WireTransferIdentifierRawP wtid_wt;
*/
static void
cb_wt_check (void *cls,
uint64_t rowid,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const char *wire_method,
const struct GNUNET_HashCode *h_wire,

View File

@ -759,6 +759,7 @@ typedef void
* transaction data associated with a wire transfer identifier.
*
* @param cls closure
* @param rowid which row in the table is the information from (for diagnostics)
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
* @param wire_method which wire plugin was used for the transfer?
* @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
@ -770,6 +771,7 @@ typedef void
*/
typedef void
(*TALER_EXCHANGEDB_WireTransferDataCallback)(void *cls,
uint64_t rowid,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const char *wire_method,
const struct GNUNET_HashCode *h_wire,