This commit is contained in:
Christian Grothoff 2020-01-12 17:58:17 +01:00
parent 00740610ba
commit c6ba84462d
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
4 changed files with 230 additions and 408 deletions

View File

@ -63,16 +63,61 @@ struct Transaction
*/ */
char *credit_account; char *credit_account;
/**
* What does the @e subject contain?
*/
enum
{
/**
* Transfer TO the exchange.
*/
T_CREDIT,
/**
* Transfer FROM the exchange.
*/
T_DEBIT
} type;
/**
* Wire transfer subject.
*/
union
{
/**
* Used if @e type is T_DEBIT.
*/
struct
{
/** /**
* Subject of the transfer. * Subject of the transfer.
*/ */
char *subject; struct TALER_WireTransferIdentifierRawP wtid;
/** /**
* Base URL of the exchange. * Base URL of the exchange.
*/ */
char *exchange_base_url; char *exchange_base_url;
} debit;
/**
* Used if @e type is T_CREDIT.
*/
struct
{
/**
* Reserve public key of the credit operation.
*/
struct TALER_ReservePublicKeyP reserve_pub;
} credit;
} subject;
/** /**
* When did the transaction happen? * When did the transaction happen?
*/ */
@ -142,43 +187,11 @@ struct TALER_FAKEBANK_Handle
/** /**
* Check that the @a want_amount was transferred from * Generate log messages for failed check operation.
* the @a want_debit to the @a want_credit account. If
* so, set the @a subject to the transfer identifier.
* If not, return #GNUNET_SYSERR.
*
* @param h bank instance
* @param want_amount transfer amount desired
* @param want_debit account that should have been debited
* @param want_credit account that should have been credited
* @param exchange_base_url expected base URL of the exchange
* i.e. "https://example.com/"; may include a port
* @param[out] subject set to the wire transfer identifier
* @return #GNUNET_OK on success
*/ */
int static void
TALER_FAKEBANK_check (struct TALER_FAKEBANK_Handle *h, check_log (struct TALER_FAKEBANK_Handle *h)
const struct TALER_Amount *want_amount,
const char *want_debit,
const char *want_credit,
const char *exchange_base_url,
char **subject)
{ {
for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
{
if ( (want_debit == t->debit_account) &&
(want_credit == t->credit_account) &&
(0 == TALER_amount_cmp (want_amount,
&t->amount)) &&
(GNUNET_NO == t->checked) &&
(0 == strcasecmp (exchange_base_url,
t->exchange_base_url)) )
{
*subject = GNUNET_strdup (t->subject);
t->checked = GNUNET_YES;
return GNUNET_OK;
}
}
fprintf (stderr, fprintf (stderr,
"Did not find matching transaction!\nI have:\n"); "Did not find matching transaction!\nI have:\n");
for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next) for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
@ -198,6 +211,87 @@ TALER_FAKEBANK_check (struct TALER_FAKEBANK_Handle *h,
(unsigned long long) want_credit, (unsigned long long) want_credit,
TALER_amount2s (want_amount), TALER_amount2s (want_amount),
exchange_base_url); exchange_base_url);
}
/**
* Check that the @a want_amount was transferred from the @a
* want_debit to the @a want_credit account. If so, set the @a subject
* to the transfer identifier and remove the transaction from the
* list. If the transaction was not recorded, return #GNUNET_SYSERR.
*
* @param h bank instance
* @param want_amount transfer amount desired
* @param want_debit account that should have been debited
* @param want_debit account that should have been credited
* @param exchange_base_url expected base URL of the exchange,
* i.e. "https://example.com/"; may include a port
* @param[out] subject set to the wire transfer identifier
* @return #GNUNET_OK on success
*/
int
TALER_FAKEBANK_check_debit (struct TALER_FAKEBANK_Handle *h,
const struct TALER_Amount *want_amount,
const char *want_debit,
const char *want_credit,
const char *exchange_base_url,
struct TALER_WireTransferIdentifierRawP **subject)
{
for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
{
if ( (want_debit == t->debit_account) &&
(want_credit == t->credit_account) &&
(0 == TALER_amount_cmp (want_amount,
&t->amount)) &&
(GNUNET_NO == t->checked) &&
(0 == strcasecmp (exchange_base_url,
t->exchange_base_url)) )
{
*subject = GNUNET_strdup (t->subject);
t->checked = GNUNET_YES;
return GNUNET_OK;
}
}
check_log (h);
return GNUNET_SYSERR;
}
/**
* Check that the @a want_amount was transferred from the @a want_debit to the
* @a want_credit account with the @a subject. If so, remove the transaction
* from the list. If the transaction was not recorded, return #GNUNET_SYSERR.
*
* @param h bank instance
* @param want_amount transfer amount desired
* @param want_debit account that should have been debited
* @param want_debit account that should have been credited
* @param reserve_pub reserve public key expected in wire subject
* @return #GNUNET_OK on success
*/
int
TALER_FAKEBANK_check_credit (struct TALER_FAKEBANK_Handle *h,
const struct TALER_Amount *want_amount,
const char *want_debit,
const char *want_credit,
const struct TALER_ReservePublicKeyP *reserve_pub)
{
for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
{
if ( (want_debit == t->debit_account) &&
(want_credit == t->credit_account) &&
(0 == TALER_amount_cmp (want_amount,
&t->amount)) &&
(GNUNET_NO == t->checked) &&
(0 == strcasecmp (exchange_base_url,
t->exchange_base_url)) )
{
*subject = GNUNET_strdup (t->subject);
t->checked = GNUNET_YES;
return GNUNET_OK;
}
}
check_log (h);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
@ -218,7 +312,8 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
const char *debit_account, const char *debit_account,
const char *credit_account, const char *credit_account,
const struct TALER_Amount *amount, const struct TALER_Amount *amount,
const char *subject, const struct
TALER_WireTransferIdentifierRawP *subject,
const char *exchange_base_url) const char *exchange_base_url)
{ {
struct Transaction *t; struct Transaction *t;
@ -234,6 +329,50 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
t->debit_account = GNUNET_strdup (debit_account); t->debit_account = GNUNET_strdup (debit_account);
t->credit_account = GNUNET_strdup (credit_account); t->credit_account = GNUNET_strdup (credit_account);
t->amount = *amount; t->amount = *amount;
t->row_id = ++h->serial_counter;
t->date = GNUNET_TIME_absolute_get ();
t->type = T_DEBIT;
t->subject.debit.exchange_base_url = GNUNET_strdup (exchange_base_url);
t->subject.debit.wtid = *subject;
GNUNET_TIME_round_abs (&t->date);
GNUNET_CONTAINER_DLL_insert_tail (h->transactions_head,
h->transactions_tail,
t);
return t->row_id;
}
/**
* Tell the fakebank to create another wire transfer *to* an exchange.
*
* @param h fake bank handle
* @param debit_account account to debit
* @param credit_account account to credit
* @param amount amount to transfer
* @param reserve_pub reserve public key to use in subject
* @return serial_id of the transfer
*/
uint64_t
TALER_FAKEBANK_make_admin_transfer (struct TALER_FAKEBANK_Handle *h,
const char *debit_account,
const char *credit_account,
const struct TALER_Amount *amount,
const struct
TALER_ReservePublicKeyP *reserve_pub)
{
struct Transaction *t;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Making transfer from %s to %s over %s and subject %s; for exchange: %s\n",
debit_account,
credit_account,
TALER_amount2s (amount),
TALER_B2S (reserve_pub),
exchange_base_url);
t = GNUNET_new (struct Transaction);
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->exchange_base_url = GNUNET_strdup (exchange_base_url);
t->row_id = ++h->serial_counter; t->row_id = ++h->serial_counter;
t->date = GNUNET_TIME_absolute_get (); t->date = GNUNET_TIME_absolute_get ();
@ -273,18 +412,12 @@ TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h)
while (NULL != t) while (NULL != t)
{ {
if (GNUNET_YES != t->checked) if (GNUNET_YES != t->checked)
{
char *s;
s = TALER_amount_to_string (&t->amount);
fprintf (stderr, fprintf (stderr,
"%s -> %s (%s) from %s\n", "%s -> %s (%s) from %s\n",
t->debit_account, t->debit_account,
t->credit_account, t->credit_account,
s, TALER_amount2s (&t->amount),
t->exchange_base_url); t->exchange_base_url);
GNUNET_free (s);
}
t = t->next; t = t->next;
} }
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -309,7 +442,8 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h)
GNUNET_free (t->subject); GNUNET_free (t->subject);
GNUNET_free (t->debit_account); GNUNET_free (t->debit_account);
GNUNET_free (t->credit_account); GNUNET_free (t->credit_account);
GNUNET_free (t->exchange_base_url); if (T_DEBIT == t->type)
GNUNET_free (t->subject.debit.exchange_base_url);
GNUNET_free (t); GNUNET_free (t);
} }
if (NULL != h->mhd_task) if (NULL != h->mhd_task)

View File

@ -1,32 +0,0 @@
/*
This file is part of TALER
(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 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/fakebank.h
* @brief definitions for the "/history" layer.
* @author Marcello Stanisci <stanisci.m@gmail.com>
*/
#ifndef FAKEBANK_H
#define FAKEBANK_H
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include "taler_bank_service.h"
#endif

View File

@ -62,7 +62,7 @@ TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h);
/** /**
* Tell the fakebank to create another wire transfer. * Tell the fakebank to create another wire transfer *from* an exchange.
* *
* @param h fake bank handle * @param h fake bank handle
* @param debit_account account to debit * @param debit_account account to debit
@ -77,18 +77,36 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
const char *debit_account, const char *debit_account,
const char *credit_account, const char *credit_account,
const struct TALER_Amount *amount, const struct TALER_Amount *amount,
const char *subject, const struct
TALER_WireTransferIdentifierRawP *subject,
const char *exchange_base_url); const char *exchange_base_url);
/**
* Tell the fakebank to create another wire transfer *to* an exchange.
*
* @param h fake bank handle
* @param debit_account account to debit
* @param credit_account account to credit
* @param amount amount to transfer
* @param reserve_pub reserve public key to use in subject
* @return serial_id of the transfer
*/
uint64_t
TALER_FAKEBANK_make_admin_transfer (struct TALER_FAKEBANK_Handle *h,
const char *debit_account,
const char *credit_account,
const struct TALER_Amount *amount,
const struct
TALER_ReservePublicKeyP *reserve_pub);
/** /**
* Check that the @a want_amount was transferred from the @a * Check that the @a want_amount was transferred from the @a
* want_debit to the @a want_credit account. If so, set the @a subject * want_debit to the @a want_credit account. If so, set the @a subject
* to the transfer identifier and remove the transaction from the * to the transfer identifier and remove the transaction from the
* list. If the transaction was not recorded, return #GNUNET_SYSERR. * list. If the transaction was not recorded, return #GNUNET_SYSERR.
* *
* Rejected transfers do NOT show with "check".
*
* @param h bank instance * @param h bank instance
* @param want_amount transfer amount desired * @param want_amount transfer amount desired
* @param want_debit account that should have been debited * @param want_debit account that should have been debited
@ -99,12 +117,32 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
* @return #GNUNET_OK on success * @return #GNUNET_OK on success
*/ */
int int
TALER_FAKEBANK_check (struct TALER_FAKEBANK_Handle *h, TALER_FAKEBANK_check_debit (struct TALER_FAKEBANK_Handle *h,
const struct TALER_Amount *want_amount, const struct TALER_Amount *want_amount,
const char *want_debit, const char *want_debit,
const char *want_credit, const char *want_credit,
const char *exchange_base_url, const char *exchange_base_url,
char **subject); struct TALER_WireTransferIdentifierRawP **subject);
/**
* Check that the @a want_amount was transferred from the @a want_debit to the
* @a want_credit account with the @a subject. If so, remove the transaction
* from the list. If the transaction was not recorded, return #GNUNET_SYSERR.
*
* @param h bank instance
* @param want_amount transfer amount desired
* @param want_debit account that should have been debited
* @param want_debit account that should have been credited
* @param reserve_pub reserve public key expected in wire subject
* @return #GNUNET_OK on success
*/
int
TALER_FAKEBANK_check_credit (struct TALER_FAKEBANK_Handle *h,
const struct TALER_Amount *want_amount,
const char *want_debit,
const char *want_credit,
const struct TALER_ReservePublicKeyP *reserve_pub);
/** /**

View File

@ -1,318 +0,0 @@
/*
This file is part of TALER
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
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 include/taler_wire_plugin.h
* @brief Plugin API for the handling of wire transactions
* @author Christian Grothoff
*/
#ifndef TALER_WIRE_PLUGIN_H
#define TALER_WIRE_PLUGIN_H
#include <gnunet/gnunet_util_lib.h>
#include "taler_util.h"
#include "taler_error_codes.h"
#include "taler_bank_service.h" /* for `enum TALER_BANK_Direction` and `struct TALER_BANK_TransferDetails` */
/**
* 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
*/
typedef void
(*TALER_WIRE_PrepareTransactionCallback) (void *cls,
const char *buf,
size_t buf_size);
/**
* Details about a valid wire transfer to the exchange.
*/
struct TALER_WIRE_CreditDetails
{
/**
* 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_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;
/**
* payto://-URL of the target account which received
* the funds.
*/
const char *target_account_url;
};
/**
* Callbacks of this type are used to serve the result of asking
* 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 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 int
(*TALER_WIRE_CreditResultCallback) (void *cls,
enum TALER_ErrorCode ec,
const void *row_off,
size_t row_off_size,
const struct
TALER_WIRE_CreditDetails *details);
/**
* Callbacks of this type are used to serve the result of asking
* 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 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 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);
/**
* Handle returned for cancelling a preparation step.
*/
struct TALER_WIRE_PrepareHandle;
/**
* Handle returned for cancelling an execution step.
*/
struct TALER_WIRE_ExecuteHandle;
/**
* Handle returned for querying the credit transaction history.
*/
struct TALER_WIRE_CreditHistoryHandle;
/**
* Handle returned for querying the debit transaction history.
*/
struct TALER_WIRE_DebitHistoryHandle;
/**
* 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 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
(*TALER_WIRE_ConfirmationCallback)(void *cls,
int success,
const void *row_id,
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.
*/
struct TALER_WIRE_Plugin
{
/**
* Closure for all callbacks.
*/
void *cls;
/**
* Name of the library which generated this plugin. Set by the
* plugin loader.
*/
char *library_name;
/**
* Which wire method (payto://METHOD/") is supported by this plugin?
* 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
* payment, but IBAN 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
*/
int
(*amount_round) (void *cls,
struct TALER_Amount *amount);
/**
* 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
*/
enum TALER_ErrorCode
(*wire_validate)(void *cls,
const char *account_url);
/**
* 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
* 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 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,
* 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_CreditHistoryHandle *
(*get_credits) (void *cls,
const char *account_section,
const void *start_off,
size_t start_off_len,
int64_t num_results,
TALER_WIRE_CreditResultCallback hres_cb,
void *hres_cb_cls);
/**
* Cancel going over the account's history.
*
* @param cls plugins' closure
* @param chh operation to cancel
*/
void
(*get_credits_cancel) (void *cls,
struct TALER_WIRE_CreditHistoryHandle *chh);
/**
* 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).
*
* @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 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,
* 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_DebitHistoryHandle *
(*get_debits) (void *cls,
const char *account_section,
const void *start_off,
size_t start_off_len,
int64_t num_results,
TALER_WIRE_DebitResultCallback hres_cb,
void *hres_cb_cls);
/**
* Cancel going over the account's history.
*
* @param cls plugins' closure
* @param dhh operation to cancel
*/
void
(*get_debits_cancel) (void *cls,
struct TALER_WIRE_DebitHistoryHandle *dhh);
};
#endif /* TALER_WIRE_PLUGIN_H */