gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated (f052527e -> 13bbcef8)


From: gnunet
Subject: [taler-exchange] branch master updated (f052527e -> 13bbcef8)
Date: Fri, 27 Mar 2020 11:26:37 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository exchange.

    from f052527e fix recoup-refresh audit logic
     new 9445343e consider that deposit fee is discounted when refund fee is 
applied
     new 62b8ca0b check coin history consistency
     new 8a90c8fb expand test suite
     new 6906538c missing break
     new 9c6aa53c improve coin audit logic
     new 1ced0438 improve error logging
     new 4856d811 fix inconsistency in field naming
     new 13bbcef8 adjust test to code changes

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 contrib/auditor-report.tex.j2            |  14 +-
 src/auditor/taler-helper-auditor-coins.c | 315 +++++++++++++++++++++++++++++--
 src/auditor/test-auditor.sh              |  43 ++++-
 src/auditor/test-revocation.sh           |  96 +++++++++-
 src/exchangedb/exchangedb_transactions.c |  23 ++-
 5 files changed, 457 insertions(+), 34 deletions(-)

diff --git a/contrib/auditor-report.tex.j2 b/contrib/auditor-report.tex.j2
index a8514aed..16b53e20 100644
--- a/contrib/auditor-report.tex.j2
+++ b/contrib/auditor-report.tex.j2
@@ -509,6 +509,7 @@ easily determined from the amounts and thus not included in 
the totals.
 \subsubsection{For coins}
 
 % Table generation tested by testcase #18 in test-auditor.sh
+% Table generation tested by testcase #3 in test-revocation.sh
 
 {% if coins.amount_arithmetic_inconsistencies|length() == 0 %}
   {\bf No arithmetic problems detected.}
@@ -541,7 +542,7 @@ easily determined from the amounts and thus not included in 
the totals.
 
 \subsubsection{For reserves}
 
-% Table generation tested by testcase #XX in test-auditor.sh
+% Table generation tested by testcase #2 in test-auditor.sh
 
 {% if reserves.amount_arithmetic_inconsistencies|length() == 0 %}
   {\bf No arithmetic problems detected.}
@@ -752,6 +753,7 @@ public key for ``recoup-master'' operations.
 \subsubsection{For coins}
 
 % Table generation tested by testcase #4/#5/#6/#13 in test-auditor.sh
+% Table generation tested by testcase #4 in test-revocation.sh
 
 {% if coins.bad_sig_losses|length() == 0 %}
   {\bf All signatures were valid.}
@@ -775,7 +777,7 @@ public key for ``recoup-master'' operations.
   \label{table:bad_signature_losses}
 \endlastfoot
 {% for item in coins.bad_sig_losses %}
-  \multicolumn{3}{l}{ {\tt \small \truncate{0.9\textwidth}{ {{ item.key_pub }} 
} } } \\
+  \multicolumn{3}{l}{ {\tt \small \truncate{0.9\textwidth}{ {{ item.coin_pub 
}} } } } \\
 \nopagebreak
   {{ item.operation }} &
   {{ item.row }} &
@@ -974,6 +976,7 @@ Deltas may indicate a corrupt database, but do not 
necessarily
 translate into a financial loss (yet).
 
 % Table generation tested by testcase #3 in test-auditor.sh
+% Table generation tested by testcase #4 in test-revocation.sh
 
 {% if reserves.reserve_balance_summary_wrong_inconsistencies|length() == 0 %}
   {\bf All balances matched up.}
@@ -1065,8 +1068,7 @@ have a clear financial impact.
 This section describes issues found by the wire auditor that
 relate to outgoing wire transfers subjects being duplicated.
 
-% Table generation tested by testcase #XX in test-auditor.sh
-% TODO: test this! #6054
+% Table generation tested by testcase #27 in test-auditor.sh
 
 {% if wire.wire_format_inconsistencies|length() == 0 %}
   {\bf No wire format inconsistencies found.}
@@ -1081,7 +1083,7 @@ relate to outgoing wire transfers subjects being 
duplicated.
   \hline \hline
 \endhead
   \hline
-  \multicolumn{2}{c}{ {\bf Row (base32)} } \\
+  \multicolumn{2}{c}{ {\bf Diagnostic} } \\
   {\bf Row (base32)}  & {\bf Amount} \\
 \endfoot
   \hline
@@ -1200,7 +1202,7 @@ impact.
 
 \subsubsection{For reserves}
 
-% Table generation tested by testcase #XX in test-auditor.sh
+% Table generation tested by testcase #4 in test-revocation.sh
 
 {% if reserves.row_inconsistencies|length() == 0 %}
   {\bf No row inconsistencies found.}
diff --git a/src/auditor/taler-helper-auditor-coins.c 
b/src/auditor/taler-helper-auditor-coins.c
index 9f9f6dc9..b292da8b 100644
--- a/src/auditor/taler-helper-auditor-coins.c
+++ b/src/auditor/taler-helper-auditor-coins.c
@@ -38,7 +38,7 @@
  * Set to a VERY low value here for testing. Practical values may be
  * in the millions.
  */
-#define MAX_COIN_SUMMARIES 4
+#define MAX_COIN_HISTORIES 4
 
 /**
  * Use a 1 day grace period to deal with clocks not being perfectly 
synchronized.
@@ -169,6 +169,89 @@ static json_t *report_refreshs_hanging;
  */
 static struct TALER_Amount total_refresh_hanging;
 
+/**
+ * Coin and associated transaction history.
+ */
+struct CoinHistory
+{
+  /**
+   * Public key of the coin.
+   */
+  struct TALER_CoinSpendPublicKeyP coin_pub;
+
+  /**
+   * The transaction list for the @a coin_pub.
+   */
+  struct TALER_EXCHANGEDB_TransactionList *tl;
+};
+
+/**
+ * Array of transaction histories for coins.  The index is based on the coin's
+ * public key.  Entries are replaced whenever we have a collision.
+ */
+static struct CoinHistory coin_histories[MAX_COIN_HISTORIES];
+
+
+/**
+ * Return the index we should use for @a coin_pub in #coin_histories.
+ *
+ * @param coin_pub a coin's public key
+ * @return index for caching this coin's history in #coin_histories
+ */
+static unsigned int
+coin_history_index (const struct TALER_CoinSpendPublicKeyP *coin_pub)
+{
+  uint32_t i;
+
+  memcpy (&i,
+          coin_pub,
+          sizeof (i));
+  return i % MAX_COIN_HISTORIES;
+}
+
+
+/**
+ * Add a coin history to our in-memory cache.
+ *
+ * @param coin_pub public key of the coin to cache
+ * @param tl history to store
+ */
+static void
+cache_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
+               struct TALER_EXCHANGEDB_TransactionList *tl)
+{
+  unsigned int i = coin_history_index (coin_pub);
+
+  if (NULL != coin_histories[i].tl)
+    TALER_ARL_edb->free_coin_transaction_list (TALER_ARL_edb->cls,
+                                               coin_histories[i].tl);
+  coin_histories[i].coin_pub = *coin_pub;
+  coin_histories[i].tl = tl;
+}
+
+
+/**
+ * Obtain a coin's history from our in-memory cache.
+ *
+ * @param coin_pub public key of the coin to cache
+ * @return NULL if @a coin_pub is not in the cache
+ */
+static struct TALER_EXCHANGEDB_TransactionList *
+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))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Found verification of %s in cache\n",
+                TALER_B2S (coin_pub));
+    return coin_histories[i].tl;
+  }
+  return NULL;
+}
+
 
 /* ***************************** Report logic **************************** */
 
@@ -362,6 +445,146 @@ report_row_inconsistency (const char *table,
 }
 
 
+/* ************* Analyze history of a coin ******************** */
+
+
+/**
+ * Obtain @a coin_pub's history, verify it, report inconsistencies
+ * and store the result in our cache.
+ *
+ * @param coin_pub public key of the coin to check the history of
+ * @param rowid a row identifying the transaction
+ * @param operation operation matching @a rowid
+ * @param value value of the respective coin's denomination
+ * @return database status code, negative on failures
+ */
+static enum GNUNET_DB_QueryStatus
+check_coin_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                    uint64_t rowid,
+                    const char *operation,
+                    const struct TALER_Amount *value)
+{
+  struct TALER_EXCHANGEDB_TransactionList *tl;
+  enum GNUNET_DB_QueryStatus qs;
+  struct TALER_Amount total;
+  struct TALER_Amount spent;
+  struct TALER_Amount refunded;
+  struct TALER_Amount deposit_fee;
+  int have_refund;
+
+  qs = TALER_ARL_edb->get_coin_transactions (TALER_ARL_edb->cls,
+                                             TALER_ARL_esession,
+                                             coin_pub,
+                                             GNUNET_YES,
+                                             &tl);
+  if (0 >= qs)
+    return qs;
+
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_get_zero (value->currency,
+                                        &refunded));
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_get_zero (value->currency,
+                                        &spent));
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_get_zero (value->currency,
+                                        &deposit_fee));
+  for (struct TALER_EXCHANGEDB_TransactionList *pos = tl;
+       NULL != pos;
+       pos = pos->next)
+  {
+    switch (pos->type)
+    {
+    case TALER_EXCHANGEDB_TT_DEPOSIT:
+      /* spent += pos->amount_with_fee */
+      GNUNET_assert (GNUNET_OK ==
+                     TALER_amount_add (&spent,
+                                       &spent,
+                                       
&pos->details.deposit->amount_with_fee));
+      deposit_fee = pos->details.deposit->deposit_fee;
+      break;
+    case TALER_EXCHANGEDB_TT_MELT:
+      /* spent += pos->amount_with_fee */
+      GNUNET_assert (GNUNET_OK ==
+                     TALER_amount_add (&spent,
+                                       &spent,
+                                       &pos->details.melt->amount_with_fee));
+      break;
+    case TALER_EXCHANGEDB_TT_REFUND:
+      /* refunded += pos->refund_amount - pos->refund_fee */
+      GNUNET_assert (GNUNET_OK ==
+                     TALER_amount_add (&refunded,
+                                       &refunded,
+                                       &pos->details.refund->refund_amount));
+      GNUNET_assert (GNUNET_OK ==
+                     TALER_amount_add (&spent,
+                                       &spent,
+                                       &pos->details.refund->refund_fee));
+      have_refund = GNUNET_YES;
+      break;
+    case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP:
+      /* refunded += pos->value */
+      GNUNET_assert (GNUNET_OK ==
+                     TALER_amount_add (&refunded,
+                                       &refunded,
+                                       &pos->details.old_coin_recoup->value));
+      break;
+    case TALER_EXCHANGEDB_TT_RECOUP:
+      /* spent += pos->value */
+      GNUNET_assert (GNUNET_OK ==
+                     TALER_amount_add (&spent,
+                                       &spent,
+                                       &pos->details.recoup->value));
+      break;
+    case TALER_EXCHANGEDB_TT_RECOUP_REFRESH:
+      /* spent += pos->value */
+      GNUNET_assert (GNUNET_OK ==
+                     TALER_amount_add (&spent,
+                                       &spent,
+                                       &pos->details.recoup_refresh->value));
+      break;
+    }
+  }
+
+  if (have_refund)
+  {
+    /* If we gave any refund, also discount ONE deposit fee */
+    GNUNET_assert (GNUNET_OK ==
+                   TALER_amount_add (&refunded,
+                                     &refunded,
+                                     &deposit_fee));
+  }
+  /* total coin value = original value plus refunds */
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_add (&total,
+                                   &refunded,
+                                   value));
+  if (1 ==
+      TALER_amount_cmp (&spent,
+                        &total))
+  {
+    /* spent > total: bad */
+    struct TALER_Amount loss;
+
+    TALER_amount_subtract (&loss,
+                           &spent,
+                           &total);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Loss detected for coin %s - %s\n",
+                TALER_B2S (coin_pub),
+                TALER_amount2s (&loss));
+    report_amount_arithmetic_inconsistency (operation,
+                                            rowid,
+                                            &spent,
+                                            &total,
+                                            -1);
+  }
+  cache_history (coin_pub,
+                 tl);
+  return qs;
+}
+
+
 /* ************************* Analyze coins ******************** */
 /* This logic checks that the exchange did the right thing for each
    coin, checking deposits, refunds, refresh* and known_coins
@@ -776,6 +999,7 @@ withdraw_cb (void *cls,
   (void) reserve_sig;
   (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;
 
@@ -930,9 +1154,12 @@ reveal_data_cb (void *cls,
 
 /**
  * Check that the @a coin_pub is a known coin with a proper
- * signature for denominatinon @a denom_pub. If not, TALER_ARL_report
+ * signature for denominatinon @a denom_pub. If not, report
  * a loss of @a loss_potential.
  *
+ * @param operation which operation is this about
+ * @param issue denomination key information about the coin
+ * @param rowid which row is this operation in
  * @param coin_pub public key of a coin
  * @param denom_pub expected denomination of the coin
  * @param loss_potential how big could the loss be if the coin is
@@ -941,13 +1168,35 @@ reveal_data_cb (void *cls,
  *  #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
  */
 static enum GNUNET_DB_QueryStatus
-check_known_coin (const struct TALER_CoinSpendPublicKeyP *coin_pub,
+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)
 {
   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);
+    if (0 > qs)
+    {
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+      return qs;
+    }
+    GNUNET_break (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs);
+  }
+
+
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Checking denomination signature on %s\n",
               TALER_B2S (coin_pub));
@@ -966,11 +1215,11 @@ check_known_coin (const struct TALER_CoinSpendPublicKeyP 
*coin_pub,
   {
     TALER_ARL_report (report_bad_sig_losses,
                       json_pack ("{s:s, s:I, s:o, s:o}",
-                                 "operation", "known-coin",
-                                 "row", (json_int_t) -1,
+                                 "operation", operation,
+                                 "row", (json_int_t) rowid,
                                  "loss", TALER_JSON_from_amount (
                                    loss_potential),
-                                 "key_pub", GNUNET_JSON_from_data_auto (
+                                 "coin_pub", GNUNET_JSON_from_data_auto (
                                    coin_pub)));
     GNUNET_assert (GNUNET_OK ==
                    TALER_amount_add (&total_bad_sig_loss,
@@ -1037,7 +1286,10 @@ refresh_session_cb (void *cls,
     cc->qs = qs;
     return GNUNET_SYSERR;
   }
-  qs = check_known_coin (coin_pub,
+  qs = check_known_coin ("melt",
+                         issue,
+                         rowid,
+                         coin_pub,
                          denom_pub,
                          amount_with_fee);
   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
@@ -1071,7 +1323,7 @@ refresh_session_cb (void *cls,
                                    "row", (json_int_t) rowid,
                                    "loss", TALER_JSON_from_amount (
                                      amount_with_fee),
-                                   "key_pub", GNUNET_JSON_from_data_auto (
+                                   "coin_pub", GNUNET_JSON_from_data_auto (
                                      coin_pub)));
       GNUNET_assert (GNUNET_OK ==
                      TALER_amount_add (&total_bad_sig_loss,
@@ -1377,7 +1629,10 @@ deposit_cb (void *cls,
     cc->qs = qs;
     return GNUNET_SYSERR;
   }
-  qs = check_known_coin (coin_pub,
+  qs = check_known_coin ("deposit",
+                         issue,
+                         rowid,
+                         coin_pub,
                          denom_pub,
                          amount_with_fee);
   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
@@ -1410,7 +1665,7 @@ deposit_cb (void *cls,
                                    "row", (json_int_t) rowid,
                                    "loss", TALER_JSON_from_amount (
                                      amount_with_fee),
-                                   "key_pub", GNUNET_JSON_from_data_auto (
+                                   "coin_pub", GNUNET_JSON_from_data_auto (
                                      coin_pub)));
       GNUNET_assert (GNUNET_OK ==
                      TALER_amount_add (&total_bad_sig_loss,
@@ -1435,7 +1690,7 @@ deposit_cb (void *cls,
                                    "row", (json_int_t) rowid,
                                    "loss", TALER_JSON_from_amount (
                                      amount_with_fee),
-                                   "key_pub", GNUNET_JSON_from_data_auto (
+                                   "coin_pub", GNUNET_JSON_from_data_auto (
                                      coin_pub)));
       GNUNET_assert (GNUNET_OK ==
                      TALER_amount_add (&total_bad_sig_loss,
@@ -1606,8 +1861,8 @@ refund_cb (void *cls,
                                    "row", (json_int_t) rowid,
                                    "loss", TALER_JSON_from_amount (
                                      amount_with_fee),
-                                   "key_pub", GNUNET_JSON_from_data_auto (
-                                     merchant_pub)));
+                                   "coin_pub", GNUNET_JSON_from_data_auto (
+                                     coin_pub)));
       GNUNET_assert (GNUNET_OK ==
                      TALER_amount_add (&total_bad_sig_loss,
                                        &total_bad_sig_loss,
@@ -1684,6 +1939,7 @@ refund_cb (void *cls,
  * and update the denomination's losses accordingly.
  *
  * @param cc the context with details about the coin
+ * @param operation name of the operation matching @a rowid
  * @param rowid row identifier used to uniquely identify the recoup operation
  * @param amount how much should be added back to the reserve
  * @param coin public information about the coin
@@ -1694,6 +1950,7 @@ refund_cb (void *cls,
  */
 static int
 check_recoup (struct CoinContext *cc,
+              const char *operation,
               uint64_t rowid,
               const struct TALER_Amount *amount,
               const struct TALER_CoinPublicInfo *coin,
@@ -1711,10 +1968,10 @@ check_recoup (struct CoinContext *cc,
   {
     TALER_ARL_report (report_bad_sig_losses,
                       json_pack ("{s:s, s:I, s:o, s:o}",
-                                 "operation", "recoup",
+                                 "operation", operation,
                                  "row", (json_int_t) rowid,
                                  "loss", TALER_JSON_from_amount (amount),
-                                 "key_pub", GNUNET_JSON_from_data_auto (
+                                 "coin_pub", GNUNET_JSON_from_data_auto (
                                    &coin->denom_pub_hash)));
     GNUNET_assert (GNUNET_OK ==
                    TALER_amount_add (&total_bad_sig_loss,
@@ -1725,7 +1982,7 @@ check_recoup (struct CoinContext *cc,
                                                 &issue);
   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   {
-    report_row_inconsistency ("recoup",
+    report_row_inconsistency (operation,
                               rowid,
                               "denomination key not found");
     return GNUNET_OK;
@@ -1738,6 +1995,18 @@ check_recoup (struct CoinContext *cc,
     cc->qs = qs;
     return GNUNET_SYSERR;
   }
+  qs = check_known_coin (operation,
+                         issue,
+                         rowid,
+                         &coin->coin_pub,
+                         denom_pub,
+                         amount);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+  {
+    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+    cc->qs = qs;
+    return GNUNET_SYSERR;
+  }
   {
     struct TALER_RecoupRequestPS pr = {
       .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
@@ -1755,7 +2024,7 @@ check_recoup (struct CoinContext *cc,
     {
       TALER_ARL_report (report_bad_sig_losses,
                         json_pack ("{s:s, s:I, s:o, s:o}",
-                                   "operation", "recoup",
+                                   "operation", operation,
                                    "row", (json_int_t) rowid,
                                    "loss", TALER_JSON_from_amount (amount),
                                    "coin_pub", GNUNET_JSON_from_data_auto (
@@ -1782,13 +2051,19 @@ check_recoup (struct CoinContext *cc,
     {
       /* Woopsie, we allowed recoup on non-revoked denomination!? */
       TALER_ARL_report (report_bad_sig_losses,
-                        json_pack ("{s:s, s:I, s:o, s:o}",
+                        json_pack ("{s:s, s:s, s:I, s:o, s:o}",
                                    "operation",
-                                   "recoup (denomination not revoked)",
+                                   operation,
+                                   "hint",
+                                   "denomination not revoked",
                                    "row", (json_int_t) rowid,
                                    "loss", TALER_JSON_from_amount (amount),
                                    "coin_pub", GNUNET_JSON_from_data_auto (
                                      &coin->coin_pub)));
+      GNUNET_assert (GNUNET_OK ==
+                     TALER_amount_add (&total_bad_sig_loss,
+                                       &total_bad_sig_loss,
+                                       amount));
     }
     GNUNET_assert (GNUNET_OK ==
                    TALER_amount_add (&ds->denom_recoup,
@@ -1835,6 +2110,7 @@ recoup_cb (void *cls,
   (void) timestamp;
   (void) reserve_pub;
   return check_recoup (cc,
+                       "recoup",
                        rowid,
                        amount,
                        coin,
@@ -1926,6 +2202,7 @@ recoup_refresh_cb (void *cls,
   }
 
   return check_recoup (cc,
+                       "recoup-refresh",
                        rowid,
                        amount,
                        coin,
diff --git a/src/auditor/test-auditor.sh b/src/auditor/test-auditor.sh
index ac498e17..c32cab44 100755
--- a/src/auditor/test-auditor.sh
+++ b/src/auditor/test-auditor.sh
@@ -352,7 +352,7 @@ echo "OK"
 # Change amount of wire transfer reported by exchange
 function test_2() {
 
-echo "===========2: reserves_in inconsitency==========="
+echo "===========2: reserves_in inconsistency==========="
 echo "UPDATE reserves_in SET credit_val=5 WHERE reserve_in_serial_id=1" | psql 
-Aqt $DB
 
 run_audit
@@ -396,7 +396,7 @@ echo "UPDATE reserves_in SET credit_val=10 WHERE 
reserve_in_serial_id=1" | psql
 # lower than what exchange claims to have received.
 function test_3() {
 
-echo "===========3: reserves_in inconsitency==========="
+echo "===========3: reserves_in inconsistency==========="
 echo "UPDATE reserves_in SET credit_val=15 WHERE reserve_in_serial_id=1" | 
psql -Aqt $DB
 
 run_audit
@@ -558,7 +558,7 @@ echo "UPDATE known_coins SET 
denom_sig='\x287369672d76616c200a2028727361200a2020
 run_audit
 
 ROW=`jq -e .bad_sig_losses[0].row < test-audit-coins.json`
-if test $ROW != "-1"
+if test $ROW != "1"
 then
     exit_fail "Row wrong, got $ROW"
 fi
@@ -570,7 +570,7 @@ then
 fi
 
 OP=`jq -r .bad_sig_losses[0].operation < test-audit-coins.json`
-if test $OP != "known-coin"
+if test $OP != "melt"
 then
     exit_fail "Wrong operation, got $OP"
 fi
@@ -1443,7 +1443,6 @@ function test_25() {
 
 echo "=========25: inconsistent coin history========="
 
-# Check wire transfer lag reported (no aggregator!)
 # NOTE: This test is EXPECTED to fail for ~1h after
 # re-generating the test database as we do not
 # report lag of less than 1h (see GRACE_PERIOD in
@@ -1729,6 +1728,40 @@ fi
 
 }
 
+
+
+
+# Test where denom_sig in known_coins table is wrong
+# (=> bad signature)
+function test_32() {
+
+# NOTE: This test is EXPECTED to fail for ~1h after
+# re-generating the test database as we do not
+# report lag of less than 1h (see GRACE_PERIOD in
+# taler-helper-auditor-wire.c)
+if [ $DATABASE_AGE -gt 3600 ]
+then
+
+    echo "===========32: known_coins signature wrong w. 
aggregation================="
+    # Modify denom_sig, so it is wrong
+    OLD_SIG=`echo 'SELECT denom_sig FROM known_coins LIMIT 1;' | psql $DB -Aqt`
+    COIN_PUB=`echo "SELECT coin_pub FROM known_coins WHERE 
denom_sig='$OLD_SIG';"  | psql $DB -Aqt`
+    echo "UPDATE known_coins SET 
denom_sig='\x287369672d76616c200a2028727361200a2020287320233542383731423743393036444643303442424430453039353246413642464132463537303139374131313437353746324632323332394644443146324643333445393939413336363430334233413133324444464239413833353833464536354442374335434445304441453035374438363336434541423834463843323843344446304144363030343430413038353435363039373833434431333239393736423642433437313041324632414132414435413833303432434346314139464635394244434346
 [...]
+
+    run_audit aggregation
+
+    # FIXME: test incomplete...
+    # BIG Q: why is wire_out empty? => aggregation test does not actually
+    # find WTIDs to check, and thus doesn't detect the bad signature!
+
+    # Cannot undo aggregation, do full reload
+    full_reload
+
+fi
+}
+
+
+
 # *************** Main test loop starts here **************
 
 
diff --git a/src/auditor/test-revocation.sh b/src/auditor/test-revocation.sh
index 7f9412af..7f4e242e 100755
--- a/src/auditor/test-revocation.sh
+++ b/src/auditor/test-revocation.sh
@@ -9,7 +9,7 @@ set -eu
 
 # Set of numbers for all the testcases.
 # When adding new tests, increase the last number:
-ALL_TESTS=`seq 0 1`
+ALL_TESTS=`seq 0 4`
 
 # $TESTS determines which tests we should run.
 # This construction is used to make it easy to
@@ -344,12 +344,106 @@ if test $WIRED != "TESTKUDOS:0"
 then
     exit_fail "Expected total missattribution in wrong, got $WIRED"
 fi
+
 # Database was unmodified, no need to undo
 echo "OK"
 }
 
 
 
+# Change recoup amount
+function test_2() {
+
+echo "===========2: recoup amount inconsistency==========="
+echo "UPDATE recoup SET amount_val=5 WHERE recoup_uuid=1" | psql -Aqt $DB
+
+run_audit
+
+# Reserve balance is now wrong
+echo -n "Testing inconsistency detection... "
+AMOUNT=`jq -r .reserve_balance_summary_wrong_inconsistencies[0].auditor < 
test-audit-reserves.json`
+if test $AMOUNT != "TESTKUDOS:3"
+then
+    exit_fail "Reserve auditor amount $AMOUNT is wrong"
+fi
+AMOUNT=`jq -r .reserve_balance_summary_wrong_inconsistencies[0].exchange < 
test-audit-reserves.json`
+if test $AMOUNT != "TESTKUDOS:0"
+then
+    exit_fail "Reserve exchange amount $AMOUNT is wrong"
+fi
+# Coin spent exceeded coin's value
+AMOUNT=`jq -r .amount_arithmetic_inconsistencies[0].auditor < 
test-audit-coins.json`
+if test $AMOUNT != "TESTKUDOS:2"
+then
+    exit_fail "Coin auditor amount $AMOUNT is wrong"
+fi
+AMOUNT=`jq -r .amount_arithmetic_inconsistencies[0].exchange < 
test-audit-coins.json`
+if test $AMOUNT != "TESTKUDOS:5"
+then
+    exit_fail "Coin exchange amount $AMOUNT is wrong"
+fi
+echo OK
+
+# Undo database modification
+echo "UPDATE recoup SET amount_val=2 WHERE recoup_uuid=1" | psql -Aqt $DB
+
+}
+
+
+# Change recoup-refresh amount
+function test_3() {
+
+echo "===========3: recoup-refresh amount inconsistency==========="
+echo "UPDATE recoup_refresh SET amount_val=5 WHERE recoup_refresh_uuid=1" | 
psql -Aqt $DB
+
+run_audit
+
+echo -n "Testing inconsistency detection... "
+# Coin spent exceeded coin's value
+AMOUNT=`jq -r .total_arithmetic_delta_minus < test-audit-coins.json`
+if test $AMOUNT != "TESTKUDOS:5"
+then
+    exit_fail "Arithmetic delta minus amount $AMOUNT is wrong"
+fi
+AMOUNT=`jq -r .total_arithmetic_delta_plus < test-audit-coins.json`
+if test $AMOUNT != "TESTKUDOS:0"
+then
+    exit_fail "Arithmetic delta plus amount $AMOUNT is wrong"
+fi
+echo OK
+
+# Undo database modification
+echo "UPDATE recoup_refresh SET amount_val=0 WHERE recoup_refresh_uuid=1" | 
psql -Aqt $DB
+
+}
+
+
+# Void recoup-refresh entry by 'unrevoking' denomination
+function test_4() {
+
+echo "===========4: invalid recoup==========="
+echo "DELETE FROM denomination_revocations;" | psql -Aqt $DB
+
+run_audit
+
+echo -n "Testing inconsistency detection... "
+# Coin spent exceeded coin's value
+jq -e .bad_sig_losses[0] < test-audit-coins.json > /dev/null || exit_fail "Bad 
recoup not detected"
+AMOUNT=`jq -r .total_bad_sig_losses < test-audit-coins.json`
+if test $AMOUNT == "TESTKUDOS:0"
+then
+    exit_fail "Total bad sig losses are wrong"
+fi
+echo OK
+
+# Undo database modification (can't easily undo DELETE, so full reload)
+full_reload
+
+}
+
+
+
+
 
 # *************** Main test loop starts here **************
 
diff --git a/src/exchangedb/exchangedb_transactions.c 
b/src/exchangedb/exchangedb_transactions.c
index c862f5a0..ade7f9cf 100644
--- a/src/exchangedb/exchangedb_transactions.c
+++ b/src/exchangedb/exchangedb_transactions.c
@@ -40,10 +40,13 @@ TALER_EXCHANGEDB_calculate_transaction_list_totals (
 {
   struct TALER_Amount spent = *off;
   struct TALER_Amount refunded;
+  struct TALER_Amount deposit_fee;
+  int have_refund;
 
   GNUNET_assert (GNUNET_OK ==
                  TALER_amount_get_zero (spent.currency,
                                         &refunded));
+  have_refund = GNUNET_NO;
   for (struct TALER_EXCHANGEDB_TransactionList *pos = tl;
        NULL != pos;
        pos = pos->next)
@@ -60,6 +63,7 @@ TALER_EXCHANGEDB_calculate_transaction_list_totals (
         GNUNET_break (0);
         return GNUNET_SYSERR;
       }
+      deposit_fee = pos->details.deposit->deposit_fee;
       break;
     case TALER_EXCHANGEDB_TT_MELT:
       /* spent += pos->amount_with_fee */
@@ -83,13 +87,14 @@ TALER_EXCHANGEDB_calculate_transaction_list_totals (
         return GNUNET_SYSERR;
       }
       if (GNUNET_OK !=
-          TALER_amount_subtract (&refunded,
-                                 &refunded,
-                                 &pos->details.refund->refund_fee))
+          TALER_amount_add (&spent,
+                            &spent,
+                            &pos->details.refund->refund_fee))
       {
         GNUNET_break (0);
         return GNUNET_SYSERR;
       }
+      have_refund = GNUNET_YES;
       break;
     case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP:
       /* refunded += pos->value */
@@ -126,6 +131,18 @@ TALER_EXCHANGEDB_calculate_transaction_list_totals (
       break;
     }
   }
+  if (have_refund)
+  {
+    /* If we gave any refund, also discount ONE deposit fee */
+    if (GNUNET_OK !=
+        TALER_amount_add (&refunded,
+                          &refunded,
+                          &deposit_fee))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+  }
   /* spent = spent - refunded */
   if (GNUNET_SYSERR ==
       TALER_amount_subtract (&spent,

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]