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:
parent
554da10133
commit
9443c10d7f
@ -558,6 +558,5 @@ AC_CONFIG_FILES([Makefile
|
||||
src/util/Makefile
|
||||
src/util/taler-config
|
||||
src/wire/Makefile
|
||||
src/wire-plugins/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
@ -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
|
||||
|
@ -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 = \
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
|
315
src/bank-lib/bank_api_credit.c
Normal file
315
src/bank-lib/bank_api_credit.c
Normal 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 */
|
@ -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 */
|
@ -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.
|
||||
*
|
||||
|
@ -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 */
|
368
src/bank-lib/bank_api_transaction.c
Normal file
368
src/bank-lib/bank_api_transaction.c
Normal 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",
|
||||
×tamp),
|
||||
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 */
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
×tamp));
|
||||
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,
|
||||
×tamp);
|
||||
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,
|
||||
×tamp);
|
||||
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 */
|
758
src/bank-lib/testing_api_cmd_history_debit.c
Normal file
758
src/bank-lib/testing_api_cmd_history_debit.c
Normal 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 */
|
@ -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 */
|
@ -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) )
|
||||
{
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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 \
|
||||
|
@ -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,
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
77
src/lib/testing_api_trait_reserve_pub.c
Normal file
77
src/lib/testing_api_trait_reserve_pub.c
Normal 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 */
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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 */
|
@ -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;
|
||||
}
|
@ -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"
|
@ -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 */
|
@ -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"
|
@ -13,7 +13,6 @@ lib_LTLIBRARIES = \
|
||||
|
||||
libtalerwire_la_SOURCES = \
|
||||
payto.c \
|
||||
wire.c \
|
||||
wire_helper.c
|
||||
libtalerwire_la_LIBADD = \
|
||||
-lgnunetutil \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
149
src/wire/wire.c
149
src/wire/wire.c
@ -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 */
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user