gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-exchange] branch master updated: complete skeleton o


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] branch master updated: complete skeleton of wire-out audit logic
Date: Sat, 18 Mar 2017 16:56:34 +0100

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

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new 9a5cef0  complete skeleton of wire-out audit logic
9a5cef0 is described below

commit 9a5cef0eb1d415eb2fce18a5d1b615b2f025ddd5
Author: Christian Grothoff <address@hidden>
AuthorDate: Sat Mar 18 16:56:31 2017 +0100

    complete skeleton of wire-out audit logic
---
 src/auditor/Makefile.am     |   1 +
 src/auditor/taler-auditor.c | 617 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 469 insertions(+), 149 deletions(-)

diff --git a/src/auditor/Makefile.am b/src/auditor/Makefile.am
index 04e7dcb..c2e77f1 100644
--- a/src/auditor/Makefile.am
+++ b/src/auditor/Makefile.am
@@ -24,6 +24,7 @@ taler_auditor_LDADD = \
   $(top_builddir)/src/wire/libtalerwire.la \
   $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
   $(top_builddir)/src/auditordb/libtalerauditordb.la \
+  -ljansson \
   -lgnunetutil
 
 taler_auditor_sign_SOURCES = \
diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c
index cf7e332..c57adb5 100644
--- a/src/auditor/taler-auditor.c
+++ b/src/auditor/taler-auditor.c
@@ -22,13 +22,13 @@
  * - 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 'wire_out' (TBD!) table. This needs to be checked separately!
+ *   given in the 'wire_out' table. This needs to be checked separately!
  *
  * TODO:
- * - implement merchant deposit audit
- *   => we need a 'wire_out' table here (amount, h-wire, date, wtid)
- * - modify auditordb to allow multiple last serial IDs per table in progress 
tracking
- * - modify auditordb to track risk with balances and fees
+ * - 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
+ *   to clarify what it is)
  * - 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
@@ -42,6 +42,7 @@
 #include "taler_auditordb_plugin.h"
 #include "taler_exchangedb_plugin.h"
 #include "taler_json_lib.h"
+#include "taler_wire_lib.h"
 #include "taler_signatures.h"
 
 
@@ -71,6 +72,11 @@ static struct TALER_EXCHANGEDB_Plugin *edb;
 static char *currency;
 
 /**
+ * Our configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
  * Our session with the #edb.
  */
 static struct TALER_EXCHANGEDB_Session *esession;
@@ -1231,115 +1237,6 @@ free_coin (void *cls,
 
 
 /**
- * Check coin's transaction history for plausibility.  Does NOT check
- * the signatures (those are checked independently), but does check
- * that the amounts add up to a plausible overall picture.
- *
- * FIXME: is it wise to do this here? Maybe better to do this during
- * processing of payments to the merchants...
- *
- * @param coin_pub public key of the coin (for reporting)
- * @param dki denomination information about the coin
- * @param tl_head head of transaction history to verify
- */
-static void
-check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
-                           const struct 
TALER_EXCHANGEDB_DenominationKeyInformationP *dki,
-                           const struct TALER_EXCHANGEDB_TransactionList 
*tl_head)
-{
-  struct TALER_Amount expenditures;
-  struct TALER_Amount refunds;
-  struct TALER_Amount fees;
-  struct TALER_Amount final_expenditures;
-
-  GNUNET_assert (NULL != tl_head);
-  TALER_amount_get_zero (currency,
-                         &expenditures);
-  TALER_amount_get_zero (currency,
-                         &refunds);
-  TALER_amount_get_zero (currency,
-                         &fees);
-  for (const struct TALER_EXCHANGEDB_TransactionList *tl = tl_head;NULL != 
tl;tl = tl->next)
-  {
-    const struct TALER_Amount *amount_with_fee;
-    const struct TALER_Amount *fee;
-    const struct TALER_AmountNBO *fee_dki;
-    struct TALER_Amount *add_to;
-    struct TALER_Amount tmp;
-
-    add_to = NULL;
-    switch (tl->type) {
-    case TALER_EXCHANGEDB_TT_DEPOSIT:
-      amount_with_fee = &tl->details.deposit->amount_with_fee;
-      fee = &tl->details.deposit->deposit_fee;
-      fee_dki = &dki->properties.fee_deposit;
-      add_to = &expenditures;
-      break;
-    case TALER_EXCHANGEDB_TT_REFRESH_MELT:
-      amount_with_fee = &tl->details.melt->amount_with_fee;
-      fee = &tl->details.melt->melt_fee;
-      fee_dki = &dki->properties.fee_refresh;
-      add_to = &expenditures;
-      break;
-    case TALER_EXCHANGEDB_TT_REFUND:
-      amount_with_fee = &tl->details.refund->refund_amount;
-      fee = &tl->details.refund->refund_fee;
-      fee_dki = &dki->properties.fee_refund;
-      add_to = &refunds;
-      // FIXME: where do we check that the refund(s)
-      // of the coin match the deposit(s) of the coin (by merchant, timestamp, 
etc.)?
-      break;
-    }
-    GNUNET_assert (NULL != add_to); /* check switch was exhaustive */
-    if (GNUNET_OK !=
-        TALER_amount_add (add_to,
-                          add_to,
-                          amount_with_fee))
-    {
-      /* overflow in history already!? inconceivable! Bad DB! */
-      GNUNET_break (0);
-      // FIXME: report!
-      return;
-    }
-    TALER_amount_ntoh (&tmp,
-                       fee_dki);
-    if (0 !=
-        TALER_amount_cmp (&tmp,
-                          fee))
-    {
-      /* Disagreement in fee structure within DB! */
-      GNUNET_break (0);
-      // FIXME: report!
-      return;
-    }
-    if (GNUNET_OK !=
-        TALER_amount_add (&fees,
-                          &fees,
-                          fee))
-    {
-      /* overflow in fee total? inconceivable! Bad DB! */
-      GNUNET_break (0);
-      // FIXME: report!
-      return;
-    }
-  } /* for 'tl' */
-
-  /* Finally, calculate total balance change, i.e. expenditures minus refunds 
*/
-  if (GNUNET_OK !=
-      TALER_amount_subtract (&final_expenditures,
-                             &expenditures,
-                             &refunds))
-  {
-    /* refunds above expenditures? inconceivable! Bad DB! */
-    GNUNET_break (0);
-    // FIXME: report!
-    return;
-  }
-
-}
-
-
-/**
  * Obtain information about the coin from the cache or the database.
  *
  * If we obtain this information for the first time, also check that
@@ -1349,10 +1246,8 @@ check_transaction_history (const struct 
TALER_CoinSpendPublicKeyP *coin_pub,
  * @param coin_pub public key of the coin to get information about
  * @return NULL on error
  */
-// FIXME: move this to _outgoing_ transaction checking,
-// replace HERE by something that just gets the denomination hash!
-// (avoids confusion on checking coin's transaction history AND
-//  makes this part WAY more efficient!)
+// FIXME: replace by something that just gets the denomination hash!
+// (makes this part WAY more efficient!)
 static struct CoinSummary *
 get_coin_summary (struct CoinContext *cc,
                   const struct TALER_CoinSpendPublicKeyP *coin_pub)
@@ -1408,11 +1303,6 @@ get_coin_summary (struct CoinContext *cc,
     return NULL;
   }
 
-  /* verify that the transaction history we are given is reasonable */
-  check_transaction_history (coin_pub,
-                             dki,
-                             tl);
-
   /* allocate coin slot in ring buffer */
   if (MAX_COIN_SUMMARIES >= cc->summaries_off)
     cc->summaries_off = 0;
@@ -1824,6 +1714,10 @@ deposit_cb (void *cls,
     }
   }
 
+  /* TODO: *if* past pay_deadline, check that
+     aggregation record exists for the deposit;
+     if NOT, check that full _refund_ exists. */
+
   return GNUNET_OK;
 }
 
@@ -2108,55 +2002,461 @@ analyze_coins (void *cls)
 
 
 /**
- * Summary data we keep per merchant.
+ * Information we keep per loaded wire plugin.
  */
-struct MerchantSummary
+struct WirePlugin
 {
 
   /**
-   * Which account were we supposed to pay?
+   * Kept in a DLL.
    */
-  struct GNUNET_HashCode h_wire;
+  struct WirePlugin *next;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct WirePlugin *prev;
 
   /**
-   * Total due to be paid to @e h_wire.
+   * Name of the wire method.
    */
-  struct TALER_Amount total_due;
+  char *type;
 
   /**
-   * Total paid to @e h_wire.
+   * Handle to the wire plugin.
    */
-  struct TALER_Amount total_paid;
+  struct TALER_WIRE_Plugin *plugin;
+
+};
+
+
+/**
+ * Closure for callbacks during #analyze_merchants().
+ */
+struct MerchantContext
+{
 
   /**
-   * Total wire fees charged.
+   * DLL of wire plugins encountered.
    */
-  struct TALER_Amount total_fees;
+  struct WirePlugin *wire_head;
 
   /**
-   * Last (expired) refund deadline of all the transactions totaled
-   * up in @e due.
+   * DLL of wire plugins encountered.
    */
-  struct GNUNET_TIME_Absolute last_refund_deadline;
+  struct WirePlugin *wire_tail;
 
 };
 
 
 /**
- * Closure for callbacks during #analyze_merchants().
+ * Find the relevant wire plugin.
+ *
+ * @param mc context to search
+ * @param type type of the wire plugin to load
+ * @return NULL on error
  */
-struct MerchantContext
+static struct TALER_WIRE_Plugin *
+get_wire_plugin (struct MerchantContext *mc,
+                 const char *type)
+{
+  struct WirePlugin *wp;
+  struct TALER_WIRE_Plugin *plugin;
+
+  for (wp = mc->wire_head; NULL != wp; wp = wp->next)
+    if (0 == strcmp (type,
+                     wp->type))
+      return wp->plugin;
+  plugin = TALER_WIRE_plugin_load (cfg,
+                                   type);
+  if (NULL == plugin)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to locate wire plugin for `%s'\n",
+                type);
+    return NULL;
+  }
+  wp = GNUNET_new (struct WirePlugin);
+  wp->type = GNUNET_strdup (type);
+  wp->plugin = plugin;
+  GNUNET_CONTAINER_DLL_insert (mc->wire_head,
+                               mc->wire_tail,
+                               wp);
+  return plugin;
+}
+
+
+/**
+ * Closure for #wire_transfer_information_cb.
+ */
+struct WireCheckContext
 {
 
   /**
-   * Map for tracking information about merchants.
+   * Corresponding merchant context.
    */
-  struct GNUNET_CONTAINER_MultiHashMap *merchants;
+  struct MerchantContext *mc;
+
+  /**
+   * Total deposits claimed by all transactions that were aggregated
+   * under the given @e wtid.
+   */
+  struct TALER_Amount total_deposits;
+
+  /**
+   * Hash of the wire transfer details of the receiver.
+   */
+  struct GNUNET_HashCode h_wire;
+
+  /**
+   * Execution time of the wire transfer.
+   */
+  struct GNUNET_TIME_Absolute date;
+
+  /**
+   * Set to error message of @e ok is #GNUNET_SYSERR.
+   */
+  const char *emsg;
+
+  /**
+   * Wire method used for the transfer.
+   */
+  const char *method;
+
+  /**
+   * Set to #GNUNET_SYSERR if there are inconsistencies.
+   */
+  int ok;
 
 };
 
 
 /**
+ * Check coin's transaction history for plausibility.  Does NOT check
+ * the signatures (those are checked independently), but does check
+ * that the amounts add up to the picture claimed by the aggregation table.
+ *
+ * @param coin_pub public key of the coin (for reporting)
+ * @param h_proposal_data hash of the proposal for which we calculate the 
amount
+ * @param merchant_pub public key of the merchant (who is allowed to issue 
refunds)
+ * @param dki denomination information about the coin
+ * @param tl_head head of transaction history to verify
+ * @param[out] final amount the coin contributes to the transaction
+ * @param[out] final fees the exchange charged for the transaction
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                           const struct GNUNET_HashCode *h_proposal_data,
+                           const struct TALER_MerchantPublicKeyP *merchant_pub,
+                           const struct 
TALER_EXCHANGEDB_DenominationKeyInformationP *dki,
+                           const struct TALER_EXCHANGEDB_TransactionList 
*tl_head,
+                           struct TALER_Amount *final_expenditures,
+                           struct TALER_Amount *final_fees)
+{
+  struct TALER_Amount expenditures;
+  struct TALER_Amount refunds;
+  struct TALER_Amount fees;
+
+  GNUNET_assert (NULL != tl_head);
+  TALER_amount_get_zero (currency,
+                         &expenditures);
+  TALER_amount_get_zero (currency,
+                         &refunds);
+  TALER_amount_get_zero (currency,
+                         &fees);
+  for (const struct TALER_EXCHANGEDB_TransactionList *tl = tl_head;NULL != 
tl;tl = tl->next)
+  {
+    const struct TALER_Amount *amount_with_fee;
+    const struct TALER_Amount *fee;
+    const struct TALER_AmountNBO *fee_dki;
+    struct TALER_Amount *add_to;
+    struct TALER_Amount tmp;
+
+    add_to = NULL;
+    // FIXME:
+    // - for refunds/deposits that apply to this merchant and this contract
+    //   we need to update the total expenditures/refunds/fees
+    // - for all other operations, we need to update the per-coin totals
+    //   and at the end check that they do not exceed the value of the coin!
+    switch (tl->type) {
+    case TALER_EXCHANGEDB_TT_DEPOSIT:
+      amount_with_fee = &tl->details.deposit->amount_with_fee;
+      fee = &tl->details.deposit->deposit_fee;
+      fee_dki = &dki->properties.fee_deposit;
+      add_to = &expenditures;
+      break;
+    case TALER_EXCHANGEDB_TT_REFRESH_MELT:
+      amount_with_fee = &tl->details.melt->amount_with_fee;
+      fee = &tl->details.melt->melt_fee;
+      fee_dki = &dki->properties.fee_refresh;
+      add_to = &expenditures;
+      break;
+    case TALER_EXCHANGEDB_TT_REFUND:
+      amount_with_fee = &tl->details.refund->refund_amount;
+      fee = &tl->details.refund->refund_fee;
+      fee_dki = &dki->properties.fee_refund;
+      add_to = &refunds;
+      // FIXME: where do we check that the refund(s)
+      // of the coin match the deposit(s) of the coin (by merchant, timestamp, 
etc.)?
+      break;
+    }
+    GNUNET_assert (NULL != add_to); /* check switch was exhaustive */
+    if (GNUNET_OK !=
+        TALER_amount_add (add_to,
+                          add_to,
+                          amount_with_fee))
+    {
+      /* overflow in history already!? inconceivable! Bad DB! */
+      GNUNET_break (0);
+      // FIXME: report!
+      return GNUNET_SYSERR;
+    }
+    TALER_amount_ntoh (&tmp,
+                       fee_dki);
+    if (0 !=
+        TALER_amount_cmp (&tmp,
+                          fee))
+    {
+      /* Disagreement in fee structure within DB! */
+      GNUNET_break (0);
+      // FIXME: report!
+      return GNUNET_SYSERR;
+    }
+    if (GNUNET_OK !=
+        TALER_amount_add (&fees,
+                          &fees,
+                          fee))
+    {
+      /* overflow in fee total? inconceivable! Bad DB! */
+      GNUNET_break (0);
+      // FIXME: report!
+      return GNUNET_SYSERR;
+    }
+  } /* for 'tl' */
+
+  /* Finally, calculate total balance change, i.e. expenditures minus refunds 
*/
+  if (GNUNET_OK !=
+      TALER_amount_subtract (final_expenditures,
+                             &expenditures,
+                             &refunds))
+  {
+    /* refunds above expenditures? inconceivable! Bad DB! */
+    GNUNET_break (0);
+    // FIXME: report!
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Function called with the results of the lookup of the
+ * transaction data associated with a wire transfer identifier.
+ *
+ * @param cls a `struct WireCheckContext`
+ * @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)
+ * @param exec_time execution time of the wire transfer (should be same for 
all callbacks with the same @e cls)
+ * @param h_proposal_data which proposal was this payment about
+ * @param coin_pub which public key was this payment about
+ * @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,
+                              const struct TALER_MerchantPublicKeyP 
*merchant_pub,
+                              const char *wire_method,
+                              const struct GNUNET_HashCode *h_wire,
+                              struct GNUNET_TIME_Absolute exec_time,
+                              const struct GNUNET_HashCode *h_proposal_data,
+                              const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                              const struct TALER_Amount *coin_value,
+                              const struct TALER_Amount *coin_fee)
+{
+  struct WireCheckContext *wcc = cls;
+  const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki;
+  struct TALER_Amount contribution;
+  struct TALER_Amount computed_value;
+  struct TALER_Amount computed_fees;
+  struct TALER_EXCHANGEDB_TransactionList *tl;
+  const struct TALER_CoinPublicInfo *coin;
+
+  /* Obtain coin's transaction history */
+  tl = edb->get_coin_transactions (edb->cls,
+                                   esession,
+                                   coin_pub);
+  if (NULL == tl)
+  {
+    wcc->ok = GNUNET_SYSERR;
+    wcc->emsg = "no transaction history for coin claimed in aggregation";
+    return;
+  }
+
+  /* Obtain general denomination information about the coin */
+  coin = NULL;
+  switch (tl->type)
+  {
+  case TALER_EXCHANGEDB_TT_DEPOSIT:
+    coin = &tl->details.deposit->coin;
+    break;
+  case TALER_EXCHANGEDB_TT_REFRESH_MELT:
+    coin = &tl->details.melt->coin;
+    break;
+  case TALER_EXCHANGEDB_TT_REFUND:
+    coin = &tl->details.refund->coin;
+    break;
+  }
+  GNUNET_assert (NULL != coin); /* hard check that switch worked */
+  if (GNUNET_OK !=
+      get_denomination_info (&coin->denom_pub,
+                             &dki,
+                             NULL))
+  {
+    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";
+    return;
+  }
+
+  /* Check transaction history to see if it supports aggregate valuation */
+  check_transaction_history (coin_pub,
+                             h_proposal_data,
+                             merchant_pub,
+                             dki,
+                             tl,
+                             &computed_value,
+                             &computed_fees);
+  if (0 !=
+      TALER_amount_cmp (&computed_value,
+                        coin_value))
+  {
+    wcc->ok = GNUNET_SYSERR;
+    wcc->emsg = "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";
+  }
+  edb->free_coin_transaction_list (edb->cls,
+                                   tl);
+
+  /* Check other details of wire transfer match */
+  if (0 != strcmp (wire_method,
+                   wcc->method))
+  {
+    wcc->ok = GNUNET_SYSERR;
+    wcc->emsg = "wire method of aggregate do not match wire transfer";
+    return;
+  }
+  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";
+    return;
+  }
+  if (exec_time.abs_value_us != wcc->date.abs_value_us)
+  {
+    wcc->ok = GNUNET_SYSERR;
+    wcc->emsg = "date given in aggregate does not match wire transfer date";
+    return;
+  }
+  if (GNUNET_SYSERR ==
+      TALER_amount_subtract (&contribution,
+                             coin_value,
+                             coin_fee))
+  {
+    wcc->ok = GNUNET_SYSERR;
+    wcc->emsg = "could not calculate contribution of coin";
+    return;
+  }
+
+  /* Add coin's contribution to total aggregate value */
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_add (&wcc->total_deposits,
+                                   &wcc->total_deposits,
+                                   &contribution));
+}
+
+
+/**
+ * Check that a wire transfer made by the exchange is valid
+ * (has matching deposits).
+ *
+ * @param cls a `struct MerchantContext`
+ * @param rowid identifier of the respective row in the database
+ * @param date timestamp of the wire transfer (roughly)
+ * @param wtid wire transfer subject
+ * @param wire wire transfer details of the receiver
+ * @param amount amount that was wired
+ */
+static void
+check_wire_out_cb (void *cls,
+                   uint64_t rowid,
+                   struct GNUNET_TIME_Absolute date,
+                   const struct TALER_WireTransferIdentifierRawP *wtid,
+                   const json_t *wire,
+                   const struct TALER_Amount *amount)
+{
+  struct MerchantContext *mc = cls;
+  struct WireCheckContext wcc;
+  json_t *method;
+  struct TALER_WIRE_Plugin *plugin;
+
+  wcc.mc = mc;
+  method = json_object_get (wire,
+                            "type");
+  if ( (NULL == method) ||
+       (! json_is_string (method)) )
+  {
+    // TODO: bitch
+  }
+  wcc.method = json_string_value (method);
+  wcc.ok = GNUNET_OK;
+  wcc.date = date;
+  TALER_amount_get_zero (amount->currency,
+                         &wcc.total_deposits);
+  TALER_JSON_hash (wire,
+                   &wcc.h_wire);
+  edb->lookup_wire_transfer (edb->cls,
+                             esession,
+                             wtid,
+                             &wire_transfer_information_cb,
+                             &wcc);
+  if (GNUNET_OK != wcc.ok)
+  {
+    // TODO: bitch
+  }
+  plugin = get_wire_plugin (mc,
+                            wcc.method);
+  if (NULL == plugin)
+  {
+    // TODO: bitch
+  }
+  if (GNUNET_OK !=
+      plugin->amount_round (plugin->cls,
+                            &wcc.total_deposits))
+  {
+    // TODO: bitch
+  }
+  if (0 != TALER_amount_cmp (amount,
+                             &wcc.total_deposits))
+  {
+    // TODO: bitch!
+  }
+}
+
+
+/**
  * Analyze the exchange aggregator's payment processing.
  *
  * @param cls closure
@@ -2166,14 +2466,32 @@ static int
 analyze_merchants (void *cls)
 {
   struct MerchantContext mc;
+  struct WirePlugin *wc;
+  int ret;
 
-  mc.merchants = GNUNET_CONTAINER_multihashmap_create (1024,
-                                                       GNUNET_YES);
-
-  // TODO
-
-  GNUNET_CONTAINER_multihashmap_destroy (mc.merchants);
-  return GNUNET_OK;
+  ret = GNUNET_OK;
+  mc.wire_head = NULL;
+  mc.wire_tail = NULL;
+  if (GNUNET_SYSERR ==
+      edb->select_wire_out_above_serial_id (edb->cls,
+                                            esession,
+                                            42 /* FIXME */,
+                                            &check_wire_out_cb,
+                                            &mc))
+  {
+    GNUNET_break (0);
+    ret = GNUNET_SYSERR;
+  }
+  while (NULL != (wc = mc.wire_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (mc.wire_head,
+                                 mc.wire_tail,
+                                 wc);
+    TALER_WIRE_plugin_unload (wc->plugin);
+    GNUNET_free (wc->type);
+    GNUNET_free (wc);
+  }
+  return ret;
 }
 
 
@@ -2364,14 +2682,15 @@ setup_sessions_and_run ()
  * @param cls closure
  * @param args remaining command-line arguments
  * @param cfgfile name of the configuration file used (for saving, can be 
NULL!)
- * @param cfg configuration
+ * @param c configuration
  */
 static void
 run (void *cls,
      char *const *args,
      const char *cfgfile,
-     const struct GNUNET_CONFIGURATION_Handle *cfg)
+     const struct GNUNET_CONFIGURATION_Handle *c)
 {
+  cfg = c;
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (cfg,
                                              "taler",

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



reply via email to

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