major refactoring, eliminating wire-plugins and moving towards new bank API. main code compiles, testcases known to fail, code sure not to fully work yet

This commit is contained in:
Christian Grothoff 2020-01-11 15:19:56 +01:00
parent 554da10133
commit 9443c10d7f
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
66 changed files with 3806 additions and 6559 deletions

View File

@ -558,6 +558,5 @@ AC_CONFIG_FILES([Makefile
src/util/Makefile
src/util/taler-config
src/wire/Makefile
src/wire-plugins/Makefile
])
AC_OUTPUT

View File

@ -22,7 +22,7 @@ pkgcfg_DATA = \
EXTRA_DIST = \
taler.conf
SUBDIRS = include util wire json curl $(PQ_DIR) mhd $(BANK_LIB) wire-plugins exchangedb exchange exchange-tools auditordb auditor
SUBDIRS = include util wire json curl $(PQ_DIR) mhd $(BANK_LIB) exchangedb exchange exchange-tools auditordb auditor
if HAVE_LIBCURL
SUBDIRS += lib benchmark
else

View File

@ -73,10 +73,12 @@ taler_wire_auditor_LDADD = \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/exchangedb/libtalerexchangedb.la \
$(top_builddir)/src/auditordb/libtalerauditordb.la \
-ljansson \
-lgnunetjson \
-lgnunetcurl \
-lgnunetutil
taler_auditor_sign_SOURCES = \

View File

@ -1010,8 +1010,7 @@ struct ReserveContext
* @param reserve_pub public key of the reserve (also the WTID)
* @param credit amount that was received
* @param sender_account_details information about the sender's bank account
* @param wire_reference unique reference identifying the wire transfer (binary blob)
* @param wire_reference_size number of bytes in @a wire_reference
* @param wire_reference unique reference identifying the wire transfer
* @param execution_date when did we receive the funds
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
@ -1021,8 +1020,7 @@ handle_reserve_in (void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *credit,
const char *sender_account_details,
const void *wire_reference,
size_t wire_reference_size,
uint64_t wire_reference,
struct GNUNET_TIME_Absolute execution_date)
{
struct ReserveContext *rc = cls;
@ -2031,35 +2029,6 @@ analyze_reserves (void *cls)
paying each merchant what they were due (and on time). */
/**
* Information we keep per loaded wire plugin.
*/
struct WirePlugin
{
/**
* Kept in a DLL.
*/
struct WirePlugin *next;
/**
* Kept in a DLL.
*/
struct WirePlugin *prev;
/**
* Name of the wire method.
*/
char *type;
/**
* Handle to the wire plugin.
*/
struct TALER_WIRE_Plugin *plugin;
};
/**
* Information about wire fees charged by the exchange.
*/
@ -2105,16 +2074,6 @@ struct WireFeeInfo
struct AggregationContext
{
/**
* DLL of wire plugins encountered.
*/
struct WirePlugin *wire_head;
/**
* DLL of wire plugins encountered.
*/
struct WirePlugin *wire_tail;
/**
* DLL of wire fees charged by the exchange.
*/
@ -2132,46 +2091,6 @@ struct AggregationContext
};
/**
* Find the relevant wire plugin.
*
* @param ac context to search
* @param type type of the wire plugin to load; it
* will be used _as is_ from the dynamic loader.
* @return NULL on error
*/
static struct TALER_WIRE_Plugin *
get_wire_plugin (struct AggregationContext *ac,
const char *type)
{
struct WirePlugin *wp;
struct TALER_WIRE_Plugin *plugin;
for (wp = ac->wire_head; NULL != wp; wp = wp->next)
if (0 == strcmp (type,
wp->type))
return wp->plugin;
/* Wants the exact *plugin name* (!= method) */
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 (ac->wire_head,
ac->wire_tail,
wp);
return plugin;
}
/**
* Closure for #wire_transfer_information_cb.
*/
@ -2884,7 +2803,6 @@ check_wire_out_cb
{
struct AggregationContext *ac = cls;
struct WireCheckContext wcc;
struct TALER_WIRE_Plugin *plugin;
struct TALER_Amount final_amount;
struct TALER_Amount exchange_gain;
enum GNUNET_DB_QueryStatus qs;
@ -2976,19 +2894,7 @@ check_wire_out_cb
}
/* Round down to amount supported by wire method */
plugin = get_wire_plugin
(ac,
TALER_WIRE_get_plugin_from_method (method));
if (NULL == plugin)
{
GNUNET_break (0);
GNUNET_free (method);
return GNUNET_SYSERR;
}
GNUNET_free (method);
GNUNET_break (GNUNET_SYSERR !=
plugin->amount_round (plugin->cls,
&final_amount));
GNUNET_break (TALER_WIRE_amount_round (&final_amount));
/* Calculate the exchange's gain as the fees plus rounding differences! */
if (GNUNET_OK !=
@ -3071,7 +2977,6 @@ static enum GNUNET_DB_QueryStatus
analyze_aggregations (void *cls)
{
struct AggregationContext ac;
struct WirePlugin *wc;
struct WireFeeInfo *wfi;
enum GNUNET_DB_QueryStatus qsx;
enum GNUNET_DB_QueryStatus qs;
@ -3125,15 +3030,6 @@ analyze_aggregations (void *cls)
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
ac.qs = qs;
}
while (NULL != (wc = ac.wire_head))
{
GNUNET_CONTAINER_DLL_remove (ac.wire_head,
ac.wire_tail,
wc);
TALER_WIRE_plugin_unload (wc->plugin);
GNUNET_free (wc->type);
GNUNET_free (wc);
}
while (NULL != (wfi = ac.fee_head))
{
GNUNET_CONTAINER_DLL_remove (ac.fee_head,

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2017-2019 Taler Systems SA
Copyright (C) 2017-2020 Taler Systems SA
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
@ -27,9 +27,11 @@
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_curl_lib.h>
#include "taler_auditordb_plugin.h"
#include "taler_exchangedb_plugin.h"
#include "taler_json_lib.h"
#include "taler_bank_service.h"
#include "taler_wire_lib.h"
#include "taler_signatures.h"
@ -65,9 +67,14 @@ struct WireAccount
struct WireAccount *prev;
/**
* Handle to the plugin.
* Authentication data for the account.
*/
struct TALER_WIRE_Plugin *wire_plugin;
struct TALER_BANK_AuthenticationData auth;
/**
* Our bank account number.
*/
struct TALER_Account account;
/**
* Name of the section that configures this account.
@ -77,7 +84,12 @@ struct WireAccount
/**
* Active wire request for the transaction history.
*/
struct TALER_WIRE_HistoryHandle *hh;
struct TALER_BANK_CreditHistoryHandle *chh;
/**
* Active wire request for the transaction history.
*/
struct TALER_BANK_DebitHistoryHandle *dhh;
/**
* Progress point for this account.
@ -92,17 +104,12 @@ struct WireAccount
/**
* Where we are in the inbound (CREDIT) transaction history.
*/
void *in_wire_off;
uint64_t in_wire_off;
/**
* Where we are in the inbound (DEBIT) transaction history.
*/
void *out_wire_off;
/**
* Number of bytes in #in_wire_off and #out_wire_off.
*/
size_t wire_off_size;
uint64_t out_wire_off;
/**
* We should check for inbound transactions to this account.
@ -341,6 +348,16 @@ static struct TALER_Amount total_wire_format_amount;
*/
static struct TALER_Amount zero;
/**
* Handle to the context for interacting with the bank.
*/
static struct GNUNET_CURL_Context *ctx;
/**
* Scheduler context for running the @e ctx.
*/
static struct GNUNET_CURL_RescheduleContext *rc;
/* ***************************** Shutdown **************************** */
@ -356,15 +373,12 @@ struct ReserveInInfo
*/
struct GNUNET_HashCode row_off_hash;
/**
* Number of bytes in @e row_off.
*/
size_t row_off_size;
/**
* Expected details about the wire transfer.
* The member "account_url" is to be allocated
* at the end of this struct!
*/
struct TALER_WIRE_TransferDetails details;
struct TALER_BANK_CreditDetails details;
/**
* RowID in reserves_in table.
@ -389,7 +403,7 @@ struct ReserveOutInfo
/**
* Expected details about the wire transfer.
*/
struct TALER_WIRE_TransferDetails details;
struct TALER_BANK_DebitDetails details;
};
@ -427,8 +441,6 @@ free_rii (void *cls,
GNUNET_CONTAINER_multihashmap_remove (in_map,
key,
rii));
GNUNET_free (rii->details.account_url);
GNUNET_free_non_null (rii->details.wtid_s); /* field not used (yet) */
GNUNET_free (rii);
return GNUNET_OK;
}
@ -453,8 +465,6 @@ free_roi (void *cls,
GNUNET_CONTAINER_multihashmap_remove (out_map,
key,
roi));
GNUNET_free (roi->details.account_url);
GNUNET_free_non_null (roi->details.wtid_s); /* field not used (yet) */
GNUNET_free (roi);
return GNUNET_OK;
}
@ -495,6 +505,17 @@ do_shutdown (void *cls)
{
struct WireAccount *wa;
if (NULL != ctx)
{
GNUNET_CURL_fini (ctx);
ctx = NULL;
}
if (NULL != rc)
{
GNUNET_CURL_gnunet_rc_destroy (rc);
rc = NULL;
}
if (NULL != report_row_inconsistencies)
{
json_t *report;
@ -617,21 +638,22 @@ do_shutdown (void *cls)
}
while (NULL != (wa = wa_head))
{
if (NULL != wa->hh)
if (NULL != wa->dhh)
{
struct TALER_WIRE_Plugin *wp = wa->wire_plugin;
wp->get_history_cancel (wp->cls,
wa->hh);
wa->hh = NULL;
TALER_BANK_debit_history_cancel (wa->dhh);
wa->dhh = NULL;
}
if (NULL != wa->chh)
{
TALER_BANK_credit_history_cancel (wa->chh);
wa->chh = NULL;
}
GNUNET_CONTAINER_DLL_remove (wa_head,
wa_tail,
wa);
TALER_WIRE_plugin_unload (wa->wire_plugin);
TALER_BANK_auth_free (&wa->auth);
TALER_WIRE_account_free (&wa->account);
GNUNET_free (wa->section_name);
GNUNET_free_non_null (wa->in_wire_off);
GNUNET_free_non_null (wa->out_wire_off);
GNUNET_free (wa);
}
if (NULL != adb)
@ -787,8 +809,7 @@ commit (enum GNUNET_DB_QueryStatus qs)
wa->section_name,
&wa->pp,
wa->in_wire_off,
wa->out_wire_off,
wa->wire_off_size);
wa->out_wire_off);
else
qs = adb->insert_wire_auditor_account_progress (adb->cls,
asession,
@ -796,8 +817,7 @@ commit (enum GNUNET_DB_QueryStatus qs)
wa->section_name,
&wa->pp,
wa->in_wire_off,
wa->out_wire_off,
wa->wire_off_size);
wa->out_wire_off);
if (0 >= qs)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@ -1250,9 +1270,7 @@ complain_out_not_found (void *cls,
"amount_wired", TALER_JSON_from_amount (
&roi->details.amount),
"amount_justified", TALER_JSON_from_amount (&zero),
"wtid", (NULL == roi->details.wtid_s)
? GNUNET_JSON_from_data_auto (&roi->details.wtid)
: json_string (roi->details.wtid_s),
"wtid", GNUNET_JSON_from_data_auto (&roi->details.wtid),
"timestamp", json_from_time_abs (
roi->details.execution_date),
"diagnostic",
@ -1317,29 +1335,28 @@ check_exchange_wire_out (struct WireAccount *wa)
/**
* This function is called for all transactions that
* are credited to the exchange's account (incoming
* are debited from the exchange's account (outgoing
* transactions).
*
* @param cls `struct WireAccount` with current wire account to process
* @param http_status_code http status of the request
* @param ec error code in case something went wrong
* @param dir direction of the transfer
* @param row_off identification of the position at which we are querying
* @param row_off_size number of bytes in @a row_off
* @param details details about the wire transfer
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
*/
static int
history_debit_cb (void *cls,
unsigned int http_status_code,
enum TALER_ErrorCode ec,
enum TALER_BANK_Direction dir,
const void *row_off,
size_t row_off_size,
const struct TALER_WIRE_TransferDetails *details)
uint64_t row_off,
const struct TALER_BANK_DebitDetails *details,
const json_t *json)
{
struct WireAccount *wa = cls;
struct ReserveOutInfo *roi;
if (TALER_BANK_DIRECTION_NONE == dir)
if (NULL == details)
{
if (TALER_EC_NONE != ec)
{
@ -1348,7 +1365,7 @@ history_debit_cb (void *cls,
"Error fetching history: %u!\n",
(unsigned int) ec);
}
wa->hh = NULL;
wa->dhh = NULL;
check_exchange_wire_out (wa);
return GNUNET_OK;
}
@ -1357,45 +1374,8 @@ history_debit_cb (void *cls,
GNUNET_STRINGS_absolute_time_to_string (details->execution_date),
TALER_amount2s (&details->amount),
TALER_B2S (&details->wtid));
if (NULL != details->wtid_s)
{
char *diagnostic;
GNUNET_asprintf (&diagnostic,
"malformed subject `%s'",
details->wtid_s);
GNUNET_break (GNUNET_OK ==
TALER_amount_add (&total_wire_format_amount,
&total_wire_format_amount,
&details->amount));
report (report_wire_format_inconsistencies,
json_pack ("{s:o, s:o, s:s}",
"amount", TALER_JSON_from_amount (&details->amount),
"wire_offset", GNUNET_JSON_from_data (row_off,
row_off_size),
"diagnostic", diagnostic));
GNUNET_free (diagnostic);
return GNUNET_OK;
}
/* Update offset */
if (NULL == wa->out_wire_off)
{
wa->wire_off_size = row_off_size;
wa->out_wire_off = GNUNET_malloc (row_off_size);
}
if (wa->wire_off_size != row_off_size)
{
GNUNET_break (0);
commit (GNUNET_DB_STATUS_HARD_ERROR);
wa->hh = NULL;
GNUNET_SCHEDULER_shutdown ();
return GNUNET_SYSERR;
}
memcpy (wa->out_wire_off,
row_off,
row_off_size);
wa->out_wire_off = row_off;
roi = GNUNET_new (struct ReserveOutInfo);
GNUNET_CRYPTO_hash (&details->wtid,
sizeof (details->wtid),
@ -1420,10 +1400,9 @@ history_debit_cb (void *cls,
&total_wire_format_amount,
&details->amount));
report (report_wire_format_inconsistencies,
json_pack ("{s:o, s:o, s:s}",
json_pack ("{s:o, s:I, s:s}",
"amount", TALER_JSON_from_amount (&details->amount),
"wire_offset", GNUNET_JSON_from_data (row_off,
row_off_size),
"wire_offset", (json_int_t) row_off,
"diagnostic", diagnostic));
GNUNET_free (diagnostic);
return GNUNET_OK;
@ -1443,7 +1422,6 @@ static void
process_debits (void *cls)
{
struct WireAccount *wa = cls;
struct TALER_WIRE_Plugin *wp;
/* skip accounts where DEBIT is not enabled */
while ( (NULL != wa) &&
@ -1459,17 +1437,16 @@ process_debits (void *cls)
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Checking bank DEBIT records of account `%s'\n",
wa->section_name);
GNUNET_assert (NULL == wa->hh);
wp = wa->wire_plugin;
wa->hh = wp->get_history (wp->cls,
wa->section_name,
TALER_BANK_DIRECTION_DEBIT,
GNUNET_assert (NULL == wa->dhh);
wa->dhh = TALER_BANK_debit_history (ctx,
wa->account.details.x_taler_bank.
account_base_url,
&wa->auth,
wa->out_wire_off,
wa->wire_off_size,
INT64_MAX,
&history_debit_cb,
wa);
if (NULL == wa->hh)
if (NULL == wa->dhh)
{
fprintf (stderr,
"Failed to obtain bank transaction history for `%s'\n",
@ -1519,24 +1496,25 @@ conclude_credit_history ()
* @param rowid unique serial ID for the entry in our DB
* @param reserve_pub public key of the reserve (also the WTID)
* @param credit amount that was received
* @param sender_url payto://-URL of the sender's bank account
* @param wire_reference unique identifier for the wire transfer (plugin-specific format)
* @param wire_reference_size number of bytes in @a wire_reference
* @param sender_account_details payto://-URL of the sender's bank account
* @param wire_reference unique identifier for the wire transfer
* @param execution_date when did we receive the funds
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
static int
reserve_in_cb (void *cls,
uint64_t rowid,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct
TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *credit,
const char *sender_url,
const void *wire_reference,
size_t wire_reference_size,
struct GNUNET_TIME_Absolute execution_date)
const char *sender_account_details,
uint64_t wire_reference,
struct GNUNET_TIME_Absolute
execution_date)
{
struct WireAccount *wa = cls;
struct ReserveInInfo *rii;
size_t slen;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Analyzing exchange wire IN (%llu) at %s of %s with reserve_pub %s\n",
@ -1544,21 +1522,20 @@ reserve_in_cb (void *cls,
GNUNET_STRINGS_absolute_time_to_string (execution_date),
TALER_amount2s (credit),
TALER_B2S (reserve_pub));
rii = GNUNET_new (struct ReserveInInfo);
GNUNET_CRYPTO_hash (wire_reference,
wire_reference_size,
&rii->row_off_hash);
rii->row_off_size = wire_reference_size;
slen = strlen (sender_account_details) + 1;
rii = GNUNET_malloc (sizeof (struct ReserveInInfo)
+ slen);
rii->rowid = rowid;
rii->details.amount = *credit;
rii->details.execution_date = execution_date;
/* reserve public key should be the WTID */
GNUNET_assert (sizeof (rii->details.wtid) ==
sizeof (*reserve_pub));
memcpy (&rii->details.wtid,
reserve_pub,
sizeof (*reserve_pub));
rii->details.account_url = GNUNET_strdup (sender_url);
rii->rowid = rowid;
rii->details.reserve_pub = *reserve_pub;
rii->details.account_url = (const char *) &rii[1];
memcpy (&rii[1],
sender_account_details,
slen);
GNUNET_CRYPTO_hash (&wire_reference,
sizeof (uint64_t),
&rii->row_off_hash);
if (GNUNET_OK !=
GNUNET_CONTAINER_multihashmap_put (in_map,
&rii->row_off_hash,
@ -1572,8 +1549,6 @@ reserve_in_cb (void *cls,
"wire_offset_hash", GNUNET_JSON_from_data_auto (
&rii->row_off_hash),
"diagnostic", "duplicate wire offset"));
GNUNET_free (rii->details.account_url);
GNUNET_free_non_null (rii->details.wtid_s); /* field not used (yet) */
GNUNET_free (rii);
return GNUNET_OK;
}
@ -1604,7 +1579,8 @@ complain_in_not_found (void *cls,
"amount_exchange_expected", TALER_JSON_from_amount (
&rii->details.amount),
"amount_wired", TALER_JSON_from_amount (&zero),
"wtid", GNUNET_JSON_from_data_auto (&rii->details.wtid),
"reserve_pub", GNUNET_JSON_from_data_auto (
&rii->details.reserve_pub),
"timestamp", json_from_time_abs (
rii->details.execution_date),
"account", wa->section_name,
@ -1635,25 +1611,24 @@ process_credits (void *cls);
*
* @param cls `struct WireAccount` we are processing
* @param ec error code in case something went wrong
* @param dir direction of the transfer
* @param row_off identification of the position at which we are querying
* @param row_off_size number of bytes in @a row_off
* @param details details about the wire transfer
* @param json raw response
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
*/
static int
history_credit_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
enum TALER_BANK_Direction dir,
const void *row_off,
size_t row_off_size,
const struct TALER_WIRE_TransferDetails *details)
uint64_t row_off,
const struct TALER_BANK_CreditDetails *details,
const json_t *json)
{
struct WireAccount *wa = cls;
struct ReserveInInfo *rii;
struct GNUNET_HashCode key;
if (TALER_BANK_DIRECTION_NONE == dir)
if (NULL == details)
{
if (TALER_EC_NONE != ec)
{
@ -1663,7 +1638,7 @@ history_credit_cb (void *cls,
(unsigned int) ec);
}
/* end of operation */
wa->hh = NULL;
wa->chh = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Reconciling CREDIT processing of account `%s'\n",
wa->section_name);
@ -1678,12 +1653,12 @@ history_credit_cb (void *cls,
return GNUNET_OK;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Analyzing bank CREDIT at %s of %s with WTID %s\n",
"Analyzing bank CREDIT at %s of %s with Reserve-pub %s\n",
GNUNET_STRINGS_absolute_time_to_string (details->execution_date),
TALER_amount2s (&details->amount),
TALER_B2S (&details->wtid));
GNUNET_CRYPTO_hash (row_off,
row_off_size,
TALER_B2S (&details->reserve_pub));
GNUNET_CRYPTO_hash (&row_off,
sizeof (row_off),
&key);
rii = GNUNET_CONTAINER_multihashmap_get (in_map,
&key);
@ -1693,55 +1668,26 @@ history_credit_cb (void *cls,
"Failed to find wire transfer at `%s' in exchange database. Audit ends at this point in time.\n",
GNUNET_STRINGS_absolute_time_to_string (
details->execution_date));
wa->hh = NULL;
wa->chh = NULL;
process_credits (wa->next);
return GNUNET_SYSERR; /* not an error, just end of processing */
}
/* Update offset */
if (NULL == wa->in_wire_off)
{
wa->wire_off_size = row_off_size;
wa->in_wire_off = GNUNET_malloc (row_off_size);
}
if (wa->wire_off_size != row_off_size)
{
GNUNET_break (0);
commit (GNUNET_DB_STATUS_HARD_ERROR);
GNUNET_SCHEDULER_shutdown ();
return GNUNET_SYSERR;
}
memcpy (wa->in_wire_off,
row_off,
row_off_size);
wa->in_wire_off = row_off;
/* compare records with expected data */
if (row_off_size != rii->row_off_size)
{
GNUNET_break (0);
report (report_row_inconsistencies,
json_pack ("{s:s, s:I, s:o, s:o, s:s}",
"table", "reserves_in",
"row", (json_int_t) rii->rowid,
"raw_bank_row", GNUNET_JSON_from_data (row_off,
row_off_size),
"wire_offset_hash", GNUNET_JSON_from_data_auto (&key),
"diagnostic", "wire reference size missmatch"));
return GNUNET_OK;
}
if (0 != GNUNET_memcmp (&details->wtid,
&rii->details.wtid))
if (0 != GNUNET_memcmp (&details->reserve_pub,
&rii->details.reserve_pub))
{
report (report_reserve_in_inconsistencies,
json_pack ("{s:I, s:o, s:o, s:o, s:o, s:o, s:s}",
json_pack ("{s:I, s:I, s:o, s:o, s:o, s:o, s:s}",
"row", (json_int_t) rii->rowid,
"raw_bank_row", GNUNET_JSON_from_data (row_off,
row_off_size),
"bank_row", (json_int_t) row_off,
"amount_exchange_expected", TALER_JSON_from_amount (
&rii->details.amount),
"amount_wired", TALER_JSON_from_amount (&zero),
"wtid", GNUNET_JSON_from_data_auto (&rii->details.wtid),
"reserve_pub", GNUNET_JSON_from_data_auto (
&rii->details.reserve_pub),
"timestamp", json_from_time_abs (
rii->details.execution_date),
"diagnostic", "wire subject does not match"));
@ -1750,15 +1696,15 @@ history_credit_cb (void *cls,
&total_bad_amount_in_minus,
&rii->details.amount));
report (report_reserve_in_inconsistencies,
json_pack ("{s:I, s:o, s:o, s:o, s:o, s:o, s:s}",
json_pack ("{s:I, s:I, s:o, s:o, s:o, s:o, s:s}",
"row", (json_int_t) rii->rowid,
"raw_bank_row", GNUNET_JSON_from_data (row_off,
row_off_size),
"bank_row", (json_int_t) row_off,
"amount_exchange_expected", TALER_JSON_from_amount (
&zero),
"amount_wired", TALER_JSON_from_amount (
&details->amount),
"wtid", GNUNET_JSON_from_data_auto (&details->wtid),
"reserve_pub", GNUNET_JSON_from_data_auto (
&details->reserve_pub),
"timestamp", json_from_time_abs (
details->execution_date),
"diagnostic", "wire subject does not match"));
@ -1773,15 +1719,15 @@ history_credit_cb (void *cls,
&details->amount))
{
report (report_reserve_in_inconsistencies,
json_pack ("{s:I, s:o, s:o, s:o, s:o, s:o, s:s}",
json_pack ("{s:I, s:I, s:o, s:o, s:o, s:o, s:s}",
"row", (json_int_t) rii->rowid,
"raw_bank_row", GNUNET_JSON_from_data (row_off,
row_off_size),
"bank_row", (json_int_t) row_off,
"amount_exchange_expected", TALER_JSON_from_amount (
&rii->details.amount),
"amount_wired", TALER_JSON_from_amount (
&details->amount),
"wtid", GNUNET_JSON_from_data_auto (&details->wtid),
"reserve_pub", GNUNET_JSON_from_data_auto (
&details->reserve_pub),
"timestamp", json_from_time_abs (
details->execution_date),
"diagnostic", "wire amount does not match"));
@ -1820,13 +1766,12 @@ history_credit_cb (void *cls,
rii->details.account_url))
{
report (report_missattribution_in_inconsistencies,
json_pack ("{s:o, s:I, s:o, s:o}",
json_pack ("{s:o, s:I, s:I, s:o}",
"amount", TALER_JSON_from_amount (&rii->details.amount),
"row", (json_int_t) rii->rowid,
"raw_bank_row", GNUNET_JSON_from_data (row_off,
row_off_size),
"wtid", GNUNET_JSON_from_data_auto (
&rii->details.wtid)));
"bank_row", (json_int_t) row_off,
"reserve_pub", GNUNET_JSON_from_data_auto (
&rii->details.reserve_pub)));
GNUNET_break (GNUNET_OK ==
TALER_amount_add (&total_missattribution_in,
&total_missattribution_in,
@ -1836,11 +1781,10 @@ history_credit_cb (void *cls,
rii->details.execution_date.abs_value_us)
{
report (report_row_minor_inconsistencies,
json_pack ("{s:s, s:I, s:o, s:s}",
json_pack ("{s:s, s:I, s:I, s:s}",
"table", "reserves_in",
"row", (json_int_t) rii->rowid,
"raw_bank_row", GNUNET_JSON_from_data (row_off,
row_off_size),
"bank_row", (json_int_t) row_off,
"diagnostic", "execution date missmatch"));
}
cleanup:
@ -1865,7 +1809,6 @@ static void
process_credits (void *cls)
{
struct WireAccount *wa = cls;
struct TALER_WIRE_Plugin *wp;
enum GNUNET_DB_QueryStatus qs;
/* skip accounts where CREDIT is not enabled */
@ -1899,16 +1842,15 @@ process_credits (void *cls)
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Starting bank CREDIT history of account `%s'\n",
wa->section_name);
wp = wa->wire_plugin;
wa->hh = wp->get_history (wp->cls,
wa->section_name,
TALER_BANK_DIRECTION_CREDIT,
wa->chh = TALER_BANK_credit_history (ctx,
wa->account.details.x_taler_bank.
account_base_url,
&wa->auth,
wa->in_wire_off,
wa->wire_off_size,
INT64_MAX,
&history_credit_cb,
wa);
if (NULL == wa->hh)
if (NULL == wa->chh)
{
fprintf (stderr,
"Failed to obtain bank transaction history\n");
@ -2037,8 +1979,7 @@ begin_transaction ()
wa->section_name,
&wa->pp,
&wa->in_wire_off,
&wa->out_wire_off,
&wa->wire_off_size);
&wa->out_wire_off);
if (0 > qsx)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
@ -2096,30 +2037,62 @@ process_account_cb (void *cls,
const struct TALER_EXCHANGEDB_AccountInfo *ai)
{
struct WireAccount *wa;
struct TALER_WIRE_Plugin *wp;
if ( (GNUNET_NO == ai->debit_enabled) &&
(GNUNET_NO == ai->credit_enabled) )
return; /* not an active exchange account */
wp = TALER_WIRE_plugin_load (cfg,
ai->plugin_name);
if (NULL == wp)
{
fprintf (stderr,
"Failed to load wire plugin `%s'\n",
ai->plugin_name);
global_ret = 1;
GNUNET_SCHEDULER_shutdown ();
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Found exchange account `%s'\n",
ai->section_name);
wa = GNUNET_new (struct WireAccount);
wa->wire_plugin = wp;
wa->section_name = GNUNET_strdup (ai->section_name);
wa->watch_debit = ai->debit_enabled;
wa->watch_credit = ai->credit_enabled;
if (GNUNET_OK !=
TALER_BANK_auth_parse_cfg (cfg,
ai->section_name,
&wa->auth))
{
GNUNET_break (0);
GNUNET_free (wa->section_name);
GNUNET_free (wa);
fprintf (stderr,
"Failed to access bank account `%s'\n",
wa->section_name);
global_ret = 1;
GNUNET_SCHEDULER_shutdown ();
return;
}
if (GNUNET_OK !=
TALER_BANK_account_parse_cfg (cfg,
wa->section_name,
&wa->account))
{
GNUNET_break (0);
TALER_BANK_auth_free (&wa->auth);
GNUNET_free (wa->section_name);
GNUNET_free (wa);
fprintf (stderr,
"Failed to access bank account `%s'\n",
wa->section_name);
global_ret = 1;
GNUNET_SCHEDULER_shutdown ();
return;
}
if (TALER_PAC_X_TALER_BANK != wa->account.type)
{
GNUNET_break (0);
TALER_WIRE_account_free (&wa->account);
TALER_BANK_auth_free (&wa->auth);
GNUNET_free (wa->section_name);
GNUNET_free (wa);
fprintf (stderr,
"Need x-taler-bank account URL in `%s'\n",
wa->section_name);
global_ret = 1;
GNUNET_SCHEDULER_shutdown ();
return;
}
GNUNET_CONTAINER_DLL_insert (wa_head,
wa_tail,
wa);
@ -2258,6 +2231,14 @@ run (void *cls,
}
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
NULL);
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
&rc);
rc = GNUNET_CURL_gnunet_rc_create (ctx);
if (NULL == ctx)
{
GNUNET_break (0);
return;
}
esession = edb->get_session (edb->cls);
if (NULL == esession)
{

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2018 GNUnet e.V.
Copyright (C) 2014-2020 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
@ -241,8 +241,8 @@ postgres_create_tables (void *cls)
",account_name TEXT NOT NULL"
",last_wire_reserve_in_serial_id INT8 NOT NULL DEFAULT 0"
",last_wire_wire_out_serial_id INT8 NOT NULL DEFAULT 0"
",wire_in_off BYTEA"
",wire_out_off BYTEA"
",wire_in_off INT8"
",wire_out_off INT8"
")"),
GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS wire_auditor_progress"
"(master_pub BYTEA CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE"
@ -2135,23 +2135,16 @@ postgres_insert_wire_auditor_account_progress (void *cls,
const struct
TALER_AUDITORDB_WireAccountProgressPoint
*pp,
const void *in_wire_off,
const void *out_wire_off,
size_t wire_off_size)
uint64_t in_wire_off,
uint64_t out_wire_off)
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (master_pub),
GNUNET_PQ_query_param_string (account_name),
GNUNET_PQ_query_param_uint64 (&pp->last_reserve_in_serial_id),
GNUNET_PQ_query_param_uint64 (&pp->last_wire_out_serial_id),
GNUNET_PQ_query_param_fixed_size (in_wire_off,
NULL == in_wire_off
? 0
: wire_off_size),
GNUNET_PQ_query_param_fixed_size (out_wire_off,
NULL == out_wire_off
? 0
: wire_off_size),
GNUNET_PQ_query_param_uint64 (&in_wire_off),
GNUNET_PQ_query_param_uint64 (&out_wire_off),
GNUNET_PQ_query_param_end
};
@ -2182,21 +2175,14 @@ postgres_update_wire_auditor_account_progress (void *cls,
const struct
TALER_AUDITORDB_WireAccountProgressPoint
*pp,
const void *in_wire_off,
const void *out_wire_off,
size_t wire_off_size)
uint64_t in_wire_off,
uint64_t out_wire_off)
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&pp->last_reserve_in_serial_id),
GNUNET_PQ_query_param_uint64 (&pp->last_wire_out_serial_id),
GNUNET_PQ_query_param_fixed_size (in_wire_off,
NULL == in_wire_off
? 0
: wire_off_size),
GNUNET_PQ_query_param_fixed_size (out_wire_off,
NULL == out_wire_off
? 0
: wire_off_size),
GNUNET_PQ_query_param_uint64 (&in_wire_off),
GNUNET_PQ_query_param_uint64 (&out_wire_off),
GNUNET_PQ_query_param_auto_from_type (master_pub),
GNUNET_PQ_query_param_string (account_name),
GNUNET_PQ_query_param_end
@ -2231,12 +2217,9 @@ postgres_get_wire_auditor_account_progress (void *cls,
struct
TALER_AUDITORDB_WireAccountProgressPoint
*pp,
void **in_wire_off,
void **out_wire_off,
size_t *wire_off_size)
uint64_t *in_wire_off,
uint64_t *out_wire_off)
{
size_t xsize;
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (master_pub),
GNUNET_PQ_query_param_string (account_name),
@ -2247,30 +2230,17 @@ postgres_get_wire_auditor_account_progress (void *cls,
&pp->last_reserve_in_serial_id),
GNUNET_PQ_result_spec_uint64 ("last_wire_wire_out_serial_id",
&pp->last_wire_out_serial_id),
GNUNET_PQ_result_spec_variable_size ("wire_in_off",
in_wire_off,
wire_off_size),
GNUNET_PQ_result_spec_variable_size ("wire_out_off",
out_wire_off,
&xsize),
GNUNET_PQ_result_spec_uint64 ("wire_in_off",
in_wire_off),
GNUNET_PQ_result_spec_uint64 ("wire_out_off",
out_wire_off),
GNUNET_PQ_result_spec_end
};
qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
"wire_auditor_account_progress_select",
params,
rs);
if (qs <= 0)
{
*wire_off_size = 0;
xsize = 0;
}
if ( (0 != xsize) &&
(0 != *wire_off_size) )
{
GNUNET_assert (xsize == *wire_off_size);
}
return qs;
}

View File

@ -39,8 +39,9 @@ libtalerbank_la_LDFLAGS = \
libtalerbank_la_SOURCES = \
bank_api_admin.c \
bank_api_common.c bank_api_common.h \
bank_api_history.c \
bank_api_reject.c \
bank_api_credit.c \
bank_api_debit.c \
bank_api_transaction.c \
bank_api_parse.c
libtalerbank_la_LIBADD = \
$(top_builddir)/src/json/libtalerjson.la \
@ -55,10 +56,10 @@ libtalerfakebank_la_LDFLAGS = \
-version-info 0:0:0 \
-no-undefined
libtalerfakebank_la_SOURCES = \
fakebank_history.c \
fakebank.c fakebank.h
fakebank.c
libtalerfakebank_la_LIBADD = \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/mhd/libtalermhd.la \
-lgnunetjson \
-lgnunetutil \
-ljansson \
@ -69,8 +70,8 @@ libtalerbanktesting_la_LDFLAGS = \
-version-info 0:0:0 \
-no-undefined
libtalerbanktesting_la_SOURCES = \
testing_api_cmd_history.c \
testing_api_cmd_reject.c \
testing_api_cmd_history_credit.c \
testing_api_cmd_history_debit.c \
testing_api_helpers.c
libtalerbanktesting_la_LIBADD = \
$(top_builddir)/src/json/libtalerjson.la \

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2015, 2016, 2017 Taler Systems SA
Copyright (C) 2015--2020 Taler Systems SA
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
@ -166,13 +166,11 @@ handle_admin_add_incoming_finished (void *cls,
* to the operators of the bank.
*
* @param ctx curl context for the event loop
* @param bank_base_url URL of the bank (used to execute this request)
* @param account_base_url URL of the bank (used to execute this request)
* @param auth authentication data to send to the bank
* @param exchange_base_url base URL of the exchange (for tracking)
* @param subject wire transfer subject for the transfer
* @param reserve_pub wire transfer subject for the transfer
* @param amount amount that was deposited
* @param debit_account_no account number to withdraw from (53 bits at most)
* @param credit_account_no account number to deposit into (53 bits at most)
* @param credit_account account to deposit into (payto)
* @param res_cb the callback to call when the final result for this request is available
* @param res_cb_cls closure for the above callback
* @return NULL
@ -181,13 +179,12 @@ handle_admin_add_incoming_finished (void *cls,
*/
struct TALER_BANK_AdminAddIncomingHandle *
TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const char *account_base_url,
const struct TALER_BANK_AuthenticationData *auth,
const char *exchange_base_url,
const char *subject,
const struct
TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *amount,
uint64_t debit_account_no,
uint64_t credit_account_no,
const char *credit_account,
TALER_BANK_AdminAddIncomingResultCallback res_cb,
void *res_cb_cls)
{
@ -195,18 +192,10 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx,
json_t *admin_obj;
CURL *eh;
if (NULL == exchange_base_url)
{
GNUNET_break (0);
return NULL;
}
admin_obj = json_pack ("{s:{s:s}, s:s, s:s, s:o, s:I, s:I}",
"auth", "type", "basic",
"exchange_url", exchange_base_url,
"subject", subject,
admin_obj = json_pack ("{s:o, s:o, s:s}",
"subject", GNUNET_JSON_from_data_auto (reserve_pub),
"amount", TALER_JSON_from_amount (amount),
"debit_account", (json_int_t) debit_account_no,
"credit_account", (json_int_t) credit_account_no);
"credit_account", credit_account);
if (NULL == admin_obj)
{
GNUNET_break (0);
@ -215,26 +204,32 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx,
aai = GNUNET_new (struct TALER_BANK_AdminAddIncomingHandle);
aai->cb = res_cb;
aai->cb_cls = res_cb_cls;
aai->request_url = TALER_BANK_path_to_url_ (bank_base_url,
aai->request_url = TALER_BANK_path_to_url_ (account_base_url,
"/admin/add/incoming");
aai->post_ctx.headers = TALER_BANK_make_auth_header_ (auth);
GNUNET_assert
(NULL != (aai->post_ctx.headers = curl_slist_append
aai->post_ctx.headers = curl_slist_append
(aai->post_ctx.headers,
"Content-Type: application/json")));
"Content-Type: application/json");
eh = curl_easy_init ();
GNUNET_assert (GNUNET_OK ==
TALER_curl_easy_post (&aai->post_ctx, eh, admin_obj));
json_decref (admin_obj);
GNUNET_assert (CURLE_OK ==
if ( (GNUNET_OK !=
TALER_BANK_setup_auth_ (eh,
auth)) ||
(CURLE_OK !=
curl_easy_setopt (eh,
CURLOPT_URL,
aai->request_url));
aai->request_url)) ||
(GNUNET_OK !=
TALER_curl_easy_post (&aai->post_ctx,
eh,
admin_obj)) )
{
GNUNET_break (0);
TALER_BANK_admin_add_incoming_cancel (aai);
curl_easy_cleanup (eh);
json_decref (admin_obj);
return NULL;
}
json_decref (admin_obj);
aai->job = GNUNET_CURL_job_add2 (ctx,
eh,

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2015, 2016, 2017 GNUnet e.V.
Copyright (C) 2015-2020 Taler Systems SA
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
@ -24,67 +24,47 @@
/**
* Append HTTP key-value pair to curl header list.
* Set authentication data in @a easy from @a auth.
* The API currently specifies the use of HTTP basic
* authentication.
*
* @param hdr list to append to, can be NULL
* @param key key to append
* @param value value to append
* @return new list, NULL on error
* @param easy curl handle to setup for authentication
* @param auth authentication data to use
* @return #GNUNET_OK in success
*/
static struct curl_slist *
append (struct curl_slist *hdr,
const char *key,
const char *value)
int
TALER_BANK_setup_auth_ (CURL *easy,
const struct TALER_BANK_AuthenticationData *auth)
{
char *str;
struct curl_slist *ret;
GNUNET_asprintf (&str,
"%s: %s",
key,
value);
ret = curl_slist_append (hdr,
str);
GNUNET_free (str);
if (NULL == ret)
{
GNUNET_break (0);
curl_slist_free_all (hdr);
return NULL;
}
return ret;
}
/**
* Build authentication header from @a auth.
*
* @param auth authentication data to use.
*
* @return NULL on error, otherwise curl headers to use.
*/
struct curl_slist *
TALER_BANK_make_auth_header_
(const struct TALER_BANK_AuthenticationData *auth)
{
struct curl_slist *authh;
int ret;
ret = GNUNET_OK;
switch (auth->method)
{
case TALER_BANK_AUTH_NONE:
return NULL;
return GNUNET_OK;
case TALER_BANK_AUTH_BASIC:
authh = append (NULL,
"X-Taler-Bank-Username",
auth->details.basic.username);
if (NULL == authh)
return NULL;
authh = append (authh,
"X-Taler-Bank-Password",
{
char *up;
GNUNET_asprintf (&up,
"%s:%s",
auth->details.basic.username,
auth->details.basic.password);
return authh;
if ( (CURLE_OK !=
curl_easy_setopt (easy,
CURLOPT_HTTPAUTH,
CURLAUTH_BASIC)) ||
(CURLE_OK !=
curl_easy_setopt (easy,
CURLOPT_USERPWD,
up)) )
ret = GNUNET_SYSERR;
GNUNET_free (up);
break;
}
return NULL;
}
return ret;
}

View File

@ -39,6 +39,18 @@ struct curl_slist *
TALER_BANK_make_auth_header_ (const struct TALER_BANK_AuthenticationData *auth);
/**
* Set authentication data in @a easy from @a auth.
*
* @param easy curl handle to setup for authentication
* @param auth authentication data to use
* @return #GNUNET_OK in success
*/
int
TALER_BANK_setup_auth_ (CURL *easy,
const struct TALER_BANK_AuthenticationData *auth);
/**
* Obtain the URL to use for an API request.
*

View File

@ -0,0 +1,315 @@
/*
This file is part of TALER
Copyright (C) 2017--2020 Taler Systems SA
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 Foundation; either version 3,
or (at your option) any later version.
TALER is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not,
see <http://www.gnu.org/licenses/>
*/
/**
* @file bank-lib/bank_api_history.c
* @brief Implementation of the /history[-range]
* requests of the bank's HTTP API.
* @author Christian Grothoff
* @author Marcello Stanisci
*/
#include "platform.h"
#include "bank_api_common.h"
#include <microhttpd.h> /* just for HTTP status codes */
#include "taler_signatures.h"
/**
* @brief A /history Handle
*/
struct TALER_BANK_CreditHistoryHandle
{
/**
* The url for this request.
*/
char *request_url;
/**
* The base URL of the bank.
*/
char *bank_base_url;
/**
* Handle for the request.
*/
struct GNUNET_CURL_Job *job;
/**
* Function to call with the result.
*/
TALER_BANK_CreditResultCallback hcb;
/**
* Closure for @a cb.
*/
void *hcb_cls;
};
/**
* Parse history given in JSON format and invoke the callback on each item.
*
* @param hh handle to the account history request
* @param history JSON array with the history
* @return #GNUNET_OK if history was valid and @a rhistory and @a balance
* were set,
* #GNUNET_SYSERR if there was a protocol violation in @a history
*/
static int
parse_account_history (struct TALER_BANK_CreditHistoryHandle *hh,
const json_t *history)
{
json_t *history_array;
if (NULL == (history_array = json_object_get (history,
"data")))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
if (! json_is_array (history_array))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
for (unsigned int i = 0; i<json_array_size (history_array); i++)
{
struct TALER_BANK_CreditDetails td;
uint64_t row_id;
struct GNUNET_JSON_Specification hist_spec[] = {
TALER_JSON_spec_amount ("amount",
&td.amount),
GNUNET_JSON_spec_absolute_time ("date",
&td.execution_date),
GNUNET_JSON_spec_uint64 ("row_id",
&row_id),
GNUNET_JSON_spec_fixed_auto ("reserve_pub",
&td.reserve_pub),
GNUNET_JSON_spec_string ("counterpart",
&td.account_url),
GNUNET_JSON_spec_end ()
};
json_t *transaction = json_array_get (history_array,
i);
if (GNUNET_OK !=
GNUNET_JSON_parse (transaction,
hist_spec,
NULL, NULL))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
hh->hcb (hh->hcb_cls,
MHD_HTTP_OK,
TALER_EC_NONE,
row_id,
&td,
transaction);
GNUNET_JSON_parse_free (hist_spec);
}
return GNUNET_OK;
}
/**
* Function called when we're done processing the
* HTTP /history request.
*
* @param cls the `struct TALER_BANK_CreditHistoryHandle`
* @param response_code HTTP response code, 0 on error
* @param response parsed JSON result, NULL on error
*/
static void
handle_history_finished (void *cls,
long response_code,
const void *response)
{
struct TALER_BANK_CreditHistoryHandle *hh = cls;
enum TALER_ErrorCode ec;
const json_t *j = response;
hh->job = NULL;
switch (response_code)
{
case 0:
ec = TALER_EC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
if (GNUNET_OK !=
parse_account_history (hh,
j))
{
GNUNET_break_op (0);
response_code = 0;
ec = TALER_EC_INVALID_RESPONSE;
break;
}
response_code = MHD_HTTP_NO_CONTENT; /* signal end of list */
ec = TALER_EC_NONE;
break;
case MHD_HTTP_NO_CONTENT:
ec = TALER_EC_NONE;
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the bank is buggy
(or API version conflict); just pass JSON reply to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_FORBIDDEN:
/* Access denied */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_UNAUTHORIZED:
/* Nothing really to verify, bank says one of the signatures is
invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
default:
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
(unsigned int) response_code);
GNUNET_break (0);
ec = TALER_BANK_parse_ec_ (j);
response_code = 0;
break;
}
hh->hcb (hh->hcb_cls,
response_code,
ec,
0LLU,
NULL,
j);
TALER_BANK_credit_history_cancel (hh);
}
/**
* Request the credit history of the exchange's bank account.
*
* @param ctx curl context for the event loop
* @param bank_base_url URL of the base INCLUDING account number
* @param auth authentication data to use
* @param start_row from which row on do we want to get results,
* use UINT64_MAX for the latest; exclusive
* @param num_results how many results do we want;
* negative numbers to go into the past, positive numbers
* to go into the future starting at @a start_row;
* must not be zero.
* @param hres_cb the callback to call with the transaction
* history
* @param hres_cb_cls closure for the above callback
* @return NULL if the inputs are invalid (i.e. zero value for
* @e num_results). In this case, the callback is not
* called.
*/
struct TALER_BANK_CreditHistoryHandle *
TALER_BANK_credit_history (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const struct TALER_BANK_AuthenticationData *auth,
uint64_t start_row,
int64_t num_results,
TALER_BANK_CreditResultCallback hres_cb,
void *hres_cb_cls)
{
char *url;
struct TALER_BANK_CreditHistoryHandle *hh;
CURL *eh;
if (0 == num_results)
{
GNUNET_break (0);
return NULL;
}
if (UINT64_MAX == start_row)
GNUNET_asprintf (&url,
"/history&delta=%lld",
(long long) num_results);
else
GNUNET_asprintf (&url,
"/history&delta=%lld&start=%llu",
(long long) num_results,
start_row);
hh = GNUNET_new (struct TALER_BANK_CreditHistoryHandle);
hh->hcb = hres_cb;
hh->hcb_cls = hres_cb_cls;
hh->bank_base_url = GNUNET_strdup (bank_base_url);
hh->request_url = TALER_BANK_path_to_url_ (bank_base_url,
url);
eh = curl_easy_init ();
if ( (GNUNET_OK !=
TALER_BANK_setup_auth_ (eh,
auth)) ||
(CURLE_OK !=
curl_easy_setopt (eh,
CURLOPT_URL,
hh->request_url)) )
{
GNUNET_break (0);
TALER_BANK_credit_history_cancel (hh);
curl_easy_cleanup (eh);
GNUNET_free (url);
return NULL;
}
hh->job = GNUNET_CURL_job_add2 (ctx,
eh,
NULL,
&handle_history_finished,
hh);
GNUNET_free (url);
return hh;
}
/**
* Cancel a history request. This function cannot be
* used on a request handle if a response is already
* served for it.
*
* @param hh the history request handle
*/
void
TALER_BANK_credit_history_cancel (struct TALER_BANK_CreditHistoryHandle *hh)
{
if (NULL != hh->job)
{
GNUNET_CURL_job_cancel (hh->job);
hh->job = NULL;
}
GNUNET_free (hh->request_url);
GNUNET_free (hh->bank_base_url);
GNUNET_free (hh);
}
/* end of bank_api_credit.c */

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2017 GNUnet e.V. & Inria
Copyright (C) 2017--2020 Taler Systems SA
TALER is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -32,7 +32,7 @@
/**
* @brief A /history Handle
*/
struct TALER_BANK_HistoryHandle
struct TALER_BANK_DebitHistoryHandle
{
/**
@ -50,15 +50,10 @@ struct TALER_BANK_HistoryHandle
*/
struct GNUNET_CURL_Job *job;
/**
* HTTP authentication-related headers for the request.
*/
struct curl_slist *authh;
/**
* Function to call with the result.
*/
TALER_BANK_HistoryResultCallback hcb;
TALER_BANK_DebitResultCallback hcb;
/**
* Closure for @a cb.
@ -77,37 +72,39 @@ struct TALER_BANK_HistoryHandle
* #GNUNET_SYSERR if there was a protocol violation in @a history
*/
static int
parse_account_history (struct TALER_BANK_HistoryHandle *hh,
parse_account_history (struct TALER_BANK_DebitHistoryHandle *hh,
const json_t *history)
{
json_t *history_array;
char *bank_hostname;
if (NULL == (history_array = json_object_get (history, "data")))
if (NULL == (history_array = json_object_get (history,
"data")))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
if (! json_is_array (history_array))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
for (unsigned int i = 0; i<json_array_size (history_array); i++)
{
struct TALER_BANK_TransferDetails td;
const char *sign;
uint64_t other_account;
struct TALER_BANK_DebitDetails td;
uint64_t row_id;
enum TALER_BANK_Direction direction;
struct GNUNET_JSON_Specification hist_spec[] = {
GNUNET_JSON_spec_string ("sign",
&sign),
TALER_JSON_spec_amount ("amount",
&td.amount),
GNUNET_JSON_spec_absolute_time ("date",
&td.execution_date),
GNUNET_JSON_spec_uint64 ("row_id",
&row_id),
GNUNET_JSON_spec_string ("wt_subject",
(const char **) &td.wire_transfer_subject),
GNUNET_JSON_spec_uint64 ("counterpart",
&other_account),
GNUNET_JSON_spec_fixed_auto ("wtid",
&td.wtid),
GNUNET_JSON_spec_string ("counterpart",
&td.account_url),
GNUNET_JSON_spec_string ("exchange_base_url",
&td.exchange_base_url),
GNUNET_JSON_spec_end ()
};
json_t *transaction = json_array_get (history_array,
@ -121,45 +118,12 @@ parse_account_history (struct TALER_BANK_HistoryHandle *hh,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
if (0 == strcasecmp (sign,
"+"))
direction = TALER_BANK_DIRECTION_CREDIT;
else if (0 == strcasecmp (sign,
"-"))
direction = TALER_BANK_DIRECTION_DEBIT;
else if (0 == strcasecmp (sign,
"cancel+"))
direction = TALER_BANK_DIRECTION_CREDIT | TALER_BANK_DIRECTION_CANCEL;
else if (0 == strcasecmp (sign,
"cancel-"))
direction = TALER_BANK_DIRECTION_DEBIT | TALER_BANK_DIRECTION_CANCEL;
else
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (hist_spec);
return GNUNET_SYSERR;
}
/* Note, bank_base_url has _always_ the protocol scheme
* and it proved to be good at this point. */
bank_hostname = strchr (hh->bank_base_url, ':');
GNUNET_assert (NULL != bank_hostname);
bank_hostname += 3;
GNUNET_asprintf (&td.account_url,
('/' == bank_hostname[strlen (bank_hostname) - 1])
? "payto://x-taler-bank/%s%llu"
: "payto://x-taler-bank/%s/%llu",
bank_hostname,
(unsigned long long) other_account);
hh->hcb (hh->hcb_cls,
MHD_HTTP_OK,
TALER_EC_NONE,
direction,
row_id,
&td,
transaction);
GNUNET_free (td.account_url);
GNUNET_JSON_parse_free (hist_spec);
}
return GNUNET_OK;
@ -170,7 +134,7 @@ parse_account_history (struct TALER_BANK_HistoryHandle *hh,
* Function called when we're done processing the
* HTTP /history request.
*
* @param cls the `struct TALER_BANK_HistoryHandle`
* @param cls the `struct TALER_BANK_DebitHistoryHandle`
* @param response_code HTTP response code, 0 on error
* @param response parsed JSON result, NULL on error
*/
@ -179,7 +143,7 @@ handle_history_finished (void *cls,
long response_code,
const void *response)
{
struct TALER_BANK_HistoryHandle *hh = cls;
struct TALER_BANK_DebitHistoryHandle *hh = cls;
enum TALER_ErrorCode ec;
const json_t *j = response;
@ -243,120 +207,19 @@ handle_history_finished (void *cls,
hh->hcb (hh->hcb_cls,
response_code,
ec,
TALER_BANK_DIRECTION_NONE,
0LLU,
NULL,
j);
TALER_BANK_history_cancel (hh);
TALER_BANK_debit_history_cancel (hh);
}
/**
* Backend of both the /history[-range] requests.
* Request the debit history of the exchange's bank account.
*
* @param ctx curl context for the event loop
* @param bank_base_url base URL of the bank.
* @param urlargs path + URL arguments.
* @param bank_base_url URL of the base INCLUDING account number
* @param auth authentication data to use
* @param hres_cb the callback to call with the transaction
* history
* @param hres_cb_cls closure for the above callback
* @return NULL if the inputs are invalid (i.e. zero value for
* @e num_results). In this case, the callback is not
* called.
*/
static struct TALER_BANK_HistoryHandle *
put_history_job (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const char *urlargs,
const struct TALER_BANK_AuthenticationData *auth,
TALER_BANK_HistoryResultCallback hres_cb,
void *hres_cb_cls)
{
struct TALER_BANK_HistoryHandle *hh;
CURL *eh;
hh = GNUNET_new (struct TALER_BANK_HistoryHandle);
hh->hcb = hres_cb;
hh->hcb_cls = hres_cb_cls;
hh->bank_base_url = GNUNET_strdup (bank_base_url);
hh->request_url = TALER_BANK_path_to_url_ (bank_base_url,
urlargs);
hh->authh = TALER_BANK_make_auth_header_ (auth);
eh = curl_easy_init ();
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_URL,
hh->request_url));
hh->job = GNUNET_CURL_job_add2 (ctx,
eh,
hh->authh,
&handle_history_finished,
hh);
return hh;
}
/**
* Convert fixed value 'direction' into string.
*
* @param direction the value to convert.
* @return string representation of @a direction. NULL on error
*/
static const char *
conv_direction (enum TALER_BANK_Direction direction)
{
if (TALER_BANK_DIRECTION_NONE == direction)
{
/* Should just never happen. */
GNUNET_break (0);
return NULL;
}
if (TALER_BANK_DIRECTION_BOTH ==
(TALER_BANK_DIRECTION_BOTH & direction))
return "both";
else if (TALER_BANK_DIRECTION_CREDIT ==
(TALER_BANK_DIRECTION_CREDIT & direction))
return "credit";
else if (TALER_BANK_DIRECTION_DEBIT ==
(TALER_BANK_DIRECTION_BOTH & direction)) /*why use 'both' flag?*/
return "debit";
/* Should just never happen. */
GNUNET_break (0);
return NULL;
}
/**
* Convert fixed value 'direction' into string representation
* of the "cancel" argument.
*
* @param direction the value to convert.
* @return string representation of @a direction
*/
static const char *
conv_cancel (enum TALER_BANK_Direction direction)
{
if (TALER_BANK_DIRECTION_CANCEL ==
(TALER_BANK_DIRECTION_CANCEL & direction))
return "show";
return "omit";
}
/**
* Request the wire transfer history of a bank account.
*
* @param ctx curl context for the event loop
* @param bank_base_url URL of the bank (used to execute this
* request)
* @param auth authentication data to use
* @param account_number which account number should we query
* @param direction what kinds of wire transfers should be
* returned
* @param ascending if GNUNET_YES, history elements will
* be returned in chronological order.
* @param start_row from which row on do we want to get results,
* use UINT64_MAX for the latest; exclusive
* @param num_results how many results do we want;
@ -370,20 +233,18 @@ conv_cancel (enum TALER_BANK_Direction direction)
* @e num_results). In this case, the callback is not
* called.
*/
struct TALER_BANK_HistoryHandle *
TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
struct TALER_BANK_DebitHistoryHandle *
TALER_BANK_debit_history (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const struct TALER_BANK_AuthenticationData *auth,
uint64_t account_number,
enum TALER_BANK_Direction direction,
unsigned int ascending,
uint64_t start_row,
int64_t num_results,
TALER_BANK_HistoryResultCallback hres_cb,
TALER_BANK_DebitResultCallback hres_cb,
void *hres_cb_cls)
{
struct TALER_BANK_HistoryHandle *hh;
char *url;
struct TALER_BANK_DebitHistoryHandle *hh;
CURL *eh;
if (0 == num_results)
{
@ -393,28 +254,40 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
if (UINT64_MAX == start_row)
GNUNET_asprintf (&url,
"/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s",
(unsigned long long) account_number,
(long long) num_results,
conv_direction (direction),
conv_cancel (direction),
(GNUNET_YES == ascending) ? "ascending" : "descending");
"/history&delta=%lld",
(long long) num_results);
else
GNUNET_asprintf (&url,
"/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s&start=%llu",
(unsigned long long) account_number,
"/history&delta=%lld&start=%llu",
(long long) num_results,
conv_direction (direction),
conv_cancel (direction),
(GNUNET_YES == ascending) ? "ascending" : "descending",
start_row);
hh = put_history_job (ctx,
bank_base_url,
url,
auth,
hres_cb,
hres_cb_cls);
hh = GNUNET_new (struct TALER_BANK_DebitHistoryHandle);
hh->hcb = hres_cb;
hh->hcb_cls = hres_cb_cls;
hh->bank_base_url = GNUNET_strdup (bank_base_url);
hh->request_url = TALER_BANK_path_to_url_ (bank_base_url,
url);
eh = curl_easy_init ();
if ( (GNUNET_OK !=
TALER_BANK_setup_auth_ (eh,
auth)) ||
(CURLE_OK !=
curl_easy_setopt (eh,
CURLOPT_URL,
hh->request_url)) )
{
GNUNET_break (0);
TALER_BANK_debit_history_cancel (hh);
curl_easy_cleanup (eh);
GNUNET_free (url);
return NULL;
}
hh->job = GNUNET_CURL_job_add2 (ctx,
eh,
NULL,
&handle_history_finished,
hh);
GNUNET_free (url);
return hh;
}
@ -428,18 +301,17 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
* @param hh the history request handle
*/
void
TALER_BANK_history_cancel (struct TALER_BANK_HistoryHandle *hh)
TALER_BANK_debit_history_cancel (struct TALER_BANK_DebitHistoryHandle *hh)
{
if (NULL != hh->job)
{
GNUNET_CURL_job_cancel (hh->job);
hh->job = NULL;
}
curl_slist_free_all (hh->authh);
GNUNET_free (hh->request_url);
GNUNET_free (hh->bank_base_url);
GNUNET_free (hh);
}
/* end of bank_api_history.c */
/* end of bank_api_debit.c */

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
Copyright (C) 2018-2020 Taler Systems SA
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,58 @@
#include "taler_bank_service.h"
/**
* Convenience method for parsing configuration section with bank account data.
*
* @param cfg configuration to parse
* @param section the section with the configuration data
* @param acc[out] set to the account details
* @return #GNUNET_OK on success
*/
int
TALER_BANK_account_parse_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *section,
struct TALER_Account *acc)
{
char *account_url;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
section,
"URL",
&account_url))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
section,
"URL");
return GNUNET_SYSERR;
}
if (TALER_EC_NONE !=
TALER_WIRE_payto_to_account (account_url,
acc))
{
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
section,
"URL",
"Malformed payto:// URL for x-taler-bank method");
GNUNET_free (account_url);
return GNUNET_SYSERR;
}
if (TALER_PAC_X_TALER_BANK != acc->type)
{
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
section,
"URL",
"Malformed payto:// URL for x-taler-bank method");
GNUNET_free (account_url);
TALER_WIRE_account_free (acc);
return GNUNET_SYSERR;
}
GNUNET_free (account_url);
return GNUNET_OK;
}
/**
* Parse configuration section with bank authentication data.
*

View File

@ -1,242 +0,0 @@
/*
This file is part of TALER
Copyright (C) 2015, 2016, 2017 Taler Systems SA
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
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file bank-lib/bank_api_reject.c
* @brief Implementation of the /reject request of the bank's HTTP API
* @author Christian Grothoff
*/
#include "platform.h"
#include "bank_api_common.h"
#include <microhttpd.h> /* just for HTTP status codes */
#include "taler_signatures.h"
/**
* @brief A /reject Handle
*/
struct TALER_BANK_RejectHandle
{
/**
* The url for this request.
*/
char *request_url;
/**
* JSON encoding of the request to POST.
*/
char *json_enc;
/**
* Handle for the request.
*/
struct GNUNET_CURL_Job *job;
/**
* HTTP authentication-related headers for the request.
*/
struct curl_slist *authh;
/**
* Function to call with the result.
*/
TALER_BANK_RejectResultCallback cb;
/**
* Closure for @a cb.
*/
void *cb_cls;
};
/**
* Function called when we're done processing the
* HTTP /reject request.
*
* @param cls the `struct TALER_BANK_RejectHandle`
* @param response_code HTTP response code, 0 on error
* @param response parsed JSON result, NULL on error
*/
static void
handle_reject_finished (void *cls,
long response_code,
const void *response)
{
struct TALER_BANK_RejectHandle *rh = cls;
enum TALER_ErrorCode ec;
const json_t *j = response;
rh->job = NULL;
switch (response_code)
{
case 0:
ec = TALER_EC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
GNUNET_break_op (0);
response_code = 0;
ec = TALER_EC_INVALID_RESPONSE;
break;
case MHD_HTTP_NO_CONTENT:
ec = TALER_EC_NONE;
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the bank is buggy
(or API version conflict); just pass JSON reply to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_FORBIDDEN:
/* Access denied */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_UNAUTHORIZED:
/* Nothing really to verify, bank says one of the signatures is
invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
default:
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
(unsigned int) response_code);
GNUNET_break (0);
ec = TALER_BANK_parse_ec_ (j);
response_code = 0;
break;
}
rh->cb (rh->cb_cls,
response_code,
ec);
TALER_BANK_reject_cancel (rh);
}
/**
* Request rejection of a wire transfer, marking it as cancelled and voiding
* its effects.
*
* @param ctx curl context for the event loop
* @param bank_base_url URL of the bank (used to execute this request)
* @param auth authentication data to use
* @param account_number which account number should we query
* @param rowid transfer to reject
* @param rcb the callback to call with the operation result
* @param rcb_cls closure for @a rcb
* @return NULL
* if the inputs are invalid.
* In this case, the callback is not called.
*/
struct TALER_BANK_RejectHandle *
TALER_BANK_reject (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const struct TALER_BANK_AuthenticationData *auth,
uint64_t account_number,
uint64_t rowid,
TALER_BANK_RejectResultCallback rcb,
void *rcb_cls)
{
struct TALER_BANK_RejectHandle *rh;
json_t *reject_obj;
CURL *eh;
reject_obj = json_pack ("{s:{s:s}, s:I, s:I}",
"auth", "type", "basic",
"row_id", (json_int_t) rowid,
"account_number", (json_int_t) account_number);
if (NULL == reject_obj)
{
GNUNET_break (0);
return NULL;
}
rh = GNUNET_new (struct TALER_BANK_RejectHandle);
rh->cb = rcb;
rh->cb_cls = rcb_cls;
rh->request_url = TALER_BANK_path_to_url_ (bank_base_url,
"/reject");
rh->authh = TALER_BANK_make_auth_header_ (auth);
/* Append content type header here, can't do it in GNUNET_CURL_job_add
as that would override the CURLOPT_HTTPHEADER instead of appending. */
{
struct curl_slist *ext;
ext = curl_slist_append (rh->authh,
"Content-Type: application/json");
if (NULL == ext)
GNUNET_break (0);
else
rh->authh = ext;
}
eh = curl_easy_init ();
GNUNET_assert (NULL != (rh->json_enc =
json_dumps (reject_obj,
JSON_COMPACT)));
json_decref (reject_obj);
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_URL,
rh->request_url));
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_POSTFIELDS,
rh->json_enc));
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_POSTFIELDSIZE,
strlen (rh->json_enc)));
rh->job = GNUNET_CURL_job_add2 (ctx,
eh,
rh->authh,
&handle_reject_finished,
rh);
return rh;
}
/**
* Cancel an reject request. This function cannot be used on a request
* handle if the response was is already served for it.
*
* @param rh the reject request handle
*/
void
TALER_BANK_reject_cancel (struct TALER_BANK_RejectHandle *rh)
{
if (NULL != rh->job)
{
GNUNET_CURL_job_cancel (rh->job);
rh->job = NULL;
}
curl_slist_free_all (rh->authh);
GNUNET_free (rh->request_url);
GNUNET_free (rh->json_enc);
GNUNET_free (rh);
}
/* end of bank_api_reject.c */

View File

@ -0,0 +1,368 @@
/*
This file is part of TALER
Copyright (C) 2015--2020 Taler Systems SA
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
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file bank-lib/bank_api_transaction.c
* @brief Implementation of the /transaction/ requests of the bank's HTTP API
* @author Christian Grothoff
*/
#include "platform.h"
#include "bank_api_common.h"
#include <microhttpd.h> /* just for HTTP status codes */
#include "taler_signatures.h"
#include "taler_curl_lib.h"
#include "taler_bank_service.h"
GNUNET_NETWORK_STRUCT_BEGIN
/**
* Data structure serialized in the prepare stage.
*/
struct WirePackP
{
/**
* Random unique identifier for the request.
*/
struct GNUNET_HashCode request_uid;
/**
* Amount to be transferred.
*/
struct TALER_AmountNBO amount;
/**
* Wire transfer identifier to use.
*/
struct TALER_WireTransferIdentifierRawP wtid;
/**
* Length of the payto:// URL of the target account,
* including 0-terminator, in network byte order.
*/
uint32_t account_len GNUNET_PACKED;
/**
* Length of the exchange's base URL,
* including 0-terminator, in network byte order.
*/
uint32_t exchange_url_len GNUNET_PACKED;
};
GNUNET_NETWORK_STRUCT_END
/**
* Prepare for exeuction of a wire transfer.
*
* @param destination_account_url payto:// URL identifying where to send the money
* @param amount amount to transfer, already rounded
* @param exchange_base_url base URL of this exchange (included in subject
* to facilitate use of tracking API by merchant backend)
* @param wtid wire transfer identifier to use
* @param buf[out] set to transaction data to persist, NULL on error
* @param buf_size[out] set to number of bytes in @a buf, 0 on error
*/
void
TALER_BANK_prepare_wire_transfer (const char *destination_account_url,
const struct TALER_Amount *amount,
const char *exchange_base_url,
const struct
TALER_WireTransferIdentifierRawP *wtid,
void **buf,
size_t *buf_size)
{
struct WirePackP *wp;
size_t d_len = strlen (destination_account_url) + 1;
size_t u_len = strlen (exchange_base_url) + 1;
char *end;
*buf_size = sizeof (*wp) + d_len + u_len;
wp = GNUNET_malloc (*buf_size);
GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
&wp->request_uid);
TALER_amount_hton (&wp->amount,
amount);
wp->wtid = *wtid;
wp->account_len = htonl ((uint32_t) d_len);
wp->exchange_url_len = htonl ((uint32_t) u_len);
end = (char *) &wp[1];
memcpy (end,
destination_account_url,
d_len);
memcpy (end + d_len,
exchange_base_url,
u_len);
*buf = (char *) wp;
}
/**
* @brief An transaction Handle
*/
struct TALER_BANK_WireExecuteHandle
{
/**
* The url for this request.
*/
char *request_url;
/**
* POST context.
*/
struct TEAH_PostContext post_ctx;
/**
* Handle for the request.
*/
struct GNUNET_CURL_Job *job;
/**
* Function to call with the result.
*/
TALER_BANK_ConfirmationCallback cb;
/**
* Closure for @a cb.
*/
void *cb_cls;
};
/**
* Function called when we're done processing the
* HTTP /transaction request.
*
* @param cls the `struct TALER_BANK_WireExecuteHandle`
* @param response_code HTTP response code, 0 on error
* @param response parsed JSON result, NULL on error
*/
static void
handle_transaction_finished (void *cls,
long response_code,
const void *response)
{
struct TALER_BANK_WireExecuteHandle *weh = cls;
uint64_t row_id = UINT64_MAX;
struct GNUNET_TIME_Absolute timestamp;
enum TALER_ErrorCode ec;
const json_t *j = response;
weh->job = NULL;
timestamp = GNUNET_TIME_UNIT_FOREVER_ABS;
switch (response_code)
{
case 0:
ec = TALER_EC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("row_id",
&row_id),
GNUNET_JSON_spec_absolute_time ("timestamp",
&timestamp),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (j,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
response_code = 0;
ec = TALER_EC_INVALID_RESPONSE;
break;
}
ec = TALER_EC_NONE;
}
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the bank is buggy
(or API version conflict); just pass JSON reply to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_FORBIDDEN:
/* Access denied */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_UNAUTHORIZED:
/* Nothing really to verify, bank says one of the signatures is
invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_NOT_ACCEPTABLE:
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
ec = TALER_BANK_parse_ec_ (j);
break;
default:
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
(unsigned int) response_code);
GNUNET_break (0);
ec = TALER_BANK_parse_ec_ (j);
response_code = 0;
break;
}
weh->cb (weh->cb_cls,
response_code,
ec,
row_id,
timestamp);
TALER_BANK_execute_wire_transfer_cancel (weh);
}
/**
* Execute a wire transfer.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param buf buffer with the prepared execution details
* @param buf_size number of bytes in @a buf
* @param cc function to call upon success
* @param cc_cls closure for @a cc
* @return NULL on error
*/
struct TALER_BANK_WireExecuteHandle *
TALER_BANK_execute_wire_transfer (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const struct
TALER_BANK_AuthenticationData *auth,
const void *buf,
size_t buf_size,
TALER_BANK_ConfirmationCallback cc,
void *cc_cls)
{
struct TALER_BANK_WireExecuteHandle *weh;
json_t *transaction_obj;
CURL *eh;
const struct WirePackP *wp = buf;
uint32_t d_len;
uint32_t u_len;
const char *destination_account_url;
const char *exchange_base_url;
struct TALER_Amount amount;
if (sizeof (*wp) > buf_size)
{
GNUNET_break (0);
return NULL;
}
d_len = ntohl (wp->account_len);
u_len = ntohl (wp->exchange_url_len);
if (sizeof (*wp) + d_len + u_len != buf_size)
{
GNUNET_break (0);
return NULL;
}
destination_account_url = (const char *) &wp[1];
exchange_base_url = destination_account_url + d_len;
if (NULL == bank_base_url)
{
GNUNET_break (0);
return NULL;
}
TALER_amount_ntoh (&amount,
&wp->amount);
transaction_obj = json_pack ("{s:o, s:o, s:s, s:o, s:o, s:s}",
"request_uid", GNUNET_JSON_from_data_auto (
&wp->request_uid),
"amount", TALER_JSON_from_amount (&amount),
"exchange_url", exchange_base_url,
"wtid", GNUNET_JSON_from_data_auto (&wp->wtid),
"credit_account", destination_account_url);
if (NULL == transaction_obj)
{
GNUNET_break (0);
return NULL;
}
weh = GNUNET_new (struct TALER_BANK_WireExecuteHandle);
weh->cb = cc;
weh->cb_cls = cc_cls;
weh->request_url = TALER_BANK_path_to_url_ (bank_base_url,
"/transaction");
weh->post_ctx.headers = curl_slist_append
(weh->post_ctx.headers,
"Content-Type: application/json");
eh = curl_easy_init ();
if ( (GNUNET_OK !=
TALER_BANK_setup_auth_ (eh,
auth)) ||
(CURLE_OK !=
curl_easy_setopt (eh,
CURLOPT_URL,
weh->request_url)) ||
(GNUNET_OK !=
TALER_curl_easy_post (&weh->post_ctx,
eh,
transaction_obj)) )
{
GNUNET_break (0);
TALER_BANK_execute_wire_transfer_cancel (weh);
curl_easy_cleanup (eh);
json_decref (transaction_obj);
return NULL;
}
json_decref (transaction_obj);
weh->job = GNUNET_CURL_job_add2 (ctx,
eh,
weh->post_ctx.headers,
&handle_transaction_finished,
weh);
return weh;
}
/**
* Cancel a wire transfer. This function cannot be used on a request handle
* if a response is already served for it.
*
* @param weh the wire transfer request handle
*/
void
TALER_BANK_execute_wire_transfer_cancel (struct
TALER_BANK_WireExecuteHandle *weh)
{
if (NULL != weh->job)
{
GNUNET_CURL_job_cancel (weh->job);
weh->job = NULL;
}
TALER_curl_easy_post_finished (&weh->post_ctx);
GNUNET_free (weh->request_url);
GNUNET_free (weh);
}
/* end of bank_api_transaction.c */

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
(C) 2016, 2017, 2018 Inria and GNUnet e.V.
(C) 2016-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -25,7 +25,7 @@
#include "platform.h"
#include "taler_fakebank_lib.h"
#include "taler_bank_service.h"
#include "fakebank.h"
#include "taler_mhd_lib.h"
/**
* Maximum POST request size (for /admin/add/incoming)
@ -33,6 +33,65 @@
#define REQUEST_BUFFER_MAX (4 * 1024)
/**
* Details about a transcation we (as the simulated bank) received.
*/
struct Transaction
{
/**
* We store transactions in a DLL.
*/
struct Transaction *next;
/**
* We store transactions in a DLL.
*/
struct Transaction *prev;
/**
* Amount to be transferred.
*/
struct TALER_Amount amount;
/**
* Account to debit.
*/
char *debit_account;
/**
* Account to credit.
*/
char *credit_account;
/**
* Subject of the transfer.
*/
char *subject;
/**
* Base URL of the exchange.
*/
char *exchange_base_url;
/**
* When did the transaction happen?
*/
struct GNUNET_TIME_Absolute date;
/**
* Number of this transaction.
*/
uint64_t row_id;
/**
* Has this transaction been subjected to #TALER_FAKEBANK_check()
* and should thus no longer be counted in
* #TALER_FAKEBANK_check_empty()?
*/
int checked;
};
/**
* Handle for the fake bank.
*/
@ -63,6 +122,11 @@ struct TALER_FAKEBANK_Handle
*/
uint64_t serial_counter;
/**
* Our port number.
*/
uint16_t port;
#if EPOLL_SUPPORT
/**
* Boxed @e mhd_fd.
@ -95,8 +159,8 @@ struct TALER_FAKEBANK_Handle
int
TALER_FAKEBANK_check (struct TALER_FAKEBANK_Handle *h,
const struct TALER_Amount *want_amount,
uint64_t want_debit,
uint64_t want_credit,
const char *want_debit,
const char *want_credit,
const char *exchange_base_url,
char **subject)
{
@ -151,8 +215,8 @@ TALER_FAKEBANK_check (struct TALER_FAKEBANK_Handle *h,
*/
uint64_t
TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
uint64_t debit_account,
uint64_t credit_account,
const char *debit_account,
const char *credit_account,
const struct TALER_Amount *amount,
const char *subject,
const char *exchange_base_url)
@ -160,15 +224,15 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
struct Transaction *t;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Making transfer from %llu to %llu over %s and subject %s; for exchange: %s\n",
(unsigned long long) debit_account,
(unsigned long long) credit_account,
"Making transfer from %s to %s over %s and subject %s; for exchange: %s\n",
debit_account,
credit_account,
TALER_amount2s (amount),
subject,
exchange_base_url);
t = GNUNET_new (struct Transaction);
t->debit_account = debit_account;
t->credit_account = credit_account;
t->debit_account = GNUNET_strdup (debit_account);
t->credit_account = GNUNET_strdup (credit_account);
t->amount = *amount;
t->exchange_base_url = GNUNET_strdup (exchange_base_url);
t->row_id = ++h->serial_counter;
@ -182,31 +246,6 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
}
/**
* Reject incoming wire transfer to account @a credit_account
* as identified by @a rowid.
*
* @param h fake bank handle
* @param rowid identifies transfer to reject
* @param credit_account account number of owner of credited account
* @return #GNUNET_YES on success, #GNUNET_NO if the wire transfer was not found
*/
int
TALER_FAKEBANK_reject_transfer (struct TALER_FAKEBANK_Handle *h,
uint64_t rowid,
uint64_t credit_account)
{
for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
if ( (t->row_id == rowid) &&
(t->credit_account == credit_account) )
{
t->rejected = GNUNET_YES;
return GNUNET_YES;
}
return GNUNET_NO;
}
/**
* Check that no wire transfers were ordered (or at least none
* that have not been taken care of via #TALER_FAKEBANK_check()).
@ -223,8 +262,7 @@ TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h)
t = h->transactions_head;
while (NULL != t)
{
if ( (GNUNET_YES != t->checked) &&
(GNUNET_YES != t->rejected) )
if (GNUNET_YES != t->checked)
break;
t = t->next;
}
@ -234,16 +272,15 @@ TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h)
"Expected empty transaction set, but I have:\n");
while (NULL != t)
{
if ( (GNUNET_YES != t->checked) &&
(GNUNET_YES != t->rejected) )
if (GNUNET_YES != t->checked)
{
char *s;
s = TALER_amount_to_string (&t->amount);
fprintf (stderr,
"%llu -> %llu (%s) from %s\n",
(unsigned long long) t->debit_account,
(unsigned long long) t->credit_account,
"%s -> %s (%s) from %s\n",
t->debit_account,
t->credit_account,
s,
t->exchange_base_url);
GNUNET_free (s);
@ -270,6 +307,8 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h)
h->transactions_tail,
t);
GNUNET_free (t->subject);
GNUNET_free (t->debit_account);
GNUNET_free (t->credit_account);
GNUNET_free (t->exchange_base_url);
GNUNET_free (t);
}
@ -290,62 +329,6 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h)
}
/**
* Create and queue a bank error message with the HTTP response
* code @a response_code on connection @a connection.
*
* @param connection where to queue the reply
* @param response_code http status code to use
* @param ec taler error code to use
* @param message human readable error message
* @return MHD status code
*/
static int
create_bank_error (struct MHD_Connection *connection,
unsigned int response_code,
enum TALER_ErrorCode ec,
const char *message)
{
json_t *json;
struct MHD_Response *resp;
void *json_str;
size_t json_len;
int ret;
json = json_pack ("{s:s, s:I}",
"error",
message,
"ec",
(json_int_t) ec);
json_str = json_dumps (json,
JSON_INDENT (2));
json_decref (json);
if (NULL == json_str)
{
GNUNET_break (0);
return MHD_NO;
}
json_len = strlen (json_str);
resp = MHD_create_response_from_buffer (json_len,
json_str,
MHD_RESPMEM_MUST_FREE);
if (NULL == resp)
{
GNUNET_break (0);
free (json_str);
return MHD_NO;
}
(void) MHD_add_response_header (resp,
MHD_HTTP_HEADER_CONTENT_TYPE,
"application/json");
ret = MHD_queue_response (connection,
response_code,
resp);
MHD_destroy_response (resp);
return ret;
}
/**
* Function called whenever MHD is done with a request. If the
* request was a POST, we may have stored a `struct Buffer *` in the
@ -394,8 +377,6 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
{
enum GNUNET_JSON_PostResult pr;
json_t *json;
struct MHD_Response *resp;
int ret;
uint64_t row_id;
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
@ -422,15 +403,14 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
}
{
const char *subject;
uint64_t debit_account;
uint64_t credit_account;
const char *debit_account;
const char *credit_account;
const char *base_url;
struct TALER_Amount amount;
char *amount_s;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("subject", &subject),
GNUNET_JSON_spec_uint64 ("debit_account", &debit_account),
GNUNET_JSON_spec_uint64 ("credit_account", &credit_account),
GNUNET_JSON_spec_string ("debit_account", &debit_account),
GNUNET_JSON_spec_string ("credit_account", &credit_account),
TALER_JSON_spec_amount ("amount", &amount),
GNUNET_JSON_spec_string ("exchange_url", &base_url),
GNUNET_JSON_spec_end ()
@ -450,80 +430,49 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
&amount,
subject,
base_url);
amount_s = TALER_amount_to_string (&amount);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Receiving incoming wire transfer: %llu->%llu, subject: %s, amount: %s, from %s\n",
(unsigned long long) debit_account,
(unsigned long long) credit_account,
"Receiving incoming wire transfer: %s->%s, subject: %s, amount: %s, from %s\n",
debit_account,
credit_account,
subject,
amount_s,
TALER_amount2s (&amount),
base_url);
GNUNET_free (amount_s);
}
json_decref (json);
/* Finally build response object */
{
void *json_str;
size_t json_len;
json = json_pack ("{s:I, s:o}",
return TALER_MHD_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:I, s:o}",
"row_id",
(json_int_t) row_id,
"timestamp", GNUNET_JSON_from_time_abs (GNUNET_TIME_UNIT_ZERO_ABS)); /*dummy tmp */
json_str = json_dumps (json,
JSON_INDENT (2));
json_decref (json);
if (NULL == json_str)
{
GNUNET_break (0);
return MHD_NO;
}
json_len = strlen (json_str);
resp = MHD_create_response_from_buffer (json_len,
json_str,
MHD_RESPMEM_MUST_FREE);
if (NULL == resp)
{
GNUNET_break (0);
free (json_str);
return MHD_NO;
}
(void) MHD_add_response_header (resp,
MHD_HTTP_HEADER_CONTENT_TYPE,
"application/json");
}
ret = MHD_queue_response (connection,
MHD_HTTP_OK,
resp);
MHD_destroy_response (resp);
return ret;
"timestamp", GNUNET_JSON_from_time_abs (
GNUNET_TIME_UNIT_ZERO_ABS)); /*dummy tmp */
}
/**
* Handle incoming HTTP request for /reject.
* Handle incoming HTTP request for /transaction.
*
* @param h the fakebank handle
* @param connection the connection
* @param account account making the transaction
* @param upload_data request data
* @param upload_data_size size of @a upload_data in bytes
* @param con_cls closure for request (a `struct Buffer *`)
* @return MHD result code
*/
static int
handle_reject (struct TALER_FAKEBANK_Handle *h,
handle_transaction (struct TALER_FAKEBANK_Handle *h,
struct MHD_Connection *connection,
const char *account,
const char *upload_data,
size_t *upload_data_size,
void **con_cls)
{
enum GNUNET_JSON_PostResult pr;
json_t *json;
struct MHD_Response *resp;
int ret;
int found;
uint64_t row_id;
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
connection,
@ -548,13 +497,25 @@ handle_reject (struct TALER_FAKEBANK_Handle *h,
break;
}
{
uint64_t row_id;
uint64_t credit_account;
struct GNUNET_HashCode uuid;
struct TALER_WireTransferIdentifierRawP wtid;
const char *credit_account;
const char *base_url;
struct TALER_Amount amount;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("row_id", &row_id),
GNUNET_JSON_spec_uint64 ("account_number", &credit_account),
GNUNET_JSON_spec_fixed_auto ("request_uid",
&uuid),
TALER_JSON_spec_amount ("amount",
&amount),
GNUNET_JSON_spec_string ("exchange_base_url",
&base_url),
GNUNET_JSON_spec_fixed_auto ("wtid",
&wtid),
GNUNET_JSON_spec_string ("credit_account",
&credit_account),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (json,
spec,
@ -564,31 +525,38 @@ handle_reject (struct TALER_FAKEBANK_Handle *h,
json_decref (json);
return MHD_NO;
}
found = TALER_FAKEBANK_reject_transfer (h,
row_id,
credit_account);
{
char *subject;
subject = GNUNET_STRINGS_data_to_string_alloc (&wtid,
sizeof (wtid));
// FIXME: use uuid here!!!
row_id = TALER_FAKEBANK_make_transfer (h,
account,
credit_account,
&amount,
subject,
base_url);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Rejected wire transfer #%llu (to %llu)\n",
(unsigned long long) row_id,
(unsigned long long) credit_account);
"Receiving incoming wire transfer: %s->%s, subject: %s, amount: %s, from %s\n",
account,
credit_account,
subject,
TALER_amount2s (&amount),
base_url);
GNUNET_free (subject);
}
}
json_decref (json);
if (GNUNET_OK != found)
return create_bank_error
(connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_TRANSACTION_NOT_FOUND,
"transaction unknown");
/* finally build regular response */
resp = MHD_create_response_from_buffer (0,
NULL,
MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection,
MHD_HTTP_NO_CONTENT,
resp);
MHD_destroy_response (resp);
return ret;
/* Finally build response object */
return TALER_MHD_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:I, s:o}",
"row_id",
(json_int_t) row_id,
"timestamp", GNUNET_JSON_from_time_abs (
GNUNET_TIME_UNIT_ZERO_ABS)); /*dummy tmp */
}
@ -626,75 +594,153 @@ handle_home_page (struct TALER_FAKEBANK_Handle *h,
/**
* Handle incoming HTTP request for /history
* This is the "base" structure for both the /history and the
* /history-range API calls.
*/
struct HistoryArgs
{
/**
* Bank account number of the requesting client.
*/
uint64_t account_number;
/**
* Index of the starting transaction.
*/
uint64_t start_idx;
/**
* Requested number of results and order
* (positive: ascending, negative: descending)
*/
int64_t delta;
/**
* Timeout for long polling.
*/
struct GNUNET_TIME_Relative lp_timeout;
/**
* #GNUNET_YES if starting point was given.
*/
int have_start;
};
/**
* Parse URL history arguments, of _both_ APIs:
* /history/incoming and /history/outgoing.
*
* @param connection MHD connection.
* @param function_name name of the caller.
* @param ha[out] will contain the parsed values.
* @return GNUNET_OK only if the parsing succeedes.
*/
static int
parse_history_common_args (struct MHD_Connection *connection,
struct HistoryArgs *ha)
{
const char *start;
const char *delta;
const char *long_poll_ms;
unsigned long long lp_timeout;
unsigned long long sval;
long long d;
start = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"start");
ha->have_start = (NULL != start);
delta = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"delta");
long_poll_ms = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"long_poll_ms");
lp_timeout = 0;
if ( (NULL == delta) ||
(1 != sscanf (delta,
"%lld",
&d)) ||
( (NULL != long_poll_ms) &&
(1 != sscanf (long_poll_ms,
"%llu",
&lp_timeout)) ) ||
( (NULL != start) &&
(1 != sscanf (start,
"%llu",
&sval)) ) )
{
/* Fail if one of the above failed. */
/* Invalid request, given that this is fakebank we impolitely
* just kill the connection instead of returning a nice error.
*/
GNUNET_break (0);
return GNUNET_NO;
}
if (NULL == start)
ha->start_idx = (d > 0) ? 0 : UINT64_MAX;
else
ha->start_idx = (uint64_t) sval;
ha->delta = (int64_t) d;
ha->lp_timeout
= GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
lp_timeout);
return GNUNET_OK;
}
/**
* Handle incoming HTTP request for /history/incoming
*
* @param h the fakebank handle
* @param connection the connection
* @param con_cls place to store state, not used
* @param account which account the request is about
* @return MHD result code
*/
static int
handle_history (struct TALER_FAKEBANK_Handle *h,
handle_credit_history (struct TALER_FAKEBANK_Handle *h,
struct MHD_Connection *connection,
void **con_cls)
const char *account)
{
struct HistoryArgs ha;
struct HistoryRangeIds hri;
const char *start;
const char *delta;
struct Transaction *pos;
json_t *history;
(void) con_cls;
if (GNUNET_OK !=
TFH_parse_history_common_args (connection,
parse_history_common_args (connection,
&ha))
{
GNUNET_break (0);
return MHD_NO;
}
start = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"start");
delta = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"delta");
if ( ((NULL != start) && (1 != sscanf (start,
"%llu",
&hri.start))) ||
(NULL == delta) || (1 != sscanf (delta,
"%lld",
&hri.count)) )
if (! ha.have_start)
{
GNUNET_break (0);
return MHD_NO;
}
ha.range = &hri;
if (NULL == start)
{
pos = 0 > hri.count ?
h->transactions_tail : h->transactions_head;
pos = (0 > ha.delta)
? h->transactions_tail
: h->transactions_head;
}
else if (NULL != h->transactions_head)
{
for (pos = h->transactions_head;
NULL != pos;
pos = pos->next)
if (pos->row_id == hri.start)
if (pos->row_id == ha.start_idx)
break;
if (NULL == pos)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Invalid range specified,"
" transaction %llu not known!\n",
(unsigned long long) hri.start);
"Invalid start specified, transaction %llu not known!\n",
(unsigned long long) ha.start_idx);
return MHD_NO;
}
/* range is exclusive, skip the matching entry */
if (hri.count > 0)
if (ha.delta > 0)
pos = pos->next;
if (hri.count < 0)
if (ha.delta < 0)
pos = pos->prev;
}
else
@ -702,15 +748,210 @@ handle_history (struct TALER_FAKEBANK_Handle *h,
/* list is empty */
pos = NULL;
}
history = json_array ();
while ( (0 != ha.delta) &&
(NULL != pos) )
{
if (0 == strcasecmp (pos->credit_account,
account))
{
json_t *trans;
trans = json_pack
("{s:I, s:o, s:o, s:s, s:s, s:s}",
"row_id", (json_int_t) pos->row_id,
"date", GNUNET_JSON_from_time_abs (pos->date),
"amount", TALER_JSON_from_amount (&pos->amount),
"credit_account", account,
"debit_account", pos->debit_account,
"wtid", pos->subject /* we "know" it is OK */);
GNUNET_assert (0 ==
json_array_append_new (history,
trans));
if (ha.delta > 0)
ha.delta--;
else
ha.delta++;
}
if (ha.delta > 0)
pos = pos->prev;
else
pos = pos->next;
}
return TALER_MHD_reply_json (connection,
history,
MHD_HTTP_OK);
}
/**
* Handle incoming HTTP request for /history/incoming
*
* @param h the fakebank handle
* @param connection the connection
* @param account which account the request is about
* @return MHD result code
*/
static int
handle_debit_history (struct TALER_FAKEBANK_Handle *h,
struct MHD_Connection *connection,
const char *account)
{
struct HistoryArgs ha;
struct Transaction *pos;
json_t *history;
if (GNUNET_OK !=
parse_history_common_args (connection,
&ha))
{
GNUNET_break (0);
return MHD_NO;
}
if (! ha.have_start)
{
pos = (0 > ha.delta)
? h->transactions_tail
: h->transactions_head;
}
else if (NULL != h->transactions_head)
{
for (pos = h->transactions_head;
NULL != pos;
pos = pos->next)
if (pos->row_id == ha.start_idx)
break;
if (NULL == pos)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Invalid start specified, transaction %llu not known!\n",
(unsigned long long) ha.start_idx);
return MHD_NO;
}
/* range is exclusive, skip the matching entry */
if (ha.delta > 0)
pos = pos->next;
if (ha.delta < 0)
pos = pos->prev;
}
else
{
/* list is empty */
pos = NULL;
}
history = json_array ();
while ( (0 != ha.delta) &&
(NULL != pos) )
{
if (0 == strcasecmp (pos->debit_account,
account))
{
json_t *trans;
trans = json_pack
("{s:I, s:o, s:o, s:s, s:s, s:s}",
"row_id", (json_int_t) pos->row_id,
"date", GNUNET_JSON_from_time_abs (pos->date),
"amount", TALER_JSON_from_amount (&pos->amount),
"credit_account", pos->credit_account,
"debit_account", account,
"reserve_pub", pos->subject /* we "know" it is OK */);
GNUNET_assert (0 ==
json_array_append_new (history,
trans));
if (ha.delta > 0)
ha.delta--;
else
ha.delta++;
}
if (ha.delta > 0)
pos = pos->prev;
else
pos = pos->next;
}
return TALER_MHD_reply_json (connection,
history,
MHD_HTTP_OK);
}
/**
* Handle incoming HTTP request.
*
* @param h our handle
* @param connection the connection
* @param url the requested url
* @param method the method (POST, GET, ...)
* @param account which account should process the request
* @param upload_data request data
* @param upload_data_size size of @a upload_data in bytes
* @param con_cls closure for request (a `struct Buffer *`)
* @return MHD result code
*/
static int
serve (struct TALER_FAKEBANK_Handle *h,
struct MHD_Connection *connection,
const char *account,
const char *url,
const char *method,
const char *upload_data,
size_t *upload_data_size,
void **con_cls)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"/history, start row (0 == no transactions exist): %llu\n",
NULL != pos ? pos->row_id : 0LL);
return TFH_build_history_response (connection,
pos,
&ha,
&TFH_handle_history_skip,
&TFH_handle_history_step,
&TFH_handle_history_advance);
"Fakebank, serving: %s\n",
url);
if ( (0 == strcmp (url,
"/")) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_GET)) )
return handle_home_page (h,
connection,
con_cls);
if ( (0 == strcmp (url,
"/admin/add/incoming")) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_POST)) )
return handle_admin_add_incoming (h,
connection,
upload_data,
upload_data_size,
con_cls);
if ( (0 == strcmp (url,
"/transaction")) &&
(NULL != account) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_POST)) )
return handle_transaction (h,
connection,
account,
upload_data,
upload_data_size,
con_cls);
if ( (0 == strcmp (url,
"/history/incoming")) &&
(NULL != account) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_GET)) )
return handle_credit_history (h,
connection,
account);
if ( (0 == strcmp (url,
"/history/outgoing")) &&
(NULL != account) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_GET)) )
return handle_debit_history (h,
connection,
account);
/* Unexpected URL path, just close the connection. */
/* we're rather impolite here, but it's a testcase. */
TALER_LOG_ERROR ("Breaking URL: %s\n",
url);
GNUNET_break_op (0);
return MHD_NO;
}
@ -738,50 +979,28 @@ handle_mhd_request (void *cls,
void **con_cls)
{
struct TALER_FAKEBANK_Handle *h = cls;
char *account = NULL;
char *end;
int ret;
(void) version;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Fakebank, serving: %s\n",
url);
if ( (0 == strcasecmp (url,
"/")) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_GET)) )
return handle_home_page (h,
connection,
con_cls);
if ( (0 == strcasecmp (url,
"/admin/add/incoming")) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_POST)) )
return handle_admin_add_incoming (h,
if ( (strlen (url) > 1) &&
(NULL != (end = strchr (url + 1, '/'))) )
{
account = GNUNET_strndup (url + 1,
end - url - 1);
url = end;
}
ret = serve (h,
connection,
account,
url,
method,
upload_data,
upload_data_size,
con_cls);
if ( (0 == strcasecmp (url,
"/reject")) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_POST)) )
return handle_reject (h,
connection,
upload_data,
upload_data_size,
con_cls);
if ( (0 == strcasecmp (url,
"/history")) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_GET)) )
return handle_history (h,
connection,
con_cls);
/* Unexpected URL path, just close the connection. */
/* we're rather impolite here, but it's a testcase. */
TALER_LOG_ERROR ("Breaking URL: %s\n",
url);
GNUNET_break_op (0);
return MHD_NO;
GNUNET_free_non_null (account);
return ret;
}
@ -918,6 +1137,7 @@ TALER_FAKEBANK_start (uint16_t port)
struct TALER_FAKEBANK_Handle *h;
h = GNUNET_new (struct TALER_FAKEBANK_Handle);
h->port = port;
h->mhd_bank = MHD_start_daemon (MHD_USE_DEBUG
#if EPOLL_SUPPORT
| MHD_USE_EPOLL_INTERNAL_THREAD

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
(C) 2016, 2017, 2018 Inria and GNUnet e.V.
(C) 2016-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -19,7 +19,7 @@
/**
* @file bank-lib/fakebank.h
* @brief definitions for the "/history[-range]" layer.
* @brief definitions for the "/history" layer.
* @author Marcello Stanisci <stanisci.m@gmail.com>
*/
@ -29,283 +29,4 @@
#include <gnunet/gnunet_util_lib.h>
#include "taler_bank_service.h"
/**
* Details about a transcation we (as the simulated bank) received.
*/
struct Transaction
{
/**
* We store transactions in a DLL.
*/
struct Transaction *next;
/**
* We store transactions in a DLL.
*/
struct Transaction *prev;
/**
* Amount to be transferred.
*/
struct TALER_Amount amount;
/**
* Account to debit.
*/
uint64_t debit_account;
/**
* Account to credit.
*/
uint64_t credit_account;
/**
* Subject of the transfer.
*/
char *subject;
/**
* Base URL of the exchange.
*/
char *exchange_base_url;
/**
* When did the transaction happen?
*/
struct GNUNET_TIME_Absolute date;
/**
* Number of this transaction.
*/
long long unsigned int row_id;
/**
* Flag set if the transfer was rejected.
*/
int rejected;
/**
* Has this transaction been subjected to #TALER_FAKEBANK_check()
* and should thus no longer be counted in
* #TALER_FAKEBANK_check_empty()?
*/
int checked;
};
/******************************************
* Definitions for "/history" start here. *
******************************************/
/**
* Needed to implement ascending/descending ordering
* of /history results.
*/
struct HistoryElement
{
/**
* History JSON element.
*/
json_t *element;
/**
* Previous element.
*/
struct HistoryElement *prev;
/**
* Next element.
*/
struct HistoryElement *next;
};
/**
* Values to implement the "/history-range" range.
*/
struct HistoryRangeDates
{
/**
* Oldest row in the results.
*/
struct GNUNET_TIME_Absolute start;
/**
* Youngest row in the results.
*/
struct GNUNET_TIME_Absolute end;
};
/**
* Values to implement the "/history" range.
*/
struct HistoryRangeIds
{
/**
* (Exclusive) row ID for the result set.
*/
unsigned long long start;
/**
* How many transactions we want in the result set. If
* negative/positive, @a start will be strictly younger/older
* of any element in the result set.
*/
long long count;
};
/**
* This is the "base" structure for both the /history and the
* /history-range API calls.
*/
struct HistoryArgs
{
/**
* Direction asked by the client: CREDIT / DEBIT / BOTH / CANCEL.
*/
enum TALER_BANK_Direction direction;
/**
* Bank account number of the requesting client.
*/
unsigned long long account_number;
/**
* Ordering of the results.
*/
unsigned int ascending;
/**
* Overloaded type that indicates the "range" to be returned
* in the results; this can be either a date range, or a
* starting row id + the count.
*/
void *range;
};
/**
* Type for a function that decides whether or not
* the history-building loop should iterate once again.
* Typically called from inside the 'while' condition.
*
* @param ha history argument.
* @param pos current position.
* @return GNUNET_YES if the iteration shuold go on.
*/
typedef int (*CheckAdvance)(const struct HistoryArgs *ha,
const struct Transaction *pos);
/**
* Type for a function that steps over the next element
* in the list of all transactions, after the current @a pos
* _got_ included in the result.
*/
typedef struct Transaction * (*Step)(const struct HistoryArgs *ha,
const struct Transaction *pos);
/*
* Type for a function that steps over the next element
* in the list of all transactions, after the current @a pos
* did _not_ get included in the result.
*/
typedef struct Transaction * (*Skip)(const struct HistoryArgs *ha,
const struct Transaction *pos);
/**
* Actual history response builder.
*
* @param pos first (included) element in the result set.
* @param ha history arguments.
* @param caller_name which function is building the history.
* @return MHD_YES / MHD_NO, after having enqueued the response
* object into MHD.
*/
int
TFH_build_history_response (struct MHD_Connection *connection,
struct Transaction *pos,
struct HistoryArgs *ha,
Skip skip,
Step step,
CheckAdvance advance);
/**
* Parse URL history arguments, of _both_ APIs:
* /history and /history-range.
*
* @param connection MHD connection.
* @param function_name name of the caller.
* @param ha[out] will contain the parsed values.
* @return GNUNET_OK only if the parsing succeedes.
*/
int
TFH_parse_history_common_args (struct MHD_Connection *connection,
struct HistoryArgs *ha);
/**
* Decides whether the history builder will advance or not
* to the next element.
*
* @param ha history args
* @return GNUNET_YES/NO to advance/not-advance.
*/
int
TFH_handle_history_advance (const struct HistoryArgs *ha,
const struct Transaction *pos);
/**
* Iterates on the "next" element to be processed. To
* be used when the current element does not get inserted in
* the result.
*
* @param ha history arguments.
* @param pos current element being processed.
* @return the next element to be processed.
*/
struct Transaction *
TFH_handle_history_skip (const struct HistoryArgs *ha,
const struct Transaction *pos);
/**
* Iterates on the "next" element to be processed. To
* be used when the current element _gets_ inserted in the result.
*
* @param ha history arguments.
* @param pos current element being processed.
* @return the next element to be processed.
*/
struct Transaction *
TFH_handle_history_step (const struct HistoryArgs *ha,
const struct Transaction *pos);
/**
* Decides whether the history builder will advance or not
* to the next element.
*
* @param ha history args
* @return GNUNET_YES/NO to advance/not-advance.
*/
int
TFH_handle_history_range_advance (const struct HistoryArgs *ha,
const struct Transaction *pos);
/**
* Iterates towards the "next" element to be processed. To
* be used when the current element does not get inserted in
* the result.
*
* @param ha history arguments.
* @param pos current element being processed.
* @return the next element to be processed.
*/
struct Transaction *
TFH_handle_history_range_skip (const struct HistoryArgs *ha,
const struct Transaction *pos);
#endif

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
(C) 2016, 2017, 2018 Inria and GNUnet e.V.
(C) 2016-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -19,92 +19,15 @@
/**
* @file bank-lib/fakebank_history.c
* @brief definitions for the "/history[-range]" layer.
* @brief definitions for the "/history" layer.
* @author Marcello Stanisci <stanisci.m@gmail.com>
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include "taler_json_lib.h"
#include "fakebank.h"
/**
* Decides whether the history builder will advance or not
* to the next element.
*
* @param ha history args
* @return GNUNET_YES/NO to advance/not-advance.
*/
int
TFH_handle_history_advance (const struct HistoryArgs *ha,
const struct Transaction *pos)
{
const struct HistoryRangeIds *hri = ha->range;
return (NULL != pos) && (0 != hri->count);
}
/**
* Iterates on the "next" element to be processed. To
* be used when the current element does not get inserted in
* the result.
*
* @param ha history arguments.
* @param pos current element being processed.
* @return the next element to be processed.
*/
struct Transaction *
TFH_handle_history_skip (const struct HistoryArgs *ha,
const struct Transaction *pos)
{
const struct HistoryRangeIds *hri = ha->range;
if (hri->count > 0)
return pos->next;
if (hri->count < 0)
return pos->prev;
return NULL;
}
/**
* Iterates on the "next" element to be processed. To
* be used when the current element _gets_ inserted in the result.
*
* @param ha history arguments.
* @param pos current element being processed.
* @return the next element to be processed.
*/
struct Transaction *
TFH_handle_history_step (const struct HistoryArgs *ha,
const struct Transaction *pos)
{
struct HistoryRangeIds *hri = ha->range;
if (hri->count > 0)
{
hri->count--;
return pos->next;
}
if (hri->count < 0)
{
hri->count++;
return pos->prev;
}
return NULL;
}
/**
* Actual history response builder.
*
* @param pos first (included) element in the result set, NULL if history is empty
* @param ha history arguments.
* @param caller_name which function is building the history.
* @return MHD_YES / MHD_NO, after having enqueued the response
* object into MHD.
*/
int
TFH_build_history_response (struct MHD_Connection *connection,
struct Transaction *pos,
@ -257,126 +180,3 @@ TFH_build_history_response (struct MHD_Connection *connection,
}
return ret;
}
/**
* Parse URL history arguments, of _both_ APIs:
* /history and /history-range.
*
* @param connection MHD connection.
* @param function_name name of the caller.
* @param ha[out] will contain the parsed values.
* @return GNUNET_OK only if the parsing succeedes.
*/
int
TFH_parse_history_common_args (struct MHD_Connection *connection,
struct HistoryArgs *ha)
{
/**
* @variable
* Just check if given and == "basic", no need to keep around.
*/
const char *auth;
/**
* All those will go into the structure, after parsing.
*/
const char *direction;
const char *cancelled;
const char *ordering;
const char *account_number;
auth = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"auth");
direction = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"direction");
cancelled = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"cancelled");
ordering = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"ordering");
account_number = MHD_lookup_connection_value
(connection,
MHD_GET_ARGUMENT_KIND,
"account_number");
/* Fail if one of the above failed. */
if ( (NULL == direction) ||
(NULL == cancelled) ||
( (0 != strcasecmp (cancelled,
"OMIT")) &&
(0 != strcasecmp (cancelled,
"SHOW")) ) ||
( (0 != strcasecmp (direction,
"BOTH")) &&
(0 != strcasecmp (direction,
"CREDIT")) &&
(0 != strcasecmp (direction,
"DEBIT")) ) ||
(1 != sscanf (account_number,
"%llu",
&ha->account_number)) ||
( (NULL == auth) || (0 != strcasecmp (auth,
"basic")) ) )
{
/* Invalid request, given that this is fakebank we impolitely
* just kill the connection instead of returning a nice error.
*/
GNUNET_break (0);
return GNUNET_NO;
}
if (0 == strcasecmp (direction,
"CREDIT"))
{
ha->direction = TALER_BANK_DIRECTION_CREDIT;
}
else if (0 == strcasecmp (direction,
"DEBIT"))
{
ha->direction = TALER_BANK_DIRECTION_DEBIT;
}
else if (0 == strcasecmp (direction,
"BOTH"))
{
ha->direction = TALER_BANK_DIRECTION_BOTH;
}
/* Direction is invalid. */
else
{
GNUNET_break (0);
return GNUNET_NO;
}
if (0 == strcasecmp (cancelled,
"OMIT"))
{
/* nothing */
}
else if (0 == strcasecmp (cancelled,
"SHOW"))
{
ha->direction |= TALER_BANK_DIRECTION_CANCEL;
}
/* Cancel-showing policy is invalid. */
else
{
GNUNET_break (0);
return GNUNET_NO;
}
if ((NULL != ordering)
&& (0 == strcmp ("ascending",
ordering)))
ha->ascending = GNUNET_YES;
else
ha->ascending = GNUNET_NO;
return GNUNET_OK;
}

View File

@ -25,9 +25,9 @@
#include "taler_bank_service.h"
/**
* Bank URL.
* Account base URL.
*/
static char *bank_url;
static char *account_base_url;
/**
* Amount to transfer.
@ -35,14 +35,9 @@ static char *bank_url;
static struct TALER_Amount amount;
/**
* Debit account number.
* Credit account payto://-URI.
*/
static unsigned long long debit_account_no;
/**
* Credit account number.
*/
static unsigned long long credit_account_no;
static char *credit_account;
/**
* Wire transfer subject.
@ -168,11 +163,23 @@ run (void *cls,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
struct TALER_BANK_AuthenticationData auth;
struct TALER_ReservePublicKeyP reserve_pub;
(void) cls;
(void) args;
(void) cfgfile;
(void) cfg;
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (subject,
strlen (subject),
&reserve_pub,
sizeof (reserve_pub)))
{
fprintf (stderr,
"Error: wire transfer subject must be a reserve public key\n");
return;
}
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
&rc);
GNUNET_assert (NULL != ctx);
@ -182,13 +189,11 @@ run (void *cls,
auth.details.basic.username = username;
auth.details.basic.password = password;
op = TALER_BANK_admin_add_incoming (ctx,
bank_url,
account_base_url,
&auth,
"https://exchange.com/legacy",
subject,
&reserve_pub,
&amount,
debit_account_no,
credit_account_no,
credit_account,
&res_cb,
NULL);
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
@ -219,26 +224,20 @@ main (int argc, char *const *argv)
(GNUNET_GETOPT_option_string ('b',
"bank",
"URL",
"base URL of the bank",
&bank_url)),
"base URL of the account at the bank",
&account_base_url)),
GNUNET_GETOPT_option_help ("Deposit funds into a Taler reserve"),
GNUNET_GETOPT_option_mandatory
(GNUNET_GETOPT_option_ulong ('C',
(GNUNET_GETOPT_option_string ('C',
"credit",
"ACCOUNT",
"number of the bank account to credit",
&credit_account_no)),
GNUNET_GETOPT_option_mandatory
(GNUNET_GETOPT_option_ulong ('D',
"debit",
"ACCOUNT",
"number of the bank account to debit",
&debit_account_no)),
"payto URL of the bank account to credit",
&credit_account)),
GNUNET_GETOPT_option_mandatory
(GNUNET_GETOPT_option_string ('s',
"subject",
"STRING",
"specifies the wire transfer subject",
"specifies the wire transfer subject (must be a reserve public key)",
&subject)),
GNUNET_GETOPT_option_mandatory
(GNUNET_GETOPT_option_string ('u',

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2016, 2017 GNUnet e.V.
Copyright (C) 2016-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
Copyright (C) 2018-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
@ -16,13 +16,11 @@
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file bank-lib/testing_api_cmd_history.c
* @brief command to check the /history API from the bank.
* @author Marcello Stanisci
*/
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
@ -40,35 +38,26 @@
struct HistoryState
{
/**
* Base URL of the bank offering the "history" operation.
* Base URL of the account offering the "history" operation.
*/
const char *bank_url;
char *account_url;
/**
* Account number to ask the history for.
*/
uint64_t account_no;
/**
* Which type of records we are interested: in-transfers
* / out-transfers / rejected transfers.
*/
enum TALER_BANK_Direction direction;
/**
* First row number we want in the result.
* Reference to command defining the
* first row number we want in the result.
*/
const char *start_row_reference;
/**
* How many rows we want in the result, _at most_.
* How many rows we want in the result, _at most_,
* and ascending/descending.
*/
unsigned long long num_results;
long long num_results;
/**
* Handle to a pending "history" operation.
*/
struct TALER_BANK_HistoryHandle *hh;
struct TALER_BANK_CreditHistoryHandle *hh;
/**
* Expected number of results (= rows).
@ -81,34 +70,9 @@ struct HistoryState
*/
int failed;
/**
* If GNUNET_YES, this parameter will ask for results in
* chronological order.
*/
unsigned int ascending;
/**********************************
* Following defs are specific to *
* the "/history-range" version. *
**********************************/
/**
* Last row number we want in the result. Only used
* as a trait source when using the /history-range API.
*/
const char *end_row_reference;
/**
* Start date for /history-range.
*/
struct GNUNET_TIME_Absolute start_date;
/**
* End date for /history-range.
*/
struct GNUNET_TIME_Absolute end_date;
};
/**
* Item in the transaction history, as reconstructed from the
* command history.
@ -119,7 +83,7 @@ struct History
/**
* Wire details.
*/
struct TALER_BANK_TransferDetails details;
struct TALER_BANK_CreditDetails details;
/**
* Serial ID of the wire transfer.
@ -127,19 +91,12 @@ struct History
uint64_t row_id;
/**
* Direction of the transfer.
* URL to free.
*/
enum TALER_BANK_Direction direction;
char *url;
};
/**
* Array mapping bank account numbers to login credentials.
*/
extern struct TALER_BANK_AuthenticationData AUTHS[];
/**
* Offer internal data to other commands.
*
@ -166,51 +123,6 @@ history_traits (void *cls,
}
/**
* Test if the CMD at offset @a off has been /rejected, and
* is indeed a wire transfer CMD.
*
* @param is interpreter state (where we are right now)
* @param off offset of the command to test for rejection.
*
* @return GNUNET_YES if the command at @a off was cancelled.
*/
static int
test_cancelled (struct TALER_TESTING_Interpreter *is,
unsigned int off)
{
const char *rejected_reference;
const struct TALER_TESTING_Command *current_cmd;
current_cmd = &is->commands[off];
TALER_LOG_INFO ("Is `%s' rejected?\n",
current_cmd->label);
for (int i = 0; i<is->ip; i++)
{
const struct TALER_TESTING_Command *c = &is->commands[i];
/* XXX: Errors reported here are NOT fatal */
/* Rejected wire transfers have a non-NULL reference to a
* reject command to mark them as rejected. So errors
* about "reject traits" not found are NOT fatal here */
if (GNUNET_OK != TALER_TESTING_get_trait_rejected
(c, 0, &rejected_reference))
continue;
TALER_LOG_INFO ("Command `%s' was rejected by `%s'.\n",
current_cmd->label,
c->label);
if (0 == strcmp (rejected_reference,
current_cmd->label))
return GNUNET_YES;
}
return GNUNET_NO;
}
/**
* Free history @a h of length @a h_len.
*
@ -222,10 +134,7 @@ free_history (struct History *h,
uint64_t h_len)
{
for (uint64_t off = 0; off<h_len; off++)
{
GNUNET_free (h[off].details.wire_transfer_subject);
GNUNET_free (h[off].details.account_url);
}
GNUNET_free (h[off].url);
GNUNET_free_non_null (h);
}
@ -251,14 +160,12 @@ print_expected (struct History *h,
for (uint64_t i = 0; i<h_len; i++)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"H(%llu): %s%s (serial: %llu, subject: %s,"
"H(%llu): %s (serial: %llu, subject: %s,"
" counterpart: %s)\n",
(unsigned long long) i,
(TALER_BANK_DIRECTION_CREDIT == h[i].direction) ?
"+" : "-",
TALER_amount2s (&h[i].details.amount),
(unsigned long long) h[i].row_id,
h[i].details.wire_transfer_subject,
TALER_B2S (&h[i].details.reserve_pub),
h[i].details.account_url);
}
}
@ -280,20 +187,6 @@ build_history_hit_limit (uint64_t total,
const struct HistoryState *hs,
const struct TALER_TESTING_Command *pos)
{
/* "/history-range" case. */
if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
hs->start_date.abs_value_us)
{
const struct GNUNET_TIME_Absolute *timestamp;
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_absolute_time (pos,
0,
&timestamp));
GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
hs->end_date.abs_value_us);
return timestamp->abs_value_us >= hs->end_date.abs_value_us;
}
return total >= hs->num_results;
}
@ -305,13 +198,6 @@ build_history_hit_limit (uint64_t total,
* to be allocated, and the second to actually populate every
* element.
*
* This command has a limitation currently: it orders the history
* list with descending elements if and only if the 'delta' was
* given negative; and will order the list with ascending elements
* if and only if the 'delta' was given positive. Therefore,
* for now it is NOT possible to test such a "/history" request:
* "/history?auth=basic&direction=both&delta=10&ordering=descending"
*
* @param is interpreter state (supposedly having the
* current CMD pointing at a "history" CMD).
* @param[out] rh history array to initialize.
@ -350,10 +236,7 @@ build_history (struct TALER_TESTING_Interpreter *is,
(add_incoming_cmd, 0, &row_id_start));
}
GNUNET_assert ((0 != hs->num_results) || /* "/history" */
(GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != /* "/history-range" */
hs->start_date.abs_value_us));
GNUNET_assert (0 != hs->num_results);
if (0 == is->ip)
{
TALER_LOG_DEBUG ("Checking history at first CMD..\n");
@ -387,8 +270,9 @@ build_history (struct TALER_TESTING_Interpreter *is,
for (unsigned int off = start; off != end + inc; off += inc)
{
const struct TALER_TESTING_Command *pos = &is->commands[off];
int cancelled;
const uint64_t *row_id;
const char *credit_account;
const char *debit_account;
/**
* The following command allows us to skip over those CMDs
@ -411,28 +295,6 @@ build_history (struct TALER_TESTING_Interpreter *is,
}
}
/* Seek "/history-range" starting row, _if_ that's the case */
if ((GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
hs->start_date.abs_value_us) && (GNUNET_YES != ok))
{
const struct GNUNET_TIME_Absolute *timestamp;
TALER_TESTING_get_trait_absolute_time (pos,
0,
&timestamp);
TALER_LOG_DEBUG
("Seeking first row, start vs timestamp: %llu vs %llu\n",
(long long unsigned int) hs->start_date.abs_value_us,
(long long unsigned int) timestamp->abs_value_us);
if (hs->start_date.abs_value_us <= timestamp->abs_value_us)
{
total = 0;
ok = GNUNET_YES;
continue;
}
}
/* when 'start' was _not_ given, then ok == GNUNET_YES */
if (GNUNET_NO == ok)
continue; /* skip until we find the marker */
@ -447,37 +309,23 @@ build_history (struct TALER_TESTING_Interpreter *is,
break;
}
cancelled = test_cancelled (is, off);
if ( (GNUNET_YES == cancelled) &&
(0 == (hs->direction & TALER_BANK_DIRECTION_CANCEL)) )
{
TALER_LOG_INFO ("Ignoring canceled wire"
" transfer from history\n");
continue;
}
const uint64_t *credit_account_no;
const uint64_t *debit_account_no;
GNUNET_assert
(GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT
(pos, &credit_account_no));
(pos, &credit_account));
GNUNET_assert
(GNUNET_OK == TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT
(pos, &debit_account_no));
(pos, &debit_account));
TALER_LOG_INFO ("Potential history element:"
" %llu->%llu; my account: %llu\n",
(unsigned long long) *debit_account_no,
(unsigned long long) *credit_account_no,
(unsigned long long) hs->account_no);
" %s->%s; my account: %s\n",
debit_account,
credit_account,
hs->account_url);
if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
(hs->account_no == *credit_account_no)) ||
( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
(hs->account_no == *debit_account_no)) )
if (0 == strcasecmp (hs->account_url,
credit_account))
{
TALER_LOG_INFO ("+1 my history\n");
total++; /* found matching record */
@ -508,11 +356,10 @@ build_history (struct TALER_TESTING_Interpreter *is,
for (unsigned int off = start; off != end + inc; off += inc)
{
const struct TALER_TESTING_Command *pos = &is->commands[off];
int cancelled;
const uint64_t *row_id;
char *bank_hostname;
const uint64_t *credit_account_no;
const uint64_t *debit_account_no;
const char *credit_account;
const char *debit_account;
if (GNUNET_OK != TALER_TESTING_GET_TRAIT_ROW_ID
(pos, &row_id))
@ -533,28 +380,6 @@ build_history (struct TALER_TESTING_Interpreter *is,
}
}
/* Seek "/history-range" starting row, _if_ that's the case */
if ((GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
hs->start_date.abs_value_us) && (GNUNET_YES != ok))
{
const struct GNUNET_TIME_Absolute *timestamp;
TALER_TESTING_get_trait_absolute_time (pos,
0,
&timestamp);
TALER_LOG_DEBUG
("Seeking first row, start vs timestamp (2): %llu vs %llu\n",
(long long unsigned int) hs->start_date.abs_value_us,
(long long unsigned int) timestamp->abs_value_us);
if (hs->start_date.abs_value_us <= timestamp->abs_value_us)
{
total = 0;
ok = GNUNET_YES;
continue;
}
}
TALER_LOG_INFO ("Found first row (2)\n");
if (GNUNET_NO == ok)
@ -574,43 +399,31 @@ build_history (struct TALER_TESTING_Interpreter *is,
GNUNET_assert
(GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT
(pos, &credit_account_no));
(pos, &credit_account));
GNUNET_assert
(GNUNET_OK == TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT
(pos, &debit_account_no));
(pos, &debit_account));
TALER_LOG_INFO ("Potential history bit:"
" %llu->%llu; my account: %llu\n",
(unsigned long long) *debit_account_no,
(unsigned long long) *credit_account_no,
(unsigned long long) hs->account_no);
" %s->%s; my account: %s\n",
debit_account,
credit_account,
hs->account_url);
/**
* Discard transactions where the audited account played
* _both_ the credit and the debit roles, but _only if_
* the audit goes on both directions.. This needs more
* explaination!
*/if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
(hs->account_no == *credit_account_no)) &&
( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
(hs->account_no == *debit_account_no)) )
*/if (0 == strcasecmp (hs->account_url,
credit_account))
{
GNUNET_break (0);
continue;
}
cancelled = test_cancelled (is, off);
if ( (GNUNET_YES == cancelled) &&
(0 == (hs->direction & TALER_BANK_DIRECTION_CANCEL)) )
{
TALER_LOG_WARNING ("`%s' was cancelled\n",
TALER_TESTING_interpreter_get_current_label
(is));
continue;
}
bank_hostname = strchr (hs->bank_url, ':');
bank_hostname = strchr (hs->account_url, ':');
GNUNET_assert (NULL != bank_hostname);
bank_hostname += 3;
@ -618,68 +431,36 @@ build_history (struct TALER_TESTING_Interpreter *is,
* information. */
/* Asked for credit, and account got the credit. */
if ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
(hs->account_no == *credit_account_no))
if (0 == strcasecmp (hs->account_url,
credit_account))
{
h[total].direction = TALER_BANK_DIRECTION_CREDIT;
if (GNUNET_YES == cancelled)
h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
GNUNET_asprintf
(&h[total].details.account_url,
('/' == bank_hostname[strlen (bank_hostname) - 1])
? "payto://x-taler-bank/%s%llu"
: "payto://x-taler-bank/%s/%llu",
bank_hostname,
(unsigned long long) *debit_account_no);
}
/* Asked for debit, and account got the debit. */
if ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
(hs->account_no == *debit_account_no))
{
h[total].direction = TALER_BANK_DIRECTION_DEBIT;
if (GNUNET_YES == cancelled)
h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
GNUNET_asprintf
(&h[total].details.account_url,
('/' == bank_hostname[strlen (bank_hostname) - 1])
? "payto://x-taler-bank/%s%llu"
: "payto://x-taler-bank/%s/%llu",
bank_hostname,
(unsigned long long) *credit_account_no);
h[total].url = GNUNET_strdup (debit_account);
h[total].details.account_url = h[total].url;
}
/* This block _completes_ the information of the current item,
* with amount / subject / exchange URL. */
if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
(hs->account_no == *credit_account_no)) ||
( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
(hs->account_no == *debit_account_no)) )
if (0 == strcasecmp (hs->account_url,
credit_account))
{
const struct TALER_Amount *amount;
const char *subject;
const char *exchange_url;
const struct TALER_ReservePublicKeyP *reserve_pub;
const char *account_url;
GNUNET_assert
(GNUNET_OK == TALER_TESTING_get_trait_amount_obj
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_amount_obj
(pos, 0, &amount));
GNUNET_assert
(GNUNET_OK == TALER_TESTING_get_trait_transfer_subject
(pos, 0, &subject));
GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_url
(pos, 0, &exchange_url));
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_reserve_pub
(pos, 0, &reserve_pub));
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_url
(pos, 1,
&account_url));
h[total].details.amount = *amount;
h[total].row_id = *row_id;
GNUNET_asprintf (&h[total].details.wire_transfer_subject,
"%s %s",
subject,
exchange_url);
h[total].details.reserve_pub = *reserve_pub;
h[total].details.account_url = account_url;
TALER_LOG_INFO ("+1-bit of my history\n");
total++;
}
@ -723,8 +504,7 @@ compute_result_count (struct TALER_TESTING_Interpreter *is)
static int
check_result (struct TALER_TESTING_Interpreter *is,
unsigned int off,
enum TALER_BANK_Direction dir,
const struct TALER_BANK_TransferDetails *details)
const struct TALER_BANK_CreditDetails *details)
{
uint64_t total;
struct History *h;
@ -737,27 +517,22 @@ check_result (struct TALER_TESTING_Interpreter *is,
" results, but got result #%u to check\n",
(unsigned int) total,
off);
print_expected (h, total, off);
print_expected (h,
total,
off);
return GNUNET_SYSERR;
}
if (h[off].direction != dir)
{
GNUNET_break (0);
print_expected (h, total, off);
free_history (h,
total);
return GNUNET_SYSERR;
}
if ( (0 != strcmp (h[off].details.wire_transfer_subject,
details->wire_transfer_subject)) ||
if ( (0 != GNUNET_memcmp (&h[off].details.reserve_pub,
&details->reserve_pub)) ||
(0 != TALER_amount_cmp (&h[off].details.amount,
&details->amount)) ||
(0 != strcasecmp (h[off].details.account_url,
details->account_url)) )
{
GNUNET_break (0);
print_expected (h, total, off);
print_expected (h,
total,
off);
free_history (h,
total);
return GNUNET_SYSERR;
@ -789,22 +564,30 @@ check_result (struct TALER_TESTING_Interpreter *is,
* @param details details about the wire transfer.
* @param json detailed response from the HTTPD, or NULL if
* reply was not in JSON.
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
*/
static void
static int
history_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
enum TALER_BANK_Direction dir,
uint64_t row_id,
const struct TALER_BANK_TransferDetails *details,
const struct TALER_BANK_CreditDetails *details,
const json_t *json)
{
struct TALER_TESTING_Interpreter *is = cls;
struct HistoryState *hs = is->commands[is->ip].cls;
(void) row_id;
/*NOTE: "204 No Content" is used to signal the end of results.*/
if (MHD_HTTP_NO_CONTENT == http_status)
if (MHD_HTTP_OK != http_status)
{
hs->hh = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unwanted response code from /history: %u\n",
http_status);
TALER_TESTING_interpreter_fail (is);
return GNUNET_SYSERR;
}
if (NULL == details)
{
hs->hh = NULL;
if ( (hs->results_obtained != compute_result_count (is)) ||
@ -829,33 +612,20 @@ history_cb (void *cls,
free_history (h,
total);
TALER_TESTING_interpreter_fail (is);
return;
return GNUNET_SYSERR;
}
TALER_TESTING_interpreter_next (is);
return;
}
if (MHD_HTTP_OK != http_status)
{
hs->hh = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unwanted response code from /history[-range]: %u\n",
http_status);
TALER_TESTING_interpreter_fail (is);
return;
return GNUNET_OK;
}
/* check current element */
if (GNUNET_OK != check_result (is,
hs->results_obtained,
dir,
details))
{
GNUNET_break (0);
{
char *acc;
GNUNET_break (0);
acc = json_dumps (json,
JSON_COMPACT);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -864,12 +634,11 @@ history_cb (void *cls,
acc);
if (NULL != acc)
free (acc);
}
hs->failed = GNUNET_YES;
return;
return GNUNET_SYSERR;
}
hs->results_obtained++;
return GNUNET_OK;
}
@ -886,9 +655,8 @@ history_run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct HistoryState *hs = cls;
uint64_t row_id = UINT64_MAX;
const uint64_t *row_id_ptr = &row_id;
struct TALER_BANK_AuthenticationData *auth;
uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX;
const uint64_t *row_ptr;
(void) cmd;
/* Get row_id from trait. */
@ -902,23 +670,20 @@ history_run (void *cls,
if (NULL == history_cmd)
TALER_TESTING_FAIL (is);
if (GNUNET_OK != TALER_TESTING_get_trait_uint64 (history_cmd,
if (GNUNET_OK !=
TALER_TESTING_get_trait_uint64 (history_cmd,
0,
&row_id_ptr))
&row_ptr))
TALER_TESTING_FAIL (is);
row_id = *row_id_ptr;
else
row_id = *row_ptr;
TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
(unsigned long long) row_id);
}
auth = &AUTHS[hs->account_no - 1];
hs->hh = TALER_BANK_history (is->ctx,
hs->bank_url,
auth,
hs->account_no,
hs->direction,
hs->ascending,
hs->hh = TALER_BANK_credit_history (is->ctx,
hs->account_url,
NULL,
row_id,
hs->num_results,
&history_cb,
@ -944,8 +709,9 @@ history_cleanup (void *cls,
if (NULL != hs->hh)
{
TALER_LOG_WARNING ("/history did not complete\n");
TALER_BANK_history_cancel (hs->hh);
TALER_BANK_credit_history_cancel (hs->hh);
}
GNUNET_free (hs->account_url);
GNUNET_free (hs);
}
@ -954,12 +720,8 @@ history_cleanup (void *cls,
* Make a "history" CMD.
*
* @param label command label.
* @param bank_url base URL of the bank offering the "history"
* @param account_url base URL of the account offering the "history"
* operation.
* @param account_no bank account number to ask the history for.
* @param direction which direction this operation is interested.
* @param ascending if #GNUNET_YES, the bank will return the rows
* in ascending (= chronological) order.
* @param start_row_reference reference to a command that can
* offer a row identifier, to be used as the starting row
* to accept in the result.
@ -967,25 +729,17 @@ history_cleanup (void *cls,
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_bank_history (const char *label,
const char *bank_url,
uint64_t account_no,
enum TALER_BANK_Direction direction,
unsigned int ascending,
TALER_TESTING_cmd_bank_credits (const char *label,
const char *account_url,
const char *start_row_reference,
unsigned long long num_results)
long long num_results)
{
struct HistoryState *hs;
hs = GNUNET_new (struct HistoryState);
hs->bank_url = bank_url;
hs->account_no = account_no;
hs->direction = direction;
hs->account_url = GNUNET_strdup (account_url);
hs->start_row_reference = start_row_reference;
hs->num_results = num_results;
hs->ascending = ascending;
hs->start_date = GNUNET_TIME_UNIT_FOREVER_ABS;
hs->end_date = GNUNET_TIME_UNIT_FOREVER_ABS;
{
struct TALER_TESTING_Command cmd = {
@ -1001,4 +755,4 @@ TALER_TESTING_cmd_bank_history (const char *label,
}
/* end of testing_api_cmd_history.c */
/* end of testing_api_cmd_credit_history.c */

View File

@ -0,0 +1,758 @@
/*
This file is part of TALER
Copyright (C) 2018-2020 Taler Systems SA
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 Foundation; either version 3, or
(at your option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file bank-lib/testing_api_cmd_history.c
* @brief command to check the /history API from the bank.
* @author Marcello Stanisci
*/
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "taler_exchange_service.h"
#include "taler_testing_lib.h"
#include "taler_testing_bank_lib.h"
#include "taler_fakebank_lib.h"
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
/**
* State for a "history" CMD.
*/
struct HistoryState
{
/**
* Base URL of the account offering the "history" operation.
*/
const char *account_url;
/**
* Reference to command defining the
* first row number we want in the result.
*/
const char *start_row_reference;
/**
* How many rows we want in the result, _at most_,
* and ascending/descending.
*/
long long num_results;
/**
* Handle to a pending "history" operation.
*/
struct TALER_BANK_DebitHistoryHandle *hh;
/**
* Expected number of results (= rows).
*/
uint64_t results_obtained;
/**
* Set to GNUNET_YES if the callback detects something
* unexpected.
*/
int failed;
};
/**
* Item in the transaction history, as reconstructed from the
* command history.
*/
struct History
{
/**
* Wire details.
*/
struct TALER_BANK_DebitDetails details;
/**
* Serial ID of the wire transfer.
*/
uint64_t row_id;
/**
* URL to free.
*/
char *url;
};
/**
* Offer internal data to other commands.
*
* @param cls closure.
* @param ret[out] set to the wanted data.
* @param trait name of the trait.
* @param index index number of the traits to be returned.
*
* @return #GNUNET_OK on success
*/
static int
history_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
(void) cls;
(void) ret;
(void) trait;
(void) index;
/* Must define this function because some callbacks
* look for certain traits on _all_ the commands. */
return GNUNET_SYSERR;
}
/**
* Free history @a h of length @a h_len.
*
* @param h history array to free.
* @param h_len number of entries in @a h.
*/
static void
free_history (struct History *h,
uint64_t h_len)
{
for (uint64_t off = 0; off<h_len; off++)
GNUNET_free (h[off].url);
GNUNET_free_non_null (h);
}
/**
* Log which history we expected. Called when an error occurs.
*
* @param h what we expected.
* @param h_len number of entries in @a h.
* @param off position of the missmatch.
*/
static void
print_expected (struct History *h,
uint64_t h_len,
unsigned int off)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Transaction history missmatch at position %u/%llu\n",
off,
(unsigned long long) h_len);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Expected history:\n");
for (uint64_t i = 0; i<h_len; i++)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"H(%llu): %s (serial: %llu, subject: %s,"
" counterpart: %s)\n",
(unsigned long long) i,
TALER_amount2s (&h[i].details.amount),
(unsigned long long) h[i].row_id,
TALER_B2S (&h[i].details.wtid),
h[i].details.account_url);
}
}
/**
* Tell if the current item is beyond the allowed limit.
*
* @param total current number of items in the built history list.
* Note, this is the list we build locally and compare with
* what the server returned.
* @param hs the history CMD state.
* @param pos current item to be evaluated or not (if the list
* has already enough elements).
* @return GNUNET_OK / GNUNET_NO.
*/
static int
build_history_hit_limit (uint64_t total,
const struct HistoryState *hs,
const struct TALER_TESTING_Command *pos)
{
return total >= hs->num_results;
}
/**
* This function constructs the list of history elements that
* interest the account number of the caller. It has two main
* loops: the first to figure out how many history elements have
* to be allocated, and the second to actually populate every
* element.
*
* @param is interpreter state (supposedly having the
* current CMD pointing at a "history" CMD).
* @param[out] rh history array to initialize.
*
* @return number of entries in @a rh.
*/
static uint64_t
build_history (struct TALER_TESTING_Interpreter *is,
struct History **rh)
{
struct HistoryState *hs = is->commands[is->ip].cls;
uint64_t total;
struct History *h;
const struct TALER_TESTING_Command *add_incoming_cmd;
int inc;
unsigned int start;
unsigned int end;
/**
* @var turns GNUNET_YES whenever either no 'start' value was
* given for the history query, or the given value is found
* in the list of all the CMDs.
*/int ok;
const uint64_t *row_id_start = NULL;
if (NULL != hs->start_row_reference)
{
TALER_LOG_INFO
("`%s': start row given via reference `%s'\n",
TALER_TESTING_interpreter_get_current_label (is),
hs->start_row_reference);
add_incoming_cmd = TALER_TESTING_interpreter_lookup_command
(is, hs->start_row_reference);
GNUNET_assert (NULL != add_incoming_cmd);
GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_uint64
(add_incoming_cmd, 0, &row_id_start));
}
GNUNET_assert (0 != hs->num_results);
if (0 == is->ip)
{
TALER_LOG_DEBUG ("Checking history at first CMD..\n");
*rh = NULL;
return 0;
}
/* AKA 'delta'. */
if (hs->num_results > 0)
{
inc = 1; /* _inc_rement */
start = 0;
end = is->ip - 1;
}
else
{
inc = -1;
start = is->ip - 1;
end = 0;
}
total = 0;
ok = GNUNET_NO;
if (NULL == row_id_start)
ok = GNUNET_YES;
/* This loop counts how many commands _later than "start"_ belong
* to the history of the caller. This is stored in the @var total
* variable. */
for (unsigned int off = start; off != end + inc; off += inc)
{
const struct TALER_TESTING_Command *pos = &is->commands[off];
const uint64_t *row_id;
const char *debit_account;
const char *credit_account;
/**
* The following command allows us to skip over those CMDs
* that do not offer a "row_id" trait. Such skipped CMDs are
* not interesting for building a history.
*/if (GNUNET_OK != TALER_TESTING_get_trait_uint64 (pos,
0,
&row_id))
continue;
/* Seek "/history" starting row. */
if (NULL != row_id_start)
{
if (*row_id_start == *row_id)
{
/* Doesn't count, start is excluded from output. */
total = 0;
ok = GNUNET_YES;
continue;
}
}
/* when 'start' was _not_ given, then ok == GNUNET_YES */
if (GNUNET_NO == ok)
continue; /* skip until we find the marker */
TALER_LOG_DEBUG ("Found first row\n");
if (build_history_hit_limit (total,
hs,
pos))
{
TALER_LOG_DEBUG ("Hit history limit\n");
break;
}
GNUNET_assert
(GNUNET_OK == TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT
(pos, &debit_account));
GNUNET_assert
(GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT
(pos, &credit_account));
TALER_LOG_INFO ("Potential history element:"
" %s->%s; my account: %s\n",
debit_account,
credit_account,
hs->account_url);
if (0 == strcasecmp (hs->account_url,
debit_account))
{
TALER_LOG_INFO ("+1 my history\n");
total++; /* found matching record */
}
}
GNUNET_assert (GNUNET_YES == ok);
if (0 == total)
{
TALER_LOG_DEBUG ("Checking history at first CMD.. (2)\n");
*rh = NULL;
return 0;
}
GNUNET_assert (total < UINT_MAX);
h = GNUNET_new_array ((unsigned int) total,
struct History);
total = 0;
ok = GNUNET_NO;
if (NULL == row_id_start)
ok = GNUNET_YES;
/**
* This loop _only_ populates the array of history elements.
*/
for (unsigned int off = start; off != end + inc; off += inc)
{
const struct TALER_TESTING_Command *pos = &is->commands[off];
const uint64_t *row_id;
char *bank_hostname;
const char *credit_account;
const char *debit_account;
if (GNUNET_OK != TALER_TESTING_GET_TRAIT_ROW_ID
(pos, &row_id))
continue;
if (NULL != row_id_start)
{
if (*row_id_start == *row_id)
{
/**
* Warning: this zeroing is superfluous, as
* total doesn't get incremented if 'start'
* was given and couldn't be found.
*/total = 0;
ok = GNUNET_YES;
continue;
}
}
TALER_LOG_INFO ("Found first row (2)\n");
if (GNUNET_NO == ok)
{
TALER_LOG_INFO ("Skip on `%s'\n",
pos->label);
continue; /* skip until we find the marker */
}
if (build_history_hit_limit (total,
hs,
pos))
{
TALER_LOG_INFO ("Hit history limit (2)\n");
break;
}
GNUNET_assert
(GNUNET_OK == TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT
(pos, &debit_account));
GNUNET_assert
(GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT
(pos, &credit_account));
TALER_LOG_INFO ("Potential history bit:"
" %s->%s; my account: %s\n",
debit_account,
credit_account,
hs->account_url);
/**
* Discard transactions where the audited account played
* _both_ the debit and the debit roles, but _only if_
* the audit goes on both directions.. This needs more
* explaination!
*/if (0 == strcasecmp (hs->account_url,
debit_account))
{
GNUNET_break (0);
continue;
}
bank_hostname = strchr (hs->account_url, ':');
GNUNET_assert (NULL != bank_hostname);
bank_hostname += 3;
/* Next two blocks only put the 'direction' and 'banking'
* information. */
/* Asked for debit, and account got the debit. */
if (0 == strcasecmp (hs->account_url,
debit_account))
{
h[total].url = GNUNET_strdup (credit_account);
h[total].details.account_url = h[total].url;
}
/* This block _completes_ the information of the current item,
* with amount / subject / exchange URL. */
if (0 == strcasecmp (hs->account_url,
debit_account))
{
const struct TALER_Amount *amount;
const struct TALER_WireTransferIdentifierRawP *wtid;
const char *account_url;
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_amount_obj
(pos, 0, &amount));
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_wtid
(pos, 0, &wtid));
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_url
(pos, 1,
&account_url));
h[total].details.amount = *amount;
h[total].row_id = *row_id;
h[total].details.wtid = *wtid;
h[total].details.account_url = account_url;
TALER_LOG_INFO ("+1-bit of my history\n");
total++;
}
}
*rh = h;
return total;
}
/**
* Compute how many results we expect to be returned for
* the current command at @a is.
*
* @param is the interpreter state to inspect.
* @return number of results expected.
*/
static uint64_t
compute_result_count (struct TALER_TESTING_Interpreter *is)
{
uint64_t total;
struct History *h;
total = build_history (is, &h);
free_history (h, total);
return total;
}
/**
* Check that the "/history" response matches the
* CMD whose offset in the list of CMDs is @a off.
*
* @param is the interpreter state.
* @param off the offset (of the CMD list) where the command
* to check is.
* @param dir the expected direction of the transaction.
* @param details the expected transaction details.
*
* @return #GNUNET_OK if the transaction is what we expect.
*/
static int
check_result (struct TALER_TESTING_Interpreter *is,
unsigned int off,
const struct TALER_BANK_DebitDetails *details)
{
uint64_t total;
struct History *h;
total = build_history (is, &h);
if (off >= total)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Test says history has at most %u"
" results, but got result #%u to check\n",
(unsigned int) total,
off);
print_expected (h,
total,
off);
return GNUNET_SYSERR;
}
if ( (0 != GNUNET_memcmp (&h[off].details.wtid,
&details->wtid)) ||
(0 != TALER_amount_cmp (&h[off].details.amount,
&details->amount)) ||
(0 != strcasecmp (h[off].details.account_url,
details->account_url)) )
{
GNUNET_break (0);
print_expected (h,
total,
off);
free_history (h,
total);
return GNUNET_SYSERR;
}
free_history (h,
total);
return GNUNET_OK;
}
/**
* This callback will (1) check that the HTTP response code
* is acceptable and (2) that the history is consistent. The
* consistency is checked by going through all the past CMDs,
* reconstructing then the expected history as of those, and
* finally check it against what the bank returned.
*
* @param cls closure.
* @param http_status HTTP response code, #MHD_HTTP_OK (200)
* for successful status request 0 if the bank's reply is
* bogus (fails to follow the protocol),
* #MHD_HTTP_NO_CONTENT if there are no more results; on
* success the last callback is always of this status
* (even if `abs(num_results)` were already returned).
* @param ec taler status code.
* @param dir direction of the transfer.
* @param row_id monotonically increasing counter corresponding to
* the transaction.
* @param details details about the wire transfer.
* @param json detailed response from the HTTPD, or NULL if
* reply was not in JSON.
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
*/
static int
history_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
uint64_t row_id,
const struct TALER_BANK_DebitDetails *details,
const json_t *json)
{
struct TALER_TESTING_Interpreter *is = cls;
struct HistoryState *hs = is->commands[is->ip].cls;
(void) row_id;
if (MHD_HTTP_OK != http_status)
{
hs->hh = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unwanted response code from /history: %u\n",
http_status);
TALER_TESTING_interpreter_fail (is);
return GNUNET_SYSERR;
}
if (NULL == details)
{
hs->hh = NULL;
if ( (hs->results_obtained != compute_result_count (is)) ||
(GNUNET_YES == hs->failed) )
{
uint64_t total;
struct History *h;
GNUNET_break (0);
total = build_history (is, &h);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Expected history of length %llu, got %llu;"
" HTTP status code: %u/%d, failed: %d\n",
(unsigned long long) total,
(unsigned long long) hs->results_obtained,
http_status,
(int) ec,
hs->failed);
print_expected (h,
total,
UINT_MAX);
free_history (h,
total);
TALER_TESTING_interpreter_fail (is);
return GNUNET_SYSERR;
}
TALER_TESTING_interpreter_next (is);
return GNUNET_OK;
}
/* check current element */
if (GNUNET_OK != check_result (is,
hs->results_obtained,
details))
{
char *acc;
GNUNET_break (0);
acc = json_dumps (json,
JSON_COMPACT);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Result %u was `%s'\n",
(unsigned int) hs->results_obtained++,
acc);
if (NULL != acc)
free (acc);
hs->failed = GNUNET_YES;
return GNUNET_SYSERR;
}
hs->results_obtained++;
return GNUNET_OK;
}
/**
* Run the command.
*
* @param cls closure.
* @param cmd the command to execute.
* @param is the interpreter state.
*/
static void
history_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct HistoryState *hs = cls;
uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX;
const uint64_t *row_ptr;
(void) cmd;
/* Get row_id from trait. */
if (NULL != hs->start_row_reference)
{
const struct TALER_TESTING_Command *history_cmd;
history_cmd = TALER_TESTING_interpreter_lookup_command
(is, hs->start_row_reference);
if (NULL == history_cmd)
TALER_TESTING_FAIL (is);
if (GNUNET_OK !=
TALER_TESTING_get_trait_uint64 (history_cmd,
0,
&row_ptr))
TALER_TESTING_FAIL (is);
else
row_id = *row_ptr;
TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
(unsigned long long) row_id);
}
hs->hh = TALER_BANK_debit_history (is->ctx,
hs->account_url,
NULL,
row_id,
hs->num_results,
&history_cb,
is);
GNUNET_assert (NULL != hs->hh);
}
/**
* Free the state from a "history" CMD, and possibly cancel
* a pending operation thereof.
*
* @param cls closure.
* @param cmd the command which is being cleaned up.
*/
static void
history_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct HistoryState *hs = cls;
(void) cmd;
if (NULL != hs->hh)
{
TALER_LOG_WARNING ("/history did not complete\n");
TALER_BANK_debit_history_cancel (hs->hh);
}
GNUNET_free (hs);
}
/**
* Make a "history" CMD.
*
* @param label command label.
* @param account_url base URL of the account offering the "history"
* operation.
* @param start_row_reference reference to a command that can
* offer a row identifier, to be used as the starting row
* to accept in the result.
* @param num_results how many rows we want in the result.
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_bank_debits (const char *label,
const char *account_url,
const char *start_row_reference,
long long num_results)
{
struct HistoryState *hs;
hs = GNUNET_new (struct HistoryState);
hs->account_url = account_url;
hs->start_row_reference = start_row_reference;
hs->num_results = num_results;
{
struct TALER_TESTING_Command cmd = {
.label = label,
.cls = hs,
.run = &history_run,
.cleanup = &history_cleanup,
.traits = &history_traits
};
return cmd;
}
}
/* end of testing_api_cmd_history_debit.c */

View File

@ -1,223 +0,0 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
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 Foundation; either version 3, or
(at your option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file bank-lib/testing_api_cmd_reject.c
* @brief command to check the /reject API from the bank.
* @author Marcello Stanisci
*/
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "taler_exchange_service.h"
#include "taler_testing_lib.h"
#include "taler_fakebank_lib.h"
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
/**
* State for a "reject" CMD.
*/
struct RejectState
{
/**
* Handle of a ongoing "reject" operation.
*/
struct TALER_BANK_RejectHandle *rh;
/**
* Reference to any command that can offer a wire
* transfer "row id" and its credit account so as
* to give input data to the "reject" operation.
*/
const char *deposit_reference;
/**
* Base URL of the bank implementing the "reject"
* operation.
*/
const char *bank_url;
};
/**
* Check that the response code from the "reject" opetation
* is acceptable, namely it equals "204 No Content".
*
* @param cls closure.
* @param http_status HTTP response code.
* @param ec taler-specific error code.
*/
static void
reject_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec)
{
struct TALER_TESTING_Interpreter *is = cls;
struct RejectState *rs = is->commands[is->ip].cls;
rs->rh = NULL;
if (MHD_HTTP_NO_CONTENT != http_status)
{
GNUNET_break (0);
fprintf (stderr,
"Unexpected response code %u/%d\n",
http_status,
(int) ec);
TALER_TESTING_interpreter_fail (is);
return;
}
TALER_TESTING_interpreter_next (is);
}
/**
* Cleanup the state of a "reject" CMD, and possibly
* cancel a pending operation thereof.
*
* @param cls closure.
* @param cmd the command.
*/
static void
reject_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct RejectState *rs = cls;
(void) cmd;
if (NULL != rs->rh)
{
TALER_LOG_WARNING ("/reject did not complete\n");
TALER_BANK_reject_cancel (rs->rh);
}
GNUNET_free (rs);
}
/**
* Run the command.
*
* @param cls closure.
* @param cmd the command to execute.
* @param is the interpreter state.
*/
static void
reject_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct RejectState *rs = cls;
const struct TALER_TESTING_Command *deposit_cmd;
const uint64_t *credit_account;
const uint64_t *row_id;
extern struct TALER_BANK_AuthenticationData AUTHS[];
(void) cmd;
deposit_cmd
= TALER_TESTING_interpreter_lookup_command (is,
rs->deposit_reference);
if (NULL == deposit_cmd)
TALER_TESTING_FAIL (is);
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT (deposit_cmd,
&credit_account));
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_GET_TRAIT_ROW_ID (deposit_cmd,
&row_id));
TALER_LOG_INFO ("Account %llu rejects deposit\n",
(unsigned long long) *credit_account);
rs->rh = TALER_BANK_reject (is->ctx,
rs->bank_url,
&AUTHS[*credit_account - 1],
*credit_account,
*row_id,
&reject_cb,
is);
GNUNET_assert (NULL != rs->rh);
}
/**
* Offer internal data from a "reject" CMD to other commands.
*
* @param cls closure.
* @param ret[out] result.
* @param trait name of the trait.
* @param index index number of the trait to return.
*
* @return #GNUNET_OK on success.
*/
static int
reject_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
struct RejectState *rs = cls;
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_rejected (0, rs->deposit_reference),
TALER_TESTING_trait_end ()
};
return TALER_TESTING_get_trait (traits,
ret,
trait,
index);
}
/**
* Create a "reject" CMD.
*
* @param label command label.
* @param bank_url base URL of the bank implementing the
* "reject" operation.
* @param deposit_reference reference to a command that will
* provide a "row id" and credit (bank) account to craft
* the "reject" request.
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_bank_reject (const char *label,
const char *bank_url,
const char *deposit_reference)
{
struct RejectState *rs;
rs = GNUNET_new (struct RejectState);
rs->bank_url = bank_url;
rs->deposit_reference = deposit_reference;
{
struct TALER_TESTING_Command cmd = {
.cls = rs,
.run = &reject_run,
.cleanup = &reject_cleanup,
.label = label,
.traits = &reject_traits
};
return cmd;
}
}
/* end of testing_api_cmd_reject.c */

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
(C) 2014-2019 Taler Systems SA
(C) 2014-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as
@ -16,15 +16,13 @@
along with TALER; see the file COPYING. If not,
see <http://www.gnu.org/licenses/>
*/
/**
* @file merchant/backend/taler-merchant-httpd.c
* @file benchmark/taler-exchange-benchmark.c
* @brief HTTP serving layer intended to perform crypto-work and
* communication with the exchange
* @author Marcello Stanisci
* @author Christian Grothoff
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include <microhttpd.h>
@ -58,23 +56,14 @@ enum BenchmarkError
*/
#define UNITY_SIZE 6
/**
* Account number of the merchant. Fakebank likes any number,
* the only requirement is that this number then matches the
* number given when building payto URLs at deposit time.
*/
#define TALER_TESTING_USER_ACCOUNT_NUMBER 3
#define FIRST_INSTRUCTION -1
#define CMD_TRANSFER_TO_EXCHANGE(label, amount) \
TALER_TESTING_cmd_fakebank_transfer_retry \
(TALER_TESTING_cmd_fakebank_transfer (label, amount, \
exchange_bank_account.details. \
x_taler_bank.bank_base_url, \
TALER_TESTING_USER_ACCOUNT_NUMBER, \
exchange_bank_account.details. \
x_taler_bank.no, \
user_bank_account.details. \
x_taler_bank.account_base_url, \
exchange_payto_url, \
"dummy_user", \
"dummy_password", \
"http://example.com/"))
@ -107,6 +96,11 @@ enum BenchmarkMode
*/
static struct TALER_Account exchange_bank_account;
/**
* Hold information about a user at the bank.
*/
static struct TALER_Account user_bank_account;
/**
* Time snapshot taken right before executing the CMDs.
*/
@ -168,6 +162,11 @@ static enum BenchmarkMode mode;
*/
static char *cfg_filename;
/**
* payto://-URL of the exchange's bank account.
*/
static char *exchange_payto_url;
/**
* Currency used.
*/
@ -405,12 +404,12 @@ stop_fakebank (void *cls)
static void
launch_fakebank (void *cls)
{
const char *bank_base_url = cls;
const char *hostname = cls;
const char *port;
long pnum;
struct TALER_FAKEBANK_Handle *fakebank;
port = strrchr (bank_base_url,
port = strrchr (hostname,
(unsigned char) ':');
if (NULL == port)
pnum = 80;
@ -419,7 +418,7 @@ launch_fakebank (void *cls)
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Starting Fakebank on port %u (%s)\n",
(unsigned int) pnum,
bank_base_url);
hostname);
fakebank = TALER_FAKEBANK_start ((uint16_t) pnum);
if (NULL == fakebank)
{
@ -466,8 +465,7 @@ parallel_benchmark (TALER_TESTING_Main main_cb,
NULL == loglev ? "INFO" : loglev,
logfile);
GNUNET_SCHEDULER_run (&launch_fakebank,
exchange_bank_account.details.x_taler_bank.
bank_base_url);
exchange_bank_account.details.x_taler_bank.hostname);
exit (0);
}
if (-1 == fakebank)
@ -824,10 +822,36 @@ main (int argc,
return BAD_CLI_ARG;
}
{
char *user_payto_url;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string
(cfg,
"benchmark",
"user-url",
&user_payto_url))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"benchmark",
"user-url");
return BAD_CONFIG_FILE;
}
if (TALER_EC_NONE !=
TALER_WIRE_payto_to_account (user_payto_url,
&user_bank_account))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_ ("Malformed payto:// URL `%s' in configuration\n"),
user_payto_url);
GNUNET_free (user_payto_url);
return BAD_CONFIG_FILE;
}
GNUNET_free (user_payto_url);
}
{
const char *bank_details_section;
char *exchange_payto_url;
GNUNET_CONFIGURATION_iterate_sections
(cfg,
@ -873,7 +897,6 @@ main (int argc,
GNUNET_free (exchange_payto_url);
return BAD_CONFIG_FILE;
}
GNUNET_free (exchange_payto_url);
}
if ( (MODE_EXCHANGE == mode) || (MODE_BOTH == mode) )
{

View File

@ -23,7 +23,9 @@ taler_wire_SOURCES = \
taler-wire.c
taler_wire_LDADD = \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/wire/libtalerwire.la \
-lgnunetcurl \
-lgnunetutil
taler_exchange_keyup_SOURCES = \
@ -32,6 +34,7 @@ taler_exchange_keyup_LDADD = \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/pq/libtalerpq.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/exchangedb/libtalerexchangedb.la \
-lgnunetutil $(XLIB)
@ -44,6 +47,7 @@ taler_exchange_wire_LDADD = \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/exchangedb/libtalerexchangedb.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunetjson \

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2018 Taler Systems SA
Copyright (C) 2014-2020 Taler Systems SA
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
@ -923,17 +923,17 @@ exchange_keys_update_denomkeys ()
* Sign @a af with @a priv
*
* @param[in,out] af fee structure to sign
* @param wireplugin name of the plugin for which we sign
* @param method name of the wire method for which we sign
* @param priv private key to use for signing
*/
static void
sign_af (struct TALER_EXCHANGEDB_AggregateFees *af,
const char *wireplugin,
const char *method,
const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
{
struct TALER_MasterWireFeePS wf;
TALER_EXCHANGEDB_fees_2_wf (wireplugin,
TALER_EXCHANGEDB_fees_2_wf (method,
af,
&wf);
GNUNET_assert (GNUNET_OK ==
@ -1101,28 +1101,15 @@ create_wire_fee_by_account (void *cls,
const struct TALER_EXCHANGEDB_AccountInfo *ai)
{
int *ret = cls;
struct TALER_WIRE_Plugin *plugin;
if (GNUNET_NO == ai->credit_enabled)
return;
plugin = TALER_WIRE_plugin_load (kcfg,
ai->plugin_name);
if (NULL == plugin)
{
fprintf (stderr,
"Failed to load wire plugin `%s' configured for account `%s'\n",
ai->plugin_name,
ai->section_name);
*ret = GNUNET_SYSERR;
return;
}
/* We may call this function repeatedly for the same method
if there are multiple accounts with plugins using the
same method, but except for some minor performance loss,
this is harmless. */
create_wire_fee_for_method (ret,
plugin->method);
TALER_WIRE_plugin_unload (plugin);
ai->method);
}

View File

@ -22,11 +22,10 @@
* @author Marcello Stanisci
* @author Christian Grothoff
*/
#include <platform.h>
#include <gnunet/gnunet_util_lib.h>
#include "taler_util.h"
#include "taler_wire_lib.h"
#include "taler_bank_service.h"
/**
* If set to #GNUNET_YES, then we'll ask the bank for a list
@ -36,16 +35,11 @@
static int history;
/**
* If set to GNUNET_YES, then we'll ask the bank to execute a
* If set to #GNUNET_YES, then we'll ask the bank to execute a
* wire transfer.
*/
static int transfer;
/**
* Name of the wire plugin to use with the bank.
*/
static char *plugin_name;
/**
* Global return code.
*/
@ -59,11 +53,9 @@ static unsigned int global_ret = 1;
static char *amount;
/**
* Base32 encoding of a transaction ID. When asking the
* bank for a transaction history, all the results will
* have a transaction ID settled *after* this one.
* Starting row.
*/
static char *since_when;
static unsigned long long start_row;
/**
* Which config section has the credentials to access the bank.
@ -77,19 +69,29 @@ static char *account_section;
static char *destination_account_url;
/**
* Handle for the wire transfer preparation task.
* Handle for executing the wire transfer.
*/
static struct TALER_WIRE_PrepareHandle *ph;
/**
* Wire plugin handle.
*/
static struct TALER_WIRE_Plugin *plugin_handle;
static struct TALER_BANK_WireExecuteHandle *eh;
/**
* Handle to ongoing history operation.
*/
static struct TALER_WIRE_HistoryHandle *hh;
static struct TALER_BANK_CreditHistoryHandle *hh;
/**
* For authentication.
*/
static struct TALER_BANK_AuthenticationData auth;
/**
* Handle to the context for interacting with the bank.
*/
static struct GNUNET_CURL_Context *ctx;
/**
* Scheduler context for running the @e ctx.
*/
static struct GNUNET_CURL_RescheduleContext *rc;
/**
@ -108,16 +110,16 @@ static struct TALER_WIRE_HistoryHandle *hh;
*/
static int
history_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
enum TALER_BANK_Direction dir,
const void *row_off,
size_t row_off_size,
const struct TALER_WIRE_TransferDetails *details)
uint64_t serial_id,
const struct TALER_BANK_CreditDetails *details,
const json_t *json)
{
char *row_off_enc;
(void) cls;
if (TALER_BANK_DIRECTION_NONE == dir)
(void) ec;
(void) http_status;
if (NULL == details)
{
fprintf (stdout,
"End of transactions list.\n");
@ -126,15 +128,9 @@ history_cb (void *cls,
return GNUNET_NO;
}
row_off_enc = GNUNET_STRINGS_data_to_string_alloc (row_off,
row_off_size);
/* Give more details on screen (??) */
fprintf (stdout,
"%s\n",
row_off_enc);
GNUNET_free (row_off_enc);
"%llu\n",
(unsigned long long) serial_id);
return GNUNET_OK;
}
@ -142,71 +138,36 @@ history_cb (void *cls,
/**
* Callback that processes the outcome of a wire transfer
* execution.
*
* @param cls closure
* @param response_code HTTP status code
* @param ec taler error code
* @param row_id unique ID of the wire transfer in the bank's records
* @param timestamp when did the transaction go into effect
*/
static void
confirmation_cb (void *cls,
int success,
const void *row_id,
size_t row_id_size,
const char *emsg)
unsigned int response_code,
enum TALER_ErrorCode ec,
uint64_t row_id,
struct GNUNET_TIME_Absolute timestamp)
{
if (GNUNET_YES != success)
if (MHD_HTTP_OK != response_code)
{
fprintf (stderr,
"The wire transfer didn't execute correctly.\n");
GNUNET_assert (NULL != emsg);
fprintf (stderr,
"%s",
emsg);
"The wire transfer didn't execute correctly (%d).\n",
ec);
GNUNET_SCHEDULER_shutdown ();
return;
}
fprintf (stdout,
"Wire transfer executed successfully.\n");
global_ret = 0;
GNUNET_SCHEDULER_shutdown ();
}
/**
* Takes prepared blob and executes the wire-transfer.
*
* @param cls NULL.
* @param buf prepared wire transfer data.
* @param buf_size size of the prepared wire transfer data.
*/
static void
prepare_cb (void *cls,
const char *buf,
size_t buf_size)
{
struct TALER_WIRE_ExecuteHandle *eh;
if (NULL == (eh = plugin_handle->execute_wire_transfer
(plugin_handle->cls,
buf,
buf_size,
confirmation_cb,
NULL)))
{
fprintf (stderr,
"Could not execute the wire transfer\n");
plugin_handle->prepare_wire_transfer_cancel
(plugin_handle->cls,
ph);
plugin_handle->execute_wire_transfer_cancel
(plugin_handle->cls,
eh);
GNUNET_SCHEDULER_shutdown ();
}
}
/**
* Ask the bank to execute a wire transfer.
*/
@ -215,6 +176,8 @@ execute_wire_transfer ()
{
struct TALER_Amount a;
struct TALER_WireTransferIdentifierRawP wtid;
void *buf;
size_t buf_size;
if (NULL == amount)
{
@ -223,7 +186,6 @@ execute_wire_transfer ()
GNUNET_SCHEDULER_shutdown ();
return;
}
if (GNUNET_OK != TALER_string_to_amount (amount,
&a))
{
@ -240,19 +202,25 @@ execute_wire_transfer ()
GNUNET_SCHEDULER_shutdown ();
return;
}
if (NULL == (ph = plugin_handle->prepare_wire_transfer
(plugin_handle->cls,
account_section,
destination_account_url,
TALER_BANK_prepare_wire_transfer (destination_account_url,
&a,
"http://exchange.example.com/",
&wtid, /* Any value will do. */
prepare_cb,
NULL)))
&wtid,
&buf,
&buf_size);
eh = TALER_BANK_execute_wire_transfer (ctx,
destination_account_url,
&auth,
buf,
buf_size,
&confirmation_cb,
NULL);
if (NULL == eh)
{
fprintf (stderr,
"Could not prepare the wire transfer\n");
"Could not execute the wire transfer\n");
GNUNET_SCHEDULER_shutdown ();
return;
}
}
@ -264,30 +232,14 @@ execute_wire_transfer ()
static void
execute_history ()
{
size_t bin_len = 0;
void *since_when_bin = NULL;
if (NULL != since_when)
{
bin_len = (strlen (since_when) * 5) / 8;
since_when_bin = GNUNET_malloc (bin_len);
GNUNET_assert
(GNUNET_OK == GNUNET_STRINGS_string_to_data
(since_when,
strlen (since_when),
since_when_bin,
bin_len));
}
if (NULL == (hh = plugin_handle->get_history (plugin_handle->cls,
account_section,
TALER_BANK_DIRECTION_BOTH,
since_when_bin,
bin_len,
hh = TALER_BANK_credit_history (ctx,
destination_account_url,
&auth,
start_row,
-10,
&history_cb,
NULL)))
NULL);
if (NULL == hh)
{
fprintf (stderr,
"Could not request the transaction history.\n");
@ -305,19 +257,27 @@ execute_history ()
static void
do_shutdown (void *cls)
{
if (NULL != ctx)
{
GNUNET_CURL_fini (ctx);
ctx = NULL;
}
if (NULL != rc)
{
GNUNET_CURL_gnunet_rc_destroy (rc);
rc = NULL;
}
if (NULL != hh)
{
plugin_handle->get_history_cancel (plugin_handle->cls,
hh);
TALER_BANK_credit_history_cancel (hh);
hh = NULL;
}
if (NULL != ph)
if (NULL != eh)
{
plugin_handle->prepare_wire_transfer_cancel (plugin_handle->cls,
ph);
ph = NULL;
TALER_BANK_execute_wire_transfer_cancel (eh);
eh = NULL;
}
TALER_WIRE_plugin_unload (plugin_handle);
TALER_BANK_auth_free (&auth);
}
@ -342,27 +302,18 @@ run (void *cls,
"The option: -s ACCOUNT-SECTION, is mandatory.\n");
return;
}
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string
(cfg,
if (GNUNET_OK !=
TALER_BANK_auth_parse_cfg (cfg,
account_section,
"plugin",
&plugin_name))
&auth))
{
fprintf (stderr,
"Could not find the 'plugin' value under %s\n",
"Authentication information not found in configuration section `%s'\n",
account_section);
GNUNET_SCHEDULER_shutdown ();
return;
}
plugin_handle = TALER_WIRE_plugin_load (cfg,
plugin_name);
if (NULL == plugin_handle)
{
fprintf (stderr,
"Could not load the wire plugin\n");
return;
}
if (GNUNET_YES == history)
execute_history ();
@ -372,6 +323,14 @@ run (void *cls,
fprintf (stderr,
"Please give either --history/-H or --transfer/t\n");
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
&rc);
rc = GNUNET_CURL_gnunet_rc_create (ctx);
if (NULL == ctx)
{
GNUNET_break (0);
return;
}
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
NULL);
}
@ -400,7 +359,7 @@ main (int argc,
"transfer",
"Execute a wire transfer.",
&transfer),
GNUNET_GETOPT_option_string ('w',
GNUNET_GETOPT_option_ulong ('w',
"since-when",
"SW",
"When asking the bank for"
@ -410,12 +369,13 @@ main (int argc,
" after SW. If not given, then"
" the 10 youngest transactions"
" are returned.",
&since_when),
GNUNET_GETOPT_option_string ('s',
&start_row),
GNUNET_GETOPT_option_mandatory
(GNUNET_GETOPT_option_string ('s',
"section",
"ACCOUNT-SECTION",
"Which config section has the credentials to access the bank. Mandatory.\n",
&account_section),
&account_section)),
GNUNET_GETOPT_option_string ('a',
"amount",
"AMOUNT",

View File

@ -29,9 +29,11 @@ taler_exchange_aggregator_LDADD = \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/exchangedb/libtalerexchangedb.la \
-ljansson \
-lgnunetcurl \
-lgnunetutil
taler_exchange_wirewatch_SOURCES = \
@ -40,9 +42,11 @@ taler_exchange_wirewatch_LDADD = \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/exchangedb/libtalerexchangedb.la \
-ljansson \
-lgnunetcurl \
-lgnunetutil
taler_exchange_httpd_SOURCES = \
@ -66,6 +70,7 @@ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd_validation.c taler-exchange-httpd_validation.h
taler_exchange_httpd_LDADD = \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/mhd/libtalermhd.la \
$(top_builddir)/src/json/libtalerjson.la \

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2016-2018 Taler Systems SA
Copyright (C) 2016-2020 Taler Systems SA
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
@ -26,6 +26,7 @@
#include "taler_exchangedb_lib.h"
#include "taler_exchangedb_plugin.h"
#include "taler_json_lib.h"
#include "taler_bank_service.h"
#include "taler_wire_lib.h"
@ -45,9 +46,14 @@ struct WireAccount
struct WireAccount *prev;
/**
* Handle to the plugin.
* Account information.
*/
struct TALER_WIRE_Plugin *wire_plugin;
struct TALER_Account account;
/**
* Authentication data.
*/
struct TALER_BANK_AuthenticationData auth;
/**
* Wire transfer fee structure.
@ -59,6 +65,11 @@ struct WireAccount
*/
char *section_name;
/**
* Name of the wire method underlying the account.
*/
char *method;
};
@ -77,7 +88,7 @@ struct WirePrepareData
/**
* Wire execution handle.
*/
struct TALER_WIRE_ExecuteHandle *eh;
struct TALER_BANK_WireExecuteHandle *eh;
/**
* Wire plugin used for this preparation.
@ -187,10 +198,6 @@ struct AggregationUnit
*/
struct CloseTransferContext
{
/**
* Handle for preparing the wire transfer.
*/
struct TALER_WIRE_PrepareHandle *ph;
/**
* Our database session.
@ -262,6 +269,16 @@ static struct WirePrepareData *wpd;
*/
static struct AggregationUnit *au;
/**
* Handle to the context for interacting with the bank.
*/
static struct GNUNET_CURL_Context *ctx;
/**
* Scheduler context for running the @e ctx.
*/
static struct GNUNET_CURL_RescheduleContext *rc;
/**
* Value to return from main(). #GNUNET_OK on success, #GNUNET_SYSERR
* on serious errors.
@ -339,7 +356,7 @@ update_fees (struct WireAccount *wa,
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
/* Let's try to load it from disk... */
wa->af = TALER_EXCHANGEDB_fees_read (cfg,
wa->wire_plugin->method);
wa->method);
advance_fees (wa,
now);
for (struct TALER_EXCHANGEDB_AggregateFees *p = wa->af;
@ -348,7 +365,7 @@ update_fees (struct WireAccount *wa,
{
qs = db_plugin->insert_wire_fee (db_plugin->cls,
session,
wa->wire_plugin->method,
wa->method,
p->start_date,
p->end_date,
&p->wire_fee,
@ -365,7 +382,7 @@ update_fees (struct WireAccount *wa,
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to find current wire transfer fees for `%s'\n",
wa->wire_plugin->method);
wa->method);
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
}
@ -381,7 +398,7 @@ find_account_by_method (const char *method)
{
for (struct WireAccount *wa = wa_head; NULL != wa; wa = wa->next)
if (0 == strcmp (method,
wa->wire_plugin->method))
wa->method))
return wa;
return NULL;
}
@ -431,13 +448,40 @@ add_account_cb (void *cls,
if (GNUNET_YES != ai->debit_enabled)
return; /* not enabled for us, skip */
wa = GNUNET_new (struct WireAccount);
wa->wire_plugin = TALER_WIRE_plugin_load (cfg,
ai->plugin_name);
if (NULL == wa->wire_plugin)
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
ai->section_name,
"METHOD",
&wa->method))
{
fprintf (stderr,
"Failed to load wire plugin for `%s'\n",
ai->plugin_name);
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
ai->section_name,
"METHOD");
GNUNET_free (wa);
return;
}
if (GNUNET_OK !=
TALER_BANK_auth_parse_cfg (cfg,
ai->section_name,
&wa->auth))
{
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"Failed to load account `%s'\n",
ai->section_name);
GNUNET_free (wa->method);
GNUNET_free (wa);
return;
}
if (GNUNET_OK !=
TALER_BANK_account_parse_cfg (cfg,
ai->section_name,
&wa->account))
{
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"Failed to load account `%s'\n",
ai->section_name);
TALER_BANK_auth_free (&wa->auth);
GNUNET_free (wa->method);
GNUNET_free (wa);
return;
}
@ -476,6 +520,16 @@ static void
shutdown_task (void *cls)
{
(void) cls;
if (NULL != ctx)
{
GNUNET_CURL_fini (ctx);
ctx = NULL;
}
if (NULL != rc)
{
GNUNET_CURL_gnunet_rc_destroy (rc);
rc = NULL;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Running shutdown\n");
if (NULL != task)
@ -487,9 +541,7 @@ shutdown_task (void *cls)
{
if (NULL != wpd->eh)
{
wpd->wa->wire_plugin->execute_wire_transfer_cancel (
wpd->wa->wire_plugin->cls,
wpd->eh);
TALER_BANK_execute_wire_transfer_cancel (wpd->eh);
wpd->eh = NULL;
}
db_plugin->rollback (db_plugin->cls,
@ -499,23 +551,12 @@ shutdown_task (void *cls)
}
if (NULL != au)
{
if (NULL != au->ph)
{
au->wa->wire_plugin->prepare_wire_transfer_cancel (
au->wa->wire_plugin->cls,
au->ph);
au->ph = NULL;
}
db_plugin->rollback (db_plugin->cls,
au->session);
cleanup_au ();
}
if (NULL != ctc)
{
ctc->wa->wire_plugin->prepare_wire_transfer_cancel (
ctc->wa->wire_plugin->cls,
ctc->ph);
ctc->ph = NULL;
db_plugin->rollback (db_plugin->cls,
ctc->session);
GNUNET_free (ctc->method);
@ -532,9 +573,11 @@ shutdown_task (void *cls)
GNUNET_CONTAINER_DLL_remove (wa_head,
wa_tail,
wa);
TALER_WIRE_plugin_unload (wa->wire_plugin);
TALER_WIRE_account_free (&wa->account);
TALER_BANK_auth_free (&wa->auth);
TALER_EXCHANGEDB_fees_free (wa->af);
GNUNET_free (wa->section_name);
GNUNET_free (wa->method);
GNUNET_free (wa);
}
}
@ -921,20 +964,6 @@ aggregate_cb (void *cls,
}
/**
* Function to be called with the prepared transfer data
* when running an aggregation on a merchant.
*
* @param cls closure with the `struct AggregationUnit`
* @param buf transaction data to persist, NULL on error
* @param buf_size number of bytes in @a buf, 0 on error
*/
static void
prepare_cb (void *cls,
const char *buf,
size_t buf_size);
/**
* Main work function that finds and triggers transfers for reserves
* closures.
@ -988,83 +1017,6 @@ commit_or_warn (struct TALER_EXCHANGEDB_Session *session)
}
/**
* Function to be called with the prepared transfer data
* when closing a reserve.
*
* @param cls closure with a `struct CloseTransferContext`
* @param buf transaction data to persist, NULL on error
* @param buf_size number of bytes in @a buf, 0 on error
*/
static void
prepare_close_cb (void *cls,
const char *buf,
size_t buf_size)
{
enum GNUNET_DB_QueryStatus qs;
GNUNET_assert (cls == ctc);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Prepared for reserve closing\n");
ctc->ph = NULL;
if (NULL == buf)
{
GNUNET_break (0); /* why? how to best recover? */
db_plugin->rollback (db_plugin->cls,
ctc->session);
/* start again */
GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
NULL);
return;
}
/* Commit our intention to execute the wire transfer! */
qs = db_plugin->wire_prepare_data_insert (db_plugin->cls,
ctc->session,
ctc->method,
buf,
buf_size);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
{
GNUNET_break (0);
db_plugin->rollback (db_plugin->cls,
ctc->session);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
return;
}
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
{
db_plugin->rollback (db_plugin->cls,
ctc->session);
/* start again */
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
NULL);
GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
return;
}
/* finally commit */
(void) commit_or_warn (ctc->session);
GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Reserve closure committed, running transfer\n");
task = GNUNET_SCHEDULER_add_now (&run_transfers,
NULL);
}
/**
* Closure for #expired_reserve_cb().
*/
@ -1113,6 +1065,8 @@ expired_reserve_cb (void *cls,
int ret;
enum GNUNET_DB_QueryStatus qs;
struct WireAccount *wa;
void *buf;
size_t buf_size;
/* NOTE: potential optimization: use custom SQL API to not
fetch this: */
@ -1121,7 +1075,7 @@ expired_reserve_cb (void *cls,
now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now);
/* lookup wire plugin */
/* lookup account we should use */
wa = find_account_by_url (account_details);
if (NULL == wa)
{
@ -1161,6 +1115,18 @@ expired_reserve_cb (void *cls,
TALER_amount_get_zero (left->currency,
&amount_without_fee));
}
/* round down to enable transfer */
if (GNUNET_SYSERR ==
TALER_WIRE_amount_round (&amount_without_fee))
{
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
return GNUNET_DB_STATUS_HARD_ERROR;
}
if ( (0 == amount_without_fee.value) &&
(0 == amount_without_fee.fraction) )
ret = GNUNET_NO;
/* NOTE: sizeof (*reserve_pub) == sizeof (wtid) right now, but to
be future-compatible, we use the memset + min construction */
@ -1171,7 +1137,7 @@ expired_reserve_cb (void *cls,
reserve_pub,
GNUNET_MIN (sizeof (wtid),
sizeof (*reserve_pub)));
if (GNUNET_SYSERR != ret)
qs = db_plugin->insert_reserve_closed (db_plugin->cls,
session,
reserve_pub,
@ -1180,52 +1146,14 @@ expired_reserve_cb (void *cls,
&wtid,
left,
closing_fee);
else
ret = GNUNET_DB_STATUS_HARD_ERROR;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Closing reserve %s over %s (%d, %d)\n",
TALER_B2S (reserve_pub),
TALER_amount2s (left),
ret,
qs);
if ( (GNUNET_OK == ret) &&
(GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) )
{
/* success, perform wire transfer */
if (GNUNET_SYSERR ==
wa->wire_plugin->amount_round (wa->wire_plugin->cls,
&amount_without_fee))
{
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
return GNUNET_DB_STATUS_HARD_ERROR;
}
ctc = GNUNET_new (struct CloseTransferContext);
ctc->wa = wa;
ctc->session = session;
ctc->method = TALER_WIRE_payto_get_method (account_details);
ctc->ph
= wa->wire_plugin->prepare_wire_transfer (wa->wire_plugin->cls,
wa->section_name,
account_details,
&amount_without_fee,
exchange_base_url,
&wtid,
&prepare_close_cb,
ctc);
if (NULL == ctc->ph)
{
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
return GNUNET_DB_STATUS_HARD_ERROR;
}
erc->async_cont = GNUNET_YES;
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
}
/* Check for hard failure */
if ( (GNUNET_SYSERR == ret) ||
(GNUNET_DB_STATUS_HARD_ERROR == qs) )
@ -1235,12 +1163,61 @@ expired_reserve_cb (void *cls,
GNUNET_SCHEDULER_shutdown ();
return GNUNET_DB_STATUS_HARD_ERROR;
}
if ( (GNUNET_OK != ret) ||
(GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) )
{
/* Reserve balance was almost zero OR soft error */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Reserve was virtually empty, moving on\n");
(void) commit_or_warn (ctc->session);
GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
task = GNUNET_SCHEDULER_add_now (&run_transfers,
NULL);
return qs;
}
/* success, perform wire transfer */
ctc = GNUNET_new (struct CloseTransferContext);
ctc->wa = wa;
ctc->session = session;
ctc->method = TALER_WIRE_payto_get_method (account_details);
TALER_BANK_prepare_wire_transfer (account_details,
&amount_without_fee,
exchange_base_url,
&wtid,
&buf,
&buf_size);
/* Commit our intention to execute the wire transfer! */
qs = db_plugin->wire_prepare_data_insert (db_plugin->cls,
ctc->session,
ctc->method,
buf,
buf_size);
GNUNET_free (buf);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
{
GNUNET_break (0);
GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
return GNUNET_DB_STATUS_HARD_ERROR;
}
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
{
/* start again */
GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
}
erc->async_cont = GNUNET_YES;
task = GNUNET_SCHEDULER_add_now (&run_transfers,
NULL);
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
}
/**
* Main work function that finds and triggers transfers for reserves
@ -1344,6 +1321,8 @@ run_aggregation (void *cls)
struct TALER_EXCHANGEDB_Session *session;
enum GNUNET_DB_QueryStatus qs;
const struct GNUNET_SCHEDULER_TaskContext *tc;
void *buf;
size_t buf_size;
(void) cls;
task = NULL;
@ -1470,8 +1449,7 @@ run_aggregation (void *cls)
&au->total_amount,
&au->wire_fee)) ||
(GNUNET_SYSERR ==
au->wa->wire_plugin->amount_round (au->wa->wire_plugin->cls,
&au->final_amount)) ||
TALER_WIRE_amount_round (&au->final_amount)) ||
( (0 == au->final_amount.value) &&
(0 == au->final_amount.fraction) ) )
{
@ -1555,70 +1533,26 @@ run_aggregation (void *cls)
char *url;
url = TALER_JSON_wire_to_payto (au->wire);
au->ph = au->wa->wire_plugin->prepare_wire_transfer (
au->wa->wire_plugin->cls,
au->wa->section_name,
url,
TALER_BANK_prepare_wire_transfer (url,
&au->final_amount,
exchange_base_url,
&au->wtid,
&prepare_cb,
au);
&buf,
&buf_size);
GNUNET_free (url);
}
if (NULL == au->ph)
{
/* something went very wrong, likely bad configuration,
abort */
db_plugin->rollback (db_plugin->cls,
session);
cleanup_au ();
GNUNET_SCHEDULER_shutdown ();
return;
}
/* otherwise we continue with #prepare_cb(), see below */
}
/**
* Function to be called with the prepared transfer data.
*
* @param cls NULL
* @param buf transaction data to persist, NULL on error
* @param buf_size number of bytes in @a buf, 0 on error
*/
static void
prepare_cb (void *cls,
const char *buf,
size_t buf_size)
{
struct TALER_EXCHANGEDB_Session *session = au->session;
enum GNUNET_DB_QueryStatus qs;
(void) cls;
GNUNET_free_non_null (au->additional_rows);
au->additional_rows = NULL;
if (NULL == buf)
{
GNUNET_break (0); /* why? how to best recover? */
db_plugin->rollback (db_plugin->cls,
session);
/* start again */
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
NULL);
cleanup_au ();
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Storing %u bytes of wire prepare data\n",
(unsigned int) buf_size);
/* Commit our intention to execute the wire transfer! */
qs = db_plugin->wire_prepare_data_insert (db_plugin->cls,
session,
au->wa->wire_plugin->method,
au->wa->method,
buf,
buf_size);
GNUNET_free (buf);
/* Commit the WTID data to 'wire_out' to finally satisfy aggregation
table constraints */
if (qs >= 0)
@ -1691,29 +1625,30 @@ prepare_cb (void *cls,
* Function called with the result from the execute step.
*
* @param cls NULL
* @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure
* @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
* @param emsg NULL on success, otherwise an error message
* @param http_status_code #MHD_HTTP_OK on success
* @param ec taler error code
* @param row_id unique ID of the wire transfer in the bank's records
* @param wire_timestamp when did the transfer happen
*/
static void
wire_confirm_cb (void *cls,
int success,
const void *row_id,
size_t row_id_size,
const char *emsg)
unsigned int http_status_code,
enum TALER_ErrorCode ec,
uint64_t row_id,
struct GNUNET_TIME_Absolute wire_timestamp)
{
struct TALER_EXCHANGEDB_Session *session = wpd->session;
enum GNUNET_DB_QueryStatus qs;
(void) cls;
(void) row_id;
(void) row_id_size;
wpd->eh = NULL;
if (GNUNET_SYSERR == success)
if (MHD_HTTP_OK != http_status_code)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire transaction failed: %s\n",
emsg);
"Wire transaction failed: %u/%d\n",
http_status_code,
ec);
db_plugin->rollback (db_plugin->cls,
session);
global_ret = GNUNET_SYSERR;
@ -1792,6 +1727,8 @@ wire_prepare_cb (void *cls,
const char *buf,
size_t buf_size)
{
struct WireAccount *wa;
(void) cls;
wpd->row_id = rowid;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@ -1811,8 +1748,11 @@ wire_prepare_cb (void *cls,
wpd = NULL;
return;
}
wpd->eh = wpd->wa->wire_plugin->execute_wire_transfer (
wpd->wa->wire_plugin->cls,
wa = wpd->wa;
wpd->eh = TALER_BANK_execute_wire_transfer (ctx,
wa->account.details.x_taler_bank.
account_base_url,
&wa->auth,
buf,
buf_size,
&wire_confirm_cb,
@ -1927,6 +1867,7 @@ run (void *cls,
(void) cls;
(void) args;
(void) cfgfile;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (c,
"exchange",
@ -1947,6 +1888,15 @@ run (void *cls,
global_ret = 1;
return;
}
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
&rc);
rc = GNUNET_CURL_gnunet_rc_create (ctx);
if (NULL == ctx)
{
GNUNET_break (0);
return;
}
task = GNUNET_SCHEDULER_add_now (&run_transfers,
NULL);
GNUNET_SCHEDULER_add_shutdown (&shutdown_task,

View File

@ -400,7 +400,6 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
json_t *json;
int res;
json_t *wire;
char *emsg;
enum TALER_ErrorCode ec;
unsigned int hc;
struct TALER_EXCHANGEDB_Deposit deposit;
@ -460,18 +459,6 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
"refund_deadline");
}
if (TALER_EC_NONE !=
(ec = TEH_json_validate_wireformat (wire,
&emsg)))
{
GNUNET_JSON_parse_free (spec);
res = TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
ec,
emsg);
GNUNET_free (emsg);
return res;
}
if (GNUNET_OK !=
check_timestamp_current (deposit.timestamp))
{

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2016, 2017, 2018 Taler Systems SA
Copyright (C) 2016-2020 Taler Systems SA
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
@ -29,40 +29,6 @@
#include "taler_wire_lib.h"
/**
* Information we keep for each plugin.
*/
struct Plugin
{
/**
* We keep plugins in a DLL.
*/
struct Plugin *next;
/**
* We keep plugins in a DLL.
*/
struct Plugin *prev;
/**
* Pointer to the plugin.
*/
struct TALER_WIRE_Plugin *plugin;
};
/**
* Head of DLL of wire plugins.
*/
static struct Plugin *wire_head;
/**
* Tail of DLL of wire plugins.
*/
static struct Plugin *wire_tail;
/**
* Array of wire methods supported by this exchange.
*/
@ -191,9 +157,8 @@ load_account (void *cls,
else
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire fees not specified for `%s', ignoring plugin %s\n",
method,
ai->plugin_name);
"Wire fees not specified for `%s'\n",
method);
*ret = GNUNET_SYSERR;
}
GNUNET_free (method);
@ -201,35 +166,15 @@ load_account (void *cls,
if (GNUNET_YES == ai->debit_enabled)
{
struct Plugin *p;
p = GNUNET_new (struct Plugin);
p->plugin = TALER_WIRE_plugin_load (cfg,
ai->plugin_name);
if (NULL == p->plugin)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to load plugin %s\n",
ai->plugin_name);
GNUNET_free (p);
*ret = GNUNET_SYSERR;
return;
}
if (GNUNET_OK !=
load_fee (p->plugin->method))
load_fee (ai->method))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Disabling plugin `%s' as wire transfer fees for `%s' are not given correctly\n",
ai->plugin_name,
p->plugin->method);
TALER_WIRE_plugin_unload (p->plugin);
GNUNET_free (p);
"Wire transfer fees for `%s' are not given correctly\n",
ai->method);
*ret = GNUNET_SYSERR;
return;
}
GNUNET_CONTAINER_DLL_insert (wire_head,
wire_tail,
p);
}
}
@ -251,12 +196,6 @@ TEH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
TALER_EXCHANGEDB_find_accounts (cfg,
&load_account,
&ret);
if (NULL == wire_head)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to find properly configured wire transfer method\n");
ret = GNUNET_SYSERR;
}
if (GNUNET_OK != ret)
TEH_VALIDATION_done ();
return ret;
@ -269,16 +208,6 @@ TEH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
void
TEH_VALIDATION_done ()
{
struct Plugin *p;
while (NULL != (p = wire_head))
{
GNUNET_CONTAINER_DLL_remove (wire_head,
wire_tail,
p);
TALER_WIRE_plugin_unload (p->plugin);
GNUNET_free (p);
}
json_decref (wire_fee_object);
wire_fee_object = NULL;
json_decref (wire_accounts_array);
@ -286,65 +215,6 @@ TEH_VALIDATION_done ()
}
/**
* Check if the given wire format JSON object is correctly formatted as
* a wire address.
*
* @param wire the JSON wire format object
* @param[out] emsg set to error message if we return an error code
* @return #TALER_EC_NONE if correctly formatted; otherwise error code
*/
enum TALER_ErrorCode
TEH_json_validate_wireformat (const json_t *wire,
char **emsg)
{
const char *payto_url;
json_error_t error;
char *method;
*emsg = NULL;
if (0 != json_unpack_ex ((json_t *) wire,
&error, 0,
"{s:s}",
"url", &payto_url))
{
GNUNET_asprintf (emsg,
"No `url' specified in the wire details\n");
return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_MISSING;
}
method = TALER_WIRE_payto_get_method (payto_url);
if (NULL == method)
{
GNUNET_asprintf (emsg,
"Malformed payto URL `%s'\n",
payto_url);
return TALER_EC_PAYTO_MALFORMED;
}
for (struct Plugin *p = wire_head; NULL != p; p = p->next)
{
if (0 == strcasecmp (p->plugin->method,
method))
{
enum TALER_ErrorCode ec;
GNUNET_free (method);
ec = p->plugin->wire_validate (p->plugin->cls,
payto_url);
if (TALER_EC_NONE != ec)
GNUNET_asprintf (emsg,
"Payto URL `%s' rejected by plugin\n",
payto_url);
return ec;
}
}
GNUNET_asprintf (emsg,
"Wire format type `%s' is not supported by this exchange\n",
method);
GNUNET_free (method);
return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_UNSUPPORTED;
}
/**
* Obtain JSON response for /wire
*

View File

@ -27,6 +27,7 @@
#include "taler_exchangedb_lib.h"
#include "taler_exchangedb_plugin.h"
#include "taler_json_lib.h"
#include "taler_bank_service.h"
#include "taler_wire_lib.h"
/**
@ -36,23 +37,6 @@
#define DELAY GNUNET_TIME_UNIT_SECONDS
/**
* Closure for #reject_cb().
*/
struct RejectContext
{
/**
* Wire transfer subject that was illformed.
*/
char *wtid_s;
/**
* Database session that encountered the problem.
*/
struct TALER_EXCHANGEDB_Session *session;
};
/**
* Information we keep for each supported account.
*/
@ -68,16 +52,21 @@ struct WireAccount
*/
struct WireAccount *prev;
/**
* Handle to the plugin.
*/
struct TALER_WIRE_Plugin *wire_plugin;
/**
* Name of the section that configures this account.
*/
char *section_name;
/**
* Account information.
*/
struct TALER_Account account;
/**
* Authentication data.
*/
struct TALER_BANK_AuthenticationData auth;
/**
* Are we running from scratch and should re-process all transactions
* for this account?
@ -107,6 +96,16 @@ static struct WireAccount *wa_tail;
*/
static struct WireAccount *wa_pos;
/**
* Handle to the context for interacting with the bank.
*/
static struct GNUNET_CURL_Context *ctx;
/**
* Scheduler context for running the @e ctx.
*/
static struct GNUNET_CURL_RescheduleContext *rc;
/**
* Which currency is used by this exchange?
*/
@ -132,23 +131,13 @@ static int global_ret;
* Encoded offset in the wire transfer list from where
* to start the next query with the bank.
*/
static void *last_row_off;
/**
* Number of bytes in #last_row_off.
*/
static size_t last_row_off_size;
static uint64_t last_row_off;
/**
* Latest row offset seen in this transaction, becomes
* the new #last_row_off upon commit.
*/
static void *latest_row_off;
/**
* Number of bytes in #latest_row_off.
*/
static size_t latest_row_off_size;
static uint64_t latest_row_off;
/**
* Should we delay the next request to the wire plugin a bit?
@ -183,12 +172,7 @@ static struct GNUNET_SCHEDULER_Task *task;
/**
* Active request for history.
*/
static struct TALER_WIRE_HistoryHandle *hh;
/**
* Active request to reject a wire transfer.
*/
static struct TALER_WIRE_RejectHandle *rt;
static struct TALER_BANK_CreditHistoryHandle *hh;
/**
@ -202,6 +186,16 @@ shutdown_task (void *cls)
struct WireAccount *wa;
(void) cls;
if (NULL != ctx)
{
GNUNET_CURL_fini (ctx);
ctx = NULL;
}
if (NULL != rc)
{
GNUNET_CURL_gnunet_rc_destroy (rc);
rc = NULL;
}
if (NULL != task)
{
GNUNET_SCHEDULER_cancel (task);
@ -209,20 +203,9 @@ shutdown_task (void *cls)
}
if (NULL != hh)
{
wa_pos->wire_plugin->get_history_cancel (wa_pos->wire_plugin->cls,
hh);
TALER_BANK_credit_history_cancel (hh);
hh = NULL;
}
if (NULL != rt)
{
char *wtid_s;
wtid_s = wa_pos->wire_plugin->reject_transfer_cancel (
wa_pos->wire_plugin->cls,
rt);
rt = NULL;
GNUNET_free (wtid_s);
}
TALER_EXCHANGEDB_plugin_unload (db_plugin);
db_plugin = NULL;
while (NULL != (wa = wa_head))
@ -230,14 +213,13 @@ shutdown_task (void *cls)
GNUNET_CONTAINER_DLL_remove (wa_head,
wa_tail,
wa);
TALER_WIRE_plugin_unload (wa->wire_plugin);
TALER_WIRE_account_free (&wa->account);
TALER_BANK_auth_free (&wa->auth);
GNUNET_free (wa->section_name);
GNUNET_free (wa);
}
wa_pos = NULL;
GNUNET_free_non_null (last_row_off);
last_row_off = NULL;
last_row_off_size = 0;
last_row_off = 0;
}
@ -259,13 +241,26 @@ add_account_cb (void *cls,
return; /* not enabled for us, skip */
wa = GNUNET_new (struct WireAccount);
wa->reset_mode = reset_mode;
wa->wire_plugin = TALER_WIRE_plugin_load (cfg,
ai->plugin_name);
if (NULL == wa->wire_plugin)
if (GNUNET_OK !=
TALER_BANK_auth_parse_cfg (cfg,
ai->section_name,
&wa->auth))
{
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"Failed to load wire plugin for `%s'\n",
ai->plugin_name);
"Failed to load account `%s'\n",
ai->section_name);
GNUNET_free (wa);
return;
}
if (GNUNET_OK !=
TALER_BANK_account_parse_cfg (cfg,
ai->section_name,
&wa->account))
{
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"Failed to load account `%s'\n",
ai->section_name);
TALER_BANK_auth_free (&wa->auth);
GNUNET_free (wa);
return;
}
@ -335,71 +330,29 @@ static void
find_transfers (void *cls);
/**
* Function called upon completion of the rejection of a wire transfer.
*
* @param cls closure with the `struct RejectContext`
* @param ec error code for the operation
*/
static void
reject_cb (void *cls,
enum TALER_ErrorCode ec)
{
struct RejectContext *rtc = cls;
enum GNUNET_DB_QueryStatus qs;
rt = NULL;
if (TALER_EC_NONE != ec)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to wire back transfer `%s': %d\n",
rtc->wtid_s,
ec);
GNUNET_free (rtc->wtid_s);
db_plugin->rollback (db_plugin->cls,
rtc->session);
GNUNET_free (rtc);
GNUNET_SCHEDULER_shutdown ();
return;
}
GNUNET_free (rtc->wtid_s);
qs = db_plugin->commit (db_plugin->cls,
rtc->session);
GNUNET_break (0 <= qs);
GNUNET_free (rtc);
task = GNUNET_SCHEDULER_add_now (&find_transfers,
NULL);
}
/**
* Callbacks of this type are used to serve the result of asking
* the bank for the transaction history.
*
* @param cls closure with the `struct TALER_EXCHANGEDB_Session *`
* @param ec taler error code
* @param dir direction of the transfer
* @param row_off identification of the position at which we are querying
* @param row_off_size number of bytes in @a row_off
* @param serial_id identification of the position at which we are querying
* @param details details about the wire transfer
* @param json raw JSON response
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
*/
static int
history_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
enum TALER_BANK_Direction dir,
const void *row_off,
size_t row_off_size,
const struct TALER_WIRE_TransferDetails *details)
uint64_t serial_id,
const struct TALER_BANK_CreditDetails *details,
const json_t *json)
{
struct TALER_EXCHANGEDB_Session *session = cls;
enum GNUNET_DB_QueryStatus qs;
struct TALER_ReservePublicKeyP reserve_pub;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Got history callback, direction %u!\n",
(unsigned int) dir);
if (TALER_BANK_DIRECTION_NONE == dir)
if (NULL == details)
{
hh = NULL;
if (TALER_EC_NONE != ec)
@ -428,11 +381,8 @@ history_cb (void *cls,
if (0 < qs)
{
/* transaction success, update #last_row_off */
GNUNET_free_non_null (last_row_off);
last_row_off = latest_row_off;
last_row_off_size = latest_row_off_size;
latest_row_off = NULL;
latest_row_off_size = 0;
latest_row_off = 0;
/* if successful at limit, try increasing transaction batch size (AIMD) */
if (current_batch_size == batch_size)
@ -462,49 +412,10 @@ history_cb (void *cls,
NULL);
return GNUNET_OK; /* will be ignored anyway */
}
if (NULL != details->wtid_s)
{
struct RejectContext *rtc;
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Wire transfer over %s has invalid subject `%s', sending it back!\n",
TALER_amount2s (&details->amount),
details->wtid_s);
GNUNET_break (0 != row_off_size);
if (latest_row_off_size != row_off_size)
{
GNUNET_free_non_null (latest_row_off);
latest_row_off = GNUNET_malloc (row_off_size);
latest_row_off_size = row_off_size;
}
memcpy (latest_row_off,
row_off,
row_off_size);
rtc = GNUNET_new (struct RejectContext);
rtc->session = session;
rtc->wtid_s = GNUNET_strdup (details->wtid_s);
rt = wa_pos->wire_plugin->reject_transfer (wa_pos->wire_plugin->cls,
wa_pos->section_name,
row_off,
row_off_size,
&reject_cb,
rtc);
if (NULL == rt)
{
GNUNET_break (0);
db_plugin->rollback (db_plugin->cls,
session);
GNUNET_assert (NULL == task);
task = GNUNET_SCHEDULER_add_now (&find_transfers,
NULL);
}
return GNUNET_SYSERR; /* will continue later... */
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Adding wire transfer over %s with (hashed) subject `%s'\n",
TALER_amount2s (&details->amount),
TALER_B2S (&details->wtid));
TALER_B2S (&details->reserve_pub));
/**
* Debug block.
@ -515,8 +426,8 @@ history_cb (void *cls,
char wtid_s[PUBSIZE];
GNUNET_break
(NULL != GNUNET_STRINGS_data_to_string (&details->wtid,
sizeof (details->wtid),
(NULL != GNUNET_STRINGS_data_to_string (&details->reserve_pub,
sizeof (details->reserve_pub),
&wtid_s[0],
PUBSIZE));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@ -525,20 +436,14 @@ history_cb (void *cls,
}
current_batch_size++;
/* Wire transfer identifier == reserve public key */
GNUNET_assert (sizeof (reserve_pub) == sizeof (details->wtid));
memcpy (&reserve_pub,
&details->wtid,
sizeof (reserve_pub));
qs = db_plugin->reserves_in_insert (db_plugin->cls,
session,
&reserve_pub,
&details->reserve_pub,
&details->amount,
details->execution_date,
details->account_url,
wa_pos->section_name,
row_off,
row_off_size);
serial_id);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
{
GNUNET_break (0);
@ -560,15 +465,7 @@ history_cb (void *cls,
return GNUNET_SYSERR;
}
if (latest_row_off_size != row_off_size)
{
GNUNET_free_non_null (latest_row_off);
latest_row_off = GNUNET_malloc (row_off_size);
latest_row_off_size = row_off_size;
}
memcpy (latest_row_off,
row_off,
row_off_size);
latest_row_off = serial_id;
return GNUNET_OK;
}
@ -615,8 +512,7 @@ find_transfers (void *cls)
qs = db_plugin->get_latest_reserve_in_reference (db_plugin->cls,
session,
wa_pos->section_name,
&last_row_off,
&last_row_off_size);
&last_row_off);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -638,17 +534,14 @@ find_transfers (void *cls)
}
}
wa_pos->reset_mode = GNUNET_NO;
GNUNET_assert ( (NULL == last_row_off) ||
( (NULL != last_row_off) &&
(0 != last_row_off_size) ) );
delay = GNUNET_YES;
current_batch_size = 0;
hh = wa_pos->wire_plugin->get_history (wa_pos->wire_plugin->cls,
wa_pos->section_name,
TALER_BANK_DIRECTION_CREDIT,
hh = TALER_BANK_credit_history (ctx,
wa_pos->account.details.x_taler_bank.
account_base_url,
&wa_pos->auth,
last_row_off,
last_row_off_size,
batch_size,
&history_cb,
session);
@ -695,6 +588,14 @@ run (void *cls,
NULL);
GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
cls);
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
&rc);
rc = GNUNET_CURL_gnunet_rc_create (ctx);
if (NULL == ctx)
{
GNUNET_break (0);
return;
}
}

View File

@ -58,7 +58,7 @@ check_for_account (void *cls,
const char *section)
{
struct FindAccountContext *ctx = cls;
char *plugin_name;
char *method;
char *payto_url;
char *wire_response_filename;
struct TALER_EXCHANGEDB_AccountInfo ai;
@ -81,12 +81,12 @@ check_for_account (void *cls,
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (ctx->cfg,
section,
"PLUGIN",
&plugin_name))
"METHOD",
&method))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
section,
"PLUGIN");
"METHOD");
GNUNET_free (payto_url);
return;
}
@ -97,7 +97,7 @@ check_for_account (void *cls,
&wire_response_filename))
wire_response_filename = NULL;
ai.section_name = section;
ai.plugin_name = plugin_name;
ai.method = method;
ai.payto_url = payto_url;
ai.wire_response_filename = wire_response_filename;
@ -112,7 +112,7 @@ check_for_account (void *cls,
ctx->cb (ctx->cb_cls,
&ai);
GNUNET_free (payto_url);
GNUNET_free (plugin_name);
GNUNET_free (method);
GNUNET_free_non_null (wire_response_filename);
}

View File

@ -144,12 +144,12 @@ TALER_EXCHANGEDB_fees_read (const struct GNUNET_CONFIGURATION_Handle *cfg,
/**
* Convert @a af to @a wf.
*
* @param wireplugin name of the wire plugin the fees are for
* @param method name of the wire method the fees are for
* @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 (const char *wireplugin,
TALER_EXCHANGEDB_fees_2_wf (const char *method,
struct TALER_EXCHANGEDB_AggregateFees *af,
struct TALER_MasterWireFeePS *wf)
{
@ -157,8 +157,8 @@ TALER_EXCHANGEDB_fees_2_wf (const char *wireplugin,
(void) GNUNET_TIME_round_abs (&af->end_date);
wf->purpose.size = htonl (sizeof (*wf));
wf->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_WIRE_FEES);
GNUNET_CRYPTO_hash (wireplugin,
strlen (wireplugin) + 1,
GNUNET_CRYPTO_hash (method,
strlen (method) + 1,
&wf->h_wire_method);
wf->start_date = GNUNET_TIME_absolute_hton (af->start_date);
wf->end_date = GNUNET_TIME_absolute_hton (af->end_date);

View File

@ -253,7 +253,7 @@ postgres_create_tables (void *cls)
GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS reserves_in"
"(reserve_in_serial_id BIGSERIAL UNIQUE"
",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE"
",wire_reference BYTEA NOT NULL"
",wire_reference INT8 NOT NULL"
",credit_val INT8 NOT NULL"
",credit_frac INT4 NOT NULL"
",sender_account_details TEXT NOT NULL"
@ -2158,8 +2158,7 @@ reserves_update (void *cls,
* @param sender_account_details account information for the sender (payto://-URL)
* @param exchange_account_section name of the section in the configuration for the exchange's
* account into which the deposit was made
* @param wire_reference unique reference identifying the wire transfer (binary blob)
* @param wire_reference_size number of bytes in @a wire_reference
* @param wire_ref unique reference identifying the wire transfer
* @return transaction status code
*/
static enum GNUNET_DB_QueryStatus
@ -2170,8 +2169,7 @@ postgres_reserves_in_insert (void *cls,
struct GNUNET_TIME_Absolute execution_time,
const char *sender_account_details,
const char *exchange_account_section,
const void *wire_reference,
size_t wire_reference_size)
uint64_t wire_ref)
{
struct PostgresClosure *pg = cls;
enum GNUNET_DB_QueryStatus reserve_exists;
@ -2252,8 +2250,7 @@ postgres_reserves_in_insert (void *cls,
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&reserve.pub),
GNUNET_PQ_query_param_fixed_size (wire_reference,
wire_reference_size),
GNUNET_PQ_query_param_uint64 (&wire_ref),
TALER_PQ_query_param_amount (balance),
GNUNET_PQ_query_param_string (exchange_account_section),
GNUNET_PQ_query_param_string (sender_account_details),
@ -2311,8 +2308,7 @@ postgres_reserves_in_insert (void *cls,
* @param session the database session handle
* @param exchange_account_name name of the section in the exchange's configuration
* for the account that we are tracking here
* @param[out] wire_reference set to unique reference identifying the wire transfer (binary blob)
* @param[out] wire_reference_size set to number of bytes in @a wire_reference
* @param[out] wire_ref set to unique reference identifying the wire transfer
* @return transaction status code
*/
static enum GNUNET_DB_QueryStatus
@ -2320,17 +2316,15 @@ postgres_get_latest_reserve_in_reference (void *cls,
struct TALER_EXCHANGEDB_Session *
session,
const char *exchange_account_name,
void **wire_reference,
size_t *wire_reference_size)
uint64_t *wire_reference)
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (exchange_account_name),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_variable_size ("wire_reference",
wire_reference,
wire_reference_size),
GNUNET_PQ_result_spec_uint64 ("wire_reference",
wire_reference),
GNUNET_PQ_result_spec_end
};
@ -6192,14 +6186,12 @@ reserves_in_serial_helper_cb (void *cls,
char *sender_account_details;
struct GNUNET_TIME_Absolute execution_date;
uint64_t rowid;
void *wire_reference;
size_t wire_reference_size;
uint64_t wire_reference;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
&reserve_pub),
GNUNET_PQ_result_spec_variable_size ("wire_reference",
&wire_reference,
&wire_reference_size),
GNUNET_PQ_result_spec_uint64 ("wire_reference",
&wire_reference),
TALER_PQ_RESULT_SPEC_AMOUNT ("credit",
&credit),
TALER_PQ_result_spec_absolute_time ("execution_date",
@ -6227,7 +6219,6 @@ reserves_in_serial_helper_cb (void *cls,
&credit,
sender_account_details,
wire_reference,
wire_reference_size,
execution_date);
GNUNET_PQ_cleanup_result (rs);
if (GNUNET_OK != ret)

View File

@ -944,8 +944,7 @@ audit_refund_cb (void *cls,
* @param reserve_pub public key of the reserve (also the WTID)
* @param credit amount that was received
* @param sender_account_details information about the sender's bank account
* @param wire_reference unique reference identifying the wire transfer (binary blob)
* @param wire_reference_size number of bytes in @a wire_reference
* @param wire_reference unique reference identifying the wire transfer
* @param execution_date when did we receive the funds
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
@ -955,8 +954,7 @@ audit_reserve_in_cb (void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *credit,
const char *sender_account_details,
const void *wire_reference,
size_t wire_reference_size,
uint64_t wire_reference,
struct GNUNET_TIME_Absolute execution_date)
{
auditor_row_cnt++;
@ -1507,8 +1505,7 @@ run (void *cls)
const char *sndr = "payto://x-taler-bank/localhost:8080/1";
unsigned int matched;
unsigned int cnt;
void *rr;
size_t rr_size;
uint64_t rr;
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Absolute now;
@ -1578,8 +1575,7 @@ run (void *cls)
plugin->get_latest_reserve_in_reference (plugin->cls,
session,
"account-1",
&rr,
&rr_size));
&rr));
now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
@ -1590,17 +1586,13 @@ run (void *cls)
now,
sndr,
"account-1",
"TEST",
4));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_latest_reserve_in_reference (plugin->cls,
session,
"account-1",
&rr,
&rr_size));
FAILIF (4 != rr_size);
FAILIF (0 != memcmp ("TEST", rr, 4));
GNUNET_free (rr);
&rr));
FAILIF (4 != rr);
FAILIF (GNUNET_OK !=
check_reserve (session,
&reserve_pub,
@ -1617,24 +1609,18 @@ run (void *cls)
now,
sndr,
"account-1",
"TEST2",
5));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_latest_reserve_in_reference (plugin->cls,
session,
"account-1",
&rr,
&rr_size));
GNUNET_free (rr);
&rr));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_latest_reserve_in_reference (plugin->cls,
session,
"account-1",
&rr,
&rr_size));
FAILIF (5 != rr_size);
FAILIF (0 != memcmp ("TEST2", rr, 5));
GNUNET_free (rr);
&rr));
FAILIF (5 != rr);
FAILIF (GNUNET_OK !=
check_reserve (session,
&reserve_pub,

View File

@ -31,8 +31,6 @@ talerinclude_HEADERS = \
taler_mhd_lib.h \
taler_pq_lib.h \
taler_signatures.h \
taler_wire_lib.h \
taler_wire_plugin.h \
taler_testing_bank_lib.h
endif

View File

@ -870,7 +870,6 @@ struct TALER_AUDITORDB_Plugin
* @param pp where is the auditor in processing
* @param in_wire_off how far are we in the incoming wire transaction history
* @param out_wire_off how far are we in the outgoing wire transaction history
* @param wire_off_size how many bytes do @a in_wire_off and @a out_wire_off take?
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
@ -883,9 +882,8 @@ struct TALER_AUDITORDB_Plugin
const struct
TALER_AUDITORDB_WireAccountProgressPoint
*pp,
const void *in_wire_off,
const void *out_wire_off,
size_t wire_off_size);
uint64_t in_wire_off,
uint64_t out_wire_off);
/**
@ -899,7 +897,6 @@ struct TALER_AUDITORDB_Plugin
* @param pp where is the auditor in processing
* @param in_wire_off how far are we in the incoming wire transaction history
* @param out_wire_off how far are we in the outgoing wire transaction history
* @param wire_off_size how many bytes do @a in_wire_off and @a out_wire_off take?
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
@ -912,9 +909,8 @@ struct TALER_AUDITORDB_Plugin
const struct
TALER_AUDITORDB_WireAccountProgressPoint
*pp,
const void *in_wire_off,
const void *out_wire_off,
size_t wire_off_size);
uint64_t in_wire_off,
uint64_t out_wire_off);
/**
@ -927,7 +923,6 @@ struct TALER_AUDITORDB_Plugin
* @param[out] pp where is the auditor in processing
* @param[out] in_wire_off how far are we in the incoming wire transaction history
* @param[out] out_wire_off how far are we in the outgoing wire transaction history
* @param[out] wire_off_size how many bytes do @a in_wire_off and @a out_wire_off take?
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
@ -939,9 +934,8 @@ struct TALER_AUDITORDB_Plugin
struct
TALER_AUDITORDB_WireAccountProgressPoint
*pp,
void **in_wire_off,
void **out_wire_off,
size_t *wire_off_size);
uint64_t *in_wire_off,
uint64_t *out_wire_off);
/**

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2015, 2016, 2017 Taler Systems SA
Copyright (C) 2015-2020 Taler Systems SA
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
@ -25,6 +25,7 @@
#include <jansson.h>
#include <gnunet/gnunet_curl_lib.h>
#include "taler_util.h"
#include "taler_wire_lib.h"
#include "taler_error_codes.h"
@ -122,13 +123,11 @@ typedef void
* to the operators of the bank.
*
* @param ctx curl context for the event loop
* @param bank_base_url URL of the bank (used to execute this request)
* @param account_base_url URL of the account (used to execute this request)
* @param auth authentication data to use
* @param exchange_base_url base URL of the exchange (for tracking)
* @param subject wire transfer subject for the transfer
* @param reserve_pub wire transfer subject for the transfer
* @param amount amount that was deposited
* @param debit_account_no account number to withdraw from (53 bits at most)
* @param credit_account_no account number to deposit into (53 bits at most)
* @param credit_account account to deposit into
* @param res_cb the callback to call when the final result for this request is available
* @param res_cb_cls closure for the above callback
* @return NULL
@ -137,13 +136,12 @@ typedef void
*/
struct TALER_BANK_AdminAddIncomingHandle *
TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const char *account_base_url,
const struct TALER_BANK_AuthenticationData *auth,
const char *exchange_base_url,
const char *subject,
const struct
TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *amount,
uint64_t debit_account_no,
uint64_t credit_account_no,
const char *credit_account,
TALER_BANK_AdminAddIncomingResultCallback res_cb,
void *res_cb_cls);
@ -159,53 +157,103 @@ TALER_BANK_admin_add_incoming_cancel (struct
TALER_BANK_AdminAddIncomingHandle *aai);
/**
* Which types of transactions should be (or is being) returned?
*/
enum TALER_BANK_Direction
{
/* ********************* /taler/transfer *********************** */
/**
* Base case, used to indicate errors or end of list.
* Prepare for exeuction of a wire transfer.
*
* @param destination_account_url payto:// URL identifying where to send the money
* @param amount amount to transfer, already rounded
* @param exchange_base_url base URL of this exchange (included in subject
* to facilitate use of tracking API by merchant backend)
* @param wtid wire transfer identifier to use
* @param buf[out] set to transaction data to persist, NULL on error
* @param buf_size[out] set to number of bytes in @a buf, 0 on error
*/
TALER_BANK_DIRECTION_NONE = 0,
/**
* Transactions where the bank account receives money.
*/
TALER_BANK_DIRECTION_CREDIT = 1,
/**
* Transactions where the bank account looses money.
*/
TALER_BANK_DIRECTION_DEBIT = 2,
/**
* Return both types of transactions.
*/
TALER_BANK_DIRECTION_BOTH = (TALER_BANK_DIRECTION_CREDIT
| TALER_BANK_DIRECTION_DEBIT),
/**
* Bit mask that is applied to view transactions that have been
* cancelled. The bit is set for cancelled transactions that are
* returned from /history, and must also be set in order for
* cancelled transactions to show up in the /history.
*/
TALER_BANK_DIRECTION_CANCEL = 4
};
void
TALER_BANK_prepare_wire_transfer (const char *destination_account_url,
const struct TALER_Amount *amount,
const char *exchange_base_url,
const struct
TALER_WireTransferIdentifierRawP *wtid,
void **buf,
size_t *buf_size);
/**
* Handle for querying the bank's transaction history.
* Handle for active wire transfer.
*/
struct TALER_BANK_HistoryHandle;
struct TALER_BANK_WireExecuteHandle;
/**
* Details about a wire transfer.
* Function called with the result from the execute step.
*
* @param cls closure
* @param response_code HTTP status code
* @param ec taler error code
* @param row_id unique ID of the wire transfer in the bank's records
* @param timestamp when did the transaction go into effect
*/
struct TALER_BANK_TransferDetails
typedef void
(*TALER_BANK_ConfirmationCallback)(void *cls,
unsigned int response_code,
enum TALER_ErrorCode ec,
uint64_t row_id,
struct GNUNET_TIME_Absolute timestamp);
/**
* Execute a wire transfer.
*
* @param ctx context for HTTP interaction
* @param bank_base_url URL of the base INCLUDING account number
* @param buf buffer with the prepared execution details
* @param buf_size number of bytes in @a buf
* @param cc function to call upon success
* @param cc_cls closure for @a cc
* @return NULL on error
*/
struct TALER_BANK_WireExecuteHandle *
TALER_BANK_execute_wire_transfer (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const struct
TALER_BANK_AuthenticationData *auth,
const void *buf,
size_t buf_size,
TALER_BANK_ConfirmationCallback cc,
void *cc_cls);
/**
* Abort execution of a wire transfer. For example, because we are
* shutting down. Note that if an execution is aborted, it may or
* may not still succeed. The caller MUST run @e
* execute_wire_transfer again for the same request as soon as
* possilbe, to ensure that the request either ultimately succeeds
* or ultimately fails. Until this has been done, the transaction is
* in limbo (i.e. may or may not have been committed).
*
* @param eh execution to cancel
*/
void
TALER_BANK_execute_wire_transfer_cancel (struct
TALER_BANK_WireExecuteHandle *eh);
/* ********************* /taler/credits *********************** */
/**
* Handle for querying the bank for transactions
* made to the exchange.
*/
struct TALER_BANK_CreditHistoryHandle;
/**
* Details about a wire transfer to the exchange.
*/
struct TALER_BANK_CreditDetails
{
/**
* Amount that was transferred
@ -218,21 +266,22 @@ struct TALER_BANK_TransferDetails
struct GNUNET_TIME_Absolute execution_date;
/**
* Wire transfer subject. Usually a reserve public key
* followed by the base URL of the exchange.
* Reserve public key encoded in the wire
* transfer subject.
*/
char *wire_transfer_subject;
struct TALER_ReservePublicKeyP reserve_pub;
/**
* payto://-URL of the other account that was involved
* payto://-URL of the source account that
* send the funds.
*/
char *account_url;
const char *account_url;
};
/**
* Callbacks of this type are used to serve the result of asking
* the bank for the transaction history.
* the bank for the credit transaction history.
*
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
@ -241,31 +290,27 @@ struct TALER_BANK_TransferDetails
* last callback is always of this status (even if `abs(num_results)` were
* already returned).
* @param ec detailed error code
* @param dir direction of the transfer
* @param serial_id monotonically increasing counter corresponding to the transaction
* @param details details about the wire transfer
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
*/
typedef void
(*TALER_BANK_HistoryResultCallback) (void *cls,
typedef int
(*TALER_BANK_CreditResultCallback) (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
enum TALER_BANK_Direction dir,
uint64_t serial_id,
const struct
TALER_BANK_TransferDetails *details,
TALER_BANK_CreditDetails *details,
const json_t *json);
/**
* Request the wire transfer history of a bank account.
* Request the wire credit history of an exchange's bank account.
*
* @param ctx curl context for the event loop
* @param bank_base_url URL of the bank (used to execute this request)
* @param account_base_url URL of the base INCLUDING account number
* @param auth authentication data to use
* @param account_number which account number should we query
* @param direction what kinds of wire transfers should be returned
* @param ascending if GNUNET_YES, history elements will be returned in chronological order.
* @param start_row from which row on do we want to get results, use UINT64_MAX for the latest; exclusive
* @param num_results how many results do we want; negative numbers to go into the past,
* positive numbers to go into the future starting at @a start_row;
@ -276,16 +321,13 @@ typedef void
* if the inputs are invalid (i.e. zero value for @e num_results).
* In this case, the callback is not called.
*/
struct TALER_BANK_HistoryHandle *
TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
struct TALER_BANK_CreditHistoryHandle *
TALER_BANK_credit_history (struct GNUNET_CURL_Context *ctx,
const char *account_base_url,
const struct TALER_BANK_AuthenticationData *auth,
uint64_t account_number,
enum TALER_BANK_Direction direction,
unsigned int ascending,
uint64_t start_row,
int64_t num_results,
TALER_BANK_HistoryResultCallback hres_cb,
TALER_BANK_CreditResultCallback hres_cb,
void *hres_cb_cls);
@ -297,64 +339,127 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
* @param hh the history request handle
*/
void
TALER_BANK_history_cancel (struct TALER_BANK_HistoryHandle *hh);
TALER_BANK_credit_history_cancel (struct TALER_BANK_CreditHistoryHandle *hh);
/* ********************* /taler/debits *********************** */
/**
* Handle for #TALER_BANK_reject() operation.
* Handle for querying the bank for transactions
* made from the exchange to merchants.
*/
struct TALER_BANK_RejectHandle;
struct TALER_BANK_DebitHistoryHandle;
/**
* Details about a wire transfer made by the exchange
* to a merchant.
*/
struct TALER_BANK_DebitDetails
{
/**
* Amount that was transferred
*/
struct TALER_Amount amount;
/**
* Time of the the transfer
*/
struct GNUNET_TIME_Absolute execution_date;
/**
* Wire transfer identifier used by the exchange.
*/
struct TALER_WireTransferIdentifierRawP wtid;
/**
* Exchange's base URL as given in the wire transfer.
*/
const char *exchange_base_url;
/**
* payto://-URL of the source account that
* send the funds.
*/
const char *account_url;
};
/**
* Callbacks of this type are used to serve the result of asking
* the bank to reject an incoming wire transfer.
* the bank for the debit transaction history.
*
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_NO_CONTENT (204) for successful status request;
* #MHD_HTTP_NOT_FOUND if the rowid is unknown;
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the bank's reply is bogus (fails to follow the protocol),
* #MHD_HTTP_NO_CONTENT if there are no more results; on success the
* last callback is always of this status (even if `abs(num_results)` were
* already returned).
* @param ec detailed error code
* @param serial_id monotonically increasing counter corresponding to the transaction
* @param details details about the wire transfer
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
*/
typedef void
(*TALER_BANK_RejectResultCallback) (void *cls,
typedef int
(*TALER_BANK_DebitResultCallback) (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec);
enum TALER_ErrorCode ec,
uint64_t serial_id,
const struct
TALER_BANK_DebitDetails *details,
const json_t *json);
/**
* Request rejection of a wire transfer, marking it as cancelled and voiding
* its effects.
* Request the wire credit history of an exchange's bank account.
*
* @param ctx curl context for the event loop
* @param bank_base_url URL of the bank (used to execute this request)
* @param bank_base_url URL of the base INCLUDING account number
* @param auth authentication data to use
* @param account_number which account number should we query
* @param rowid transfer to reject
* @param rcb the callback to call with the operation result
* @param rcb_cls closure for @a rcb
* @param start_row from which row on do we want to get results, use UINT64_MAX for the latest; exclusive
* @param num_results how many results do we want; negative numbers to go into the past,
* positive numbers to go into the future starting at @a start_row;
* must not be zero.
* @param hres_cb the callback to call with the transaction history
* @param hres_cb_cls closure for the above callback
* @return NULL
* if the inputs are invalid.
* if the inputs are invalid (i.e. zero value for @e num_results).
* In this case, the callback is not called.
*/
struct TALER_BANK_RejectHandle *
TALER_BANK_reject (struct GNUNET_CURL_Context *ctx,
struct TALER_BANK_DebitHistoryHandle *
TALER_BANK_debit_history (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const struct TALER_BANK_AuthenticationData *auth,
uint64_t account_number,
uint64_t rowid,
TALER_BANK_RejectResultCallback rcb,
void *rcb_cls);
uint64_t start_row,
int64_t num_results,
TALER_BANK_DebitResultCallback hres_cb,
void *hres_cb_cls);
/**
* Cancel an reject request. This function cannot be used on a request
* handle if the response was is already served for it.
* Cancel an history request. This function cannot be used on a request
* handle if the last response (anything with a status code other than
* 200) is already served for it.
*
* @param rh the reject request handle
* @param hh the history request handle
*/
void
TALER_BANK_reject_cancel (struct TALER_BANK_RejectHandle *rh);
TALER_BANK_debit_history_cancel (struct TALER_BANK_DebitHistoryHandle *hh);
/**
* Convenience method for parsing configuration section with bank account data.
*
* @param cfg configuration to parse
* @param section the section with the configuration data
* @param acc[out] set to the account details
* @return #GNUNET_OK on success
*/
int
TALER_BANK_account_parse_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *section,
struct TALER_Account *acc);
/**

View File

@ -425,12 +425,12 @@ TALER_EXCHANGEDB_fees_read (const struct GNUNET_CONFIGURATION_Handle *cfg,
/**
* Convert @a af to @a wf.
*
* @param wireplugin name of the wire plugin the fees are for
* @param wiremethod name of the wire method the fees are for
* @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 (const char *wireplugin,
TALER_EXCHANGEDB_fees_2_wf (const char *wiremethod,
struct TALER_EXCHANGEDB_AggregateFees *af,
struct TALER_MasterWireFeePS *wf);
@ -470,10 +470,9 @@ struct TALER_EXCHANGEDB_AccountInfo
const char *section_name;
/**
* Name of the wire plugin that should be used to access
* the account.
* Name of the wire method used by this account.
*/
const char *plugin_name;
const char *method;
/**
* payto://-URL of the account.

View File

@ -960,8 +960,7 @@ typedef int
* @param reserve_pub public key of the reserve (also the WTID)
* @param credit amount that was received
* @param sender_account_details information about the sender's bank account, in payto://-format
* @param wire_reference unique identifier for the wire transfer (plugin-specific format)
* @param wire_reference_size number of bytes in @a wire_reference
* @param wire_reference unique identifier for the wire transfer
* @param execution_date when did we receive the funds
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
@ -972,8 +971,7 @@ typedef int
TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *credit,
const char *sender_account_details,
const void *wire_reference,
size_t wire_reference_size,
uint64_t wire_reference,
struct GNUNET_TIME_Absolute
execution_date);
@ -1500,8 +1498,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param balance the amount that has to be added to the reserve
* @param execution_time when was the amount added
* @param sender_account_details information about the sender's bank account, in payto://-format
* @param wire_reference unique reference identifying the wire transfer (binary blob)
* @param wire_reference_size number of bytes in @a wire_reference
* @param wire_reference unique reference identifying the wire transfer
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
@ -1512,8 +1509,7 @@ struct TALER_EXCHANGEDB_Plugin
struct GNUNET_TIME_Absolute execution_time,
const char *sender_account_details,
const char *exchange_account_name,
const void *wire_reference,
size_t wire_reference_size);
uint64_t wire_reference);
/**
@ -1521,16 +1517,14 @@ struct TALER_EXCHANGEDB_Plugin
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param db the database connection handle
* @param[out] wire_reference set to unique reference identifying the wire transfer (binary blob)
* @param[out] wire_reference_size set to number of bytes in @a wire_reference
* @param[out] wire_ref set to unique reference identifying the wire transfer
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
(*get_latest_reserve_in_reference)(void *cls,
struct TALER_EXCHANGEDB_Session *db,
const char *exchange_account_name,
void **wire_reference,
size_t *wire_reference_size);
uint64_t *wire_ref);
/**

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
(C) 2016 Inria and GNUnet e.V.
(C) 2016-2020 Taler Systems SA
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
@ -74,8 +74,8 @@ TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h);
*/
uint64_t
TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
uint64_t debit_account,
uint64_t credit_account,
const char *debit_account,
const char *credit_account,
const struct TALER_Amount *amount,
const char *subject,
const char *exchange_base_url);
@ -101,27 +101,12 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
int
TALER_FAKEBANK_check (struct TALER_FAKEBANK_Handle *h,
const struct TALER_Amount *want_amount,
uint64_t want_debit,
uint64_t want_credit,
const char *want_debit,
const char *want_credit,
const char *exchange_base_url,
char **subject);
/**
* Reject incoming wire transfer to account @a credit_account
* as identified by @a rowid.
*
* @param h fake bank handle
* @param rowid identifies transfer to reject
* @param credit_account account number of owner of credited account
* @return #GNUNET_YES on success, #GNUNET_NO if the wire transfer was not found
*/
int
TALER_FAKEBANK_reject_transfer (struct TALER_FAKEBANK_Handle *h,
uint64_t rowid,
uint64_t credit_account);
/**
* Stop running the fake bank.
*

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014 GNUnet e.V.
Copyright (C) 2014-2020 Taler Systems SA
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

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
(C) 2018 Taler Systems SA
(C) 2018-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
@ -103,15 +103,31 @@ TALER_TESTING_has_in_name (const char *prog,
/* ************** Specific interpreter commands ************ */
/**
* Make a "history" CMD.
* Make a credit "history" CMD.
*
* @param label command label.
* @param bank_url base URL of the bank offering the "history"
* @param account_url base URL of the account offering the "history"
* operation.
* @param start_row_reference reference to a command that can
* offer a row identifier, to be used as the starting row
* to accept in the result.
* @param num_results how many rows we want in the result,
* and ascending/descending call
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_bank_credits (const char *label,
const char *account_url,
const char *start_row_reference,
long long num_results);
/**
* Make a debit "history" CMD.
*
* @param label command label.
* @param account_url base URL of the account offering the "history"
* operation.
* @param account_no bank account number to ask the history for.
* @param direction which direction this operation is interested
* @param ascending if #GNUNET_YES, it ask the bank to return results
* in chronological order.
* @param start_row_reference reference to a command that can
* offer a row identifier, to be used as the starting row
* to accept in the result.
@ -119,30 +135,10 @@ TALER_TESTING_has_in_name (const char *prog,
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_bank_history (const char *label,
const char *bank_url,
uint64_t account_no,
enum TALER_BANK_Direction direction,
unsigned int ascending,
TALER_TESTING_cmd_bank_debits (const char *label,
const char *account_url,
const char *start_row_reference,
unsigned long long num_results);
long long num_results);
/**
* Create a "reject" CMD.
*
* @param label command label.
* @param bank_url base URL of the bank implementing the
* "reject" operation.
* @param deposit_reference reference to a command that will
* provide a "row id" and credit (bank) account to craft
* the "reject" request.
*
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_bank_reject (const char *label,
const char *bank_url,
const char *deposit_reference);
#endif

View File

@ -48,18 +48,6 @@
} while (0)
#define TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT(cmd,out) \
TALER_TESTING_get_trait_uint64 (cmd, 0, out)
#define TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT(data) \
TALER_TESTING_make_trait_uint64 (0, data)
#define TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT(cmd,out) \
TALER_TESTING_get_trait_uint64 (cmd, 1, out)
#define TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT(data) \
TALER_TESTING_make_trait_uint64 (1, data)
#define TALER_TESTING_GET_TRAIT_ROW_ID(cmd,out) \
TALER_TESTING_get_trait_uint64 (cmd, 3, out)
@ -67,6 +55,19 @@
TALER_TESTING_make_trait_uint64 (3, data)
#define TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT(cmd,out) \
TALER_TESTING_get_trait_string (cmd, 4, out)
#define TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT(data) \
TALER_TESTING_make_trait_string (4, data)
#define TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT(cmd,out) \
TALER_TESTING_get_trait_string (cmd, 5, out)
#define TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT(data) \
TALER_TESTING_make_trait_string (5, data)
/**
* Allocate and return a piece of wire-details. Combines
* the @a account_no and the @a bank_url to a
@ -715,13 +716,9 @@ TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb,
*
* @param label command label.
* @param amount amount to transfer.
* @param bank_url base URL of the bank that implements this
* wire transer. For simplicity, both credit and debit
* bank account exist at the same bank.
* @param debit_account_no which account (expressed as a number)
* gives money.
* @param credit_account_no which account (expressed as a number)
* receives money.
* @param account_base_url base URL of the account that implements this
* wire transer (which account gives money).
* @param payto_credit_account which account receives money.
* @param auth_username username identifying the @a
* debit_account_no at the bank.
* @param auth_password password for @a auth_username.
@ -734,50 +731,13 @@ TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb,
struct TALER_TESTING_Command
TALER_TESTING_cmd_fakebank_transfer (const char *label,
const char *amount,
const char *bank_url,
uint64_t debit_account_no,
uint64_t credit_account_no,
const char *account_base_url,
const char *payto_credit_account,
const char *auth_username,
const char *auth_password,
const char *exchange_url);
/**
* Create "fakebank transfer" CMD, letting the caller specifying
* the subject line.
*
* @param label command label.
* @param amount amount to transfer.
* @param bank_url base URL of the bank that implements this
* wire transer. For simplicity, both credit and debit
* bank account exist at the same bank.
* @param debit_account_no which account (expressed as a number)
* gives money.
* @param credit_account_no which account (expressed as a number)
* receives money.
*
* @param auth_username username identifying the @a
* debit_account_no at the bank.
* @param auth_password password for @a auth_username.
* @param subject wire transfer's subject line.
* @param exchange_url which exchange is involved in this transfer.
* This data is used for tracking purposes (FIXME: explain
* _how_).
*
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_fakebank_transfer_with_subject (const char *label,
const char *amount,
const char *bank_url,
uint64_t debit_account_no,
uint64_t credit_account_no,
const char *auth_username,
const char *auth_password,
const char *subject,
const char *exchange_url);
/**
* Create "fakebank transfer" CMD, letting the caller specify
* a reference to a command that can offer a reserve private key.
@ -786,11 +746,9 @@ TALER_TESTING_cmd_fakebank_transfer_with_subject (const char *label,
*
* @param label command label.
* @param amount the amount to transfer.
* @param bank_url base URL of the bank running the transfer.
* @param debit_account_no which account (expressed as a number)
* gives money.
* @param credit_account_no which account (expressed as a number)
* receives money.
* @param account_base_url base URL of the account that implements this
* wire transer (which account gives money).
* @param payto_credit_account which account receives money.
* @param auth_username username identifying the @a
* debit_account_no at the bank.
* @param auth_password password for @a auth_username.
@ -804,9 +762,9 @@ TALER_TESTING_cmd_fakebank_transfer_with_subject (const char *label,
struct TALER_TESTING_Command
TALER_TESTING_cmd_fakebank_transfer_with_ref (const char *label,
const char *amount,
const char *bank_url,
uint64_t debit_account_no,
uint64_t credit_account_no,
const char *account_base_url,
const char *payto_credit_account,
const char *auth_username,
const char *auth_password,
const char *ref,
@ -822,14 +780,9 @@ TALER_TESTING_cmd_fakebank_transfer_with_ref (const char *label,
*
* @param label command label.
* @param amount amount to transfer.
* @param bank_url base URL of the bank that implements this
* wire transer. For simplicity, both credit and debit
* bank account exist at the same bank.
* @param debit_account_no which account (expressed as a number)
* gives money.
* @param credit_account_no which account (expressed as a number)
* receives money.
*
* @param account_base_url base URL of the account that implements this
* wire transer (which account gives money).
* @param payto_credit_account which account receives money.
* @param auth_username username identifying the @a
* debit_account_no at the bank.
* @param auth_password password for @a auth_username.
@ -847,9 +800,9 @@ TALER_TESTING_cmd_fakebank_transfer_with_ref (const char *label,
struct TALER_TESTING_Command
TALER_TESTING_cmd_fakebank_transfer_with_instance (const char *label,
const char *amount,
const char *bank_url,
uint64_t debit_account_no,
uint64_t credit_account_no,
const char *account_base_url,
const char *
payto_credit_account,
const char *auth_username,
const char *auth_password,
const char *instance,
@ -1268,8 +1221,8 @@ struct TALER_TESTING_Command
TALER_TESTING_cmd_check_bank_transfer (const char *label,
const char *exchange_base_url,
const char *amount,
uint64_t debit_account,
uint64_t credit_account);
const char *debit_account,
const char *credit_account);
/**
@ -1617,7 +1570,6 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
*
* @return the trait.
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_reserve_priv (unsigned int index,
const struct
@ -1640,6 +1592,34 @@ TALER_TESTING_get_trait_reserve_priv (const struct TALER_TESTING_Command *cmd,
TALER_ReservePrivateKeyP **reserve_priv);
/**
* Offer a reserve public key.
*
* @param index reserve pubs's index number.
* @param reserve_priv reserve public key to offer.
* @return the trait.
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_reserve_pub (unsigned int index,
const struct
TALER_ReservePublicKeyP *reserve_pub);
/**
* Obtain a reserve public key from a @a cmd.
*
* @param cmd command to extract the reserve pub from.
* @param index reserve pub's index number.
* @param reserve_pub[out] set to the reserve pub.
* @return #GNUNET_OK on success.
*/
int
TALER_TESTING_get_trait_reserve_pub (const struct TALER_TESTING_Command *cmd,
unsigned int index,
const struct
TALER_ReservePublicKeyP **reserve_pub);
/**
* Make a trait for a exchange signature.
*
@ -2129,34 +2109,34 @@ TALER_TESTING_make_trait_peer_key_pub (unsigned int index,
/**
* Obtain a transfer subject from @a cmd.
* Obtain a string from @a cmd.
*
* @param cmd command to extract the subject from.
* @param index index number associated with the transfer
* subject to offer.
* @param transfer_subject[out] where to write the offered
* transfer subject.
* @param s[out] where to write the offered
* string.
*
* @return #GNUNET_OK on success.
*/
int
TALER_TESTING_get_trait_transfer_subject (const struct
TALER_TESTING_get_trait_string (const struct
TALER_TESTING_Command *cmd,
unsigned int index,
const char **transfer_subject);
const char **s);
/**
* Offer transfer subject.
* Offer string subject.
*
* @param index index number associated with the transfer
* subject being offered.
* @param transfer_subject transfer subject to offer.
* @param s string to offer.
* @return the trait.
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_transfer_subject (unsigned int index,
const char *transfer_subject);
TALER_TESTING_make_trait_string (unsigned int index,
const char *s);
/**
@ -2223,7 +2203,6 @@ TALER_TESTING_get_trait_amount (const struct TALER_TESTING_Command *cmd,
* @param index which url is to be picked,
* in case multiple are offered.
* @param url the url to offer.
*
* @return the trait.
*/
struct TALER_TESTING_Trait

View File

@ -22,7 +22,7 @@
#define TALER_WIRE_H
#include <gnunet/gnunet_util_lib.h>
#include "taler_wire_plugin.h"
/**
* Different account types supported by payto://.
@ -46,6 +46,7 @@ enum TALER_PaytoAccountType
TALER_PAC_IBAN
};
/**
* Information about an account extracted from a payto://-URL.
*/
@ -71,19 +72,15 @@ struct TALER_Account
{
/**
* Hostname of the bank (possibly including port).
* Bank account base URL.
*/
char *account_base_url;
/**
* Only the hostname of the bank.
*/
char *hostname;
/**
* Bank account number.
*/
unsigned long long no;
/**
* Base URL of the bank hosting the account above.
*/
char *bank_base_url;
} x_taler_bank;
/**
@ -113,6 +110,18 @@ void
TALER_WIRE_account_free (struct TALER_Account *acc);
/**
* Round the amount to something that can be
* transferred on the wire.
*
* @param[in,out] amount amount to round down
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
* #GNUNET_SYSERR if the amount or currency was invalid
*/
int
TALER_WIRE_amount_round (struct TALER_Amount *amount);
/**
* Parse @a payto_url and store the result in @a acc
*
@ -135,36 +144,4 @@ char *
TALER_WIRE_payto_get_method (const char *payto_url);
/**
* Get the plugin name from the payment method.
*
* @param method the method implemented by the plugin (for
* simplicity, we assume 1 method is implemented by 1 plugin).
* @return the plugin name, NULL if not found.
*/
const char *
TALER_WIRE_get_plugin_from_method (const char *method);
/**
* Load a WIRE plugin.
*
* @param cfg configuration to use
* @param plugin_name name of the plugin to load
* @return #GNUNET_OK on success
*/
struct TALER_WIRE_Plugin *
TALER_WIRE_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *plugin_name);
/**
* Unload a WIRE plugin.
*
* @param plugin the plugin to unload
*/
void
TALER_WIRE_plugin_unload (struct TALER_WIRE_Plugin *plugin);
#endif

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2016, 2017 GNUnet e.V. & Inria
Copyright (C) 2016-2020 Taler Systems SA
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
@ -40,23 +40,10 @@ typedef void
size_t buf_size);
/**
* Callback to process a merchant registration outcome.
*
* @param cls closure
* @param status GNUNET_OK if the registration succeeded,
* GNUNET_NO otherwise.
*/
typedef void
(*TALER_WIRE_MerchantRegisterCallback) (void *cls,
unsigned int status);
/**
* Details about a valid wire transfer to the exchange.
* It is the plugin's responsibility to filter and undo
* invalid transfers.
*/
struct TALER_WIRE_TransferDetails
struct TALER_WIRE_CreditDetails
{
/**
* Amount that was transferred
@ -69,22 +56,44 @@ struct TALER_WIRE_TransferDetails
struct GNUNET_TIME_Absolute execution_date;
/**
* Binary data that was encoded in the wire transfer subject, if
* it decoded properly. Otherwise all-zeros and @e wtid_s is set.
* Binary data that was encoded in the wire transfer subject.
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* payto://-URL of the source's account (used
* when the reserve is closed or for debugging).
*/
const char *source_account_url;
};
/**
* Details about a valid wire transfer made by the
* exchange's aggregator to a merchant.
*/
struct TALER_WIRE_DebitDetails
{
/**
* Amount that was transferred
*/
struct TALER_Amount amount;
/**
* Time of the the transfer
*/
struct GNUNET_TIME_Absolute execution_date;
/**
* Binary data that was encoded in the wire transfer subject.
*/
struct TALER_WireTransferIdentifierRawP wtid;
/**
* Wire transfer identifer as a string. Set to NULL if the
* identifier was properly Base32 encoded and this @e wtid could be
* set instead.
* payto://-URL of the target account which received
* the funds.
*/
char *wtid_s;
/**
* payto://-URL of the other account that was involved
*/
char *account_url;
const char *target_account_url;
};
@ -96,33 +105,40 @@ struct TALER_WIRE_TransferDetails
*
* @param cls closure
* @param ec taler error code
* @param dir direction of the transfer, #TALER_BANK_DIRECTION_NONE when
* the iteration is complete
* @param row_off identification of the position at which we are querying
* @param row_off_size number of bytes in @a row_off
* @param details details about the wire transfer
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
*/
typedef int
(*TALER_WIRE_HistoryResultCallback) (void *cls,
(*TALER_WIRE_CreditResultCallback) (void *cls,
enum TALER_ErrorCode ec,
enum TALER_BANK_Direction dir,
const void *row_off,
size_t row_off_size,
const struct
TALER_WIRE_TransferDetails *details);
TALER_WIRE_CreditDetails *details);
/**
* Callbacks of this type are used to serve the result of asking
* the bank to reject a wire transfer.
* the bank for the transaction history. NOTE: this function will
* NOT get the list of history elements, but rather get (iteratively)
* called for each (parsed) history element.
*
* @param cls closure
* @param ec status of the operation, #TALER_EC_NONE on success
* @param ec taler error code
* @param row_off identification of the position at which we are querying
* @param row_off_size number of bytes in @a row_off
* @param details details about the wire transfer
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
*/
typedef void
(*TALER_WIRE_RejectTransferCallback) (void *cls,
enum TALER_ErrorCode ec);
typedef int
(*TALER_WIRE_DebitResultCallback) (void *cls,
enum TALER_ErrorCode ec,
const void *row_off,
size_t row_off_size,
const struct
TALER_WIRE_DebitDetails *details);
/**
@ -136,9 +152,14 @@ struct TALER_WIRE_PrepareHandle;
struct TALER_WIRE_ExecuteHandle;
/**
* Handle returned for querying the transaction history.
* Handle returned for querying the credit transaction history.
*/
struct TALER_WIRE_HistoryHandle;
struct TALER_WIRE_CreditHistoryHandle;
/**
* Handle returned for querying the debit transaction history.
*/
struct TALER_WIRE_DebitHistoryHandle;
/**
@ -146,7 +167,8 @@ struct TALER_WIRE_HistoryHandle;
*
* @param cls closure
* @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure
* @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
* @param row_id unique ID of the wire transfer in the bank's records; NULL on error
* @param row_id_size number of bytes in @e row_id
* @param emsg NULL on success, otherwise an error message
*/
typedef void
@ -156,6 +178,7 @@ typedef void
size_t row_id_size,
const char *emsg);
/**
* @brief The plugin API, returned from the plugin's "init" function.
* The argument given to "init" is simply a configuration handle.
@ -176,11 +199,10 @@ struct TALER_WIRE_Plugin
/**
* Which wire method (payto://METHOD/") is supported by this plugin?
* For example, "iban" or "x-taler-bank".
* For example, "x-taler-bank" or "iban".
*/
const char *method;
/**
* Round amount DOWN to the amount that can be transferred via the wire
* method. For example, Taler may support 0.000001 EUR as a unit of
@ -210,80 +232,7 @@ struct TALER_WIRE_Plugin
/**
* Prepare for exeuction of a wire transfer.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param origin_account_section configuration section specifying the origin
* account of the exchange to use
* @param destination_account_url payto:// URL identifying where to send the money
* @param amount amount to transfer, already rounded
* @param exchange_base_url base URL of this exchange (included in subject
* to facilitate use of tracking API by merchant backend)
* @param wtid wire transfer identifier to use
* @param ptc function to call with the prepared data to persist
* @param ptc_cls closure for @a ptc
* @return NULL on failure
*/
struct TALER_WIRE_PrepareHandle *
(*prepare_wire_transfer) (void *cls,
const char *origin_account_section,
const char *destination_account_url,
const struct TALER_Amount *amount,
const char *exchange_base_url,
const struct TALER_WireTransferIdentifierRawP *wtid,
TALER_WIRE_PrepareTransactionCallback ptc,
void *ptc_cls);
/**
* Abort preparation of a wire transfer. For example,
* because we are shutting down.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param pth preparation to cancel
*/
void
(*prepare_wire_transfer_cancel) (void *cls,
struct TALER_WIRE_PrepareHandle *pth);
/**
* Execute a wire transfer.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param buf buffer with the prepared execution details
* @param buf_size number of bytes in @a buf
* @param cc function to call upon success
* @param cc_cls closure for @a cc
* @return NULL on error
*/
struct TALER_WIRE_ExecuteHandle *
(*execute_wire_transfer) (void *cls,
const char *buf,
size_t buf_size,
TALER_WIRE_ConfirmationCallback cc,
void *cc_cls);
/**
* Abort execution of a wire transfer. For example, because we are
* shutting down. Note that if an execution is aborted, it may or
* may not still succeed. The caller MUST run @e
* execute_wire_transfer again for the same request as soon as
* possilbe, to ensure that the request either ultimately succeeds
* or ultimately fails. Until this has been done, the transaction is
* in limbo (i.e. may or may not have been committed).
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param eh execution to cancel
*/
void
(*execute_wire_transfer_cancel) (void *cls,
struct TALER_WIRE_ExecuteHandle *eh);
/**
* Query transfer history of an account. We use the variable-size
* Query credits made to exchange account. We use the variable-size
* @a start_off to indicate which transfers we are interested in as
* different banking systems may have different ways to identify
* transfers. The @a start_off value must thus match the value of
@ -295,7 +244,6 @@ struct TALER_WIRE_Plugin
* @param cls the @e cls of this struct with the plugin-specific state
* @param account_section specifies the configuration section which
* identifies the account for which we should get the history
* @param direction what kinds of wire transfers should be returned
* @param start_off from which row on do we want to get results, use NULL for the latest; exclusive
* @param start_off_len number of bytes in @a start_off
* @param num_results how many results do we want; negative numbers to go into the past,
@ -304,70 +252,65 @@ struct TALER_WIRE_Plugin
* @param hres_cb the callback to call with the transaction history
* @param hres_cb_cls closure for the above callback
*/
struct TALER_WIRE_HistoryHandle *
(*get_history) (void *cls,
struct TALER_WIRE_CreditHistoryHandle *
(*get_credits) (void *cls,
const char *account_section,
enum TALER_BANK_Direction direction,
const void *start_off,
size_t start_off_len,
int64_t num_results,
TALER_WIRE_HistoryResultCallback hres_cb,
TALER_WIRE_CreditResultCallback hres_cb,
void *hres_cb_cls);
/**
* Cancel going over the account's history.
*
* @param cls plugins' closure
* @param whh operation to cancel
* @param chh operation to cancel
*/
void
(*get_history_cancel) (void *cls,
struct TALER_WIRE_HistoryHandle *whh);
(*get_credits_cancel) (void *cls,
struct TALER_WIRE_CreditHistoryHandle *chh);
/**
* Reject an incoming wire transfer that was obtained from the
* history. This function can be used to transfer funds back to
* the sender if the WTID was malformed (i.e. due to a typo).
* Query debits (transfers to merchants) made by an exchange. We use the
* variable-size @a start_off to indicate which transfers we are interested
* in as different banking systems may have different ways to identify
* transfers. The @a start_off value must thus match the value of a
* `row_off` argument previously given to the @a hres_cb. Use NULL to query
* transfers from the beginning of time (with positive @a num_results) or
* from the latest committed transfers (with negative @a num_results).
*
* Calling `reject_transfer` twice on the same wire transfer should
* be idempotent, i.e. not cause the funds to be wired back twice.
* Furthermore, the transfer should henceforth be removed from the
* results returned by @e get_history.
*
* @param cls plugin's closure
* @param cls the @e cls of this struct with the plugin-specific state
* @param account_section specifies the configuration section which
* identifies the account to use to reject the transfer
* @param start_off offset of the wire transfer in plugin-specific format
* identifies the account for which we should get the history
* @param start_off from which row on do we want to get results, use NULL for the latest; exclusive
* @param start_off_len number of bytes in @a start_off
* @param rej_cb function to call with the result of the operation
* @param rej_cb_cls closure for @a rej_cb
* @return handle to cancel the operation
* @param num_results how many results do we want; negative numbers to go into the past,
* positive numbers to go into the future starting at @a start_row;
* must not be zero.
* @param hres_cb the callback to call with the transaction history
* @param hres_cb_cls closure for the above callback
*/
struct TALER_WIRE_RejectHandle *
(*reject_transfer)(void *cls,
struct TALER_WIRE_DebitHistoryHandle *
(*get_debits) (void *cls,
const char *account_section,
const void *start_off,
size_t start_off_len,
TALER_WIRE_RejectTransferCallback rej_cb,
void *rej_cb_cls);
int64_t num_results,
TALER_WIRE_DebitResultCallback hres_cb,
void *hres_cb_cls);
/**
* Cancel ongoing reject operation. Note that the rejection may still
* proceed. Basically, if this function is called, the rejection may
* have happened or not. This function is usually used during shutdown
* or system upgrades. At a later point, the application must call
* @e reject_transfer again for this wire transfer, unless the
* @e get_history shows that the wire transfer no longer exists.
* Cancel going over the account's history.
*
* @param cls plugins' closure
* @param rh operation to cancel
* @return closure of the callback of the operation
* @param dhh operation to cancel
*/
void *
(*reject_transfer_cancel)(void *cls,
struct TALER_WIRE_RejectHandle *rh);
void
(*get_debits_cancel) (void *cls,
struct TALER_WIRE_DebitHistoryHandle *dhh);
};

View File

@ -103,6 +103,7 @@ libtalertesting_la_SOURCES = \
testing_api_trait_exchange_sig.c \
testing_api_trait_json.c \
testing_api_trait_process.c \
testing_api_trait_reserve_pub.c \
testing_api_trait_reserve_priv.c \
testing_api_trait_number.c \
testing_api_trait_fresh_coin.c \

View File

@ -52,12 +52,12 @@ struct BankCheckState
/**
* Expected debit bank account.
*/
uint64_t debit_account;
const char *debit_account;
/**
* Expected credit bank account.
*/
uint64_t credit_account;
const char *credit_account;
/**
* Wire transfer subject (set by fakebank-lib).
@ -95,18 +95,16 @@ check_bank_transfer_run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct BankCheckState *bcs = cls;
struct TALER_Amount amount;
const uint64_t *debit_account;
const uint64_t *credit_account;
const char *debit_account;
const char *credit_account;
const char *exchange_base_url;
if (NULL == bcs->deposit_reference)
{
TALER_LOG_INFO ("Deposit reference NOT given\n");
debit_account = &bcs->debit_account;
credit_account = &bcs->credit_account;
debit_account = bcs->debit_account;
credit_account = bcs->credit_account;
exchange_base_url = bcs->exchange_base_url;
if (GNUNET_OK !=
@ -154,14 +152,13 @@ check_bank_transfer_run (void *cls,
GNUNET_assert
(GNUNET_OK == TALER_TESTING_get_trait_url
(deposit_cmd, 0, &exchange_base_url)); // check 0 works!
}
if (GNUNET_OK !=
TALER_FAKEBANK_check (is->fakebank,
&amount,
*debit_account,
*credit_account,
debit_account,
credit_account,
exchange_base_url,
&bcs->subject))
{
@ -217,9 +214,8 @@ check_bank_transfer_traits (void *cls,
wtid_ptr = NULL;
else
wtid_ptr = &bcs->wtid;
{
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_transfer_subject (0, bcs->subject),
TALER_TESTING_make_trait_wtid (0, wtid_ptr),
TALER_TESTING_make_trait_url (0, bcs->exchange_base_url),
TALER_TESTING_trait_end ()
@ -230,6 +226,7 @@ check_bank_transfer_traits (void *cls,
trait,
index);
}
}
/**
@ -250,8 +247,8 @@ TALER_TESTING_cmd_check_bank_transfer
(const char *label,
const char *exchange_base_url,
const char *amount,
uint64_t debit_account,
uint64_t credit_account)
const char *debit_account,
const char *credit_account)
{
struct BankCheckState *bcs;
@ -260,9 +257,8 @@ TALER_TESTING_cmd_check_bank_transfer
bcs->amount = amount;
bcs->debit_account = debit_account;
bcs->credit_account = credit_account;
bcs->deposit_reference = NULL;
{
struct TALER_TESTING_Command cmd = {
.label = label,
.cls = bcs,
@ -273,6 +269,7 @@ TALER_TESTING_cmd_check_bank_transfer
return cmd;
}
}
/**

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
Copyright (C) 2018-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@ -51,24 +51,14 @@ struct FakebankTransferState
struct TALER_Amount amount;
/**
* Wire transfer subject.
* Base URL of the debit account.
*/
const char *subject;
const char *debit_url;
/**
* Base URL of the bank serving the request.
* Money receiver account URL.
*/
const char *bank_url;
/**
* Money sender account number.
*/
uint64_t debit_account_no;
/**
* Money receiver account number.
*/
uint64_t credit_account_no;
const char *payto_credit_account;
/**
* Username to use for authentication.
@ -86,6 +76,11 @@ struct FakebankTransferState
*/
struct TALER_ReservePrivateKeyP reserve_priv;
/**
* Reserve public key matching @e reserve_priv.
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* Handle to the pending request at the fakebank.
*/
@ -188,16 +183,15 @@ do_retry (void *cls)
* @param ec taler-specific error code, #TALER_EC_NONE on success
* @param serial_id unique ID of the wire transfer
* @param timestamp time stamp of the transaction made.
* @param full_response full response from the exchange (for
* logging, in case of errors)
* @param json raw response
*/
static void
add_incoming_cb (void *cls,
confirmation_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
uint64_t serial_id,
struct GNUNET_TIME_Absolute timestamp,
const json_t *full_response)
const json_t *json)
{
struct FakebankTransferState *fts = cls;
struct TALER_TESTING_Interpreter *is = fts->is;
@ -256,16 +250,8 @@ fakebank_transfer_run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct FakebankTransferState *fts = cls;
char *subject;
struct TALER_BANK_AuthenticationData auth;
struct TALER_ReservePublicKeyP reserve_pub;
if (NULL != fts->subject)
{
subject = GNUNET_strdup (fts->subject);
}
else
{
/* Use reserve public key as subject */
if (NULL != fts->reserve_reference)
{
@ -358,28 +344,21 @@ fakebank_transfer_run (void *cls,
GNUNET_free (priv);
}
}
GNUNET_CRYPTO_eddsa_key_get_public
(&fts->reserve_priv.eddsa_priv, &reserve_pub.eddsa_pub);
subject = GNUNET_STRINGS_data_to_string_alloc
(&reserve_pub, sizeof (reserve_pub));
}
GNUNET_CRYPTO_eddsa_key_get_public (&fts->reserve_priv.eddsa_priv,
&fts->reserve_pub.eddsa_pub);
auth.method = TALER_BANK_AUTH_BASIC;
auth.details.basic.username = (char *) fts->auth_username;
auth.details.basic.password = (char *) fts->auth_password;
fts->is = is;
fts->aih = TALER_BANK_admin_add_incoming
(TALER_TESTING_interpreter_get_context (is),
fts->bank_url,
fts->debit_url,
&auth,
fts->exchange_url,
subject,
&fts->reserve_pub,
&fts->amount,
fts->debit_account_no,
fts->credit_account_no,
&add_incoming_cb,
fts->payto_credit_account,
&confirmation_cb,
fts);
GNUNET_free (subject);
if (NULL == fts->aih)
{
GNUNET_break (0);
@ -408,6 +387,7 @@ fakebank_transfer_cleanup (void *cls,
"Command %s did not complete\n",
cmd->label);
TALER_BANK_admin_add_incoming_cancel (fts->aih);
fts->aih = NULL;
}
if (NULL != fts->retry_task)
{
@ -435,32 +415,21 @@ fakebank_transfer_traits (void *cls,
unsigned int index)
{
struct FakebankTransferState *fts = cls;
#define MANDATORY 7
struct TALER_TESTING_Trait traits[MANDATORY + 1] = {
TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT
(&fts->debit_account_no),
TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT
(&fts->credit_account_no),
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_url (0, fts->exchange_url),
TALER_TESTING_make_trait_url (1, fts->debit_url),
TALER_TESTING_MAKE_TRAIT_ROW_ID (&fts->serial_id),
TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT (fts->payto_credit_account),
TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT (fts->debit_url),
TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp)
TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp),
TALER_TESTING_make_trait_reserve_priv (0,
&fts->reserve_priv),
TALER_TESTING_make_trait_reserve_pub (0,
&fts->reserve_pub),
TALER_TESTING_trait_end ()
};
/**
* The user gave explicit subject,
* there must be NO reserve priv. */
if (NULL != fts->subject)
traits[MANDATORY - 1] =
TALER_TESTING_make_trait_transfer_subject (0,
fts->subject);
/* A reserve priv must exist if no subject was given. */
else
traits[MANDATORY - 1] = TALER_TESTING_make_trait_reserve_priv
(0, &fts->reserve_priv),
traits[MANDATORY] = TALER_TESTING_trait_end ();
return TALER_TESTING_get_trait (traits,
ret,
trait,
@ -475,27 +444,21 @@ fakebank_transfer_traits (void *cls,
*
* @param label command label.
* @param amount amount to transfer.
* @param bank_url base URL of the bank that implements this
* wire transer. For simplicity, both credit and debit
* bank account exist at the same bank.
* @param debit_account_no which account (expressed as a number)
* gives money.
* @param credit_account_no which account (expressed as a number)
* receives money.
* @param account_base_url base URL of the account that implements this
* wire transer (which account gives money).
* @param payto_credit_account which account receives money.
* @param auth_username username identifying the @a
* debit_account_no at the bank.
* @param auth_password password for @a auth_username.
* @param exchange_url which exchange is involved in this transfer.
*
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_fakebank_transfer
(const char *label,
const char *amount,
const char *bank_url,
uint64_t debit_account_no,
uint64_t credit_account_no,
const char *account_base_url,
const char *payto_credit_account,
const char *auth_username,
const char *auth_password,
const char *exchange_url)
@ -503,9 +466,8 @@ TALER_TESTING_cmd_fakebank_transfer
struct FakebankTransferState *fts;
fts = GNUNET_new (struct FakebankTransferState);
fts->bank_url = bank_url;
fts->credit_account_no = credit_account_no;
fts->debit_account_no = debit_account_no;
fts->debit_url = account_base_url;
fts->payto_credit_account = payto_credit_account;
fts->auth_username = auth_username;
fts->auth_password = auth_password;
fts->exchange_url = exchange_url;
@ -520,6 +482,7 @@ TALER_TESTING_cmd_fakebank_transfer
GNUNET_assert (0);
}
{
struct TALER_TESTING_Command cmd = {
.cls = fts,
.label = label,
@ -530,77 +493,6 @@ TALER_TESTING_cmd_fakebank_transfer
return cmd;
}
/**
* Create "fakebank transfer" CMD, letting the caller specifying
* the subject line.
*
* @param label command label.
* @param amount amount to transfer.
* @param bank_url base URL of the bank that implements this
* wire transer. For simplicity, both credit and debit
* bank account exist at the same bank.
* @param debit_account_no which account (expressed as a number)
* gives money.
* @param credit_account_no which account (expressed as a number)
* receives money.
*
* @param auth_username username identifying the @a
* debit_account_no at the bank.
* @param auth_password password for @a auth_username.
* @param subject wire transfer's subject line.
* @param exchange_url which exchange is involved in this transfer.
*
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_fakebank_transfer_with_subject
(const char *label,
const char *amount,
const char *bank_url,
uint64_t debit_account_no,
uint64_t credit_account_no,
const char *auth_username,
const char *auth_password,
const char *subject,
const char *exchange_url)
{
struct FakebankTransferState *fts;
fts = GNUNET_new (struct FakebankTransferState);
TALER_LOG_DEBUG ("%s:FTS@%p\n",
label,
fts);
fts->bank_url = bank_url;
fts->credit_account_no = credit_account_no;
fts->debit_account_no = debit_account_no;
fts->auth_username = auth_username;
fts->auth_password = auth_password;
fts->subject = subject;
fts->exchange_url = exchange_url;
if (GNUNET_OK !=
TALER_string_to_amount (amount,
&fts->amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse amount `%s' at %s\n",
amount,
label);
GNUNET_assert (0);
}
struct TALER_TESTING_Command cmd = {
.cls = fts,
.label = label,
.run = &fakebank_transfer_run,
.cleanup = &fakebank_transfer_cleanup,
.traits = &fakebank_transfer_traits
};
return cmd;
}
@ -631,9 +523,8 @@ struct TALER_TESTING_Command
TALER_TESTING_cmd_fakebank_transfer_with_ref
(const char *label,
const char *amount,
const char *bank_url,
uint64_t debit_account_no,
uint64_t credit_account_no,
const char *account_base_url,
const char *payto_credit_account,
const char *auth_username,
const char *auth_password,
const char *ref,
@ -642,9 +533,8 @@ TALER_TESTING_cmd_fakebank_transfer_with_ref
struct FakebankTransferState *fts;
fts = GNUNET_new (struct FakebankTransferState);
fts->bank_url = bank_url;
fts->credit_account_no = credit_account_no;
fts->debit_account_no = debit_account_no;
fts->debit_url = account_base_url;
fts->payto_credit_account = payto_credit_account;
fts->auth_username = auth_username;
fts->auth_password = auth_password;
fts->reserve_reference = ref;
@ -659,7 +549,7 @@ TALER_TESTING_cmd_fakebank_transfer_with_ref
label);
GNUNET_assert (0);
}
{
struct TALER_TESTING_Command cmd = {
.cls = fts,
.label = label,
@ -670,6 +560,7 @@ TALER_TESTING_cmd_fakebank_transfer_with_ref
return cmd;
}
}
/**
@ -705,9 +596,8 @@ struct TALER_TESTING_Command
TALER_TESTING_cmd_fakebank_transfer_with_instance
(const char *label,
const char *amount,
const char *bank_url,
uint64_t debit_account_no,
uint64_t credit_account_no,
const char *account_base_url,
const char *payto_credit_account,
const char *auth_username,
const char *auth_password,
const char *instance,
@ -717,9 +607,8 @@ TALER_TESTING_cmd_fakebank_transfer_with_instance
struct FakebankTransferState *fts;
fts = GNUNET_new (struct FakebankTransferState);
fts->bank_url = bank_url;
fts->credit_account_no = credit_account_no;
fts->debit_account_no = debit_account_no;
fts->debit_url = account_base_url;
fts->payto_credit_account = payto_credit_account;
fts->auth_username = auth_username;
fts->auth_password = auth_password;
fts->instance = instance;
@ -735,7 +624,7 @@ TALER_TESTING_cmd_fakebank_transfer_with_instance
label);
GNUNET_assert (0);
}
{
struct TALER_TESTING_Command cmd = {
.cls = fts,
.label = label,
@ -746,6 +635,7 @@ TALER_TESTING_cmd_fakebank_transfer_with_instance
return cmd;
}
}
/**

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2018 Taler Systems SA
Copyright (C) 2014-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
@ -146,6 +146,7 @@ status_run (void *cls,
const struct TALER_TESTING_Command *create_reserve;
const struct TALER_ReservePrivateKeyP *reserve_priv;
struct TALER_ReservePublicKeyP reserve_pub;
const struct TALER_ReservePublicKeyP *reserve_pubp;
ss->is = is;
GNUNET_assert (NULL != ss->reserve_reference);
@ -163,44 +164,31 @@ status_run (void *cls,
/* NOTE: the following line might generate a ERROR log
* statements, but it can be ignored. */
if (GNUNET_OK == TALER_TESTING_get_trait_reserve_priv
(create_reserve,
if (GNUNET_OK ==
TALER_TESTING_get_trait_reserve_priv (create_reserve,
0,
&reserve_priv))
{
GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
&reserve_pub.eddsa_pub);
reserve_pubp = &reserve_pub;
}
else
{
const char *transfer_subject;
if (GNUNET_OK != TALER_TESTING_get_trait_transfer_subject
(create_reserve,
0,
&transfer_subject))
{
GNUNET_break (0);
TALER_LOG_ERROR ("The reserve has neither a priv nor a subject line.\n");
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (transfer_subject,
strlen (transfer_subject),
&reserve_pub.eddsa_pub,
sizeof (struct TALER_ReservePublicKeyP)))
TALER_TESTING_get_trait_reserve_pub (create_reserve,
0,
&reserve_pubp))
{
GNUNET_break (0);
TALER_LOG_ERROR ("Transfer subject is not a public key.\n");
TALER_LOG_ERROR ("The reserve has neither a priv nor a pub.\n");
TALER_TESTING_interpreter_fail (is);
return;
}
}
ss->rsh = TALER_EXCHANGE_reserve_status (is->exchange,
&reserve_pub,
reserve_pubp,
&reserve_status_cb,
ss);
}

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2018 Taler Systems SA
Copyright (C) 2014-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
@ -190,15 +190,11 @@ deposit_wtid_cb
if (NULL != tts->bank_transfer_reference)
{
const struct TALER_TESTING_Command *bank_transfer_cmd;
char *ws;
const struct TALER_WireTransferIdentifierRawP *wtid_want;
/* _this_ wire transfer subject line. */
ws = GNUNET_STRINGS_data_to_string_alloc (wtid,
sizeof (*wtid));
bank_transfer_cmd = TALER_TESTING_interpreter_lookup_command
(is, tts->bank_transfer_reference);
if (NULL == bank_transfer_cmd)
{
GNUNET_break (0);
@ -206,12 +202,9 @@ deposit_wtid_cb
return;
}
/* expected wire transfer subject line. */
const char *transfer_subject;
if (GNUNET_OK !=
TALER_TESTING_get_trait_transfer_subject
(bank_transfer_cmd, 0, &transfer_subject))
TALER_TESTING_get_trait_wtid
(bank_transfer_cmd, 0, &wtid_want))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
@ -219,15 +212,13 @@ deposit_wtid_cb
}
/* Compare that expected and gotten subjects match. */
if (0 != strcmp (ws, transfer_subject))
if (0 != GNUNET_memcmp (wtid,
wtid_want))
{
GNUNET_break (0);
GNUNET_free (ws);
TALER_TESTING_interpreter_fail (tts->is);
return;
}
GNUNET_free (ws);
}
break;
case MHD_HTTP_ACCEPTED:

View File

@ -0,0 +1,77 @@
/*
This file is part of TALER
Copyright (C) 2018-2020 Taler Systems SA
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 Foundation; either version 3, or
(at your option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_trait_reserve_pub.c
* @brief implements reserve public key trait
* @author Christian Grothoff
* @author Marcello Stanisci
*/
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "exchange_api_handle.h"
#include "taler_signatures.h"
#include "taler_testing_lib.h"
#define TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY \
"reserve-public-key"
/**
* Obtain a reserve public key from a @a cmd.
*
* @param cmd command to extract the reserve pub from.
* @param index reserve pub's index number.
* @param reserve_pub[out] set to the reserve pub.
* @return #GNUNET_OK on success.
*/
int
TALER_TESTING_get_trait_reserve_pub
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
const struct TALER_ReservePublicKeyP **reserve_pub)
{
return cmd->traits (cmd->cls,
(const void **) reserve_pub,
TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY,
index);
}
/**
* Offer a reserve public key.
*
* @param index reserve pub's index number.
* @param reserve_pub reserve public key to offer.
* @return the trait.
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_reserve_pub
(unsigned int index,
const struct TALER_ReservePublicKeyP *reserve_pub)
{
struct TALER_TESTING_Trait ret = {
.index = index,
.trait_name = TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY,
.ptr = (const void *) reserve_pub
};
return ret;
}
/* end of testing_api_trait_reserve_pub.c */

View File

@ -30,7 +30,7 @@
#include "taler_testing_lib.h"
#define TALER_TESTING_TRAIT_CONTRACT_TERMS "contract-terms"
#define TALER_TESTING_TRAIT_TRANSFER_SUBJECT "transfer-subject"
#define TALER_TESTING_TRAIT_STRING "string"
#define TALER_TESTING_TRAIT_AMOUNT "amount"
#define TALER_TESTING_TRAIT_URL "url"
#define TALER_TESTING_TRAIT_ORDER_ID "order-id"
@ -80,46 +80,45 @@ TALER_TESTING_make_trait_contract_terms
/**
* Obtain a transfer subject from @a cmd.
* Obtain a string from @a cmd.
*
* @param cmd command to extract the subject from.
* @param index index number associated with the transfer
* subject to offer.
* @param transfer_subject[out] where to write the offered
* transfer subject.
* @param s[out] where to write the offered
* string
* @return #GNUNET_OK on success.
*/
int
TALER_TESTING_get_trait_transfer_subject
TALER_TESTING_get_trait_string
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
const char **transfer_subject)
const char **s)
{
return cmd->traits (cmd->cls,
(const void **) transfer_subject,
TALER_TESTING_TRAIT_TRANSFER_SUBJECT,
(const void **) s,
TALER_TESTING_TRAIT_STRING,
index);
}
/**
* Offer transfer subject.
* Offer string.
*
* @param index index number associated with the transfer
* subject being offered.
* @param transfer_subject transfer subject to offer.
*
* @param s transfer subject to offer.
* @return the trait.
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_transfer_subject
TALER_TESTING_make_trait_string
(unsigned int index,
const char *transfer_subject)
const char *s)
{
struct TALER_TESTING_Trait ret = {
.index = index,
.trait_name = TALER_TESTING_TRAIT_TRANSFER_SUBJECT,
.ptr = (const void *) transfer_subject
.trait_name = TALER_TESTING_TRAIT_STRING,
.ptr = (const void *) s
};
return ret;
}

View File

@ -1,81 +0,0 @@
# This Makefile.am is in the public domain
AM_CPPFLAGS = -I$(top_srcdir)/src/include
if USE_COVERAGE
AM_CFLAGS = --coverage -O0
XLIB = -lgcov
endif
pkgcfgdir = $(prefix)/share/taler/config.d/
EXTRA_DIST = \
test_wire_plugin.conf \
test_wire_plugin_transactions_taler-bank.conf
plugindir = $(libdir)/taler
if HAVE_LIBCURL
plugin_LTLIBRARIES = \
libtaler_plugin_wire_taler_bank.la
else
if HAVE_LIBGNURL
plugin_LTLIBRARIES = \
libtaler_plugin_wire_taler_bank.la
endif
endif
noinst_LTLIBRARIES = \
libtaler_plugin_wire_template.la
libtaler_plugin_wire_taler_bank_la_SOURCES = \
plugin_wire_taler-bank.c
libtaler_plugin_wire_taler_bank_la_LIBADD = \
$(LTLIBINTL)
libtaler_plugin_wire_taler_bank_la_LDFLAGS = \
$(TALER_PLUGIN_LDFLAGS) \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunetcurl \
-lgnunetutil $(XLIB)
libtaler_plugin_wire_template_la_SOURCES = \
plugin_wire_template.c
libtaler_plugin_wire_template_la_LIBADD = \
$(LTLIBINTL)
libtaler_plugin_wire_template_la_LDFLAGS = \
$(TALER_PLUGIN_LDFLAGS) \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunetutil $(XLIB)
AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
TESTS = \
test_wire_plugin \
test_wire_plugin_transactions_taler_bank
check_PROGRAMS= $(TESTS)
test_wire_plugin_SOURCES = \
test_wire_plugin.c
test_wire_plugin_LDADD = \
-lgnunetutil \
$(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/util/libtalerutil.la
test_wire_plugin_transactions_taler_bank_SOURCES = \
test_wire_plugin_transactions_taler-bank.c
test_wire_plugin_transactions_taler_bank_LDADD = \
-lgnunetjson \
-lgnunetutil \
-ljansson \
$(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/bank-lib/libtalerfakebank.la \
$(top_builddir)/src/util/libtalerutil.la

File diff suppressed because it is too large Load Diff

View File

@ -1,384 +0,0 @@
/*
This file is part of TALER
Copyright (C) 2016, 2018 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
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file plugin_wire_template.c
* @brief template for wire plugins; replace "template" with real plugin name!
* @author Florian Dold
* @author Christian Grothoff
* @author Sree Harsha Totakura
*/
#include "platform.h"
#include "taler_wire_plugin.h"
/**
* Type of the "cls" argument given to each of the functions in
* our API.
*/
struct TemplateClosure
{
/**
* Which currency do we support?
*/
char *currency;
/**
* Which configuration do we use to lookup accounts?
*/
struct GNUNET_CONFIGURATION_Handle *cfg;
};
/**
* Round amount DOWN to the amount that can be transferred via the wire
* method. For example, Taler may support 0.000001 EUR as a unit of
* payment, but SEPA only supports 0.01 EUR. This function would
* round 0.125 EUR to 0.12 EUR in this case.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param[in,out] amount amount to round down
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
* #GNUNET_SYSERR if the amount or currency was invalid
*/
static int
template_amount_round (void *cls,
struct TALER_Amount *amount)
{
struct TemplateClosure *tc = cls;
if (0 != strcasecmp (amount->currency,
tc->currency))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
GNUNET_break (0); // not implemented
return GNUNET_SYSERR;
}
/**
* Check if the given payto:// URL is correctly formatted for this plugin
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param account_url the payto:// URL
* @return #TALER_EC_NONE if correctly formatted
*/
static enum TALER_ErrorCode
template_wire_validate (void *cls,
const char *account_url)
{
(void) cls;
(void) account_url;
GNUNET_break (0);
return TALER_EC_NOT_IMPLEMENTED;
}
/**
* Prepare for exeuction of a wire transfer.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param origin_account_section configuration section specifying the origin
* account of the exchange to use
* @param destination_account_url payto:// URL identifying where to send the money
* @param amount amount to transfer, already rounded
* @param exchange_base_url base URL of the exchange (for tracking)
* @param wtid wire transfer identifier to use
* @param ptc function to call with the prepared data to persist
* @param ptc_cls closure for @a ptc
* @return NULL on failure
*/
static struct TALER_WIRE_PrepareHandle *
template_prepare_wire_transfer (void *cls,
const char *origin_account_section,
const char *destination_account_url,
const struct TALER_Amount *amount,
const char *exchange_base_url,
const struct
TALER_WireTransferIdentifierRawP *wtid,
TALER_WIRE_PrepareTransactionCallback ptc,
void *ptc_cls)
{
(void) cls;
(void) origin_account_section;
(void) destination_account_url;
(void) amount;
(void) exchange_base_url;
(void) wtid;
(void) ptc;
(void) ptc_cls;
GNUNET_break (0);
return NULL;
}
/**
* Abort preparation of a wire transfer. For example,
* because we are shutting down.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param pth preparation to cancel
*/
static void
template_prepare_wire_transfer_cancel (void *cls,
struct TALER_WIRE_PrepareHandle *pth)
{
(void) cls;
(void) pth;
GNUNET_break (0);
}
/**
* Execute a wire transfer.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param buf buffer with the prepared execution details
* @param buf_size number of bytes in @a buf
* @param cc function to call upon success
* @param cc_cls closure for @a cc
* @return NULL on error
*/
static struct TALER_WIRE_ExecuteHandle *
template_execute_wire_transfer (void *cls,
const char *buf,
size_t buf_size,
TALER_WIRE_ConfirmationCallback cc,
void *cc_cls)
{
(void) cls;
(void) buf;
(void) buf_size;
(void) cc;
(void) cc_cls;
GNUNET_break (0);
return NULL;
}
/**
* Abort execution of a wire transfer. For example, because we are
* shutting down. Note that if an execution is aborted, it may or
* may not still succeed. The caller MUST run @e
* execute_wire_transfer again for the same request as soon as
* possilbe, to ensure that the request either ultimately succeeds
* or ultimately fails. Until this has been done, the transaction is
* in limbo (i.e. may or may not have been committed).
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param eh execution to cancel
*/
static void
template_execute_wire_transfer_cancel (void *cls,
struct TALER_WIRE_ExecuteHandle *eh)
{
(void) cls;
(void) eh;
GNUNET_break (0);
}
/**
* Query transfer history of an account. We use the variable-size
* @a start_off to indicate which transfers we are interested in as
* different banking systems may have different ways to identify
* transfers. The @a start_off value must thus match the value of
* a `row_off` argument previously given to the @a hres_cb. Use
* NULL to query transfers from the beginning of time (with
* positive @a num_results) or from the latest committed transfers
* (with negative @a num_results).
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param account_section specifies the configuration section which
* identifies the account for which we should get the history
* @param direction what kinds of wire transfers should be returned
* @param start_off from which row on do we want to get results, use NULL for the latest; exclusive
* @param start_off_len number of bytes in @a start_off; must be `sizeof(uint64_t)`.
* @param num_results how many results do we want; negative numbers to go into the past,
* positive numbers to go into the future starting at @a start_row;
* must not be zero.
* @param hres_cb the callback to call with the transaction history
* @param hres_cb_cls closure for the above callback
*/
static struct TALER_WIRE_HistoryHandle *
template_get_history (void *cls,
const char *account_section,
enum TALER_BANK_Direction direction,
const void *start_off,
size_t start_off_len,
int64_t num_results,
TALER_WIRE_HistoryResultCallback hres_cb,
void *hres_cb_cls)
{
(void) cls;
(void) account_section;
(void) direction;
(void) start_off;
(void) start_off_len;
(void) num_results;
(void) hres_cb;
(void) hres_cb_cls;
GNUNET_break (0);
return NULL;
}
/**
* Cancel going over the account's history.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param whh operation to cancel
*/
static void
template_get_history_cancel (void *cls,
struct TALER_WIRE_HistoryHandle *whh)
{
(void) cls;
(void) whh;
GNUNET_break (0);
}
/**
* Reject an incoming wire transfer that was obtained from the
* history. This function can be used to transfer funds back to
* the sender if the WTID was malformed (i.e. due to a typo).
*
* Calling `reject_transfer` twice on the same wire transfer should
* be idempotent, i.e. not cause the funds to be wired back twice.
* Furthermore, the transfer should henceforth be removed from the
* results returned by @e get_history.
*
* @param cls plugin's closure
* @param account_section specifies the configuration section which
* identifies the account to use to reject the transfer
* @param start_off offset of the wire transfer in plugin-specific format
* @param start_off_len number of bytes in @a start_off
* @param rej_cb function to call with the result of the operation
* @param rej_cb_cls closure for @a rej_cb
* @return handle to cancel the operation
*/
static struct TALER_WIRE_RejectHandle *
template_reject_transfer (void *cls,
const char *account_section,
const void *start_off,
size_t start_off_len,
TALER_WIRE_RejectTransferCallback rej_cb,
void *rej_cb_cls)
{
(void) cls;
(void) account_section;
(void) start_off;
(void) start_off_len;
(void) rej_cb;
(void) rej_cb_cls;
GNUNET_break (0);
return NULL;
}
/**
* Cancel ongoing reject operation. Note that the rejection may still
* proceed. Basically, if this function is called, the rejection may
* have happened or not. This function is usually used during shutdown
* or system upgrades. At a later point, the application must call
* @e reject_transfer again for this wire transfer, unless the
* @e get_history shows that the wire transfer no longer exists.
*
* @param cls plugins' closure
* @param rh operation to cancel
* @return closure of the callback of the operation
*/
static void *
template_reject_transfer_cancel (void *cls,
struct TALER_WIRE_RejectHandle *rh)
{
(void) cls;
(void) rh;
GNUNET_break (0);
return NULL;
}
/**
* Initialize template-wire subsystem.
*
* @param cls a configuration instance
* @return NULL on error, otherwise a `struct TALER_WIRE_Plugin`
*/
void *
libtaler_plugin_wire_template_init (void *cls)
{
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
struct TemplateClosure *tc;
struct TALER_WIRE_Plugin *plugin;
tc = GNUNET_new (struct TemplateClosure);
tc->cfg = cfg;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
"taler",
"CURRENCY",
&tc->currency))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"taler",
"CURRENCY");
GNUNET_free (tc);
return NULL;
}
plugin = GNUNET_new (struct TALER_WIRE_Plugin);
plugin->cls = tc;
plugin->method = "FIXME-REPLACE-BY-METHOD";
plugin->amount_round = &template_amount_round;
plugin->wire_validate = &template_wire_validate;
plugin->prepare_wire_transfer = &template_prepare_wire_transfer;
plugin->prepare_wire_transfer_cancel = &template_prepare_wire_transfer_cancel;
plugin->execute_wire_transfer = &template_execute_wire_transfer;
plugin->execute_wire_transfer_cancel = &template_execute_wire_transfer_cancel;
plugin->get_history = &template_get_history;
plugin->get_history_cancel = &template_get_history_cancel;
plugin->reject_transfer = &template_reject_transfer;
plugin->reject_transfer_cancel = &template_reject_transfer_cancel;
return plugin;
}
/**
* Shutdown Template wire subsystem.
*
* @param cls a `struct TALER_WIRE_Plugin`
* @return NULL (always)
*/
void *
libtaler_plugin_wire_template_done (void *cls)
{
struct TALER_WIRE_Plugin *plugin = cls;
struct TemplateClosure *tc = plugin->cls;
GNUNET_free (tc->currency);
GNUNET_free (tc);
GNUNET_free (plugin);
return NULL;
}
/* end of plugin_wire_template.c */

View File

@ -1,189 +0,0 @@
/*
This file is part of TALER
(C) 2015, 2016, 2017 GNUnet e.V. and Inria
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
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file wire/test_wire_plugin.c
* @brief Tests for wire plugins
* @author Christian Grothoff
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_wire_lib.h"
#include "taler_wire_plugin.h"
#include <gnunet/gnunet_json_lib.h>
/**
* Definitions for a test with a plugin.
*/
struct TestBlock
{
/**
* Name of the plugin to test.
*/
const char *plugin_name;
/**
* Amount to give to the rounding function.
*/
const char *round_in;
/**
* Expected result from rounding.
*/
const char *round_out;
/**
* Currency to give to the plugin.
*/
const char *currency;
};
/**
* List of plugins and (unsigned) JSON account definitions
* to use for the tests.
*/
static struct TestBlock tests[] = {
#if HAVE_LIBCURL
{
.plugin_name = "taler_bank",
.round_in = "KUDOS:0.123456",
.round_out = "KUDOS:0.12",
.currency = "KUDOS"
},
#endif
{
NULL, NULL, NULL, NULL
}
};
/**
* Our configuration.
*/
static struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Run the test.
*
* @param test details of the test
* @param plugin plugin to test
* @return #GNUNET_OK on success
*/
static int
run_test (const struct TestBlock *test,
struct TALER_WIRE_Plugin *plugin)
{
struct GNUNET_HashCode salt;
struct TALER_Amount in;
struct TALER_Amount expect;
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
&salt,
sizeof (salt));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (test->round_in,
&in));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (test->round_out,
&expect));
if (GNUNET_OK !=
plugin->amount_round (plugin->cls,
&in))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
if (0 != TALER_amount_cmp (&in, &expect))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
if (GNUNET_NO !=
plugin->amount_round (plugin->cls,
&in))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
memset (&in, 0, sizeof (in));
GNUNET_log_skip (GNUNET_ERROR_TYPE_ERROR, 1);
if (GNUNET_SYSERR !=
plugin->amount_round (plugin->cls,
&in))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
int
main (int argc,
const char *const argv[])
{
int ret;
struct TALER_WIRE_Plugin *plugin;
const struct TestBlock *test;
GNUNET_log_setup ("test-wire-plugin",
"WARNING",
NULL);
cfg = GNUNET_CONFIGURATION_create ();
GNUNET_assert (GNUNET_OK ==
GNUNET_CONFIGURATION_load (cfg,
"test_wire_plugin.conf"));
ret = GNUNET_OK;
for (unsigned int i = 0; NULL != (test = &tests[i])->plugin_name; i++)
{
GNUNET_CONFIGURATION_set_value_string (cfg,
"taler",
"CURRENCY",
test->currency);
plugin = TALER_WIRE_plugin_load (cfg,
test->plugin_name);
if (NULL == plugin)
{
TALER_LOG_ERROR ("Could not load plugin `%s'\n",
test->plugin_name);
return 77;
}
ret = run_test (test, plugin);
TALER_WIRE_plugin_unload (plugin);
if (GNUNET_OK != ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"%s FAILED\n",
test->plugin_name);
break;
}
else
{
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"%s PASS\n",
test->plugin_name);
}
}
GNUNET_CONFIGURATION_destroy (cfg);
if (GNUNET_OK != ret)
return 1;
return 0;
}

View File

@ -1,25 +0,0 @@
# This file is in the public domain.
#
[account-taler-bank]
# This is the response we give out for the /wire request. It provides
# wallets with the bank information for transfers to the exchange.
WIRE_JSON = test_wire_plugin_test.json
# Our bank account URL
URL = payto://x-taler-bank/2
# Which wire plugin should we used to access the account?
PLUGIN = taler_bank
[account-sepa]
# This is the response we give out for the /wire request. It provides
# wallets with the bank information for transfers to the exchange.
WIRE_JSON = test_wire_plugin_sepa.json
# Which wire plugin should we used to access the account?
PLUGIN = ebics
[taler]
CURRENCY = "EUR"

View File

@ -1,365 +0,0 @@
/*
This file is part of TALER
(C) 2015-2018 Taler Systems SA
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
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file wire/test_wire_plugin_transactions_taler-bank.c
* @brief Tests performing actual transactions with the taler-bank wire plugin against FAKEBANK
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_wire_lib.h"
#include "taler_wire_plugin.h"
#include "taler_fakebank_lib.h"
#include <gnunet/gnunet_json_lib.h>
/**
* When does the test timeout? Right now, we expect this to be very
* fast.
*/
#define TIMEOUT GNUNET_TIME_UNIT_SECONDS
/**
* Destination account to use.
*/
static const char *dest_account = "payto://x-taler-bank/localhost:8088/42";
/**
* Origin account, section in the configuration file.
*/
static const char *my_account = "account-test";
/**
* Our configuration.
*/
static struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Set to #GNUNET_SYSERR if the test failed.
*/
static int global_ret;
/**
* The 'test' plugin that we are using for the test.
*/
static struct TALER_WIRE_Plugin *plugin;
/**
* Active preparation handle, or NULL if not active.
*/
static struct TALER_WIRE_PrepareHandle *ph;
/**
* Active execution handle, or NULL if not active.
*/
static struct TALER_WIRE_ExecuteHandle *eh;
/**
* Handle to the bank.
*/
static struct TALER_FAKEBANK_Handle *fb;
/**
* Handle to the history request.
*/
static struct TALER_WIRE_HistoryHandle *hh;
/**
* Handle to the history-range request (the "legacy" bank API).
*/
static struct TALER_WIRE_HistoryHandle *hhr;
/**
* Handle for the timeout task.
*/
static struct GNUNET_SCHEDULER_Task *tt;
/**
* Which serial ID do we expect to get from /history?
*/
static uint64_t serial_target;
/**
* Wire transfer identifier we are using.
*/
static struct TALER_WireTransferIdentifierRawP wtid;
/**
* Function called on shutdown (regular, error or CTRL-C).
*
* @param cls NULL
*/
static void
do_shutdown (void *cls)
{
(void) cls;
TALER_FAKEBANK_stop (fb);
fb = NULL;
if (NULL != eh)
{
plugin->execute_wire_transfer_cancel (plugin->cls,
eh);
eh = NULL;
}
if (NULL != ph)
{
plugin->prepare_wire_transfer_cancel (plugin->cls,
ph);
ph = NULL;
}
if (NULL != hh)
{
plugin->get_history_cancel (plugin->cls,
hh);
hh = NULL;
}
if (NULL != hhr)
{
plugin->get_history_cancel (plugin->cls,
hhr);
hhr = NULL;
}
if (NULL != tt)
{
GNUNET_SCHEDULER_cancel (tt);
tt = NULL;
}
TALER_WIRE_plugin_unload (plugin);
}
/**
* Function called on timeout.
*
* @param cls NULL
*/
static void
timeout_cb (void *cls)
{
tt = NULL;
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
}
/**
* Callbacks of this type are used to serve the result of asking
* the bank for the transaction history.
*
* @param cls closure
* @param ec taler status code
* @param dir direction of the transfer
* @param row_off identification of the position at
* which we are querying
* @param row_off_size number of bytes in @a row_off
* @param details details about the wire transfer
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to
* abort iteration
*/
static int
history_result_cb
(void *cls,
enum TALER_ErrorCode ec,
enum TALER_BANK_Direction dir,
const void *row_off,
size_t row_off_size,
const struct TALER_WIRE_TransferDetails *details)
{
uint64_t *serialp;
uint64_t serialh;
struct TALER_Amount amount;
if ( (TALER_BANK_DIRECTION_NONE == dir) &&
(GNUNET_OK == global_ret) )
{
GNUNET_SCHEDULER_shutdown ();
hh = NULL;
return GNUNET_OK;
}
if (sizeof (uint64_t) != row_off_size)
{
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
return GNUNET_SYSERR;
}
serialp = (uint64_t *) row_off;
serialh = GNUNET_ntohll (*serialp);
if (serialh != serial_target)
{
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
return GNUNET_SYSERR;
}
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("KUDOS:5.01",
&amount));
if (0 != TALER_amount_cmp (&amount,
&details->amount))
{
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
return GNUNET_SYSERR;
}
if (0 != GNUNET_memcmp (&wtid,
&details->wtid))
{
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
return GNUNET_SYSERR;
}
global_ret = GNUNET_OK;
return GNUNET_OK;
}
/**
* Function called with the result from the execute step.
*
* @param cls closure
* @param success #GNUNET_OK on success,
* #GNUNET_SYSERR on failure
* @param row_id ID of the fresh transaction,
* in _network_ byte order.
* @param emsg NULL on success, otherwise an error message
*/
static void
confirmation_cb (void *cls,
int success,
const void *row_id,
size_t row_id_size,
const char *emsg)
{
uint64_t tmp;
eh = NULL;
if (GNUNET_OK != success)
{
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
return;
}
memcpy (&tmp,
row_id,
row_id_size);
serial_target = GNUNET_ntohll (tmp);
hh = plugin->get_history (plugin->cls,
my_account,
TALER_BANK_DIRECTION_BOTH,
NULL,
0,
5,
&history_result_cb,
NULL);
}
/**
* Callback with prepared transaction.
*
* @param cls closure
* @param buf transaction data to persist, NULL on error
* @param buf_size number of bytes in @a buf, 0 on error
*/
static void
prepare_cb (void *cls,
const char *buf,
size_t buf_size)
{
ph = NULL;
if (NULL == buf)
{
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
return;
}
plugin->execute_wire_transfer (plugin->cls,
buf,
buf_size,
&confirmation_cb,
NULL);
}
/**
* Run the test.
*
* @param cls NULL
*/
static void
run (void *cls)
{
struct TALER_Amount amount;
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
NULL);
tt = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
&timeout_cb,
NULL);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&wtid,
sizeof (wtid));
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("KUDOS:5.01",
&amount));
fb = TALER_FAKEBANK_start (8088);
ph = plugin->prepare_wire_transfer (plugin->cls,
my_account,
dest_account,
&amount,
"https://exchange.net/",
&wtid,
&prepare_cb,
NULL);
}
int
main (int argc,
const char *const argv[])
{
GNUNET_log_setup ("test-wire-plugin-transactions-test",
"WARNING",
NULL);
cfg = GNUNET_CONFIGURATION_create ();
GNUNET_assert (GNUNET_OK ==
GNUNET_CONFIGURATION_load (cfg,
"test_wire_plugin_transactions_taler-bank.conf"));
global_ret = GNUNET_OK;
plugin = TALER_WIRE_plugin_load (cfg,
"taler_bank");
GNUNET_assert (NULL != plugin);
GNUNET_SCHEDULER_run (&run,
NULL);
GNUNET_CONFIGURATION_destroy (cfg);
if (GNUNET_OK != global_ret)
return 1;
return 0;
}
/* end of test_wire_plugin_transactions_taler-bank.c */

View File

@ -1,12 +0,0 @@
# This file is in the public domain.
#
[account-test]
# This is the response we give out for the /wire request. It provides
# wallets with the bank information for transfers to the exchange.
TALER_BANK_AUTH_METHOD = NONE
URL = payto://x-taler-bank/localhost:8088/2
[taler]
CURRENCY = "KUDOS"

View File

@ -13,7 +13,6 @@ lib_LTLIBRARIES = \
libtalerwire_la_SOURCES = \
payto.c \
wire.c \
wire_helper.c
libtalerwire_la_LIBADD = \
-lgnunetutil \

View File

@ -20,6 +20,7 @@
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_bank_service.h"
#include "taler_wire_lib.h"
/**
@ -43,8 +44,8 @@ TALER_WIRE_account_free (struct TALER_Account *acc)
case TALER_PAC_X_TALER_BANK:
GNUNET_free (acc->details.x_taler_bank.hostname);
acc->details.x_taler_bank.hostname = NULL;
GNUNET_free (acc->details.x_taler_bank.bank_base_url);
acc->details.x_taler_bank.bank_base_url = NULL;
GNUNET_free (acc->details.x_taler_bank.account_base_url);
acc->details.x_taler_bank.account_base_url = NULL;
break;
case TALER_PAC_IBAN:
GNUNET_free (acc->details.iban.number);
@ -410,7 +411,8 @@ parse_payto_x_taler_bank (const char *account_url,
const char *hostname;
const char *account;
const char *q;
unsigned long long no;
unsigned int port;
char *p;
#define PREFIX "payto://x-taler-bank/"
if (0 != strncasecmp (account_url,
@ -422,47 +424,22 @@ parse_payto_x_taler_bank (const char *account_url,
(unsigned char) '/')))
return TALER_EC_PAYTO_MALFORMED;
account++;
if (NULL != (q = strchr (account,
(unsigned char) '?')))
{
char *s;
s = GNUNET_strndup (account,
q - account);
if (1 != sscanf (s,
"%llu",
&no))
{
GNUNET_free (s);
return TALER_EC_PAYTO_MALFORMED;
}
GNUNET_free (s);
}
else if (1 != sscanf (account,
"%llu",
&no))
{
return TALER_EC_PAYTO_MALFORMED;
}
if (no > MAX_ACCOUNT_NO)
return TALER_EC_PAYTO_MALFORMED;
if (NULL != r_account)
{
long long unsigned port;
char *p;
if (NULL == r_account)
return TALER_EC_NONE;
q = strchr (account,
(unsigned char) '?');
if (0 == q)
q = account + strlen (account);
r_account->details.x_taler_bank.hostname
= GNUNET_strndup (hostname,
account - hostname);
r_account->details.x_taler_bank.no = no;
port = 443; /* if non given, equals 443. */
if (NULL != (p = strchr (r_account->details.x_taler_bank.hostname,
(unsigned char) ':')))
{
p++;
if (1 != sscanf (p,
"%llu",
"%u",
&port))
{
GNUNET_break (0);
@ -476,20 +453,23 @@ parse_payto_x_taler_bank (const char *account_url,
{
GNUNET_assert
(GNUNET_SYSERR != GNUNET_asprintf
(&r_account->details.x_taler_bank.bank_base_url,
"http://%s",
r_account->details.x_taler_bank.hostname));
(&r_account->details.x_taler_bank.account_base_url,
"http://%s/%.*s",
r_account->details.x_taler_bank.hostname,
(int) (q - account),
account));
}
else
{
GNUNET_assert
(GNUNET_SYSERR != GNUNET_asprintf
(&r_account->details.x_taler_bank.bank_base_url,
"https://%s",
r_account->details.x_taler_bank.hostname));
(&r_account->details.x_taler_bank.account_base_url,
"https://%s/%.*s",
r_account->details.x_taler_bank.hostname,
(int) (q - account),
account));
}
r_account->type = TALER_PAC_X_TALER_BANK;
}
return TALER_EC_NONE;
}

View File

@ -1,149 +0,0 @@
/*
This file is part of TALER
(C) 2015, 2016, 2017, 2018 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
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file wire/wire.c
* @brief Functions for loading wire plugins
* @author Christian Grothoff <christian@grothoff.org>
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_wire_lib.h"
/**
* A wire plugin that we have loaded.
*/
struct WirePlugin
{
/**
* We keep these in a DLL.
*/
struct WirePlugin *next;
/**
* We keep these in a DLL.
*/
struct WirePlugin *prev;
/**
* Type of this wire plugin.
*/
char *type;
/**
* Wire plugin
*/
struct TALER_WIRE_Plugin *plugin;
/**
* Reference counter for the plugin.
*/
unsigned int rc;
};
/**
* Head of the DLL of loaded wire plugins.
*/
static struct WirePlugin *wp_head;
/**
* Tail of the DLL of loaded wire plugins.
*/
static struct WirePlugin *wp_tail;
/**
* Load a WIRE plugin.
*
* @param cfg configuration to use
* @param plugin_name name of the plugin to load
* @return the plugin object pointer, or NULL upon errors.
*/
struct TALER_WIRE_Plugin *
TALER_WIRE_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *plugin_name)
{
char *lib_name;
struct TALER_WIRE_Plugin *plugin;
struct WirePlugin *wp;
for (wp = wp_head; NULL != wp; wp = wp->next)
if (0 == strcasecmp (plugin_name,
wp->type))
{
wp->rc++;
return wp->plugin;
}
(void) GNUNET_asprintf (&lib_name,
"libtaler_plugin_wire_%s",
plugin_name);
plugin = GNUNET_PLUGIN_load (lib_name,
(void *) cfg);
if (NULL != plugin)
plugin->library_name = lib_name;
else
GNUNET_free (lib_name);
if (NULL == plugin)
return NULL;
wp = GNUNET_new (struct WirePlugin);
wp->plugin = plugin;
wp->type = GNUNET_strdup (plugin_name);
GNUNET_CONTAINER_DLL_insert (wp_head,
wp_tail,
wp);
wp->rc = 1;
return plugin;
}
/**
* Unload a WIRE plugin.
*
* @param plugin the plugin to unload
*/
void
TALER_WIRE_plugin_unload (struct TALER_WIRE_Plugin *plugin)
{
struct WirePlugin *wp;
char *lib_name;
if (NULL == plugin)
return;
for (wp = wp_head; NULL != wp; wp = wp->next)
{
if (plugin == wp->plugin)
{
wp->rc--;
if (0 < wp->rc)
return;
GNUNET_CONTAINER_DLL_remove (wp_head,
wp_tail,
wp);
GNUNET_free (wp->type);
GNUNET_free (wp);
break;
}
}
lib_name = plugin->library_name;
GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
plugin));
GNUNET_free (lib_name);
}
/* end of wire.c */

View File

@ -20,6 +20,7 @@
/**
* @file wire/wire_helper.c
* @brief Helper functions for dealing with wire formats
* @author Christian Grothoff <christian@grothoff.org>
*/
#include "platform.h"
@ -32,23 +33,6 @@
#define PAYTO "payto://"
/**
* Maps wire methods to plugin names.
*/
struct ConversionTable
{
/**
* Wire method (e.g. 'iban', 'x-taler-bank', ..)
*/
const char *method;
/**
* Plugin name, e.g. 'taler_bank', ..
*/
const char *plugin_name;
};
/**
* Obtain the payment method from a @a payto_url
*
@ -76,35 +60,23 @@ TALER_WIRE_payto_get_method (const char *payto_url)
/**
* Get the plugin name from the payment method.
* Round the amount to something that can be
* transferred on the wire.
*
* FIXME: this is ugly, would be better to have
* a way to iterate over all plugins and interrogate
* them as to what wire method(s) they support!
*
* @param method the method implemented by the plugin (for
* simplicity, we assume 1 method is implemented by 1 plugin).
* @return the plugin name, NULL if not found.
* @param[in,out] amount amount to round down
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
* #GNUNET_SYSERR if the amount or currency was invalid
*/
const char *
TALER_WIRE_get_plugin_from_method (const char *method)
int
TALER_WIRE_amount_round (struct TALER_Amount *amount)
{
static const struct ConversionTable ct[] = {
{"x-taler-bank", "taler_bank"},
{"iban", "taler_bank"},
{NULL, NULL}
};
uint32_t delta;
for (unsigned int i = 0;
NULL != ct[i].method;
i++)
{
if (0 == strcmp (method,
ct[i].method))
return ct[i].plugin_name;
}
return NULL;
delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / 100);
if (0 == delta)
return GNUNET_NO;
amount->fraction -= delta;
return GNUNET_OK;
}