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: implement #4929: ad


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] branch master updated: implement #4929: add wire transfer fee to /wire (but not yet charged by aggregator)
Date: Fri, 03 Mar 2017 20:31:36 +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 f406f96  implement #4929: add wire transfer fee to /wire (but not yet 
charged by aggregator)
f406f96 is described below

commit f406f96129766c144c1531dc853969664f410d8c
Author: Christian Grothoff <address@hidden>
AuthorDate: Fri Mar 3 20:31:29 2017 +0100

    implement #4929: add wire transfer fee to /wire (but not yet charged by 
aggregator)
---
 .gitignore                                     |   2 +
 src/exchange-lib/test_exchange_api.conf        |  27 ++++
 src/exchange-tools/Makefile.am                 |   1 +
 src/exchange-tools/taler-exchange-keyup.c      | 197 ++++++++++++++++++++++++-
 src/exchange/taler-exchange-httpd_validation.c |  50 +++++--
 src/exchange/taler-exchange-httpd_wire.c       |  73 ++++++++-
 src/exchange/taler-exchange-httpd_wire.h       |  10 ++
 src/exchangedb/Makefile.am                     |  14 +-
 src/exchangedb/exchangedb_denomkeys.c          |   9 +-
 src/exchangedb/exchangedb_fees.c               |   2 +-
 src/exchangedb/test_exchangedb_fees.c          | 104 ++++++++++++-
 src/include/taler_exchangedb_lib.h             |  78 +++++++++-
 src/include/taler_signatures.h                 |  38 ++++-
 13 files changed, 578 insertions(+), 27 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6a6c27d..0896a4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,9 +35,11 @@ src/bank-lib/test_bank_api
 src/bank-lib/test_bank_api_with_fakebank
 src/exchange-lib/test_exchange_api
 src/exchange-lib/test_exchange_api_home/.local/share/taler/exchange/live-keys/
+src/exchange-lib/test_exchange_api_home/.local/share/taler/exchange/wirefees/
 src/exchange/taler-exchange-aggregator
 src/exchange/test_taler_exchange_aggregator-postgres
 
src/exchange/test_taler_exchange_httpd_home/.local/share/taler/exchange/live-keys/
+src/exchange/test_taler_exchange_httpd_home/.local/share/taler/exchange/wirefees/
 src/exchange-tools/taler-auditor-sign
 src/exchange-tools/taler-exchange-dbinit
 src/exchange-tools/taler-exchange-keycheck
diff --git a/src/exchange-lib/test_exchange_api.conf 
b/src/exchange-lib/test_exchange_api.conf
index 76ade18..42861ea 100644
--- a/src/exchange-lib/test_exchange_api.conf
+++ b/src/exchange-lib/test_exchange_api.conf
@@ -30,6 +30,19 @@ DB_CONN_STR = "postgres:///talercheck"
 # Enable 'sepa' to test SEPA-specific routines.
 ENABLE = YES
 
+# Fees for the forseeable future...
+# If you see this after 2017, update to match the next 10 years...
+WIRE-FEE-2017 = EUR:0.01
+WIRE-FEE-2018 = EUR:0.01
+WIRE-FEE-2019 = EUR:0.01
+WIRE-FEE-2020 = EUR:0.01
+WIRE-FEE-2021 = EUR:0.01
+WIRE-FEE-2022 = EUR:0.01
+WIRE-FEE-2023 = EUR:0.01
+WIRE-FEE-2024 = EUR:0.01
+WIRE-FEE-2025 = EUR:0.01
+WIRE-FEE-2026 = EUR:0.01
+
 [exchange-wire-incoming-sepa]
 # This is the response we give out for the /wire request.  It provides
 # wallets with the bank information for transfers to the exchange.
@@ -39,6 +52,20 @@ SEPA_RESPONSE_FILE = ${TALER_CONFIG_HOME}/sepa.json
 # Enable 'test' for testing of the actual coin operations.
 ENABLE = YES
 
+# Fees for the forseeable future...
+# If you see this after 2017, update to match the next 10 years...
+WIRE-FEE-2017 = EUR:0.01
+WIRE-FEE-2018 = EUR:0.01
+WIRE-FEE-2019 = EUR:0.01
+WIRE-FEE-2020 = EUR:0.01
+WIRE-FEE-2021 = EUR:0.01
+WIRE-FEE-2022 = EUR:0.01
+WIRE-FEE-2023 = EUR:0.01
+WIRE-FEE-2024 = EUR:0.01
+WIRE-FEE-2025 = EUR:0.01
+WIRE-FEE-2026 = EUR:0.01
+
+
 [exchange-wire-incoming-test]
 # This is the response we give out for the /wire request.  It provides
 # wallets with the bank information for transfers to the exchange.
diff --git a/src/exchange-tools/Makefile.am b/src/exchange-tools/Makefile.am
index 9c2580e..60b2cc2 100644
--- a/src/exchange-tools/Makefile.am
+++ b/src/exchange-tools/Makefile.am
@@ -25,6 +25,7 @@ taler_exchange_keyup_LDADD = \
   $(LIBGCRYPT_LIBS) \
   $(top_builddir)/src/util/libtalerutil.la \
   $(top_builddir)/src/pq/libtalerpq.la \
+  $(top_builddir)/src/wire/libtalerwire.la \
   $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
   -lgnunetutil $(XLIB)
 taler_exchange_keyup_LDFLAGS = $(POSTGRESQL_LDFLAGS)
diff --git a/src/exchange-tools/taler-exchange-keyup.c 
b/src/exchange-tools/taler-exchange-keyup.c
index 7680173..c3e58db 100644
--- a/src/exchange-tools/taler-exchange-keyup.c
+++ b/src/exchange-tools/taler-exchange-keyup.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+  Copyright (C) 2014-2017 GNUnet e.V.
 
   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
@@ -23,6 +23,7 @@
  */
 #include <platform.h>
 #include "taler_exchangedb_lib.h"
+#include "taler_wire_lib.h"
 
 /**
  * When generating filenames from a cryptographic hash, we do not use
@@ -189,6 +190,11 @@ static char *exchange_directory;
 static char *pretend_time_str;
 
 /**
+ * Directory where we should write the wire transfer fee structure.
+ */
+static char *feedir;
+
+/**
  * Handle to the exchange's configuration
  */
 static const struct GNUNET_CONFIGURATION_Handle *kcfg;
@@ -215,6 +221,11 @@ static struct TALER_MasterPublicKeyP master_public_key;
 static struct GNUNET_TIME_Absolute lookahead_sign_stamp;
 
 /**
+ * Largest duration for spending of any key.
+ */
+static struct GNUNET_TIME_Relative max_duration_spend;
+
+/**
  * Return value from main().
  */
 static int global_ret;
@@ -598,6 +609,8 @@ get_cointype_params (const char *ct,
     return GNUNET_SYSERR;
   }
   GNUNET_TIME_round_rel (&params->duration_spend);
+  max_duration_spend = GNUNET_TIME_relative_max (max_duration_spend,
+                                                 params->duration_spend);
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_time (kcfg,
                                            ct,
@@ -862,6 +875,151 @@ exchange_keys_update_denomkeys ()
 
 
 /**
+ * Sign @a af with @a priv
+ *
+ * @param[in|out] af fee structure to sign
+ * @param priv private key to use for signing
+ */
+static void
+sign_af (struct TALER_EXCHANGEDB_AggregateFees *af,
+         const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
+{
+  struct TALER_MasterWireFeePS wf;
+
+  TALER_EXCHANGEDB_fees_2_wf (af,
+                              &wf);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CRYPTO_eddsa_sign (priv,
+                                           &wf.purpose,
+                                           &af->master_sig.eddsa_signature));
+}
+
+
+/**
+ * Output the wire fee structure.  Must be run after #max_duration_spend
+ * was initialized.
+ *
+ * @param cls pointer to `int`, set to #GNUNET_SYSERR on error
+ * @param wiremethod method to write fees for
+ */
+static void
+create_wire_fee_for_method (void *cls,
+                            const char *wiremethod)
+{
+  int *ret = cls;
+  struct TALER_EXCHANGEDB_AggregateFees *af_head;
+  struct TALER_EXCHANGEDB_AggregateFees *af_tail;
+  unsigned int year;
+  struct GNUNET_TIME_Absolute last_date;
+  struct GNUNET_TIME_Absolute start_date;
+  struct GNUNET_TIME_Absolute end_date;
+  char yearstr[12];
+  char *fn;
+  char *section;
+
+  if (GNUNET_OK != *ret)
+    return;
+  last_date = GNUNET_TIME_absolute_max (last_date,
+                                        GNUNET_TIME_absolute_add 
(lookahead_sign_stamp,
+                                                                  
max_duration_spend));
+  GNUNET_asprintf (&section,
+                   "exchange-wire-%s",
+                   wiremethod);
+  GNUNET_asprintf (&fn,
+                   "%s%s.fee",
+                   feedir,
+                   wiremethod);
+  af_head = NULL;
+  af_tail = NULL;
+  year = GNUNET_TIME_get_current_year ();
+  start_date = GNUNET_TIME_year_to_time (year);
+  while (start_date.abs_value_us < last_date.abs_value_us)
+  {
+    struct TALER_EXCHANGEDB_AggregateFees *af;
+    char *opt;
+    char *amounts;
+
+    GNUNET_snprintf (yearstr,
+                     sizeof (yearstr),
+                     "%u",
+                     year);
+    end_date = GNUNET_TIME_year_to_time (year + 1);
+    af = GNUNET_new (struct TALER_EXCHANGEDB_AggregateFees);
+    af->start_date = start_date;
+    af->end_date = end_date;
+    GNUNET_asprintf (&opt,
+                     "wire-fee-%u",
+                     year);
+    if (GNUNET_OK !=
+        GNUNET_CONFIGURATION_get_value_string (kcfg,
+                                               section,
+                                               opt,
+                                               &amounts))
+    {
+      GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                                 section,
+                                 opt);
+      *ret = GNUNET_SYSERR;
+      GNUNET_free (opt);
+      break;
+    }
+    if (GNUNET_OK !=
+        TALER_string_to_amount (amounts,
+                                &af->wire_fee))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Invalid amount `%s' specified in `%s' under `%s'\n",
+                  amounts,
+                  wiremethod,
+                  opt);
+      *ret = GNUNET_SYSERR;
+      GNUNET_free (amounts);
+      GNUNET_free (opt);
+      break;
+    }
+    GNUNET_free (amounts);
+    GNUNET_free (opt);
+    sign_af (af,
+             &master_priv.eddsa_priv);
+    if (NULL == af_tail)
+      af_head = af;
+    else
+      af_tail->next = af;
+    af_tail = af;
+    start_date = end_date;
+    year++;
+  }
+  if ( (GNUNET_OK == *ret) &&
+       (GNUNET_OK !=
+        TALER_EXCHANGEDB_fees_write (fn,
+                                     af_head)) )
+    *ret = GNUNET_SYSERR;
+  GNUNET_free (section);
+  GNUNET_free (fn);
+  TALER_EXCHANGEDB_fees_free (af_head);
+}
+
+
+/**
+ * Output the wire fee structure.  Must be run after #max_duration_spend
+ * was initialized.
+ *
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+create_wire_fees ()
+{
+  int ret;
+
+  ret = GNUNET_OK;
+  TALER_WIRE_find_enabled (kcfg,
+                           &create_wire_fee_for_method,
+                           &ret);
+  return ret;
+}
+
+
+/**
  * Main function that will be run.
  *
  * @param cls closure
@@ -896,6 +1054,29 @@ run (void *cls,
   {
     now = GNUNET_TIME_absolute_get ();
   }
+  if (NULL == feedir)
+  {
+    if (GNUNET_OK !=
+        GNUNET_CONFIGURATION_get_value_filename (kcfg,
+                                                 "exchangedb",
+                                                 "WIREFEE_BASE_DIR",
+                                                 &feedir))
+    {
+      fprintf (stderr,
+               "Wire fee directory not given in neither configuration nor 
command-line\n");
+      global_ret = 1;
+      return;
+    }
+  }
+  if (GNUNET_OK !=
+      GNUNET_DISK_directory_create (feedir))
+  {
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+                              "mkdir",
+                              feedir);
+    global_ret = 1;
+    return;
+  }
   GNUNET_TIME_round_abs (&now);
   if ( (NULL == masterkeyfile) &&
        (GNUNET_OK !=
@@ -1022,10 +1203,10 @@ run (void *cls,
     global_ret = 1;
     return;
   }
-  if (NULL != auditor_output_file)
+  if (GNUNET_OK != create_wire_fees ())
   {
-    FCLOSE (auditor_output_file);
-    auditor_output_file = NULL;
+    global_ret = 1;
+    return;
   }
 }
 
@@ -1051,6 +1232,9 @@ main (int argc,
     {'m', "master-key", "FILE",
      "master key file (private key)", 1,
      &GNUNET_GETOPT_set_filename, &masterkeyfile},
+    {'f', "feedir", "DIRNAME",
+     "directory where to write wire transfer fee structure", 1,
+     &GNUNET_GETOPT_set_filename, &feedir},
     {'o', "output", "FILE",
      "auditor denomination key signing request file to create", 1,
      &GNUNET_GETOPT_set_filename, &auditorrequestfile},
@@ -1072,6 +1256,11 @@ main (int argc,
                          options,
                          &run, NULL))
     return 1;
+  if (NULL != auditor_output_file)
+  {
+    FCLOSE (auditor_output_file);
+    auditor_output_file = NULL;
+  }
   return global_ret;
 }
 
diff --git a/src/exchange/taler-exchange-httpd_validation.c 
b/src/exchange/taler-exchange-httpd_validation.c
index 14c1476..f8a1f7c 100644
--- a/src/exchange/taler-exchange-httpd_validation.c
+++ b/src/exchange/taler-exchange-httpd_validation.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2016 GNUnet e.V.
+  Copyright (C) 2016, 2017 GNUnet e.V.
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -23,6 +23,7 @@
 #include <gnunet/gnunet_util_lib.h>
 #include "taler-exchange-httpd.h"
 #include "taler-exchange-httpd_validation.h"
+#include "taler-exchange-httpd_wire.h"
 #include "taler_wire_lib.h"
 
 
@@ -77,6 +78,7 @@ load_plugin (void *cls,
 {
   int *ret = cls;
   struct Plugin *p;
+  json_t *fees;
 
   p = GNUNET_new (struct Plugin);
   p->type = GNUNET_strdup (name);
@@ -84,13 +86,26 @@ load_plugin (void *cls,
                                       name);
   if (NULL == p->plugin)
   {
-    GNUNET_free (p);
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Failed to load plugin %s\n",
                 name);
+    GNUNET_free (p->type);
+    GNUNET_free (p);
+    *ret = GNUNET_SYSERR;
+    return;
+  }
+  fees = TEH_WIRE_get_fees (name);
+  if (NULL == fees)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Disabling method `%s' as wire transfer fees are not given 
correctly\n",
+                name);
+    GNUNET_free (p->type);
+    GNUNET_free (p);
     *ret = GNUNET_SYSERR;
     return;
   }
+  json_decref (fees);
   GNUNET_CONTAINER_DLL_insert (wire_head,
                                wire_tail,
                                p);
@@ -114,9 +129,8 @@ TEH_VALIDATION_init (const struct 
GNUNET_CONFIGURATION_Handle *cfg)
                            &ret);
   if (NULL == wire_head)
   {
-    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-                               "exchange",
-                               "wireformat");
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to find properly configured wire transfer method\n");
     ret = GNUNET_SYSERR;
   }
   if (GNUNET_OK != ret)
@@ -201,17 +215,17 @@ json_t *
 TEH_VALIDATION_get_wire_methods (const char *prefix)
 {
   json_t *methods;
-  json_t *method;
-  struct Plugin *p;
-  struct TALER_WIRE_Plugin *plugin;
   char *account_name;
   char *emsg;
   enum TALER_ErrorCode ec;
 
   methods = json_object ();
-  for (p=wire_head;NULL != p;p = p->next)
+  for (struct Plugin *p=wire_head;NULL != p;p = p->next)
   {
-    plugin = p->plugin;
+    struct TALER_WIRE_Plugin *plugin = p->plugin;
+    json_t *method;
+    json_t *fees;
+
     GNUNET_asprintf (&account_name,
                      "%s-%s",
                      prefix,
@@ -233,6 +247,22 @@ TEH_VALIDATION_get_wire_methods (const char *prefix)
       json_decref (method);
       method = NULL;
     }
+    fees = TEH_WIRE_get_fees (p->type);
+    if (NULL == fees)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Disabling method `%s' as wire transfer fees are not given 
correctly\n",
+                  p->type);
+      json_decref (method);
+      method = NULL;
+    }
+    else
+    {
+      json_object_set_new (method,
+                           "fees",
+                           fees);
+    }
+
     if (NULL != method)
       json_object_set_new (methods,
                            p->type,
diff --git a/src/exchange/taler-exchange-httpd_wire.c 
b/src/exchange/taler-exchange-httpd_wire.c
index 7857a5b..9c8b2ff 100644
--- a/src/exchange/taler-exchange-httpd_wire.c
+++ b/src/exchange/taler-exchange-httpd_wire.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2015, 2016 GNUnet e.V. and INRIA
+  Copyright (C) 2015-2017 GNUnet e.V. and INRIA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -24,6 +24,7 @@
 #include "taler-exchange-httpd_responses.h"
 #include "taler-exchange-httpd_validation.h"
 #include "taler-exchange-httpd_wire.h"
+#include "taler_json_lib.h"
 #include <jansson.h>
 
 /**
@@ -33,6 +34,76 @@ static json_t *wire_methods;
 
 
 /**
+ * Convert fee structure to JSON result to be returned
+ * as part of a /wire response.
+ *
+ * @param af fee structure to convert
+ * @return NULL on error, otherwise json data structure for /wire.
+ */
+static json_t *
+fees_to_json (struct TALER_EXCHANGEDB_AggregateFees *af)
+{
+  json_t *a;
+
+  a = json_array ();
+  while (NULL != af)
+  {
+    if ( (GNUNET_NO == GNUNET_TIME_round_abs (&af->start_date)) ||
+         (GNUNET_NO == GNUNET_TIME_round_abs (&af->end_date)) )
+    {
+      json_decref (a);
+      return NULL;
+    }
+    json_array_append_new (a,
+                           json_pack ("{s:o, s:o, s:o, s:o}",
+                                      "wire_fee", TALER_JSON_from_amount 
(&af->wire_fee),
+                                      "start_date", GNUNET_JSON_from_time_abs 
(af->start_date),
+                                      "end_date", GNUNET_JSON_from_time_abs 
(af->end_date),
+                                      "sig", GNUNET_JSON_from_data_auto 
(&af->master_sig)));
+    af = af->next;
+  }
+  return a;
+}
+
+
+/**
+ * Obtain fee structure for @a wire_plugin_name wire transfers.
+ *
+ * @param wire_plugin_name name of the plugin to load fees for
+ * @return JSON object (to be freed by caller) with fee structure
+ */
+json_t *
+TEH_WIRE_get_fees (const char *wire_plugin_name)
+{
+  struct TALER_EXCHANGEDB_AggregateFees *af;
+  json_t *j;
+  struct GNUNET_TIME_Absolute now;
+
+  af = TALER_EXCHANGEDB_fees_read (cfg,
+                                   wire_plugin_name);
+  now = GNUNET_TIME_absolute_get ();
+  while ( (NULL != af) &&
+          (af->end_date.abs_value_us < now.abs_value_us) )
+  {
+    struct TALER_EXCHANGEDB_AggregateFees *n = af->next;
+
+    GNUNET_free (af);
+    af = n;
+  }
+  if (NULL == af)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to find current wire transfer fees for `%s'\n",
+                wire_plugin_name);
+    return NULL;
+  }
+  j = fees_to_json (af);
+  TALER_EXCHANGEDB_fees_free (af);
+  return j;
+}
+
+
+/**
  * Handle a "/wire" request.
  *
  * @param rh context of the handler
diff --git a/src/exchange/taler-exchange-httpd_wire.h 
b/src/exchange/taler-exchange-httpd_wire.h
index d67c16a..a85fde6 100644
--- a/src/exchange/taler-exchange-httpd_wire.h
+++ b/src/exchange/taler-exchange-httpd_wire.h
@@ -27,6 +27,16 @@
 
 
 /**
+ * Obtain fee structure for @a wire_plugin_name wire transfers.
+ *
+ * @param wire_plugin_name name of the plugin to load fees for
+ * @return JSON object (to be freed by caller) with fee structure
+ */
+json_t *
+TEH_WIRE_get_fees (const char *wire_plugin_name);
+
+
+/**
  * Handle a "/wire" request.
  *
  * @param rh context of the handler
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am
index f6754e8..2122c17 100644
--- a/src/exchangedb/Makefile.am
+++ b/src/exchangedb/Makefile.am
@@ -44,6 +44,7 @@ lib_LTLIBRARIES = \
 libtalerexchangedb_la_SOURCES = \
   exchangedb_auditorkeys.c \
   exchangedb_denomkeys.c \
+  exchangedb_fees.c \
   exchangedb_signkeys.c \
   exchangedb_plugin.c
 
@@ -60,6 +61,7 @@ libtalerexchangedb_la_LDFLAGS = \
 check_PROGRAMS = \
   test-exchangedb-auditors \
   test-exchangedb-denomkeys \
+  test-exchangedb-fees \
   test-exchangedb-signkeys \
   test-exchangedb-postgres \
   test-perf-taler-exchangedb \
@@ -68,10 +70,11 @@ check_PROGRAMS = \
 AM_TESTS_ENVIRONMENT=export 
TALER_PREFIX=$${TALER_PREFIX:address@hidden@};export 
PATH=$${TALER_PREFIX:address@hidden@}/bin:$$PATH;
 TESTS = \
   test-exchangedb-auditors \
+  test-exchangedb-denomkeys \
+  test-exchangedb-fees \
   test-exchangedb-postgres \
   test-exchangedb-signkeys \
-  test-perf-taler-exchangedb \
-  test-exchangedb-denomkeys
+  test-perf-taler-exchangedb
 
 test_exchangedb_auditors_SOURCES = \
   test_exchangedb_auditors.c
@@ -87,6 +90,13 @@ test_exchangedb_denomkeys_LDADD = \
   $(top_srcdir)/src/util/libtalerutil.la \
   -lgnunetutil
 
+test_exchangedb_fees_SOURCES = \
+  test_exchangedb_fees.c
+test_exchangedb_fees_LDADD = \
+  libtalerexchangedb.la \
+  $(top_srcdir)/src/util/libtalerutil.la \
+  -lgnunetutil
+
 test_exchangedb_signkeys_SOURCES = \
   test_exchangedb_signkeys.c
 test_exchangedb_signkeys_LDADD = \
diff --git a/src/exchangedb/exchangedb_denomkeys.c 
b/src/exchangedb/exchangedb_denomkeys.c
index 7e7a73a..de8dfa6 100644
--- a/src/exchangedb/exchangedb_denomkeys.c
+++ b/src/exchangedb/exchangedb_denomkeys.c
@@ -42,10 +42,11 @@ TALER_EXCHANGEDB_denomination_key_read (const char 
*filename,
   void *data;
   struct GNUNET_CRYPTO_RsaPrivateKey *priv;
 
-  if (GNUNET_OK != GNUNET_DISK_file_size (filename,
-                                          &size,
-                                          GNUNET_YES,
-                                          GNUNET_YES))
+  if (GNUNET_OK !=
+      GNUNET_DISK_file_size (filename,
+                             &size,
+                             GNUNET_YES,
+                             GNUNET_YES))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "Skipping inaccessable denomination key file `%s'\n",
diff --git a/src/exchangedb/exchangedb_fees.c b/src/exchangedb/exchangedb_fees.c
index 938b61c..5adee5d 100644
--- a/src/exchangedb/exchangedb_fees.c
+++ b/src/exchangedb/exchangedb_fees.c
@@ -92,7 +92,7 @@ TALER_EXCHANGEDB_fees_read (const struct 
GNUNET_CONFIGURATION_Handle *cfg,
                                                &wirefee_base_dir))
     return NULL;
   GNUNET_asprintf (&fn,
-                   "%s" DIR_SEPARATOR_STR "%s.fee",
+                   "%s/%s.fee",
                    wirefee_base_dir,
                    wireplugin);
   GNUNET_free (wirefee_base_dir);
diff --git a/src/exchangedb/test_exchangedb_fees.c 
b/src/exchangedb/test_exchangedb_fees.c
index e23879e..b82abc5 100644
--- a/src/exchangedb/test_exchangedb_fees.c
+++ b/src/exchangedb/test_exchangedb_fees.c
@@ -24,23 +24,121 @@
 #include "taler_exchangedb_lib.h"
 
 
+/**
+ * Sign @a af with @a priv
+ *
+ * @param[in|out] af fee structure to sign
+ * @param priv private key to use for signing
+ */
+static void
+sign_af (struct TALER_EXCHANGEDB_AggregateFees *af,
+         const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
+{
+  struct TALER_MasterWireFeePS wf;
+
+  TALER_EXCHANGEDB_fees_2_wf (af,
+                              &wf);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CRYPTO_eddsa_sign (priv,
+                                           &wf.purpose,
+                                           &af->master_sig.eddsa_signature));
+}
+
+
 int
 main (int argc,
       const char *const argv[])
 {
   struct GNUNET_CONFIGURATION_Handle *cfg;
+  struct TALER_EXCHANGEDB_AggregateFees *af;
+  struct TALER_EXCHANGEDB_AggregateFees *n;
+  struct TALER_MasterPublicKeyP master_pub;
+  struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+  char *tmpdir;
+  char *tmpfile = NULL;
   int ret;
+  unsigned int year;
 
-  ret = 1;
   GNUNET_log_setup ("test-exchangedb-fees",
                     "WARNING",
                     NULL);
+  tmpdir = GNUNET_DISK_mkdtemp ("test_exchangedb_fees");
+  if (NULL == tmpdir)
+    return 77; /* skip test */
+  priv = GNUNET_CRYPTO_eddsa_key_create ();
+  GNUNET_CRYPTO_eddsa_key_get_public (priv,
+                                      &master_pub.eddsa_pub);
   cfg = GNUNET_CONFIGURATION_create ();
-
   GNUNET_CONFIGURATION_set_value_string (cfg,
                                          "exchangedb",
-                                         "AUDITOR_BASE_DIR",
+                                         "WIREFEE_BASE_DIR",
                                          tmpdir);
+  GNUNET_asprintf (&tmpfile,
+                   "%s/%s.fee",
+                   tmpdir,
+                   "test");
   ret = 0;
+  af = GNUNET_new (struct TALER_EXCHANGEDB_AggregateFees);
+  year = GNUNET_TIME_get_current_year ();
+  af->start_date = GNUNET_TIME_year_to_time (year);
+  af->end_date = GNUNET_TIME_year_to_time (year + 1);
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount ("EUR:1.0",
+                                         &af->wire_fee));
+  sign_af (af,
+           priv);
+  n = GNUNET_new (struct TALER_EXCHANGEDB_AggregateFees);
+  n->start_date = GNUNET_TIME_year_to_time (year + 1);
+  n->end_date = GNUNET_TIME_year_to_time (year + 2);
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount ("EUR:0.1",
+                                         &n->wire_fee));
+  sign_af (n,
+           priv);
+  af->next = n;
+
+  if (GNUNET_OK !=
+      TALER_EXCHANGEDB_fees_write (tmpfile,
+                                   af))
+  {
+    GNUNET_break (0);
+    ret = 1;
+  }
+  TALER_EXCHANGEDB_fees_free (af);
+  GNUNET_free (tmpfile);
+  af = TALER_EXCHANGEDB_fees_read (cfg,
+                                   "test");
+  if (NULL == af)
+  {
+    GNUNET_break (0);
+    ret = 1;
+  }
+  else
+  {
+    for (struct TALER_EXCHANGEDB_AggregateFees *p = af;
+         NULL != p;
+         p = p->next)
+    {
+      struct TALER_MasterWireFeePS wf;
+
+      TALER_EXCHANGEDB_fees_2_wf (p,
+                                  &wf);
+      if (GNUNET_OK !=
+          GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_FEES,
+                                      &wf.purpose,
+                                      &p->master_sig.eddsa_signature,
+                                      &master_pub.eddsa_pub))
+      {
+        GNUNET_break (0);
+        ret = 1;
+      }
+    }
+    TALER_EXCHANGEDB_fees_free (af);
+  }
+
+  (void) GNUNET_DISK_directory_remove (tmpdir);
+  GNUNET_free (tmpdir);
+  GNUNET_free (priv);
+  GNUNET_CONFIGURATION_destroy (cfg);
   return ret;
 }
diff --git a/src/include/taler_exchangedb_lib.h 
b/src/include/taler_exchangedb_lib.h
index 4ebe484..02e8cdf 100644
--- a/src/include/taler_exchangedb_lib.h
+++ b/src/include/taler_exchangedb_lib.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016 Inria & GNUnet e.V.
+  Copyright (C) 2014-2017 Inria & GNUnet e.V.
 
   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
@@ -25,6 +25,7 @@
 
 #include "taler_signatures.h"
 
+
 /**
  * Subdirectroy under the exchange's base directory which contains
  * the exchange's signing keys.
@@ -297,4 +298,79 @@ void
 TALER_EXCHANGEDB_plugin_unload (struct TALER_EXCHANGEDB_Plugin *plugin);
 
 
+/**
+ * Sorted list of fees to be paid for aggregate wire transfers.
+ */
+struct TALER_EXCHANGEDB_AggregateFees
+{
+  /**
+   * This is a linked list.
+   */
+  struct TALER_EXCHANGEDB_AggregateFees *next;
+
+  /**
+   * Fee to be paid.
+   */
+  struct TALER_Amount wire_fee;
+
+  /**
+   * Time when this fee goes into effect (inclusive)
+   */
+  struct GNUNET_TIME_Absolute start_date;
+
+  /**
+   * Time when this fee stops being in effect (exclusive).
+   */
+  struct GNUNET_TIME_Absolute end_date;
+
+  /**
+   * Signature affirming the above fee structure.
+   */
+  struct TALER_MasterSignatureP master_sig;
+};
+
+
+/**
+ * Read the current fee structure from disk.
+ *
+ * @param cfg configuration to use
+ * @param wireplugin name of the wire plugin to read fees for
+ * @return sorted list of aggregation fees, NULL on error
+ */
+struct TALER_EXCHANGEDB_AggregateFees *
+TALER_EXCHANGEDB_fees_read (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                            const char *wireplugin);
+
+
+/**
+ * Convert @a af to @a wf.
+ *
+ * @param[in,out] af aggregate fees, host format (updated to round time)
+ * @param[out] wf aggregate fees, disk / signature format
+ */
+void
+TALER_EXCHANGEDB_fees_2_wf (struct TALER_EXCHANGEDB_AggregateFees *af,
+                            struct TALER_MasterWireFeePS *wf);
+
+
+/**
+ * Write given fee structure to disk.
+ *
+ * @param filename where to write the fees
+ * @param af fee structure to write
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+TALER_EXCHANGEDB_fees_write (const char *filename,
+                             struct TALER_EXCHANGEDB_AggregateFees *af);
+
+
+/**
+ * Free @a af data structure
+ *
+ * @param af list to free
+ */
+void
+TALER_EXCHANGEDB_fees_free (struct TALER_EXCHANGEDB_AggregateFees *af);
+
 #endif
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index ef241c8..3596739 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+  Copyright (C) 2014-2017 GNUnet e.V.
 
   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
@@ -78,6 +78,11 @@
  */
 #define TALER_SIGNATURE_MASTER_TEST_DETAILS 1027
 
+/**
+ * Fees charged per (aggregate) wire transfer to the merchant.
+ */
+#define TALER_SIGNATURE_MASTER_WIRE_FEES 1028
+
 
 /*********************************************/
 /* Exchange online signatures (with signing key) */
@@ -879,6 +884,37 @@ struct TALER_MasterWireDetailsPS
 };
 
 
+
+/**
+ * @brief Information signed by the exchange's master
+ * key stating the wire fee to be paid per wire transfer.
+ */
+struct TALER_MasterWireFeePS
+{
+
+  /**
+   * Purpose is #TALER_SIGNATURE_MASTER_WIRE_FEES.
+   */
+  struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+  /**
+   * Start date when the fee goes into effect.
+   */
+  struct GNUNET_TIME_AbsoluteNBO start_date;
+
+  /**
+   * End date when the fee stops being in effect (exclusive)
+   */
+  struct GNUNET_TIME_AbsoluteNBO end_date;
+
+  /**
+   * Fee charged to the merchant per wire transfer.
+   */
+  struct TALER_AmountNBO wire_fee;
+
+};
+
+
 /**
  * @brief Format used to generate the signature on a request to obtain
  * the wire transfer identifier associated with a deposit.

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



reply via email to

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