From 160a4ef52caf601107e401d8352a6d5b34f50911 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 28 Sep 2019 20:53:44 +0200 Subject: add test for emergencies, and associated bugfixes to auditor and auditor report --- src/auditor/taler-auditor.c | 131 ++++++++++++++++++++++++++++++++++---------- src/auditor/test-auditor.sh | 54 +++++++++++++++++- 2 files changed, 155 insertions(+), 30 deletions(-) (limited to 'src/auditor') diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c index 9d4dff83f..6ab9bb344 100644 --- a/src/auditor/taler-auditor.c +++ b/src/auditor/taler-auditor.c @@ -268,10 +268,25 @@ static json_int_t number_missed_deposit_confirmations; */ static struct TALER_Amount total_missed_deposit_confirmations; +/** + * Total amount reported in all calls to #report_emergency_by_count(). + */ +static struct TALER_Amount reported_emergency_risk_by_count; + /** * Total amount reported in all calls to #report_emergency(). */ -static struct TALER_Amount reported_emergency_sum; +static struct TALER_Amount reported_emergency_risk_by_amount; + +/** + * Total amount in losses reported in all calls to #report_emergency(). + */ +static struct TALER_Amount reported_emergency_loss; + +/** + * Total amount in losses reported in all calls to #report_emergency_by_count(). + */ +static struct TALER_Amount reported_emergency_loss_by_count; /** * Expected balance in the escrow account. @@ -419,9 +434,13 @@ report_emergency_by_amount (const struct "value", TALER_JSON_from_amount_nbo (&dki->properties.value))); GNUNET_assert (GNUNET_OK == - TALER_amount_add (&reported_emergency_sum, - &reported_emergency_sum, + TALER_amount_add (&reported_emergency_risk_by_amount, + &reported_emergency_risk_by_amount, risk)); + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&reported_emergency_loss, + &reported_emergency_loss, + loss)); } @@ -446,6 +465,8 @@ report_emergency_by_count (const struct uint64_t num_known, const struct TALER_Amount *risk) { + struct TALER_Amount denom_value; + report (report_emergencies_by_count, json_pack ("{s:o, s:I, s:I, s:o, s:o, s:o, s:o}", "denompub_hash", @@ -463,9 +484,17 @@ report_emergency_by_count (const struct "value", TALER_JSON_from_amount_nbo (&dki->properties.value))); GNUNET_assert (GNUNET_OK == - TALER_amount_add (&reported_emergency_sum, - &reported_emergency_sum, + TALER_amount_add (&reported_emergency_risk_by_count, + &reported_emergency_risk_by_count, risk)); + TALER_amount_ntoh (&denom_value, + &dki->properties.value); + for (uint64_t i = num_issued; iqs = qs; } - cleanup: +cleanup: GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (rc->reserves, key, @@ -3859,16 +3888,28 @@ refresh_session_cb (void *cls, { dso->denom_balance = tmp; } - if (GNUNET_SYSERR == - TALER_amount_subtract (&total_escrow_balance, - &total_escrow_balance, - amount_with_fee)) + if (-1 == TALER_amount_cmp (&total_escrow_balance, + amount_with_fee)) { - /* This should not be possible, unless the AUDITOR - has a bug in tracking total balance. */ - GNUNET_break (0); - cc->qs = GNUNET_DB_STATUS_HARD_ERROR; - return GNUNET_SYSERR; + /* 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 + { + GNUNET_assert (GNUNET_SYSERR != + TALER_amount_subtract (&total_escrow_balance, + &total_escrow_balance, + amount_with_fee)); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -4030,16 +4071,29 @@ deposit_cb (void *cls, { ds->denom_balance = tmp; } - if (GNUNET_SYSERR == - TALER_amount_subtract (&total_escrow_balance, - &total_escrow_balance, - amount_with_fee)) + + if (-1 == TALER_amount_cmp (&total_escrow_balance, + amount_with_fee)) { - /* This should not be possible, unless the AUDITOR - has a bug in tracking total balance. */ - GNUNET_break (0); - cc->qs = GNUNET_DB_STATUS_HARD_ERROR; - return GNUNET_SYSERR; + /* 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, + amount_with_fee, + 0); + } + else + { + GNUNET_assert (GNUNET_SYSERR != + TALER_amount_subtract (&total_escrow_balance, + &total_escrow_balance, + amount_with_fee)); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -5094,7 +5148,16 @@ run (void *cls, "Starting audit\n"); GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (currency, - &reported_emergency_sum)); + &reported_emergency_loss)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (currency, + &reported_emergency_risk_by_amount)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (currency, + &reported_emergency_risk_by_count)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (currency, + &reported_emergency_loss_by_count)); GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (currency, &total_escrow_balance)); @@ -5213,7 +5276,8 @@ run (void *cls, " s:o, s:o, s:o, s:o, s:o," " s:o, s:o, s:o, s:o, s:o," " s:o, s:o, s:o, s:o, s:I," - " s:o, s:o, s:o }", + " s:o, s:o, s:o, s:o, s:o," + " s:o }", /* blocks of 5 for easier counting/matching to format string */ /* block */ "reserve_balance_insufficient_inconsistencies", @@ -5248,8 +5312,9 @@ run (void *cls, TALER_JSON_from_amount (&income_fee_total), "emergencies", report_emergencies, - "emergencies_risk_total", - TALER_JSON_from_amount (&reported_emergency_sum), + "emergencies_risk_by_amount", + TALER_JSON_from_amount ( + &reported_emergency_risk_by_amount), "reserve_not_closed_inconsistencies", report_reserve_not_closed_inconsistencies, /* block */ @@ -5309,7 +5374,15 @@ run (void *cls, "total_payback_loss", TALER_JSON_from_amount (&total_payback_loss), "emergencies_by_count", - report_emergencies_by_count + report_emergencies_by_count, + "emergencies_risk_by_count", + TALER_JSON_from_amount ( + &reported_emergency_risk_by_count), + "emergencies_loss", + TALER_JSON_from_amount (&reported_emergency_loss), + /* block */ + "emergencies_loss_by_count", + TALER_JSON_from_amount (&reported_emergency_loss_by_count) ); GNUNET_break (NULL != report); json_dumpf (report, diff --git a/src/auditor/test-auditor.sh b/src/auditor/test-auditor.sh index 83de1f6c0..d56497a9c 100755 --- a/src/auditor/test-auditor.sh +++ b/src/auditor/test-auditor.sh @@ -83,7 +83,7 @@ function audit_only () { # Cleanup to run after the auditor function post_audit () { - kill -9 `jobs -p` >/dev/null 2>/dev/null || true + kill -TERM `jobs -p` >/dev/null 2>/dev/null || true echo -n "TeXing ." ../../contrib/render.py test-audit.json test-wire-audit.json < ../../contrib/auditor-report.tex.j2 > test-report.tex || exit_fail "Renderer failed" @@ -980,6 +980,58 @@ echo "UPDATE app_banktransaction SET date='${OLD_DATE}' WHERE id='${OLD_ID}';" | +# Test where we trigger an emergency. +function test_18() { +echo "===========18: emergency=================" + +echo "DELETE FROM reserves_out;" | psql -Aqt $DB + +run_audit + +echo -n "Testing emergency detection... " + +jq -e .reserve_balance_summary_wrong_inconsistencies[0] < test-audit.json > /dev/null || exit_fail "Reserve balance inconsistency not detected" + +jq -e .emergencies[0] < test-audit.json > /dev/null || exit_fail "Emergency not detected" +jq -e .emergencies_by_count[0] < test-audit.json > /dev/null || exit_fail "Emergency by count not detected" +jq -e .amount_arithmetic_inconsistencies[0] < test-audit.json > /dev/null || exit_fail "Escrow balance calculation impossibility not detected" + +echo PASS + +echo -n "Testing risk/loss calculation... " + +AMOUNT=`jq -r .emergencies_risk_by_amount < test-audit.json` +if test "x$AMOUNT" == "xTESTKUDOS:0" +then + exit_fail "Reported amount wrong: $AMOUNT" +fi +AMOUNT=`jq -r .emergencies_risk_by_count < test-audit.json` +if test "x$AMOUNT" == "xTESTKUDOS:0" +then + exit_fail "Reported amount wrong: $AMOUNT" +fi +AMOUNT=`jq -r .emergencies_loss < test-audit.json` +if test "x$AMOUNT" == "xTESTKUDOS:0" +then + exit_fail "Reported amount wrong: $AMOUNT" +fi +AMOUNT=`jq -r .emergencies_loss_by_count < test-audit.json` +if test "x$AMOUNT" == "xTESTKUDOS:0" +then + exit_fail "Reported amount wrong: $AMOUNT" +fi + +echo PASS + + +# cannot easily undo broad DELETE operation, hence full reload +echo -n "Reloading database ..." +full_reload +echo "DONE" +} + + + # ************************************************** # FIXME: Add more tests here! :-) # Specifically: -- cgit v1.2.3