complete taler-exchange-httpd_reserves_close.c logic (first pass, still without DB logic or tests)
This commit is contained in:
parent
4a36ed7fbf
commit
1ce70b1dab
@ -23,6 +23,7 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include <gnunet/gnunet_util_lib.h>
|
#include <gnunet/gnunet_util_lib.h>
|
||||||
#include <jansson.h>
|
#include <jansson.h>
|
||||||
|
#include "taler_kyclogic_lib.h"
|
||||||
#include "taler_mhd_lib.h"
|
#include "taler_mhd_lib.h"
|
||||||
#include "taler_json_lib.h"
|
#include "taler_json_lib.h"
|
||||||
#include "taler_dbevents.h"
|
#include "taler_dbevents.h"
|
||||||
@ -59,26 +60,40 @@ struct ReserveCloseContext
|
|||||||
*/
|
*/
|
||||||
struct TALER_ReserveSignatureP reserve_sig;
|
struct TALER_ReserveSignatureP reserve_sig;
|
||||||
|
|
||||||
/**
|
|
||||||
* Wire fees applying to the request.
|
|
||||||
*/
|
|
||||||
const struct TALER_WireFeeSet *wf;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Amount that will be wired (after closing fees).
|
* Amount that will be wired (after closing fees).
|
||||||
*/
|
*/
|
||||||
struct TALER_Amount wire_amount;
|
struct TALER_Amount wire_amount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current balance of the reserve.
|
||||||
|
*/
|
||||||
|
struct TALER_Amount balance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Where to wire the funds, may be NULL.
|
* Where to wire the funds, may be NULL.
|
||||||
*/
|
*/
|
||||||
const char *payto_uri;
|
const char *payto_uri;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash of the @e payto_uri.
|
* Hash of the @e payto_uri, if given (otherwise zero).
|
||||||
*/
|
*/
|
||||||
struct TALER_PaytoHashP h_payto;
|
struct TALER_PaytoHashP h_payto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KYC status for the request.
|
||||||
|
*/
|
||||||
|
struct TALER_EXCHANGEDB_KycStatus kyc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash of the payto-URI that was used for the KYC decision.
|
||||||
|
*/
|
||||||
|
struct TALER_PaytoHashP kyc_payto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query status from the amount_it() helper function.
|
||||||
|
*/
|
||||||
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -101,6 +116,46 @@ reply_reserve_close_success (struct MHD_Connection *connection,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function called to iterate over KYC-relevant
|
||||||
|
* transaction amounts for a particular time range.
|
||||||
|
* Called within a database transaction, so must
|
||||||
|
* not start a new one.
|
||||||
|
*
|
||||||
|
* @param cls closure, identifies the event type and
|
||||||
|
* account to iterate over events for
|
||||||
|
* @param limit maximum time-range for which events
|
||||||
|
* should be fetched (timestamp in the past)
|
||||||
|
* @param cb function to call on each event found,
|
||||||
|
* events must be returned in reverse chronological
|
||||||
|
* order
|
||||||
|
* @param cb_cls closure for @a cb
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
amount_it (void *cls,
|
||||||
|
struct GNUNET_TIME_Absolute limit,
|
||||||
|
TALER_EXCHANGEDB_KycAmountCallback cb,
|
||||||
|
void *cb_cls)
|
||||||
|
{
|
||||||
|
struct ReserveCloseContext *rcc = cls;
|
||||||
|
enum GNUNET_GenericReturnValue ret;
|
||||||
|
|
||||||
|
ret = cb (cb_cls,
|
||||||
|
&rcc->balance,
|
||||||
|
GNUNET_TIME_absolute_get ());
|
||||||
|
GNUNET_break (GNUNET_SYSERR != ret);
|
||||||
|
if (GNUNET_OK != ret)
|
||||||
|
return;
|
||||||
|
rcc->qs
|
||||||
|
= TEH_plugin->iterate_reserve_close_info (
|
||||||
|
TEH_plugin->cls,
|
||||||
|
&rcc->kyc_payto,
|
||||||
|
limit,
|
||||||
|
cb,
|
||||||
|
cb_cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function implementing /reserves/$RID/close transaction. Given the public
|
* Function implementing /reserves/$RID/close transaction. Given the public
|
||||||
* key of a reserve, return the associated transaction close. Runs the
|
* key of a reserve, return the associated transaction close. Runs the
|
||||||
@ -124,17 +179,14 @@ reserve_close_transaction (void *cls,
|
|||||||
struct ReserveCloseContext *rcc = cls;
|
struct ReserveCloseContext *rcc = cls;
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
struct TALER_Amount balance;
|
struct TALER_Amount balance;
|
||||||
char *payto_uri;
|
char *payto_uri = NULL;
|
||||||
|
const struct TALER_WireFeeSet *wf;
|
||||||
|
|
||||||
#if FIXME
|
qs = TEH_plugin->select_reserve_close_info (
|
||||||
qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls,
|
TEH_plugin->cls,
|
||||||
rcc->reserve_pub,
|
rcc->reserve_pub,
|
||||||
&balance,
|
&balance,
|
||||||
&payto_uri);
|
&payto_uri);
|
||||||
#else
|
|
||||||
qs = GNUNET_DB_STATUS_HARD_ERROR;
|
|
||||||
payto_uri = NULL;
|
|
||||||
#endif
|
|
||||||
switch (qs)
|
switch (qs)
|
||||||
{
|
{
|
||||||
case GNUNET_DB_STATUS_HARD_ERROR:
|
case GNUNET_DB_STATUS_HARD_ERROR:
|
||||||
@ -143,7 +195,7 @@ reserve_close_transaction (void *cls,
|
|||||||
= TALER_MHD_reply_with_error (connection,
|
= TALER_MHD_reply_with_error (connection,
|
||||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||||
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
||||||
"get_reserve_balance");
|
"select_reserve_close_info");
|
||||||
return qs;
|
return qs;
|
||||||
case GNUNET_DB_STATUS_SOFT_ERROR:
|
case GNUNET_DB_STATUS_SOFT_ERROR:
|
||||||
return qs;
|
return qs;
|
||||||
@ -174,27 +226,66 @@ reserve_close_transaction (void *cls,
|
|||||||
(0 != strcmp (payto_uri,
|
(0 != strcmp (payto_uri,
|
||||||
rcc->payto_uri)) ) )
|
rcc->payto_uri)) ) )
|
||||||
{
|
{
|
||||||
struct TALER_EXCHANGEDB_KycStatus kyc;
|
const char *kyc_needed;
|
||||||
struct TALER_PaytoHashP kyc_payto;
|
|
||||||
|
|
||||||
/* FIXME: also fetch KYC status from reserve
|
TALER_payto_hash (rcc->payto_uri,
|
||||||
in query above, and if payto_uri specified
|
&rcc->kyc_payto);
|
||||||
and KYC not yet done (check KYC triggers!),
|
rcc->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
|
||||||
fail with 451 kyc required! */
|
kyc_needed
|
||||||
*mhd_ret
|
= TALER_KYCLOGIC_kyc_test_required (
|
||||||
= TEH_RESPONSE_reply_kyc_required (connection,
|
TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE,
|
||||||
&kyc_payto,
|
&rcc->kyc_payto,
|
||||||
&kyc);
|
TEH_plugin->select_satisfied_kyc_processes,
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
TEH_plugin->cls,
|
||||||
|
&amount_it,
|
||||||
|
rcc);
|
||||||
|
if (rcc->qs < 0)
|
||||||
|
{
|
||||||
|
if (GNUNET_DB_STATUS_SOFT_ERROR == rcc->qs)
|
||||||
|
return rcc->qs;
|
||||||
|
GNUNET_break (0);
|
||||||
|
*mhd_ret
|
||||||
|
= TALER_MHD_reply_with_error (connection,
|
||||||
|
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||||
|
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
||||||
|
"iterate_reserve_close_info");
|
||||||
|
return qs;
|
||||||
|
}
|
||||||
|
rcc->kyc.ok = false;
|
||||||
|
return TEH_plugin->insert_kyc_requirement_for_account (
|
||||||
|
TEH_plugin->cls,
|
||||||
|
kyc_needed,
|
||||||
|
&rcc->kyc_payto,
|
||||||
|
&rcc->kyc.requirement_row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rcc->kyc.ok = true;
|
||||||
if (NULL == rcc->payto_uri)
|
if (NULL == rcc->payto_uri)
|
||||||
rcc->payto_uri = payto_uri;
|
rcc->payto_uri = payto_uri;
|
||||||
|
|
||||||
|
{
|
||||||
|
char *method;
|
||||||
|
|
||||||
|
method = TALER_payto_get_method (rcc->payto_uri);
|
||||||
|
wf = TEH_wire_fees_by_time (rcc->timestamp,
|
||||||
|
method);
|
||||||
|
if (NULL == wf)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
||||||
|
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||||
|
TALER_EC_EXCHANGE_WIRE_FEES_NOT_CONFIGURED,
|
||||||
|
method);
|
||||||
|
GNUNET_free (method);
|
||||||
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
|
}
|
||||||
|
GNUNET_free (method);
|
||||||
|
}
|
||||||
|
|
||||||
if (0 >
|
if (0 >
|
||||||
TALER_amount_subtract (&rcc->wire_amount,
|
TALER_amount_subtract (&rcc->wire_amount,
|
||||||
&balance,
|
&balance,
|
||||||
&rcc->wf->closing))
|
&wf->closing))
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
"Client attempted to close reserve with insufficient balance.\n");
|
"Client attempted to close reserve with insufficient balance.\n");
|
||||||
@ -206,34 +297,29 @@ reserve_close_transaction (void *cls,
|
|||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
qs = TEH_plugin->insert_close_request (TEH_plugin->cls,
|
||||||
|
rcc->reserve_pub,
|
||||||
|
payto_uri,
|
||||||
|
&rcc->reserve_sig,
|
||||||
|
rcc->timestamp,
|
||||||
|
&wf->closing,
|
||||||
|
&rcc->wire_amount);
|
||||||
|
GNUNET_free (payto_uri);
|
||||||
|
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
||||||
{
|
{
|
||||||
#if FIXME
|
GNUNET_break (0);
|
||||||
qs = TEH_plugin->insert_close_request (TEH_plugin->cls,
|
*mhd_ret
|
||||||
rcc->reserve_pub,
|
= TALER_MHD_reply_with_error (connection,
|
||||||
payto_uri,
|
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||||
&rcc->reserve_sig,
|
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
||||||
rcc->timestamp,
|
"insert_close_request");
|
||||||
&rcc->wf->closing,
|
return qs;
|
||||||
&rcc->wire_amount);
|
}
|
||||||
#else
|
if (qs <= 0)
|
||||||
qs = GNUNET_DB_STATUS_HARD_ERROR;
|
{
|
||||||
#endif
|
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
|
||||||
GNUNET_free (payto_uri);
|
return qs;
|
||||||
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
*mhd_ret
|
|
||||||
= TALER_MHD_reply_with_error (connection,
|
|
||||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
|
||||||
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
|
||||||
"insert_close_request");
|
|
||||||
return qs;
|
|
||||||
}
|
|
||||||
if (qs <= 0)
|
|
||||||
{
|
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
|
|
||||||
return qs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
@ -295,18 +381,6 @@ TEH_handler_reserves_close (struct TEH_RequestContext *rc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: can only do this later, as we may get the payto://-URI
|
|
||||||
// with the method from the database!
|
|
||||||
rcc.wf = TEH_wire_fees_by_time (rcc.timestamp,
|
|
||||||
"FIXME-method");
|
|
||||||
if (NULL == rcc.wf)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return TALER_MHD_reply_with_error (rc->connection,
|
|
||||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
|
||||||
TALER_EC_EXCHANGE_WIRE_FEES_NOT_CONFIGURED,
|
|
||||||
"FIXME-method");
|
|
||||||
}
|
|
||||||
if (NULL != rcc.payto_uri)
|
if (NULL != rcc.payto_uri)
|
||||||
TALER_payto_hash (rcc.payto_uri,
|
TALER_payto_hash (rcc.payto_uri,
|
||||||
&rcc.h_payto);
|
&rcc.h_payto);
|
||||||
@ -322,6 +396,7 @@ TEH_handler_reserves_close (struct TEH_RequestContext *rc,
|
|||||||
TALER_EC_EXCHANGE_RESERVES_CLOSE_BAD_SIGNATURE,
|
TALER_EC_EXCHANGE_RESERVES_CLOSE_BAD_SIGNATURE,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TEH_DB_run_transaction (rc->connection,
|
TEH_DB_run_transaction (rc->connection,
|
||||||
"reserve close",
|
"reserve close",
|
||||||
@ -332,6 +407,11 @@ TEH_handler_reserves_close (struct TEH_RequestContext *rc,
|
|||||||
{
|
{
|
||||||
return mhd_ret;
|
return mhd_ret;
|
||||||
}
|
}
|
||||||
|
if (! rcc.kyc.ok)
|
||||||
|
return TEH_RESPONSE_reply_kyc_required (rc->connection,
|
||||||
|
&rcc.kyc_payto,
|
||||||
|
&rcc.kyc);
|
||||||
|
|
||||||
return reply_reserve_close_success (rc->connection,
|
return reply_reserve_close_success (rc->connection,
|
||||||
&rcc);
|
&rcc);
|
||||||
}
|
}
|
||||||
|
@ -4092,6 +4092,47 @@ struct TALER_EXCHANGEDB_Plugin
|
|||||||
const struct GNUNET_TIME_Timestamp *final_expiration);
|
const struct GNUNET_TIME_Timestamp *final_expiration);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select information needed to see if we can close
|
||||||
|
* a reserve.
|
||||||
|
*
|
||||||
|
* @param cls closure
|
||||||
|
* @param reserve_pub which reserve is this about?
|
||||||
|
* @param[out] balance current reserve balance
|
||||||
|
* @param[out] payto_uri set to URL of account that
|
||||||
|
* originally funded the reserve;
|
||||||
|
* could be set to NULL if not known
|
||||||
|
* @return transaction status code, 0 if reserve unknown
|
||||||
|
*/
|
||||||
|
enum GNUNET_DB_QueryStatus
|
||||||
|
(*select_reserve_close_info)(
|
||||||
|
void *cls,
|
||||||
|
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||||
|
struct TALER_Amount *balance,
|
||||||
|
char **payto_uri);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select information needed for KYC checks on reserve close: historic
|
||||||
|
* reserve closures going to the same account.
|
||||||
|
*
|
||||||
|
* @param cls closure
|
||||||
|
* @param h_payto which target account is this about?
|
||||||
|
* @param h_payto account identifier
|
||||||
|
* @param time_limit oldest transaction that could be relevant
|
||||||
|
* @param kac function to call for each applicable amount, in reverse chronological order (or until @a kac aborts by returning anything except #GNUNET_OK).
|
||||||
|
* @param kac_cls closure for @a kac
|
||||||
|
* @return transaction status code, @a kac aborting with #GNUNET_NO is not an error
|
||||||
|
*/
|
||||||
|
enum GNUNET_DB_QueryStatus
|
||||||
|
(*iterate_reserve_close_info)(
|
||||||
|
void *cls,
|
||||||
|
const struct TALER_PaytoHashP *h_payto,
|
||||||
|
struct GNUNET_TIME_Absolute time_limit,
|
||||||
|
TALER_EXCHANGEDB_KycAmountCallback kac,
|
||||||
|
void *kac_cls);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert reserve close operation into database.
|
* Insert reserve close operation into database.
|
||||||
*
|
*
|
||||||
@ -5537,16 +5578,20 @@ struct TALER_EXCHANGEDB_Plugin
|
|||||||
*
|
*
|
||||||
* @param cls the @e cls of this struct with the plugin-specific state
|
* @param cls the @e cls of this struct with the plugin-specific state
|
||||||
* @param reserve_pub public key of the account to close
|
* @param reserve_pub public key of the account to close
|
||||||
|
* @param payto_uri where to wire the funds
|
||||||
* @param reserve_sig signature affiming that the account is to be closed
|
* @param reserve_sig signature affiming that the account is to be closed
|
||||||
* @param request_timestamp timestamp of the close request
|
* @param request_timestamp timestamp of the close request
|
||||||
|
* @param closing_fee closing fee to charge
|
||||||
* @param[out] final_balance set to the final balance in the account that will be wired back to the origin account
|
* @param[out] final_balance set to the final balance in the account that will be wired back to the origin account
|
||||||
* @return transaction status code
|
* @return transaction status code
|
||||||
*/
|
*/
|
||||||
enum GNUNET_DB_QueryStatus
|
enum GNUNET_DB_QueryStatus
|
||||||
(*insert_close_request)(void *cls,
|
(*insert_close_request)(void *cls,
|
||||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||||
|
const char *payto_uri,
|
||||||
const struct TALER_ReserveSignatureP *reserve_sig,
|
const struct TALER_ReserveSignatureP *reserve_sig,
|
||||||
struct GNUNET_TIME_Timestamp request_timestamp,
|
struct GNUNET_TIME_Timestamp request_timestamp,
|
||||||
|
const struct TALER_Amount *closing_fee,
|
||||||
struct TALER_Amount *final_balance);
|
struct TALER_Amount *final_balance);
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,7 +68,12 @@ enum TALER_KYCLOGIC_KycTriggerEvent
|
|||||||
/**
|
/**
|
||||||
* Wallet balance exceeds threshold.
|
* Wallet balance exceeds threshold.
|
||||||
*/
|
*/
|
||||||
TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE = 3
|
TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE = 3,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserve is being closed by force.
|
||||||
|
*/
|
||||||
|
TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE = 4
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -183,6 +183,7 @@ TALER_KYCLOGIC_kyc_trigger_from_string (const char *trigger_s,
|
|||||||
{ "deposit", TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT },
|
{ "deposit", TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT },
|
||||||
{ "merge", TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
|
{ "merge", TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
|
||||||
{ "balance", TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
|
{ "balance", TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
|
||||||
|
{ "close", TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -213,6 +214,8 @@ TALER_KYCLOGIC_kyc_trigger2s (enum TALER_KYCLOGIC_KycTriggerEvent trigger)
|
|||||||
return "merge";
|
return "merge";
|
||||||
case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE:
|
case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE:
|
||||||
return "balance";
|
return "balance";
|
||||||
|
case TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE:
|
||||||
|
return "close";
|
||||||
}
|
}
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user