aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-03-04 16:49:33 +0100
committerChristian Grothoff <christian@grothoff.org>2017-03-04 16:49:33 +0100
commit6ab67a3a76ee5ce8f8dec910dae7da524f066d2a (patch)
treee9f0a94960ad977eef19332bf836666e12aa38f2
parentf406f96129766c144c1531dc853969664f410d8c (diff)
implementing #4929
-rw-r--r--src/exchange-lib/exchange_api_track_transfer.c6
-rw-r--r--src/exchange-lib/test_exchange_api.c46
-rw-r--r--src/exchange/taler-exchange-aggregator.c159
-rw-r--r--src/exchange/taler-exchange-httpd_db.c41
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c7
-rw-r--r--src/exchange/taler-exchange-httpd_responses.h2
-rw-r--r--src/exchange/test-taler-exchange-aggregator-postgres.conf14
-rw-r--r--src/exchange/test_taler_exchange_aggregator.c42
-rw-r--r--src/exchangedb/exchangedb.conf2
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c236
-rw-r--r--src/exchangedb/test_exchangedb.c4
-rw-r--r--src/include/taler_error_codes.h15
-rw-r--r--src/include/taler_exchange_service.h2
-rw-r--r--src/include/taler_exchangedb_plugin.h50
-rw-r--r--src/include/taler_signatures.h5
15 files changed, 573 insertions, 58 deletions
diff --git a/src/exchange-lib/exchange_api_track_transfer.c b/src/exchange-lib/exchange_api_track_transfer.c
index 819a00adf..dff39eb29 100644
--- a/src/exchange-lib/exchange_api_track_transfer.c
+++ b/src/exchange-lib/exchange_api_track_transfer.c
@@ -87,12 +87,14 @@ check_track_transfer_response_ok (struct TALER_EXCHANGE_TrackTransferHandle *wdh
struct GNUNET_HashCode h_wire;
struct GNUNET_TIME_Absolute exec_time;
struct TALER_Amount total_amount;
+ struct TALER_Amount wire_fee;
struct TALER_MerchantPublicKeyP merchant_pub;
unsigned int num_details;
struct TALER_ExchangePublicKeyP exchange_pub;
struct TALER_ExchangeSignatureP exchange_sig;
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount ("total", &total_amount),
+ TALER_JSON_spec_amount ("wire_fee", &wire_fee),
GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
GNUNET_JSON_spec_fixed_auto ("H_wire", &h_wire),
GNUNET_JSON_spec_absolute_time ("execution_time", &exec_time),
@@ -158,6 +160,8 @@ check_track_transfer_response_ok (struct TALER_EXCHANGE_TrackTransferHandle *wdh
wdp.purpose.size = htonl (sizeof (struct TALER_WireDepositDataPS));
TALER_amount_hton (&wdp.total,
&total_amount);
+ TALER_amount_hton (&wdp.wire_fee,
+ &wire_fee);
wdp.merchant_pub = merchant_pub;
wdp.h_wire = h_wire;
GNUNET_CRYPTO_hash_context_finish (hash_context,
@@ -186,6 +190,7 @@ check_track_transfer_response_ok (struct TALER_EXCHANGE_TrackTransferHandle *wdh
&h_wire,
exec_time,
&total_amount,
+ &wire_fee,
num_details,
details);
}
@@ -257,6 +262,7 @@ handle_track_transfer_finished (void *cls,
NULL,
GNUNET_TIME_UNIT_ZERO_ABS,
NULL,
+ NULL,
0, NULL);
TALER_EXCHANGE_track_transfer_cancel (wdh);
}
diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c
index 2456d77a7..3e69c25bb 100644
--- a/src/exchange-lib/test_exchange_api.c
+++ b/src/exchange-lib/test_exchange_api.c
@@ -540,6 +540,12 @@ struct Command
*/
const char *total_amount_expected;
+ /**
+ * What is the expected wire fee? Only used if
+ * @e expected_response_code was #MHD_HTTP_OK.
+ */
+ const char *wire_fee_expected;
+
/* TODO: may want to add list of deposits we expected
to see aggregated here in the future. */
@@ -1417,6 +1423,7 @@ wire_cb (void *cls,
* @param execution_time time when the exchange claims to have performed the wire transfer
* @param total_amount total amount of the wire transfer, or NULL if the exchange could
* not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
+ * @param wire_fee wire fee that was charged by the exchange
* @param details_length length of the @a details array
* @param details array with details about the combined transactions
*/
@@ -1429,6 +1436,7 @@ wire_deposits_cb (void *cls,
const struct GNUNET_HashCode *h_wire,
struct GNUNET_TIME_Absolute execution_time,
const struct TALER_Amount *total_amount,
+ const struct TALER_Amount *wire_fee,
unsigned int details_length,
const struct TALER_TrackTransferDetails *details)
{
@@ -1469,6 +1477,24 @@ wire_deposits_cb (void *cls,
fail (is);
return;
}
+ if (GNUNET_OK !=
+ TALER_string_to_amount (cmd->details.wire_deposits.wire_fee_expected,
+ &expected_amount))
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
+ if (0 != TALER_amount_cmp (wire_fee,
+ &expected_amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire fee missmatch to command %s\n",
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ fail (is);
+ return;
+ }
ref = find_command (is,
cmd->details.wire_deposits.wtid_ref);
GNUNET_assert (NULL != ref);
@@ -2923,28 +2949,28 @@ run (void *cls)
{ .oc = OC_CHECK_BANK_TRANSFER,
.label = "check_bank_transfer-499c",
.details.check_bank_transfer.exchange_base_url = "https://exchange.com/",
- .details.check_bank_transfer.amount = "EUR:4.99",
+ .details.check_bank_transfer.amount = "EUR:4.98",
.details.check_bank_transfer.account_debit = 2,
.details.check_bank_transfer.account_credit = 42
},
{ .oc = OC_CHECK_BANK_TRANSFER,
.label = "check_bank_transfer-99c1",
.details.check_bank_transfer.exchange_base_url = "https://exchange.com/",
- .details.check_bank_transfer.amount = "EUR:0.99",
+ .details.check_bank_transfer.amount = "EUR:0.98",
.details.check_bank_transfer.account_debit = 2,
.details.check_bank_transfer.account_credit = 42
},
{ .oc = OC_CHECK_BANK_TRANSFER,
.label = "check_bank_transfer-99c2",
.details.check_bank_transfer.exchange_base_url = "https://exchange.com/",
- .details.check_bank_transfer.amount = "EUR:0.99",
+ .details.check_bank_transfer.amount = "EUR:0.98",
.details.check_bank_transfer.account_debit = 2,
.details.check_bank_transfer.account_credit = 42
},
{ .oc = OC_CHECK_BANK_TRANSFER,
.label = "check_bank_transfer-9c",
.details.check_bank_transfer.exchange_base_url = "https://exchange.com/",
- .details.check_bank_transfer.amount = "EUR:0.09",
+ .details.check_bank_transfer.amount = "EUR:0.08",
.details.check_bank_transfer.account_debit = 2,
.details.check_bank_transfer.account_credit = 43
},
@@ -2959,16 +2985,18 @@ run (void *cls)
.details.deposit_wtid.bank_transfer_ref = "check_bank_transfer-499c" },
{ .oc = OC_WIRE_DEPOSITS,
- .label = "wire-deposits-sucess-bank",
+ .label = "wire-deposits-success-bank",
.expected_response_code = MHD_HTTP_OK,
.details.wire_deposits.wtid_ref = "check_bank_transfer-99c1",
- .details.wire_deposits.total_amount_expected = "EUR:0.99" },
+ .details.wire_deposits.total_amount_expected = "EUR:0.98",
+ .details.wire_deposits.wire_fee_expected = "EUR:0.01" },
{ .oc = OC_WIRE_DEPOSITS,
- .label = "wire-deposits-sucess-wtid",
+ .label = "wire-deposits-success-wtid",
.expected_response_code = MHD_HTTP_OK,
.details.wire_deposits.wtid_ref = "deposit-wtid-ok",
- .details.wire_deposits.total_amount_expected = "EUR:4.99" },
+ .details.wire_deposits.total_amount_expected = "EUR:4.98",
+ .details.wire_deposits.wire_fee_expected = "EUR:0.01" },
/* ************** End of tracking API testing************* */
@@ -3030,7 +3058,7 @@ run (void *cls)
{ .oc = OC_CHECK_BANK_TRANSFER,
.label = "check_bank_transfer-pre-refund",
.details.check_bank_transfer.exchange_base_url = "https://exchange.com/",
- .details.check_bank_transfer.amount = "EUR:4.98",
+ .details.check_bank_transfer.amount = "EUR:4.97",
.details.check_bank_transfer.account_debit = 2,
.details.check_bank_transfer.account_credit = 42
},
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
index 96ec7627f..cbf3fb5d3 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.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
@@ -53,6 +53,12 @@ struct WirePlugin
* Name of the plugin.
*/
char *type;
+
+ /**
+ * Wire transfer fee structure.
+ */
+ struct TALER_EXCHANGEDB_AggregateFees *af;
+
};
@@ -103,6 +109,11 @@ struct AggregationUnit
struct TALER_Amount total_amount;
/**
+ * Wire fee we charge for @e wp at @e execution_time.
+ */
+ struct TALER_Amount wire_fee;
+
+ /**
* Hash of @e wire.
*/
struct GNUNET_HashCode h_wire;
@@ -260,6 +271,83 @@ extract_type (const json_t *wire)
/**
+ * Advance the "af" pointer in @a wp to point to the
+ * currently valid record.
+ *
+ * @param wp wire transfer fee data structure to update
+ * @param now timestamp to update fees to
+ */
+static void
+advance_fees (struct WirePlugin *wp,
+ struct GNUNET_TIME_Absolute now)
+{
+ struct TALER_EXCHANGEDB_AggregateFees *af;
+
+ /* First, try to see if we have current fee information in memory */
+ af = wp->af;
+ 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;
+ }
+ wp->af = af;
+}
+
+
+/**
+ * Update wire transfer fee data structure in @a wp.
+ *
+ * @param wp wire transfer fee data structure to update
+ * @param now timestamp to update fees to
+ * @param session DB session to use
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if we
+ * lack current fee information (and need to exit)
+ */
+static int
+update_fees (struct WirePlugin *wp,
+ struct GNUNET_TIME_Absolute now,
+ struct TALER_EXCHANGEDB_Session *session)
+{
+ advance_fees (wp,
+ now);
+ if (NULL != wp->af)
+ return GNUNET_OK;
+ /* Let's try to load it from disk... */
+ wp->af = TALER_EXCHANGEDB_fees_read (cfg,
+ wp->type);
+ advance_fees (wp,
+ now);
+ for (struct TALER_EXCHANGEDB_AggregateFees *p = wp->af;
+ NULL != p;
+ p = p->next)
+ {
+ if (GNUNET_SYSERR ==
+ db_plugin->insert_wire_fee (db_plugin->cls,
+ session,
+ wp->type,
+ p->start_date,
+ p->end_date,
+ &p->wire_fee,
+ &p->master_sig))
+ {
+ TALER_EXCHANGEDB_fees_free (wp->af);
+ wp->af = NULL;
+ return GNUNET_SYSERR;
+ }
+ }
+ if (NULL != wp->af)
+ return GNUNET_OK;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to find current wire transfer fees for `%s'\n",
+ wp->type);
+ return GNUNET_SYSERR;
+}
+
+
+/**
* Find the wire plugin for the given wire address.
*
* @param type wire plugin type we need a plugin for
@@ -345,6 +433,7 @@ shutdown_task (void *cls)
wp_tail,
wp);
TALER_WIRE_plugin_unload (wp->wire_plugin);
+ TALER_EXCHANGEDB_fees_free (wp->af);
GNUNET_free (wp->type);
GNUNET_free (wp);
}
@@ -433,9 +522,8 @@ deposit_cb (void *cls,
return GNUNET_SYSERR;
}
au->row_id = row_id;
+ GNUNET_assert (NULL == au->wire);
au->wire = json_incref ((json_t *) wire);
- au->execution_time = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&au->execution_time);
TALER_JSON_hash (au->wire,
&au->h_wire);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
@@ -444,6 +532,21 @@ deposit_cb (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Starting aggregation under H(WTID)=%s\n",
TALER_B2S (&au->wtid));
+
+ au->wp = find_plugin (extract_type (au->wire));
+ if (NULL == au->wp)
+ return GNUNET_SYSERR;
+
+ /* make sure we have current fees */
+ au->execution_time = GNUNET_TIME_absolute_get ();
+ (void) GNUNET_TIME_round_abs (&au->execution_time);
+ if (GNUNET_OK !=
+ update_fees (au->wp,
+ au->execution_time,
+ au->session))
+ return GNUNET_SYSERR;
+ au->wire_fee = au->wp->af->wire_fee;
+
if (GNUNET_OK !=
db_plugin->insert_aggregation_tracking (db_plugin->cls,
au->session,
@@ -585,7 +688,7 @@ run_aggregation (void *cls)
unsigned int i;
int ret;
const struct GNUNET_SCHEDULER_TaskContext *tc;
- struct WirePlugin *wp;
+ struct TALER_Amount final_amount;
task = NULL;
tc = GNUNET_SCHEDULER_get_task_context ();
@@ -650,18 +753,6 @@ run_aggregation (void *cls)
return;
}
- wp = find_plugin (extract_type (au->wire));
- if (NULL == wp)
- {
- json_decref (au->wire);
- GNUNET_free (au);
- au = NULL;
- db_plugin->rollback (db_plugin->cls,
- session);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
-
/* Now try to find other deposits to aggregate */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Found ready deposit for %s, aggregating\n",
@@ -689,13 +780,18 @@ run_aggregation (void *cls)
return;
}
- /* Round to the unit supported by the wire transfer method */
- GNUNET_assert (GNUNET_SYSERR !=
- wp->wire_plugin->amount_round (wp->wire_plugin->cls,
- &au->total_amount));
- /* Check if after rounding down, we still have an amount to transfer */
- if ( (0 == au->total_amount.value) &&
- (0 == au->total_amount.fraction) )
+ /* Subtract wire transfer fee and round to the unit supported by the
+ wire transfer method; Check if after rounding down, we still have
+ an amount to transfer, and if not mark as 'tiny'. */
+ if ( (GNUNET_OK !=
+ TALER_amount_subtract (&final_amount,
+ &au->total_amount,
+ &au->wire_fee)) ||
+ (GNUNET_SYSERR ==
+ au->wp->wire_plugin->amount_round (au->wp->wire_plugin->cls,
+ &final_amount)) ||
+ ( (0 == final_amount.value) &&
+ (0 == final_amount.fraction) ) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Aggregate value too low for transfer\n");
@@ -755,21 +851,20 @@ run_aggregation (void *cls)
{
char *amount_s;
- amount_s = TALER_amount_to_string (&au->total_amount);
+ amount_s = TALER_amount_to_string (&final_amount);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Preparing wire transfer of %s to %s\n",
amount_s,
TALER_B2S (&au->merchant_pub));
GNUNET_free (amount_s);
}
- au->wp = wp;
- au->ph = wp->wire_plugin->prepare_wire_transfer (wp->wire_plugin->cls,
- au->wire,
- &au->total_amount,
- exchange_base_url,
- &au->wtid,
- &prepare_cb,
- au);
+ au->ph = au->wp->wire_plugin->prepare_wire_transfer (au->wp->wire_plugin->cls,
+ au->wire,
+ &final_amount,
+ exchange_base_url,
+ &au->wtid,
+ &prepare_cb,
+ au);
if (NULL == au->ph)
{
GNUNET_break (0); /* why? how to best recover? */
diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c
index b9d3451af..9257cbef8 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -1865,6 +1865,11 @@ struct WtidTransactionContext
struct TALER_MerchantPublicKeyP merchant_pub;
/**
+ * Which method was used to wire the funds?
+ */
+ char *wire_method;
+
+ /**
* Hash of the wire details of the merchant (identical for all
* deposits), only valid if @e is_valid is #GNUNET_YES.
*/
@@ -1918,6 +1923,7 @@ struct WtidTransactionContext
static void
handle_transaction_data (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,
@@ -1936,6 +1942,7 @@ handle_transaction_data (void *cls,
ctx->merchant_pub = *merchant_pub;
ctx->h_wire = *h_wire;
ctx->exec_time = exec_time;
+ ctx->wire_method = GNUNET_strdup (wire_method);
ctx->is_valid = GNUNET_YES;
if (GNUNET_OK !=
TALER_amount_subtract (&ctx->total,
@@ -1952,6 +1959,8 @@ handle_transaction_data (void *cls,
if ( (0 != memcmp (&ctx->merchant_pub,
merchant_pub,
sizeof (struct TALER_MerchantPublicKeyP))) ||
+ (0 != strcmp (wire_method,
+ ctx->wire_method)) ||
(0 != memcmp (&ctx->h_wire,
h_wire,
sizeof (struct GNUNET_HashCode))) )
@@ -2006,6 +2015,10 @@ TEH_DB_execute_track_transfer (struct MHD_Connection *connection,
struct WtidTransactionContext ctx;
struct TALER_EXCHANGEDB_Session *session;
struct TEH_TrackTransferDetail *wdd;
+ struct GNUNET_TIME_Absolute wire_fee_start_date;
+ struct GNUNET_TIME_Absolute wire_fee_end_date;
+ struct TALER_Amount wire_fee;
+ struct TALER_MasterSignatureP wire_fee_master_sig;
if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
{
@@ -2016,6 +2029,7 @@ TEH_DB_execute_track_transfer (struct MHD_Connection *connection,
ctx.is_valid = GNUNET_NO;
ctx.wdd_head = NULL;
ctx.wdd_tail = NULL;
+ ctx.wire_method = NULL;
ret = TEH_plugin->lookup_wire_transfer (TEH_plugin->cls,
session,
wtid,
@@ -2042,10 +2056,36 @@ TEH_DB_execute_track_transfer (struct MHD_Connection *connection,
"wtid");
goto cleanup;
}
+ if (GNUNET_OK !=
+ TEH_plugin->get_wire_fee (TEH_plugin->cls,
+ session,
+ ctx.wire_method,
+ ctx.exec_time,
+ &wire_fee_start_date,
+ &wire_fee_end_date,
+ &wire_fee,
+ &wire_fee_master_sig))
+ {
+ GNUNET_break (0);
+ ret = TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_TRACK_TRANSFER_WIRE_FEE_NOT_FOUND);
+ goto cleanup;
+ }
+ if (GNUNET_OK !=
+ TALER_amount_subtract (&ctx.total,
+ &ctx.total,
+ &wire_fee))
+ {
+ GNUNET_break (0);
+ ret = TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_TRACK_TRANSFER_WIRE_FEE_INCONSISTENT);
+ goto cleanup;
+ }
ret = TEH_RESPONSE_reply_track_transfer_details (connection,
&ctx.total,
&ctx.merchant_pub,
&ctx.h_wire,
+ &wire_fee,
ctx.exec_time,
ctx.wdd_head);
cleanup:
@@ -2056,6 +2096,7 @@ TEH_DB_execute_track_transfer (struct MHD_Connection *connection,
wdd);
GNUNET_free (wdd);
}
+ GNUNET_free_non_null (ctx.wire_method);
return ret;
}
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index bae6707f1..1caef3469 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -1214,6 +1214,7 @@ TEH_RESPONSE_reply_track_transaction (struct MHD_Connection *connection,
* @param total total amount that was transferred
* @param merchant_pub public key of the merchant
* @param h_wire destination account
+ * @param wire_fee wire fee that was charged
* @param exec_time execution time of the wire transfer
* @param wdd_head linked list with details about the combined deposits
* @return MHD result code
@@ -1223,6 +1224,7 @@ TEH_RESPONSE_reply_track_transfer_details (struct MHD_Connection *connection,
const struct TALER_Amount *total,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct GNUNET_HashCode *h_wire,
+ const struct TALER_Amount *wire_fee,
struct GNUNET_TIME_Absolute exec_time,
const struct TEH_TrackTransferDetail *wdd_head)
{
@@ -1261,6 +1263,8 @@ TEH_RESPONSE_reply_track_transfer_details (struct MHD_Connection *connection,
wdp.purpose.size = htonl (sizeof (struct TALER_WireDepositDataPS));
TALER_amount_hton (&wdp.total,
total);
+ TALER_amount_hton (&wdp.wire_fee,
+ wire_fee);
wdp.merchant_pub = *merchant_pub;
wdp.h_wire = *h_wire;
GNUNET_CRYPTO_hash_context_finish (hash_context,
@@ -1270,8 +1274,9 @@ TEH_RESPONSE_reply_track_transfer_details (struct MHD_Connection *connection,
&sig);
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
- "{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:o}",
"total", TALER_JSON_from_amount (total),
+ "wire_fee", TALER_JSON_from_amount (wire_fee),
"merchant_pub", GNUNET_JSON_from_data_auto (merchant_pub),
"H_wire", GNUNET_JSON_from_data_auto (h_wire),
"execution_time", GNUNET_JSON_from_time_abs (exec_time),
diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h
index 17abd7ecb..179ae0066 100644
--- a/src/exchange/taler-exchange-httpd_responses.h
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -399,6 +399,7 @@ struct TEH_TrackTransferDetail
* @param total total amount that was transferred
* @param merchant_pub public key of the merchant
* @param h_wire destination account
+ * @param wire_fee wire fee that was charged
* @param exec_time execution time of the wire transfer
* @param wdd_head linked list with details about the combined deposits
* @return MHD result code
@@ -408,6 +409,7 @@ TEH_RESPONSE_reply_track_transfer_details (struct MHD_Connection *connection,
const struct TALER_Amount *total,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct GNUNET_HashCode *h_wire,
+ const struct TALER_Amount *wire_fee,
struct GNUNET_TIME_Absolute exec_time,
const struct TEH_TrackTransferDetail *wdd_head);
diff --git a/src/exchange/test-taler-exchange-aggregator-postgres.conf b/src/exchange/test-taler-exchange-aggregator-postgres.conf
index 4aa74b037..e70a933b7 100644
--- a/src/exchange/test-taler-exchange-aggregator-postgres.conf
+++ b/src/exchange/test-taler-exchange-aggregator-postgres.conf
@@ -29,6 +29,20 @@ DB_CONN_STR = postgres:///talercheck
# 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-outgoing-test]
# What is the main website of the bank?
BANK_URI = "http://localhost:8082/"
diff --git a/src/exchange/test_taler_exchange_aggregator.c b/src/exchange/test_taler_exchange_aggregator.c
index 6bd0d709b..5a3974f34 100644
--- a/src/exchange/test_taler_exchange_aggregator.c
+++ b/src/exchange/test_taler_exchange_aggregator.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2016 Inria and GNUnet e.V.
+ (C) 2016, 2017 Inria and 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
@@ -621,7 +621,7 @@ run_test ()
.details.expect_transaction.debit_account = 3,
.details.expect_transaction.credit_account = 4,
.details.expect_transaction.exchange_base_url = "https://exchange.taler.net/",
- .details.expect_transaction.amount = "EUR:0.9"
+ .details.expect_transaction.amount = "EUR:0.89"
},
{
@@ -668,7 +668,7 @@ run_test ()
.details.expect_transaction.debit_account = 3,
.details.expect_transaction.credit_account = 4,
.details.expect_transaction.exchange_base_url = "https://exchange.taler.net/",
- .details.expect_transaction.amount = "EUR:1.8"
+ .details.expect_transaction.amount = "EUR:1.79"
},
{
@@ -714,7 +714,7 @@ run_test ()
.details.expect_transaction.debit_account = 3,
.details.expect_transaction.credit_account = 4,
.details.expect_transaction.exchange_base_url = "https://exchange.taler.net/",
- .details.expect_transaction.amount = "EUR:0.9"
+ .details.expect_transaction.amount = "EUR:0.89"
},
{
.opcode = OPCODE_EXPECT_TRANSACTION,
@@ -722,7 +722,7 @@ run_test ()
.details.expect_transaction.debit_account = 3,
.details.expect_transaction.credit_account = 4,
.details.expect_transaction.exchange_base_url = "https://exchange.taler.net/",
- .details.expect_transaction.amount = "EUR:0.9"
+ .details.expect_transaction.amount = "EUR:0.89"
},
{
.opcode = OPCODE_EXPECT_TRANSACTION,
@@ -730,7 +730,7 @@ run_test ()
.details.expect_transaction.debit_account = 3,
.details.expect_transaction.credit_account = 5,
.details.expect_transaction.exchange_base_url = "https://exchange.taler.net/",
- .details.expect_transaction.amount = "EUR:0.9"
+ .details.expect_transaction.amount = "EUR:0.89"
},
{
.opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
@@ -779,7 +779,7 @@ run_test ()
.details.expect_transaction.debit_account = 3,
.details.expect_transaction.credit_account = 4,
.details.expect_transaction.exchange_base_url = "https://exchange.taler.net/",
- .details.expect_transaction.amount = "EUR:0.2"
+ .details.expect_transaction.amount = "EUR:0.19"
},
/* test picking all deposits at earliest deadline */
@@ -824,7 +824,7 @@ run_test ()
.details.expect_transaction.debit_account = 3,
.details.expect_transaction.credit_account = 4,
.details.expect_transaction.exchange_base_url = "https://exchange.taler.net/",
- .details.expect_transaction.amount = "EUR:0.2"
+ .details.expect_transaction.amount = "EUR:0.19"
},
/* Test NEVER running 'tiny' unless they make up minimum unit */
@@ -894,7 +894,7 @@ run_test ()
.details.deposit.merchant_name = "bob",
.details.deposit.merchant_account = 4,
.details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
- .details.deposit.amount_with_fee = "EUR:0.102",
+ .details.deposit.amount_with_fee = "EUR:0.112",
.details.deposit.deposit_fee = "EUR:0.1"
},
{
@@ -934,7 +934,7 @@ run_test ()
.details.deposit.merchant_name = "bob",
.details.deposit.merchant_account = 4,
.details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
- .details.deposit.amount_with_fee = "EUR:0.109",
+ .details.deposit.amount_with_fee = "EUR:0.119",
.details.deposit.deposit_fee = "EUR:0.1"
},
{
@@ -969,7 +969,7 @@ run_test ()
.details.expect_transaction.debit_account = 3,
.details.expect_transaction.credit_account = 4,
.details.expect_transaction.exchange_base_url = "https://exchange.taler.net/",
- .details.expect_transaction.amount = "EUR:0.02"
+ .details.expect_transaction.amount = "EUR:0.01"
},
/* Test that aggregation would happen fully if wire deadline is long */
@@ -1027,7 +1027,7 @@ run_test ()
.details.expect_transaction.debit_account = 3,
.details.expect_transaction.credit_account = 4,
.details.expect_transaction.exchange_base_url = "https://exchange.taler.net/",
- .details.expect_transaction.amount = "EUR:0.04"
+ .details.expect_transaction.amount = "EUR:0.03"
},
@@ -1087,7 +1087,7 @@ run_test ()
.details.expect_transaction.debit_account = 3,
.details.expect_transaction.credit_account = 4,
.details.expect_transaction.exchange_base_url = "https://exchange.taler.net/",
- .details.expect_transaction.amount = "EUR:0.02"
+ .details.expect_transaction.amount = "EUR:0.01"
},
/* Everything tested, terminate with success */
@@ -1203,6 +1203,7 @@ main (int argc,
{
const char *plugin_name;
char *testname;
+ struct GNUNET_OS_Process *proc;
struct GNUNET_CONFIGURATION_Handle *cfg;
struct GNUNET_SIGNAL_Context *shc_chld;
@@ -1225,6 +1226,21 @@ main (int argc,
GNUNET_log_setup ("test_taler_exchange_aggregator",
"WARNING",
NULL);
+ proc = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-keyup",
+ "taler-exchange-keyup",
+ "-c", config_filename,
+ NULL);
+ if (NULL == proc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to run `taler-exchange-keyup`, is your PATH correct?\n");
+ return 77;
+ }
+ GNUNET_OS_process_wait (proc);
+ GNUNET_OS_process_destroy (proc);
cfg = GNUNET_CONFIGURATION_create ();
if (GNUNET_OK !=
GNUNET_CONFIGURATION_parse (cfg,
diff --git a/src/exchangedb/exchangedb.conf b/src/exchangedb/exchangedb.conf
index 4640507dc..73e1603a9 100644
--- a/src/exchangedb/exchangedb.conf
+++ b/src/exchangedb/exchangedb.conf
@@ -11,4 +11,4 @@ AUDITOR_BASE_DIR = ${TALER_DATA_HOME}/auditors/
# the merchant per wire transfer. The directory is expected to
# contain files "$METHOD.fee" with the cost structure, where
# $METHOD corresponds to a wire transfer method.
-WIREFEE_BASE_DIR = ${TALER_DATA_HOME}/wirefees/
+WIREFEE_BASE_DIR = ${TALER_DATA_HOME}/exchange/wirefees/
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index ebca07fae..feb03f975 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -216,6 +216,8 @@ postgres_drop_tables (void *cls)
SQLEXEC_ (conn,
"DROP TABLE IF EXISTS aggregation_tracking;");
SQLEXEC_ (conn,
+ "DROP TABLE IF EXISTS wire_fee;");
+ SQLEXEC_ (conn,
"DROP TABLE IF EXISTS deposits;");
SQLEXEC_ (conn,
"DROP TABLE IF EXISTS refresh_out;");
@@ -472,6 +474,23 @@ postgres_create_tables (void *cls)
SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_wtid_index "
"ON aggregation_tracking(wtid_raw)");
+
+ /* Table for the wire fees. */
+ SQLEXEC("CREATE TABLE IF NOT EXISTS wire_fee "
+ "(wire_method VARCHAR NOT NULL"
+ ",start_date INT8 NOT NULL"
+ ",end_date INT8 NOT NULL"
+ ",wire_fee_val INT8 NOT NULL"
+ ",wire_fee_frac INT4 NOT NULL"
+ ",wire_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)"
+ ",PRIMARY KEY (wire_method, start_date)" /* this combo must be unique */
+ ")");
+ /* Index for lookup_transactions statement on wtid */
+ SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_wtid_index "
+ "ON aggregation_tracking(wtid_raw)");
+
+
/* This table contains the pre-commit data for
wire transfers the exchange is about to execute. */
SQLEXEC("CREATE TABLE IF NOT EXISTS prewire "
@@ -1193,6 +1212,7 @@ postgres_prepare (PGconn *db_conn)
PREPARE ("lookup_transactions",
"SELECT"
" deposits.h_proposal_data"
+ ",deposits.wire"
",deposits.h_wire"
",deposits.coin_pub"
",deposits.merchant_pub"
@@ -1241,6 +1261,35 @@ postgres_prepare (PGconn *db_conn)
"($1, $2, $3)",
3, NULL);
+ /* Used in #postgres_get_wire_fee() */
+ PREPARE ("get_wire_fee",
+ "SELECT "
+ " start_date"
+ ",end_date"
+ ",wire_fee_val"
+ ",wire_fee_frac"
+ ",wire_fee_curr"
+ ",master_sig"
+ " FROM wire_fee"
+ " WHERE wire_method=$1"
+ " AND start_date <= $2"
+ " AND end_date > $2",
+ 2, NULL);
+
+ /* Used in #postgres_insert_wire_fee */
+ PREPARE ("insert_wire_fee",
+ "INSERT INTO wire_fee "
+ "(wire_method"
+ ",start_date"
+ ",end_date"
+ ",wire_fee_val"
+ ",wire_fee_frac"
+ ",wire_fee_curr"
+ ",master_sig"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7)",
+ 7, NULL);
+
/* Used in #postgres_wire_prepare_data_insert() to store
wire transfer information before actually committing it with the bank */
@@ -3980,15 +4029,19 @@ postgres_lookup_wire_transfer (void *cls,
struct GNUNET_TIME_Absolute exec_time;
struct TALER_Amount amount_with_fee;
struct TALER_Amount deposit_fee;
+ json_t *wire;
+ json_t *t;
+ const char *wire_method;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("h_proposal_data", &h_proposal_data),
+ TALER_PQ_result_spec_json ("wire", &wire),
GNUNET_PQ_result_spec_auto_from_type ("h_wire", &h_wire),
GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &coin_pub),
GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", &merchant_pub),
GNUNET_PQ_result_spec_absolute_time ("execution_time", &exec_time),
TALER_PQ_result_spec_amount ("amount_with_fee", &amount_with_fee),
TALER_PQ_result_spec_amount ("fee_deposit", &deposit_fee),
- GNUNET_PQ_result_spec_end
+ GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
@@ -3999,8 +4052,23 @@ postgres_lookup_wire_transfer (void *cls,
PQclear (result);
return GNUNET_SYSERR;
}
+ t = json_object_get (wire, "type");
+ if (NULL == t)
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ wire_method = json_string_value (t);
+ if (NULL == wire_method)
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
cb (cb_cls,
&merchant_pub,
+ wire_method,
&h_wire,
exec_time,
&h_proposal_data,
@@ -4211,6 +4279,170 @@ postgres_insert_aggregation_tracking (void *cls,
/**
+ * Obtain wire fee from database.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param type type of wire transfer the fee applies for
+ * @param date for which date do we want the fee?
+ * @param[out] start_date when does the fee go into effect
+ * @param[out] end_date when does the fee end being valid
+ * @param[out] wire_fee how high is the wire transfer fee
+ * @param[out] master_sig signature over the above by the exchange master key
+ * @return #GNUNET_OK on success, #GNUNET_NO if no fee is known
+ * #GNUNET_SYSERR on failure
+ */
+static int
+postgres_get_wire_fee (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const char *type,
+ struct GNUNET_TIME_Absolute date,
+ struct GNUNET_TIME_Absolute *start_date,
+ struct GNUNET_TIME_Absolute *end_date,
+ struct TALER_Amount *wire_fee,
+ struct TALER_MasterSignatureP *master_sig)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (type),
+ GNUNET_PQ_query_param_absolute_time (&date),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_absolute_time ("start_date", start_date),
+ GNUNET_PQ_result_spec_absolute_time ("end_date", end_date),
+ TALER_PQ_result_spec_amount ("wire_fee", wire_fee),
+ GNUNET_PQ_result_spec_auto_from_type ("master_sig", master_sig),
+ GNUNET_PQ_result_spec_end
+ };
+ PGresult *result;
+ int nrows;
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "get_wire_fee",
+ params);
+ if (PGRES_TUPLES_OK !=
+ PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ /* no matches found */
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ if (1 != nrows)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ 0))
+ {
+ PQclear (result);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Insert wire transfer fee into database.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param type type of wire transfer this fee applies for
+ * @param start_date when does the fee go into effect
+ * @param end_date when does the fee end being valid
+ * @param wire_fee how high is the wire transfer fee
+ * @param master_sig signature over the above by the exchange master key
+ * @return #GNUNET_OK on success, #GNUNET_NO if the record exists,
+ * #GNUNET_SYSERR on failure
+ */
+static int
+postgres_insert_wire_fee (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const char *type,
+ struct GNUNET_TIME_Absolute start_date,
+ struct GNUNET_TIME_Absolute end_date,
+ const struct TALER_Amount *wire_fee,
+ const struct TALER_MasterSignatureP *master_sig)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (type),
+ GNUNET_PQ_query_param_absolute_time (&start_date),
+ GNUNET_PQ_query_param_absolute_time (&end_date),
+ TALER_PQ_query_param_amount (wire_fee),
+ GNUNET_PQ_query_param_auto_from_type (master_sig),
+ GNUNET_PQ_query_param_end
+ };
+ PGresult *result;
+ struct TALER_Amount wf;
+ struct TALER_MasterSignatureP sig;
+ struct GNUNET_TIME_Absolute sd;
+ struct GNUNET_TIME_Absolute ed;
+
+ if (GNUNET_OK ==
+ postgres_get_wire_fee (cls,
+ session,
+ type,
+ start_date,
+ &sd,
+ &ed,
+ &wf,
+ &sig))
+ {
+ if (0 != memcmp (&sig,
+ master_sig,
+ sizeof (sig)))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (0 != TALER_amount_cmp (wire_fee,
+ &wf))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if ( (sd.abs_value_us != start_date.abs_value_us) ||
+ (ed.abs_value_us != end_date.abs_value_us) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ /* equal record already exists */
+ return GNUNET_NO;
+ }
+
+ result = GNUNET_PQ_exec_prepared (session->conn,
+ "insert_wire_fee",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 != strcmp ("1", PQcmdTuples (result)))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
+}
+
+
+/**
* Function called to insert wire transfer commit data into the DB.
*
* @param cls closure
@@ -5090,6 +5322,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
plugin->lookup_wire_transfer = &postgres_lookup_wire_transfer;
plugin->wire_lookup_deposit_wtid = &postgres_wire_lookup_deposit_wtid;
plugin->insert_aggregation_tracking = &postgres_insert_aggregation_tracking;
+ plugin->insert_wire_fee = &postgres_insert_wire_fee;
+ plugin->get_wire_fee = &postgres_get_wire_fee;
plugin->wire_prepare_data_insert = &postgres_wire_prepare_data_insert;
plugin->wire_prepare_data_mark_finished = &postgres_wire_prepare_data_mark_finished;
plugin->wire_prepare_data_get = &postgres_wire_prepare_data_get;
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index c37a590c3..a29e04513 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -783,6 +783,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
static void
cb_wt_never (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,
@@ -825,6 +826,7 @@ static struct TALER_WireTransferIdentifierRawP wtid_wt;
static void
cb_wt_check (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,
@@ -836,6 +838,8 @@ cb_wt_check (void *cls,
GNUNET_assert (0 == memcmp (merchant_pub,
&merchant_pub_wt,
sizeof (struct TALER_MerchantPublicKeyP)));
+ GNUNET_assert (0 == strcmp (wire_method,
+ "SEPA"));
GNUNET_assert (0 == memcmp (h_wire,
&h_wire_wt,
sizeof (struct GNUNET_HashCode)));
diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h
index 770a8ad67..4b90281f0 100644
--- a/src/include/taler_error_codes.h
+++ b/src/include/taler_error_codes.h
@@ -779,6 +779,19 @@ enum TALER_ErrorCode
*/
TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND = 1702,
+ /**
+ * The exchange did not find information about the wire transfer
+ * fees it charged. This response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSFER_WIRE_FEE_NOT_FOUND = 1703,
+
+ /**
+ * The exchange found a wire fee that was above the total transfer
+ * value (and thus could not have been charged). This response is
+ * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_TRACK_TRANSFER_WIRE_FEE_INCONSISTENT = 1704,
/**
* The exchange found internally inconsistent fee data when
@@ -1145,7 +1158,7 @@ enum TALER_ErrorCode
/**
* The backend encountered an error while trying to store the
- * h_proposal_data into the database.
+ * h_proposal_data into the database.
* The response is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
*/
TALER_EC_PROPOSAL_STORE_DB_ERROR = 2501,
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index 05256ddb9..3ac4069f3 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -1130,6 +1130,7 @@ struct TALER_EXCHANGE_TrackTransferHandle;
* @param execution_time time when the exchange claims to have performed the wire transfer
* @param total_amount total amount of the wire transfer, or NULL if the exchange could
* not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
+ * @param wire_fee wire fee that was charged by the exchange
* @param details_length length of the @a details array
* @param details array with details about the combined transactions
*/
@@ -1142,6 +1143,7 @@ typedef void
const struct GNUNET_HashCode *h_wire,
struct GNUNET_TIME_Absolute execution_time,
const struct TALER_Amount *total_amount,
+ const struct TALER_Amount *wire_fee,
unsigned int details_length,
const struct TALER_TrackTransferDetails *details);
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index fa0c48a8b..e7ba06f4c 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -762,6 +762,7 @@ typedef void
*
* @param cls closure
* @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
@@ -772,6 +773,7 @@ typedef void
typedef void
(*TALER_EXCHANGEDB_WireTransferDataCallback)(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,
@@ -1521,6 +1523,54 @@ struct TALER_EXCHANGEDB_Plugin
/**
+ * Insert wire transfer fee into database.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param wire_method which wire method is the fee about?
+ * @param start_date when does the fee go into effect
+ * @param end_date when does the fee end being valid
+ * @param wire_fee how high is the wire transfer fee
+ * @param master_sig signature over the above by the exchange master key
+ * @return #GNUNET_OK on success, #GNUNET_NO if the record exists,
+ * #GNUNET_SYSERR on failure
+ */
+ int
+ (*insert_wire_fee)(void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const char *wire_method,
+ struct GNUNET_TIME_Absolute start_date,
+ struct GNUNET_TIME_Absolute end_date,
+ const struct TALER_Amount *wire_fee,
+ const struct TALER_MasterSignatureP *master_sig);
+
+
+ /**
+ * Obtain wire fee from database.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param type type of wire transfer the fee applies for
+ * @param date for which date do we want the fee?
+ * @param[out] start_date when does the fee go into effect
+ * @param[out] end_date when does the fee end being valid
+ * @param[out] wire_fee how high is the wire transfer fee
+ * @param[out] master_sig signature over the above by the exchange master key
+ * @return #GNUNET_OK on success, #GNUNET_NO if no fee is known
+ * #GNUNET_SYSERR on failure
+ */
+ int
+ (*get_wire_fee) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session,
+ const char *type,
+ struct GNUNET_TIME_Absolute date,
+ struct GNUNET_TIME_Absolute *start_date,
+ struct GNUNET_TIME_Absolute *end_date,
+ struct TALER_Amount *wire_fee,
+ struct TALER_MasterSignatureP *master_sig);
+
+
+ /**
* Function called to insert wire transfer commit data into the DB.
*
* @param cls closure
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index 35967399d..8659deb3a 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -1004,6 +1004,11 @@ struct TALER_WireDepositDataPS
struct TALER_AmountNBO total;
/**
+ * Wire fee that was charged.
+ */
+ struct TALER_AmountNBO wire_fee;
+
+ /**
* Public key of the merchant (for all aggregated transactions).
*/
struct TALER_MerchantPublicKeyP merchant_pub;