major rework of withdraw transaction to use stored procedure and (presumably) reduce serialization failures by avoiding SELECT before INSERT
This commit is contained in:
parent
c0d2af8a49
commit
67de20d26e
@ -2110,6 +2110,8 @@ TEH_keys_denomination_by_hash2 (
|
|||||||
&h_denom_pub->hash);
|
&h_denom_pub->hash);
|
||||||
if (NULL == dk)
|
if (NULL == dk)
|
||||||
{
|
{
|
||||||
|
if (NULL == conn)
|
||||||
|
return NULL;
|
||||||
*mret = TEH_RESPONSE_reply_unknown_denom_pub_hash (conn,
|
*mret = TEH_RESPONSE_reply_unknown_denom_pub_hash (conn,
|
||||||
h_denom_pub);
|
h_denom_pub);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -235,11 +235,13 @@ reserve_history_transaction (void *cls,
|
|||||||
MHD_RESULT *mhd_ret)
|
MHD_RESULT *mhd_ret)
|
||||||
{
|
{
|
||||||
struct ReserveHistoryContext *rsc = cls;
|
struct ReserveHistoryContext *rsc = cls;
|
||||||
|
struct TALER_Amount balance;
|
||||||
|
|
||||||
(void) connection;
|
(void) connection;
|
||||||
(void) mhd_ret;
|
(void) mhd_ret;
|
||||||
return TEH_plugin->get_reserve_history (TEH_plugin->cls,
|
return TEH_plugin->get_reserve_history (TEH_plugin->cls,
|
||||||
&rsc->reserve_pub,
|
&rsc->reserve_pub,
|
||||||
|
&balance,
|
||||||
&rsc->rh);
|
&rsc->rh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,21 +91,6 @@ struct WithdrawContext
|
|||||||
*/
|
*/
|
||||||
struct TALER_WithdrawRequestPS wsrd;
|
struct TALER_WithdrawRequestPS wsrd;
|
||||||
|
|
||||||
/**
|
|
||||||
* Value of the coin plus withdraw fee.
|
|
||||||
*/
|
|
||||||
struct TALER_Amount amount_required;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash of the denomination public key.
|
|
||||||
*/
|
|
||||||
struct TALER_DenominationHash denom_pub_hash;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signature over the request.
|
|
||||||
*/
|
|
||||||
struct TALER_ReserveSignatureP signature;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blinded planchet.
|
* Blinded planchet.
|
||||||
*/
|
*/
|
||||||
@ -126,39 +111,9 @@ struct WithdrawContext
|
|||||||
*/
|
*/
|
||||||
struct TALER_EXCHANGEDB_KycStatus kyc;
|
struct TALER_EXCHANGEDB_KycStatus kyc;
|
||||||
|
|
||||||
/**
|
|
||||||
* Set to true if the operation was denied due to
|
|
||||||
* failing @e kyc checks.
|
|
||||||
*/
|
|
||||||
bool kyc_denied;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function called with another amount that was
|
|
||||||
* already withdrawn. Accumulates all amounts in
|
|
||||||
* @a cls.
|
|
||||||
*
|
|
||||||
* @param[in,out] cls a `struct TALER_Amount`
|
|
||||||
* @param val value to add to @a cls
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
accumulate_withdraws (void *cls,
|
|
||||||
const struct TALER_Amount *val)
|
|
||||||
{
|
|
||||||
struct TALER_Amount *acc = cls;
|
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
TALER_amount_is_valid (acc))
|
|
||||||
return; /* ignore */
|
|
||||||
GNUNET_break (0 <=
|
|
||||||
TALER_amount_add (acc,
|
|
||||||
acc,
|
|
||||||
val));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function implementing withdraw transaction. Runs the
|
* Function implementing withdraw transaction. Runs the
|
||||||
* transaction logic; IF it returns a non-error code, the transaction
|
* transaction logic; IF it returns a non-error code, the transaction
|
||||||
@ -182,67 +137,34 @@ withdraw_transaction (void *cls,
|
|||||||
MHD_RESULT *mhd_ret)
|
MHD_RESULT *mhd_ret)
|
||||||
{
|
{
|
||||||
struct WithdrawContext *wc = cls;
|
struct WithdrawContext *wc = cls;
|
||||||
struct TALER_EXCHANGEDB_Reserve r;
|
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
struct TALER_BlindedDenominationSignature denom_sig;
|
bool found = false;
|
||||||
|
bool balance_ok = false;
|
||||||
|
uint64_t reserve_uuid;
|
||||||
|
struct GNUNET_TIME_Absolute now;
|
||||||
|
|
||||||
/* store away optimistic signature to protect
|
now = GNUNET_TIME_absolute_get ();
|
||||||
it from being overwritten by get_withdraw_info */
|
(void) GNUNET_TIME_round_abs (&now);
|
||||||
denom_sig = wc->collectable.sig;
|
|
||||||
memset (&wc->collectable.sig,
|
|
||||||
0,
|
|
||||||
sizeof (wc->collectable.sig));
|
|
||||||
qs = TEH_plugin->get_withdraw_info (TEH_plugin->cls,
|
|
||||||
&wc->wsrd.h_coin_envelope,
|
|
||||||
&wc->collectable);
|
|
||||||
if (0 > qs)
|
|
||||||
{
|
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
|
|
||||||
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
|
||||||
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
|
||||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
|
||||||
TALER_EC_GENERIC_DB_FETCH_FAILED,
|
|
||||||
"withdraw details");
|
|
||||||
wc->collectable.sig = denom_sig;
|
|
||||||
return qs;
|
|
||||||
}
|
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
wc->collectable.reserve_pub = wc->wsrd.reserve_pub;
|
||||||
"Asked to withdraw from %s amount of %s\n",
|
wc->collectable.h_coin_envelope = wc->wsrd.h_coin_envelope;
|
||||||
TALER_B2S (&wc->wsrd.reserve_pub),
|
qs = TEH_plugin->do_withdraw (TEH_plugin->cls,
|
||||||
TALER_amount2s (&wc->amount_required));
|
&wc->collectable,
|
||||||
/* Don't sign again if we have already signed the coin */
|
now,
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
|
&found,
|
||||||
{
|
&balance_ok,
|
||||||
/* Toss out the optimistic signature, we got another one from the DB;
|
&wc->kyc,
|
||||||
optimization trade-off loses in this case: we unnecessarily computed
|
&reserve_uuid);
|
||||||
a signature :-( */
|
|
||||||
TALER_blinded_denom_sig_free (&denom_sig);
|
|
||||||
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
|
|
||||||
}
|
|
||||||
/* We should never get more than one result, and we handled
|
|
||||||
the errors (negative case) above, so that leaves no results. */
|
|
||||||
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
|
|
||||||
wc->collectable.sig = denom_sig;
|
|
||||||
|
|
||||||
/* Check if balance is sufficient */
|
|
||||||
r.pub = wc->wsrd.reserve_pub; /* other fields of 'r' initialized in reserves_get (if successful) */
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
||||||
"Trying to withdraw from reserve: %s\n",
|
|
||||||
TALER_B2S (&r.pub));
|
|
||||||
qs = TEH_plugin->reserves_get (TEH_plugin->cls,
|
|
||||||
&r,
|
|
||||||
&wc->kyc);
|
|
||||||
if (0 > qs)
|
if (0 > qs)
|
||||||
{
|
{
|
||||||
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
||||||
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
*mhd_ret = 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,
|
||||||
"reserves");
|
"do_withdraw");
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
|
if (! found)
|
||||||
{
|
{
|
||||||
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
||||||
MHD_HTTP_NOT_FOUND,
|
MHD_HTTP_NOT_FOUND,
|
||||||
@ -250,29 +172,29 @@ withdraw_transaction (void *cls,
|
|||||||
NULL);
|
NULL);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
if (0 < TALER_amount_cmp (&wc->amount_required,
|
if (! balance_ok)
|
||||||
&r.balance))
|
|
||||||
{
|
{
|
||||||
struct TALER_EXCHANGEDB_ReserveHistory *rh;
|
struct TALER_EXCHANGEDB_ReserveHistory *rh;
|
||||||
|
struct TALER_Amount balance;
|
||||||
|
|
||||||
|
TEH_plugin->rollback (TEH_plugin->cls);
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TEH_plugin->start (TEH_plugin->cls,
|
||||||
|
"get_reserve_history on insufficient balance"))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
if (NULL != mhd_ret)
|
||||||
|
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
||||||
|
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||||
|
TALER_EC_GENERIC_DB_START_FAILED,
|
||||||
|
NULL);
|
||||||
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
|
}
|
||||||
/* The reserve does not have the required amount (actual
|
/* The reserve does not have the required amount (actual
|
||||||
* amount + withdraw fee) */
|
* amount + withdraw fee) */
|
||||||
#if GNUNET_EXTRA_LOGGING
|
|
||||||
{
|
|
||||||
char *amount_required;
|
|
||||||
char *r_balance;
|
|
||||||
|
|
||||||
amount_required = TALER_amount_to_string (&wc->amount_required);
|
|
||||||
r_balance = TALER_amount_to_string (&r.balance);
|
|
||||||
TALER_LOG_DEBUG ("Asked %s over a reserve worth %s\n",
|
|
||||||
amount_required,
|
|
||||||
r_balance);
|
|
||||||
GNUNET_free (amount_required);
|
|
||||||
GNUNET_free (r_balance);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
qs = TEH_plugin->get_reserve_history (TEH_plugin->cls,
|
qs = TEH_plugin->get_reserve_history (TEH_plugin->cls,
|
||||||
&wc->wsrd.reserve_pub,
|
&wc->wsrd.reserve_pub,
|
||||||
|
&balance,
|
||||||
&rh);
|
&rh);
|
||||||
if (NULL == rh)
|
if (NULL == rh)
|
||||||
{
|
{
|
||||||
@ -284,41 +206,41 @@ withdraw_transaction (void *cls,
|
|||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
*mhd_ret = reply_withdraw_insufficient_funds (connection,
|
*mhd_ret = reply_withdraw_insufficient_funds (connection,
|
||||||
&r.balance,
|
&balance,
|
||||||
rh);
|
rh);
|
||||||
TEH_plugin->free_reserve_history (TEH_plugin->cls,
|
TEH_plugin->free_reserve_history (TEH_plugin->cls,
|
||||||
rh);
|
rh);
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
if ( (TEH_KYC_NONE != TEH_kyc_config.mode) &&
|
||||||
"KYC status is %s for %s\n",
|
(! wc->kyc.ok) &&
|
||||||
wc->kyc.ok ? "ok" : "missing",
|
|
||||||
TALER_B2S (&r.pub));
|
|
||||||
if ( (! wc->kyc.ok) &&
|
|
||||||
(TEH_KYC_NONE != TEH_kyc_config.mode) &&
|
|
||||||
(TALER_EXCHANGEDB_KYC_W2W == wc->kyc.type) )
|
(TALER_EXCHANGEDB_KYC_W2W == wc->kyc.type) )
|
||||||
{
|
{
|
||||||
/* Wallet-to-wallet payments _always_ require KYC */
|
/* Wallet-to-wallet payments _always_ require KYC */
|
||||||
wc->kyc_denied = true;
|
*mhd_ret = TALER_MHD_REPLY_JSON_PACK (
|
||||||
return qs;
|
connection,
|
||||||
|
MHD_HTTP_ACCEPTED,
|
||||||
|
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
|
||||||
|
wc->kyc.payment_target_uuid));
|
||||||
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
if ( (! wc->kyc.ok) &&
|
if ( (TEH_KYC_NONE != TEH_kyc_config.mode) &&
|
||||||
(TEH_KYC_NONE != TEH_kyc_config.mode) &&
|
(! wc->kyc.ok) &&
|
||||||
(TALER_EXCHANGEDB_KYC_WITHDRAW == wc->kyc.type) &&
|
(TALER_EXCHANGEDB_KYC_WITHDRAW == wc->kyc.type) &&
|
||||||
(! GNUNET_TIME_relative_is_zero (TEH_kyc_config.withdraw_period)) )
|
(! GNUNET_TIME_relative_is_zero (TEH_kyc_config.withdraw_period)) )
|
||||||
{
|
{
|
||||||
/* Withdraws require KYC if above threshold */
|
/* Withdraws require KYC if above threshold */
|
||||||
struct TALER_Amount acc;
|
|
||||||
enum GNUNET_DB_QueryStatus qs2;
|
enum GNUNET_DB_QueryStatus qs2;
|
||||||
|
bool below_limit;
|
||||||
|
|
||||||
acc = wc->amount_required;
|
qs2 = TEH_plugin->do_withdraw_limit_check (
|
||||||
qs2 = TEH_plugin->select_withdraw_amounts_by_account (
|
|
||||||
TEH_plugin->cls,
|
TEH_plugin->cls,
|
||||||
&wc->wsrd.reserve_pub,
|
reserve_uuid,
|
||||||
TEH_kyc_config.withdraw_period,
|
GNUNET_TIME_absolute_subtract (now,
|
||||||
&accumulate_withdraws,
|
TEH_kyc_config.withdraw_period),
|
||||||
&acc);
|
&TEH_kyc_config.withdraw_limit,
|
||||||
|
&below_limit);
|
||||||
if (0 > qs2)
|
if (0 > qs2)
|
||||||
{
|
{
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs2);
|
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs2);
|
||||||
@ -326,52 +248,18 @@ withdraw_transaction (void *cls,
|
|||||||
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
*mhd_ret = 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,
|
||||||
"withdraw details");
|
"do_withdraw_limit_check");
|
||||||
return qs2;
|
return qs2;
|
||||||
}
|
}
|
||||||
|
if (! below_limit)
|
||||||
if (GNUNET_OK !=
|
|
||||||
TALER_amount_is_valid (&acc))
|
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
*mhd_ret = TALER_MHD_REPLY_JSON_PACK (
|
||||||
*mhd_ret = TALER_MHD_reply_with_ec (connection,
|
connection,
|
||||||
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
|
MHD_HTTP_ACCEPTED,
|
||||||
NULL);
|
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
|
||||||
|
wc->kyc.payment_target_uuid));
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||||
}
|
}
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
||||||
"Amount withdrawn so far is %s\n",
|
|
||||||
TALER_amount2s (&acc));
|
|
||||||
if (1 == /* 1: acc > withdraw_limit */
|
|
||||||
TALER_amount_cmp (&acc,
|
|
||||||
&TEH_kyc_config.withdraw_limit))
|
|
||||||
{
|
|
||||||
wc->kyc_denied = true;
|
|
||||||
return qs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Balance is good, persist signature */
|
|
||||||
wc->collectable.denom_pub_hash = wc->denom_pub_hash;
|
|
||||||
wc->collectable.amount_with_fee = wc->amount_required;
|
|
||||||
wc->collectable.reserve_pub = wc->wsrd.reserve_pub;
|
|
||||||
wc->collectable.h_coin_envelope = wc->wsrd.h_coin_envelope;
|
|
||||||
wc->collectable.reserve_sig = wc->signature;
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
||||||
"Persisting withdraw from %s over %s\n",
|
|
||||||
TALER_B2S (&r.pub),
|
|
||||||
TALER_amount2s (&wc->amount_required));
|
|
||||||
qs = TEH_plugin->insert_withdraw_info (TEH_plugin->cls,
|
|
||||||
&wc->collectable);
|
|
||||||
if (0 > qs)
|
|
||||||
{
|
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
|
|
||||||
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
|
||||||
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
|
||||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
|
||||||
TALER_EC_GENERIC_DB_STORE_FAILED,
|
|
||||||
"withdraw details");
|
|
||||||
return qs;
|
|
||||||
}
|
}
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
@ -432,9 +320,9 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
(void **) &wc.blinded_msg,
|
(void **) &wc.blinded_msg,
|
||||||
&wc.blinded_msg_len),
|
&wc.blinded_msg_len),
|
||||||
GNUNET_JSON_spec_fixed_auto ("reserve_sig",
|
GNUNET_JSON_spec_fixed_auto ("reserve_sig",
|
||||||
&wc.signature),
|
&wc.collectable.reserve_sig),
|
||||||
GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
|
GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
|
||||||
&wc.denom_pub_hash),
|
&wc.collectable.denom_pub_hash),
|
||||||
GNUNET_JSON_spec_end ()
|
GNUNET_JSON_spec_end ()
|
||||||
};
|
};
|
||||||
enum TALER_ErrorCode ec;
|
enum TALER_ErrorCode ec;
|
||||||
@ -487,7 +375,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
return mret;
|
return mret;
|
||||||
}
|
}
|
||||||
dk = TEH_keys_denomination_by_hash2 (ksh,
|
dk = TEH_keys_denomination_by_hash2 (ksh,
|
||||||
&wc.denom_pub_hash,
|
&wc.collectable.denom_pub_hash,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
if (NULL == dk)
|
if (NULL == dk)
|
||||||
@ -497,8 +385,9 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
&mret))
|
&mret))
|
||||||
{
|
{
|
||||||
GNUNET_JSON_parse_free (spec);
|
GNUNET_JSON_parse_free (spec);
|
||||||
return TEH_RESPONSE_reply_unknown_denom_pub_hash (rc->connection,
|
return TEH_RESPONSE_reply_unknown_denom_pub_hash (
|
||||||
&wc.denom_pub_hash);
|
rc->connection,
|
||||||
|
&wc.collectable.denom_pub_hash);
|
||||||
}
|
}
|
||||||
GNUNET_JSON_parse_free (spec);
|
GNUNET_JSON_parse_free (spec);
|
||||||
return mret;
|
return mret;
|
||||||
@ -519,7 +408,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
GNUNET_JSON_parse_free (spec);
|
GNUNET_JSON_parse_free (spec);
|
||||||
return TEH_RESPONSE_reply_expired_denom_pub_hash (
|
return TEH_RESPONSE_reply_expired_denom_pub_hash (
|
||||||
rc->connection,
|
rc->connection,
|
||||||
&wc.denom_pub_hash,
|
&wc.collectable.denom_pub_hash,
|
||||||
now,
|
now,
|
||||||
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
|
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
|
||||||
"WITHDRAW");
|
"WITHDRAW");
|
||||||
@ -538,7 +427,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
GNUNET_JSON_parse_free (spec);
|
GNUNET_JSON_parse_free (spec);
|
||||||
return TEH_RESPONSE_reply_expired_denom_pub_hash (
|
return TEH_RESPONSE_reply_expired_denom_pub_hash (
|
||||||
rc->connection,
|
rc->connection,
|
||||||
&wc.denom_pub_hash,
|
&wc.collectable.denom_pub_hash,
|
||||||
now,
|
now,
|
||||||
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
|
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
|
||||||
"WITHDRAW");
|
"WITHDRAW");
|
||||||
@ -557,7 +446,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
GNUNET_JSON_parse_free (spec);
|
GNUNET_JSON_parse_free (spec);
|
||||||
return TEH_RESPONSE_reply_expired_denom_pub_hash (
|
return TEH_RESPONSE_reply_expired_denom_pub_hash (
|
||||||
rc->connection,
|
rc->connection,
|
||||||
&wc.denom_pub_hash,
|
&wc.collectable.denom_pub_hash,
|
||||||
now,
|
now,
|
||||||
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
|
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
|
||||||
"WITHDRAW");
|
"WITHDRAW");
|
||||||
@ -569,7 +458,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
|
|
||||||
{
|
{
|
||||||
if (0 >
|
if (0 >
|
||||||
TALER_amount_add (&wc.amount_required,
|
TALER_amount_add (&wc.collectable.amount_with_fee,
|
||||||
&dk->meta.value,
|
&dk->meta.value,
|
||||||
&dk->meta.fee_withdraw))
|
&dk->meta.fee_withdraw))
|
||||||
{
|
{
|
||||||
@ -580,7 +469,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
TALER_amount_hton (&wc.wsrd.amount_with_fee,
|
TALER_amount_hton (&wc.wsrd.amount_with_fee,
|
||||||
&wc.amount_required);
|
&wc.collectable.amount_with_fee);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* verify signature! */
|
/* verify signature! */
|
||||||
@ -589,14 +478,15 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
wc.wsrd.purpose.purpose
|
wc.wsrd.purpose.purpose
|
||||||
= htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
|
= htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
|
||||||
wc.wsrd.h_denomination_pub
|
wc.wsrd.h_denomination_pub
|
||||||
= wc.denom_pub_hash;
|
= wc.collectable.denom_pub_hash;
|
||||||
TALER_coin_ev_hash (wc.blinded_msg,
|
TALER_coin_ev_hash (wc.blinded_msg,
|
||||||
wc.blinded_msg_len,
|
wc.blinded_msg_len,
|
||||||
&wc.wsrd.h_coin_envelope);
|
&wc.wsrd.h_coin_envelope);
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW,
|
GNUNET_CRYPTO_eddsa_verify (
|
||||||
|
TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW,
|
||||||
&wc.wsrd,
|
&wc.wsrd,
|
||||||
&wc.signature.eddsa_signature,
|
&wc.collectable.reserve_sig.eddsa_signature,
|
||||||
&wc.wsrd.reserve_pub.eddsa_pub))
|
&wc.wsrd.reserve_pub.eddsa_pub))
|
||||||
{
|
{
|
||||||
TALER_LOG_WARNING (
|
TALER_LOG_WARNING (
|
||||||
@ -611,7 +501,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
/* Sign before transaction! */
|
/* Sign before transaction! */
|
||||||
ec = TALER_EC_NONE;
|
ec = TALER_EC_NONE;
|
||||||
wc.collectable.sig
|
wc.collectable.sig
|
||||||
= TEH_keys_denomination_sign (&wc.denom_pub_hash,
|
= TEH_keys_denomination_sign (&wc.collectable.denom_pub_hash,
|
||||||
wc.blinded_msg,
|
wc.blinded_msg,
|
||||||
wc.blinded_msg_len,
|
wc.blinded_msg_len,
|
||||||
&ec);
|
&ec);
|
||||||
@ -625,7 +515,6 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* run transaction and sign (if not optimistically signed before) */
|
/* run transaction and sign (if not optimistically signed before) */
|
||||||
wc.kyc_denied = false;
|
|
||||||
{
|
{
|
||||||
MHD_RESULT mhd_ret;
|
MHD_RESULT mhd_ret;
|
||||||
|
|
||||||
@ -647,16 +536,6 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
|
|||||||
/* Clean up and send back final response */
|
/* Clean up and send back final response */
|
||||||
GNUNET_JSON_parse_free (spec);
|
GNUNET_JSON_parse_free (spec);
|
||||||
|
|
||||||
if (wc.kyc_denied)
|
|
||||||
{
|
|
||||||
TALER_blinded_denom_sig_free (&wc.collectable.sig);
|
|
||||||
return TALER_MHD_REPLY_JSON_PACK (
|
|
||||||
rc->connection,
|
|
||||||
MHD_HTTP_ACCEPTED,
|
|
||||||
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
|
|
||||||
wc.kyc.payment_target_uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
MHD_RESULT ret;
|
MHD_RESULT ret;
|
||||||
|
|
||||||
|
1
src/exchangedb/.gitignore
vendored
1
src/exchangedb/.gitignore
vendored
@ -4,3 +4,4 @@ test-exchangedb-fees
|
|||||||
test-exchangedb-postgres
|
test-exchangedb-postgres
|
||||||
test-exchangedb-signkeys
|
test-exchangedb-signkeys
|
||||||
test-perf-taler-exchangedb
|
test-perf-taler-exchangedb
|
||||||
|
bench-db-postgres
|
||||||
|
@ -54,6 +54,10 @@ DROP TABLE IF EXISTS reserves CASCADE;
|
|||||||
DROP TABLE IF EXISTS denomination_revocations CASCADE;
|
DROP TABLE IF EXISTS denomination_revocations CASCADE;
|
||||||
DROP TABLE IF EXISTS denominations CASCADE;
|
DROP TABLE IF EXISTS denominations CASCADE;
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS exchange_do_withdraw(bigint,integer,bytea,bytea,bytea,bytea,bytea,bigint,bigint) ;
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS exchange_do_withdraw_limit_check(bigint,bigint,bigint,int) ;
|
||||||
|
|
||||||
|
|
||||||
-- And we're out of here...
|
-- And we're out of here...
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
@ -680,6 +680,211 @@ CREATE INDEX IF NOT EXISTS revolving_work_shards_index
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
-- Stored procedures
|
||||||
|
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS exchange_do_withdraw(bigint,integer,bytea,bytea,bytea,bytea,bytea,bigint,bigint) ;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION exchange_do_withdraw(
|
||||||
|
IN amount_val INT8,
|
||||||
|
IN amount_frac INT4,
|
||||||
|
IN h_denom_pub BYTEA,
|
||||||
|
IN rpub BYTEA,
|
||||||
|
IN reserve_sig BYTEA,
|
||||||
|
IN h_coin_envelope BYTEA,
|
||||||
|
IN denom_sig BYTEA,
|
||||||
|
IN now INT8,
|
||||||
|
IN min_reserve_gc INT8,
|
||||||
|
OUT reserve_found BOOLEAN,
|
||||||
|
OUT balance_ok BOOLEAN,
|
||||||
|
OUT kycok BOOLEAN,
|
||||||
|
OUT ruuid INT8,
|
||||||
|
OUT account_uuid INT8)
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
reserve_gc INT8;
|
||||||
|
DECLARE
|
||||||
|
denom_serial INT8;
|
||||||
|
DECLARE
|
||||||
|
reserve_val INT8;
|
||||||
|
DECLARE
|
||||||
|
reserve_frac INT4;
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
SELECT denominations_serial INTO denom_serial
|
||||||
|
FROM denominations
|
||||||
|
WHERE denom_pub_hash=h_denom_pub;
|
||||||
|
|
||||||
|
IF NOT FOUND
|
||||||
|
THEN
|
||||||
|
-- denomination unknown, should be impossible!
|
||||||
|
reserve_found=FALSE;
|
||||||
|
balance_ok=FALSE;
|
||||||
|
kycok=FALSE;
|
||||||
|
ruuid=0;
|
||||||
|
account_uuid=0;
|
||||||
|
ASSERT false, 'denomination unknown';
|
||||||
|
RETURN;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
reserves.reserve_uuid
|
||||||
|
,current_balance_val
|
||||||
|
,current_balance_frac
|
||||||
|
,expiration_date
|
||||||
|
,gc_date
|
||||||
|
INTO
|
||||||
|
ruuid
|
||||||
|
,reserve_val
|
||||||
|
,reserve_frac
|
||||||
|
,reserve_gc
|
||||||
|
FROM reserves
|
||||||
|
WHERE reserves.reserve_pub=rpub;
|
||||||
|
|
||||||
|
IF NOT FOUND
|
||||||
|
THEN
|
||||||
|
-- reserve unknown
|
||||||
|
reserve_found=FALSE;
|
||||||
|
balance_ok=FALSE;
|
||||||
|
kycok=FALSE;
|
||||||
|
account_uuid=0;
|
||||||
|
RETURN;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- We optimistically insert, and then on conflict declare
|
||||||
|
-- the query successful due to idempotency.
|
||||||
|
INSERT INTO reserves_out
|
||||||
|
(h_blind_ev
|
||||||
|
,denominations_serial
|
||||||
|
,denom_sig
|
||||||
|
,reserve_uuid
|
||||||
|
,reserve_sig
|
||||||
|
,execution_date
|
||||||
|
,amount_with_fee_val
|
||||||
|
,amount_with_fee_frac)
|
||||||
|
VALUES
|
||||||
|
(h_coin_envelope
|
||||||
|
,denom_serial
|
||||||
|
,denom_sig
|
||||||
|
,ruuid
|
||||||
|
,reserve_sig
|
||||||
|
,now
|
||||||
|
,amount_val
|
||||||
|
,amount_frac)
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
IF NOT FOUND
|
||||||
|
THEN
|
||||||
|
-- idempotent query, all constraints must be satisfied
|
||||||
|
reserve_found=TRUE;
|
||||||
|
balance_ok=TRUE;
|
||||||
|
kycok=TRUE;
|
||||||
|
account_uuid=0;
|
||||||
|
RETURN;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Check reserve balance is sufficient.
|
||||||
|
IF (reserve_val > amount_val)
|
||||||
|
THEN
|
||||||
|
IF (reserve_frac > amount_frac)
|
||||||
|
THEN
|
||||||
|
reserve_val=reserve_val - amount_val;
|
||||||
|
reserve_frac=reserve_frac - amount_frac;
|
||||||
|
ELSE
|
||||||
|
reserve_val=reserve_val - amount_val - 1;
|
||||||
|
reserve_frac=reserve_frac + 100000000 - amount_frac;
|
||||||
|
END IF;
|
||||||
|
ELSE
|
||||||
|
IF (reserve_val = amount_val) AND (reserve_frac >= amount_frac)
|
||||||
|
THEN
|
||||||
|
reserve_val=0;
|
||||||
|
reserve_frac=reserve_frac - amount_frac;
|
||||||
|
ELSE
|
||||||
|
reserve_found=TRUE;
|
||||||
|
balance_ok=FALSE;
|
||||||
|
kycok=FALSE; -- we do not really know or care
|
||||||
|
account_uuid=0;
|
||||||
|
RETURN;
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Calculate new expiration dates.
|
||||||
|
min_reserve_gc=GREATEST(min_reserve_gc,reserve_gc);
|
||||||
|
|
||||||
|
-- Update reserve balance.
|
||||||
|
UPDATE reserves SET
|
||||||
|
gc_date=min_reserve_gc
|
||||||
|
,current_balance_val=reserve_val
|
||||||
|
,current_balance_frac=reserve_frac
|
||||||
|
WHERE
|
||||||
|
reserves.reserve_uuid=ruuid;
|
||||||
|
|
||||||
|
reserve_found=TRUE;
|
||||||
|
balance_ok=TRUE;
|
||||||
|
|
||||||
|
-- Obtain KYC status based on the last wire transfer into
|
||||||
|
-- this reserve. FIXME: likely not adequate for reserves that got P2P transfers!
|
||||||
|
SELECT
|
||||||
|
kyc_ok
|
||||||
|
,wire_source_serial_id
|
||||||
|
INTO
|
||||||
|
kycok
|
||||||
|
,account_uuid
|
||||||
|
FROM reserves_in
|
||||||
|
JOIN wire_targets ON (wire_source_serial_id = wire_target_serial_id)
|
||||||
|
WHERE reserve_uuid=ruuid
|
||||||
|
LIMIT 1; -- limit 1 should not be required (without p2p transfers)
|
||||||
|
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
COMMENT ON FUNCTION exchange_do_withdraw(INT8, INT4, BYTEA, BYTEA, BYTEA, BYTEA, BYTEA, INT8, INT8)
|
||||||
|
IS 'Checks whether the reserve has sufficient balance for a withdraw operation (or the request is repeated and was previously approved) and if so updates the database with the result';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS exchange_do_withdraw_limit_check(bigint,bigint,bigint,int) ;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION exchange_do_withdraw_limit_check(
|
||||||
|
IN ruuid INT8,
|
||||||
|
IN start_time INT8,
|
||||||
|
IN upper_limit_val INT8,
|
||||||
|
IN upper_limit_frac INT4,
|
||||||
|
OUT below_limit BOOLEAN)
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
total_val INT8;
|
||||||
|
DECLARE
|
||||||
|
total_frac INT8; -- INT4 could overflow during accumulation!
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
SUM(amount_with_fee_val) -- overflow here is not plausible
|
||||||
|
,SUM(CAST(amount_with_fee_frac AS INT8)) -- compute using 64 bits
|
||||||
|
INTO
|
||||||
|
total_val
|
||||||
|
,total_frac
|
||||||
|
FROM reserves_out
|
||||||
|
WHERE reserves_out.reserve_uuid=ruuid
|
||||||
|
AND execution_date > start_time;
|
||||||
|
|
||||||
|
-- normalize result
|
||||||
|
total_val = total_val + total_frac / 100000000;
|
||||||
|
total_frac = total_frac % 100000000;
|
||||||
|
|
||||||
|
-- compare to threshold
|
||||||
|
below_limit = (total_val < upper_limit_val) OR
|
||||||
|
( (total_val = upper_limit_val) AND
|
||||||
|
(total_frac <= upper_limit_frac) );
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
COMMENT ON FUNCTION exchange_do_withdraw_limit_check(INT8, INT8, INT8, INT4)
|
||||||
|
IS 'Check whether the withdrawals from the given reserve since the given time are below the given threshold';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Complete transaction
|
-- Complete transaction
|
||||||
|
@ -596,6 +596,34 @@ prepare_statements (struct PostgresClosure *pg)
|
|||||||
"lock_withdraw",
|
"lock_withdraw",
|
||||||
"LOCK TABLE reserves_out;",
|
"LOCK TABLE reserves_out;",
|
||||||
0),
|
0),
|
||||||
|
/* Used in #postgres_do_withdraw() to store
|
||||||
|
the signature of a blinded coin with the blinded coin's
|
||||||
|
details before returning it during /reserve/withdraw. We store
|
||||||
|
the coin's denomination information (public key, signature)
|
||||||
|
and the blinded message as well as the reserve that the coin
|
||||||
|
is being withdrawn from and the signature of the message
|
||||||
|
authorizing the withdrawal. */
|
||||||
|
GNUNET_PQ_make_prepare (
|
||||||
|
"call_withdraw",
|
||||||
|
"SELECT "
|
||||||
|
" reserve_found"
|
||||||
|
",balance_ok"
|
||||||
|
",kycok AS kyc_ok"
|
||||||
|
",ruuid AS reserve_uuid"
|
||||||
|
",account_uuid AS payment_target_uuid"
|
||||||
|
" FROM exchange_do_withdraw"
|
||||||
|
" ($1,$2,$3,$4,$5,$6,$7,$8,$9);",
|
||||||
|
9),
|
||||||
|
/* Used in #postgres_do_withdraw_limit_check() to check
|
||||||
|
if the withdrawals remain below the limit under which
|
||||||
|
KYC is not required. */
|
||||||
|
GNUNET_PQ_make_prepare (
|
||||||
|
"call_withdraw_limit_check",
|
||||||
|
"SELECT "
|
||||||
|
" below_limit"
|
||||||
|
" FROM exchange_do_withdraw_limit_check"
|
||||||
|
" ($1,$2,$3,$4);",
|
||||||
|
4),
|
||||||
/* Used in #postgres_insert_withdraw_info() to store
|
/* Used in #postgres_insert_withdraw_info() to store
|
||||||
the signature of a blinded coin with the blinded coin's
|
the signature of a blinded coin with the blinded coin's
|
||||||
details before returning it during /reserve/withdraw. We store
|
details before returning it during /reserve/withdraw. We store
|
||||||
@ -3378,11 +3406,11 @@ dominations_cb_helper (void *cls,
|
|||||||
struct TALER_DenominationPublicKey denom_pub;
|
struct TALER_DenominationPublicKey denom_pub;
|
||||||
struct TALER_MasterSignatureP master_sig;
|
struct TALER_MasterSignatureP master_sig;
|
||||||
struct TALER_DenominationHash h_denom_pub;
|
struct TALER_DenominationHash h_denom_pub;
|
||||||
uint8_t revoked;
|
bool revoked;
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("master_sig",
|
GNUNET_PQ_result_spec_auto_from_type ("master_sig",
|
||||||
&master_sig),
|
&master_sig),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("revoked",
|
GNUNET_PQ_result_spec_bool ("revoked",
|
||||||
&revoked),
|
&revoked),
|
||||||
TALER_PQ_result_spec_absolute_time ("valid_from",
|
TALER_PQ_result_spec_absolute_time ("valid_from",
|
||||||
&meta.start),
|
&meta.start),
|
||||||
@ -3422,7 +3450,7 @@ dominations_cb_helper (void *cls,
|
|||||||
&h_denom_pub,
|
&h_denom_pub,
|
||||||
&meta,
|
&meta,
|
||||||
&master_sig,
|
&master_sig,
|
||||||
(0 != revoked));
|
revoked);
|
||||||
GNUNET_PQ_cleanup_result (rs);
|
GNUNET_PQ_cleanup_result (rs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3777,7 +3805,6 @@ postgres_reserves_get (void *cls,
|
|||||||
GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
|
GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
uint8_t ok8;
|
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
|
TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
|
||||||
&reserve->balance),
|
&reserve->balance),
|
||||||
@ -3787,19 +3814,16 @@ postgres_reserves_get (void *cls,
|
|||||||
&reserve->gc),
|
&reserve->gc),
|
||||||
GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
|
GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
|
||||||
&kyc->payment_target_uuid),
|
&kyc->payment_target_uuid),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
|
GNUNET_PQ_result_spec_bool ("kyc_ok",
|
||||||
&ok8),
|
&kyc->ok),
|
||||||
GNUNET_PQ_result_spec_end
|
GNUNET_PQ_result_spec_end
|
||||||
};
|
};
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
|
||||||
|
|
||||||
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
kyc->type = TALER_EXCHANGEDB_KYC_WITHDRAW;
|
||||||
|
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||||
"reserves_get_with_kyc",
|
"reserves_get_with_kyc",
|
||||||
params,
|
params,
|
||||||
rs);
|
rs);
|
||||||
kyc->type = TALER_EXCHANGEDB_KYC_WITHDRAW;
|
|
||||||
kyc->ok = (0 != ok8);
|
|
||||||
return qs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3874,23 +3898,19 @@ postgres_get_kyc_status (void *cls,
|
|||||||
GNUNET_PQ_query_param_string (payto_uri),
|
GNUNET_PQ_query_param_string (payto_uri),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
uint8_t ok8;
|
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
|
GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
|
||||||
&kyc->payment_target_uuid),
|
&kyc->payment_target_uuid),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
|
GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
|
||||||
&ok8),
|
&kyc->ok),
|
||||||
GNUNET_PQ_result_spec_end
|
GNUNET_PQ_result_spec_end
|
||||||
};
|
};
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
|
||||||
|
|
||||||
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT;
|
||||||
|
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||||
"get_kyc_status",
|
"get_kyc_status",
|
||||||
params,
|
params,
|
||||||
rs);
|
rs);
|
||||||
kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT;
|
|
||||||
kyc->ok = (0 != ok8);
|
|
||||||
return qs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3914,24 +3934,20 @@ postgres_select_kyc_status (void *cls,
|
|||||||
GNUNET_PQ_query_param_uint64 (&payment_target_uuid),
|
GNUNET_PQ_query_param_uint64 (&payment_target_uuid),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
uint8_t ok8;
|
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("h_payto",
|
GNUNET_PQ_result_spec_auto_from_type ("h_payto",
|
||||||
h_payto),
|
h_payto),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
|
GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
|
||||||
&ok8),
|
&kyc->ok),
|
||||||
GNUNET_PQ_result_spec_end
|
GNUNET_PQ_result_spec_end
|
||||||
};
|
};
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
|
||||||
|
|
||||||
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
kyc->type = TALER_EXCHANGEDB_KYC_UNKNOWN;
|
||||||
|
kyc->payment_target_uuid = payment_target_uuid;
|
||||||
|
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||||
"select_kyc_status",
|
"select_kyc_status",
|
||||||
params,
|
params,
|
||||||
rs);
|
rs);
|
||||||
kyc->type = TALER_EXCHANGEDB_KYC_UNKNOWN;
|
|
||||||
kyc->ok = (0 != ok8);
|
|
||||||
kyc->payment_target_uuid = payment_target_uuid;
|
|
||||||
return qs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3962,12 +3978,11 @@ inselect_account_kyc_status (
|
|||||||
GNUNET_PQ_query_param_auto_from_type (&h_payto),
|
GNUNET_PQ_query_param_auto_from_type (&h_payto),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
uint8_t ok8 = 0;
|
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
GNUNET_PQ_result_spec_uint64 ("wire_target_serial_id",
|
GNUNET_PQ_result_spec_uint64 ("wire_target_serial_id",
|
||||||
&kyc->payment_target_uuid),
|
&kyc->payment_target_uuid),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
|
GNUNET_PQ_result_spec_bool ("kyc_ok",
|
||||||
&ok8),
|
&kyc->ok),
|
||||||
GNUNET_PQ_result_spec_end
|
GNUNET_PQ_result_spec_end
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3998,10 +4013,6 @@ inselect_account_kyc_status (
|
|||||||
return GNUNET_DB_STATUS_SOFT_ERROR;
|
return GNUNET_DB_STATUS_SOFT_ERROR;
|
||||||
kyc->ok = false;
|
kyc->ok = false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
kyc->ok = (0 != ok8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
kyc->type = TALER_EXCHANGEDB_KYC_BALANCE;
|
kyc->type = TALER_EXCHANGEDB_KYC_BALANCE;
|
||||||
return qs;
|
return qs;
|
||||||
@ -4478,86 +4489,104 @@ postgres_get_withdraw_info (
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store collectable bit coin under the corresponding
|
* Perform withdraw operation, checking for sufficient balance
|
||||||
* hash of the blinded message.
|
* and possibly persisting the withdrawal details.
|
||||||
*
|
*
|
||||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||||
* @param collectable corresponding collectable coin (blind signature)
|
* @param collectable corresponding collectable coin (blind signature)
|
||||||
* if a coin is found
|
* if a coin is found
|
||||||
|
* @param now current time (rounded)
|
||||||
|
* @param[out] found set to true if the reserve was found
|
||||||
|
* @param[out] balance_ok set to true if the balance was sufficient
|
||||||
|
* @param[out] kyc_ok set to true if the kyc status of the reserve is satisfied
|
||||||
|
* @param[out] reserve_uuid set to the UUID of the reserve
|
||||||
* @return query execution status
|
* @return query execution status
|
||||||
*/
|
*/
|
||||||
static enum GNUNET_DB_QueryStatus
|
static enum GNUNET_DB_QueryStatus
|
||||||
postgres_insert_withdraw_info (
|
postgres_do_withdraw (
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
|
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
|
||||||
|
struct GNUNET_TIME_Absolute now,
|
||||||
|
bool *found,
|
||||||
|
bool *balance_ok,
|
||||||
|
struct TALER_EXCHANGEDB_KycStatus *kyc,
|
||||||
|
uint64_t *reserve_uuid)
|
||||||
{
|
{
|
||||||
struct PostgresClosure *pg = cls;
|
struct PostgresClosure *pg = cls;
|
||||||
struct TALER_EXCHANGEDB_Reserve reserve;
|
|
||||||
struct GNUNET_TIME_Absolute now;
|
|
||||||
struct GNUNET_TIME_Absolute gc;
|
struct GNUNET_TIME_Absolute gc;
|
||||||
struct GNUNET_PQ_QueryParam params[] = {
|
struct GNUNET_PQ_QueryParam params[] = {
|
||||||
GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
|
TALER_PQ_query_param_amount (&collectable->amount_with_fee),
|
||||||
GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
|
GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
|
||||||
TALER_PQ_query_param_blinded_denom_sig (&collectable->sig),
|
|
||||||
GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub),
|
GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub),
|
||||||
GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
|
GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
|
||||||
|
GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
|
||||||
|
TALER_PQ_query_param_blinded_denom_sig (&collectable->sig),
|
||||||
TALER_PQ_query_param_absolute_time (&now),
|
TALER_PQ_query_param_absolute_time (&now),
|
||||||
TALER_PQ_query_param_amount (&collectable->amount_with_fee),
|
TALER_PQ_query_param_absolute_time (&gc),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
|
GNUNET_PQ_result_spec_bool ("reserve_found",
|
||||||
|
found),
|
||||||
|
GNUNET_PQ_result_spec_bool ("balance_ok",
|
||||||
|
balance_ok),
|
||||||
|
GNUNET_PQ_result_spec_bool ("kyc_ok",
|
||||||
|
&kyc->ok),
|
||||||
|
GNUNET_PQ_result_spec_uint64 ("reserve_uuid",
|
||||||
|
reserve_uuid),
|
||||||
|
GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
|
||||||
|
&kyc->payment_target_uuid),
|
||||||
|
GNUNET_PQ_result_spec_end
|
||||||
|
};
|
||||||
|
|
||||||
now = GNUNET_TIME_absolute_get ();
|
|
||||||
(void) GNUNET_TIME_round_abs (&now);
|
|
||||||
qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
|
||||||
"insert_withdraw_info",
|
|
||||||
params);
|
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
|
|
||||||
{
|
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
|
|
||||||
return qs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update reserve balance */
|
|
||||||
reserve.pub = collectable->reserve_pub;
|
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
|
||||||
(qs = reserves_get_internal (pg,
|
|
||||||
&reserve)))
|
|
||||||
{
|
|
||||||
/* Should have been checked before we got here... */
|
|
||||||
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
|
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
|
|
||||||
qs = GNUNET_DB_STATUS_HARD_ERROR;
|
|
||||||
return qs;
|
|
||||||
}
|
|
||||||
if (0 >
|
|
||||||
TALER_amount_subtract (&reserve.balance,
|
|
||||||
&reserve.balance,
|
|
||||||
&collectable->amount_with_fee))
|
|
||||||
{
|
|
||||||
/* The reserve history was checked to make sure there is enough of a balance
|
|
||||||
left before we tried this; however, concurrent operations may have changed
|
|
||||||
the situation by now, causing us to fail here. As reserves can no longer
|
|
||||||
be topped up, retrying should not help either. */
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"Withdrawal from reserve `%s' refused due to insufficient balance.\n",
|
|
||||||
TALER_B2S (&collectable->reserve_pub));
|
|
||||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
|
||||||
}
|
|
||||||
gc = GNUNET_TIME_absolute_add (now,
|
gc = GNUNET_TIME_absolute_add (now,
|
||||||
pg->legal_reserve_expiration_time);
|
pg->legal_reserve_expiration_time);
|
||||||
reserve.gc = GNUNET_TIME_absolute_max (gc,
|
(void) GNUNET_TIME_round_abs (&gc);
|
||||||
reserve.gc);
|
kyc->type = TALER_EXCHANGEDB_KYC_WITHDRAW;
|
||||||
(void) GNUNET_TIME_round_abs (&reserve.gc);
|
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||||
qs = reserves_update (pg,
|
"call_withdraw",
|
||||||
&reserve);
|
params,
|
||||||
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
|
rs);
|
||||||
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
qs = GNUNET_DB_STATUS_HARD_ERROR;
|
|
||||||
}
|
}
|
||||||
return qs;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that reserve remains below threshold for KYC
|
||||||
|
* checks after withdraw operation.
|
||||||
|
*
|
||||||
|
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||||
|
* @param reserve_uuid reserve to check
|
||||||
|
* @param withdraw_start starting point to accumulate from
|
||||||
|
* @param upper_limit maximum amount allowed
|
||||||
|
* @param[out] below_limit set to true if the limit was not exceeded
|
||||||
|
* @return query execution status
|
||||||
|
*/
|
||||||
|
static enum GNUNET_DB_QueryStatus
|
||||||
|
postgres_do_withdraw_limit_check (
|
||||||
|
void *cls,
|
||||||
|
uint64_t reserve_uuid,
|
||||||
|
struct GNUNET_TIME_Absolute withdraw_start,
|
||||||
|
const struct TALER_Amount *upper_limit,
|
||||||
|
bool *below_limit)
|
||||||
|
{
|
||||||
|
struct PostgresClosure *pg = cls;
|
||||||
|
struct GNUNET_PQ_QueryParam params[] = {
|
||||||
|
GNUNET_PQ_query_param_uint64 (&reserve_uuid),
|
||||||
|
TALER_PQ_query_param_absolute_time (&withdraw_start),
|
||||||
|
TALER_PQ_query_param_amount (upper_limit),
|
||||||
|
GNUNET_PQ_query_param_end
|
||||||
|
};
|
||||||
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
|
GNUNET_PQ_result_spec_bool ("below_limit",
|
||||||
|
below_limit),
|
||||||
|
GNUNET_PQ_result_spec_end
|
||||||
|
};
|
||||||
|
|
||||||
|
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||||
|
"call_withdraw_limit_check",
|
||||||
|
params,
|
||||||
|
rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4587,11 +4616,21 @@ struct ReserveHistoryContext
|
|||||||
*/
|
*/
|
||||||
struct PostgresClosure *pg;
|
struct PostgresClosure *pg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sum of all credit transactions.
|
||||||
|
*/
|
||||||
|
struct TALER_Amount balance_in;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sum of all debit transactions.
|
||||||
|
*/
|
||||||
|
struct TALER_Amount balance_out;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set to #GNUNET_SYSERR on serious internal errors during
|
* Set to #GNUNET_SYSERR on serious internal errors during
|
||||||
* the callbacks.
|
* the callbacks.
|
||||||
*/
|
*/
|
||||||
int status;
|
enum GNUNET_GenericReturnValue status;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -4667,6 +4706,10 @@ add_bank_to_exchange (void *cls,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GNUNET_assert (0 <=
|
||||||
|
TALER_amount_add (&rhc->balance_in,
|
||||||
|
&rhc->balance_in,
|
||||||
|
&bt->amount));
|
||||||
bt->reserve_pub = *rhc->reserve_pub;
|
bt->reserve_pub = *rhc->reserve_pub;
|
||||||
tail = append_rh (rhc);
|
tail = append_rh (rhc);
|
||||||
tail->type = TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE;
|
tail->type = TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE;
|
||||||
@ -4724,6 +4767,10 @@ add_withdraw_coin (void *cls,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GNUNET_assert (0 <=
|
||||||
|
TALER_amount_add (&rhc->balance_out,
|
||||||
|
&rhc->balance_out,
|
||||||
|
&cbc->amount_with_fee));
|
||||||
cbc->reserve_pub = *rhc->reserve_pub;
|
cbc->reserve_pub = *rhc->reserve_pub;
|
||||||
tail = append_rh (rhc);
|
tail = append_rh (rhc);
|
||||||
tail->type = TALER_EXCHANGEDB_RO_WITHDRAW_COIN;
|
tail->type = TALER_EXCHANGEDB_RO_WITHDRAW_COIN;
|
||||||
@ -4784,6 +4831,10 @@ add_recoup (void *cls,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GNUNET_assert (0 <=
|
||||||
|
TALER_amount_add (&rhc->balance_in,
|
||||||
|
&rhc->balance_in,
|
||||||
|
&recoup->value));
|
||||||
recoup->reserve_pub = *rhc->reserve_pub;
|
recoup->reserve_pub = *rhc->reserve_pub;
|
||||||
tail = append_rh (rhc);
|
tail = append_rh (rhc);
|
||||||
tail->type = TALER_EXCHANGEDB_RO_RECOUP_COIN;
|
tail->type = TALER_EXCHANGEDB_RO_RECOUP_COIN;
|
||||||
@ -4840,6 +4891,10 @@ add_exchange_to_bank (void *cls,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GNUNET_assert (0 <=
|
||||||
|
TALER_amount_add (&rhc->balance_out,
|
||||||
|
&rhc->balance_out,
|
||||||
|
&closing->amount));
|
||||||
closing->reserve_pub = *rhc->reserve_pub;
|
closing->reserve_pub = *rhc->reserve_pub;
|
||||||
tail = append_rh (rhc);
|
tail = append_rh (rhc);
|
||||||
tail->type = TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK;
|
tail->type = TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK;
|
||||||
@ -4854,12 +4909,14 @@ add_exchange_to_bank (void *cls,
|
|||||||
*
|
*
|
||||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||||
* @param reserve_pub public key of the reserve
|
* @param reserve_pub public key of the reserve
|
||||||
|
* @param[out] balance set to the reserve balance
|
||||||
* @param[out] rhp set to known transaction history (NULL if reserve is unknown)
|
* @param[out] rhp set to known transaction history (NULL if reserve is unknown)
|
||||||
* @return transaction status
|
* @return transaction status
|
||||||
*/
|
*/
|
||||||
static enum GNUNET_DB_QueryStatus
|
static enum GNUNET_DB_QueryStatus
|
||||||
postgres_get_reserve_history (void *cls,
|
postgres_get_reserve_history (void *cls,
|
||||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||||
|
struct TALER_Amount *balance,
|
||||||
struct TALER_EXCHANGEDB_ReserveHistory **rhp)
|
struct TALER_EXCHANGEDB_ReserveHistory **rhp)
|
||||||
{
|
{
|
||||||
struct PostgresClosure *pg = cls;
|
struct PostgresClosure *pg = cls;
|
||||||
@ -4902,6 +4959,12 @@ postgres_get_reserve_history (void *cls,
|
|||||||
rhc.rh_tail = NULL;
|
rhc.rh_tail = NULL;
|
||||||
rhc.pg = pg;
|
rhc.pg = pg;
|
||||||
rhc.status = GNUNET_OK;
|
rhc.status = GNUNET_OK;
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_set_zero (pg->currency,
|
||||||
|
&rhc.balance_in));
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_set_zero (pg->currency,
|
||||||
|
&rhc.balance_out));
|
||||||
qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; /* make static analysis happy */
|
qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; /* make static analysis happy */
|
||||||
for (unsigned int i = 0; NULL != work[i].cb; i++)
|
for (unsigned int i = 0; NULL != work[i].cb; i++)
|
||||||
{
|
{
|
||||||
@ -4927,6 +4990,10 @@ postgres_get_reserve_history (void *cls,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*rhp = rhc.rh;
|
*rhp = rhc.rh;
|
||||||
|
GNUNET_assert (0 <=
|
||||||
|
TALER_amount_subtract (balance,
|
||||||
|
&rhc.balance_in,
|
||||||
|
&rhc.balance_out));
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5308,13 +5375,12 @@ postgres_get_ready_deposit (void *cls,
|
|||||||
void *deposit_cb_cls)
|
void *deposit_cb_cls)
|
||||||
{
|
{
|
||||||
struct PostgresClosure *pg = cls;
|
struct PostgresClosure *pg = cls;
|
||||||
uint8_t kyc_override = (kyc_off) ? 1 : 0;
|
|
||||||
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
|
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
|
||||||
struct GNUNET_PQ_QueryParam params[] = {
|
struct GNUNET_PQ_QueryParam params[] = {
|
||||||
TALER_PQ_query_param_absolute_time (&now),
|
TALER_PQ_query_param_absolute_time (&now),
|
||||||
GNUNET_PQ_query_param_uint64 (&start_shard_row),
|
GNUNET_PQ_query_param_uint64 (&start_shard_row),
|
||||||
GNUNET_PQ_query_param_uint64 (&end_shard_row),
|
GNUNET_PQ_query_param_uint64 (&end_shard_row),
|
||||||
GNUNET_PQ_query_param_auto_from_type (&kyc_override),
|
GNUNET_PQ_query_param_bool (kyc_off),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
struct TALER_Amount amount_with_fee;
|
struct TALER_Amount amount_with_fee;
|
||||||
@ -6609,7 +6675,6 @@ add_coin_deposit (void *cls,
|
|||||||
chc->have_deposit_or_melt = true;
|
chc->have_deposit_or_melt = true;
|
||||||
deposit = GNUNET_new (struct TALER_EXCHANGEDB_DepositListEntry);
|
deposit = GNUNET_new (struct TALER_EXCHANGEDB_DepositListEntry);
|
||||||
{
|
{
|
||||||
uint8_t done = 0;
|
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||||
&deposit->amount_with_fee),
|
&deposit->amount_with_fee),
|
||||||
@ -6636,7 +6701,7 @@ add_coin_deposit (void *cls,
|
|||||||
GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
|
GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
|
||||||
&serial_id),
|
&serial_id),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("done",
|
GNUNET_PQ_result_spec_auto_from_type ("done",
|
||||||
&done),
|
&deposit->done),
|
||||||
GNUNET_PQ_result_spec_end
|
GNUNET_PQ_result_spec_end
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -6650,7 +6715,6 @@ add_coin_deposit (void *cls,
|
|||||||
chc->failed = true;
|
chc->failed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
deposit->done = (0 != done);
|
|
||||||
}
|
}
|
||||||
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
|
||||||
tl->next = chc->head;
|
tl->next = chc->head;
|
||||||
@ -7340,7 +7404,6 @@ postgres_lookup_transfer_by_deposit (
|
|||||||
/* Check if transaction exists in deposits, so that we just
|
/* Check if transaction exists in deposits, so that we just
|
||||||
do not have a WTID yet. In that case, return without wtid
|
do not have a WTID yet. In that case, return without wtid
|
||||||
(by setting 'pending' true). */
|
(by setting 'pending' true). */
|
||||||
uint8_t ok8 = 0;
|
|
||||||
struct GNUNET_PQ_ResultSpec rs2[] = {
|
struct GNUNET_PQ_ResultSpec rs2[] = {
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
|
GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
|
||||||
&wire_salt),
|
&wire_salt),
|
||||||
@ -7349,7 +7412,7 @@ postgres_lookup_transfer_by_deposit (
|
|||||||
GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
|
GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
|
||||||
&kyc->payment_target_uuid),
|
&kyc->payment_target_uuid),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
|
GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
|
||||||
&ok8),
|
&kyc->ok),
|
||||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||||
amount_with_fee),
|
amount_with_fee),
|
||||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
|
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
|
||||||
@ -7377,7 +7440,6 @@ postgres_lookup_transfer_by_deposit (
|
|||||||
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
|
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
|
||||||
}
|
}
|
||||||
kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT;
|
kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT;
|
||||||
kyc->ok = (0 != ok8);
|
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8164,7 +8226,7 @@ deposit_serial_helper_cb (void *cls,
|
|||||||
struct TALER_EXCHANGEDB_Deposit deposit;
|
struct TALER_EXCHANGEDB_Deposit deposit;
|
||||||
struct GNUNET_TIME_Absolute exchange_timestamp;
|
struct GNUNET_TIME_Absolute exchange_timestamp;
|
||||||
struct TALER_DenominationPublicKey denom_pub;
|
struct TALER_DenominationPublicKey denom_pub;
|
||||||
uint8_t done = 0;
|
bool done;
|
||||||
uint64_t rowid;
|
uint64_t rowid;
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||||
@ -8191,7 +8253,7 @@ deposit_serial_helper_cb (void *cls,
|
|||||||
&deposit.wire_salt),
|
&deposit.wire_salt),
|
||||||
GNUNET_PQ_result_spec_string ("receiver_wire_account",
|
GNUNET_PQ_result_spec_string ("receiver_wire_account",
|
||||||
&deposit.receiver_wire_account),
|
&deposit.receiver_wire_account),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("done",
|
GNUNET_PQ_result_spec_bool ("done",
|
||||||
&done),
|
&done),
|
||||||
GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
|
GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
|
||||||
&rowid),
|
&rowid),
|
||||||
@ -8213,7 +8275,7 @@ deposit_serial_helper_cb (void *cls,
|
|||||||
exchange_timestamp,
|
exchange_timestamp,
|
||||||
&deposit,
|
&deposit,
|
||||||
&denom_pub,
|
&denom_pub,
|
||||||
(0 != done) ? true : false);
|
done);
|
||||||
GNUNET_PQ_cleanup_result (rs);
|
GNUNET_PQ_cleanup_result (rs);
|
||||||
if (GNUNET_OK != ret)
|
if (GNUNET_OK != ret)
|
||||||
break;
|
break;
|
||||||
@ -9783,8 +9845,8 @@ missing_wire_cb (void *cls,
|
|||||||
struct TALER_Amount amount;
|
struct TALER_Amount amount;
|
||||||
char *payto_uri;
|
char *payto_uri;
|
||||||
struct GNUNET_TIME_Absolute deadline;
|
struct GNUNET_TIME_Absolute deadline;
|
||||||
uint8_t tiny;
|
bool tiny;
|
||||||
uint8_t done;
|
bool done;
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
|
GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
|
||||||
&rowid),
|
&rowid),
|
||||||
@ -9796,9 +9858,9 @@ missing_wire_cb (void *cls,
|
|||||||
&payto_uri),
|
&payto_uri),
|
||||||
TALER_PQ_result_spec_absolute_time ("wire_deadline",
|
TALER_PQ_result_spec_absolute_time ("wire_deadline",
|
||||||
&deadline),
|
&deadline),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("tiny",
|
GNUNET_PQ_result_spec_bool ("tiny",
|
||||||
&tiny),
|
&tiny),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("done",
|
GNUNET_PQ_result_spec_bool ("done",
|
||||||
&done),
|
&done),
|
||||||
GNUNET_PQ_result_spec_end
|
GNUNET_PQ_result_spec_end
|
||||||
};
|
};
|
||||||
@ -9923,22 +9985,18 @@ postgres_lookup_auditor_status (
|
|||||||
GNUNET_PQ_query_param_auto_from_type (auditor_pub),
|
GNUNET_PQ_query_param_auto_from_type (auditor_pub),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
uint8_t enabled8 = 0;
|
|
||||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||||
GNUNET_PQ_result_spec_string ("auditor_url",
|
GNUNET_PQ_result_spec_string ("auditor_url",
|
||||||
auditor_url),
|
auditor_url),
|
||||||
GNUNET_PQ_result_spec_auto_from_type ("is_active",
|
GNUNET_PQ_result_spec_bool ("is_active",
|
||||||
&enabled8),
|
enabled),
|
||||||
GNUNET_PQ_result_spec_end
|
GNUNET_PQ_result_spec_end
|
||||||
};
|
};
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
|
||||||
|
|
||||||
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||||
"lookup_auditor_status",
|
"lookup_auditor_status",
|
||||||
params,
|
params,
|
||||||
rs);
|
rs);
|
||||||
*enabled = (0 != enabled8);
|
|
||||||
return qs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -9996,12 +10054,11 @@ postgres_update_auditor (void *cls,
|
|||||||
bool enabled)
|
bool enabled)
|
||||||
{
|
{
|
||||||
struct PostgresClosure *pg = cls;
|
struct PostgresClosure *pg = cls;
|
||||||
uint8_t enabled8 = enabled ? 1 : 0;
|
|
||||||
struct GNUNET_PQ_QueryParam params[] = {
|
struct GNUNET_PQ_QueryParam params[] = {
|
||||||
GNUNET_PQ_query_param_auto_from_type (auditor_pub),
|
GNUNET_PQ_query_param_auto_from_type (auditor_pub),
|
||||||
GNUNET_PQ_query_param_string (auditor_url),
|
GNUNET_PQ_query_param_string (auditor_url),
|
||||||
GNUNET_PQ_query_param_string (auditor_name),
|
GNUNET_PQ_query_param_string (auditor_name),
|
||||||
GNUNET_PQ_query_param_auto_from_type (&enabled8),
|
GNUNET_PQ_query_param_bool (enabled),
|
||||||
GNUNET_PQ_query_param_absolute_time (&change_date),
|
GNUNET_PQ_query_param_absolute_time (&change_date),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
@ -10091,10 +10148,9 @@ postgres_update_wire (void *cls,
|
|||||||
bool enabled)
|
bool enabled)
|
||||||
{
|
{
|
||||||
struct PostgresClosure *pg = cls;
|
struct PostgresClosure *pg = cls;
|
||||||
uint8_t enabled8 = enabled ? 1 : 0;
|
|
||||||
struct GNUNET_PQ_QueryParam params[] = {
|
struct GNUNET_PQ_QueryParam params[] = {
|
||||||
GNUNET_PQ_query_param_string (payto_uri),
|
GNUNET_PQ_query_param_string (payto_uri),
|
||||||
GNUNET_PQ_query_param_auto_from_type (&enabled8),
|
GNUNET_PQ_query_param_bool (enabled),
|
||||||
GNUNET_PQ_query_param_absolute_time (&change_date),
|
GNUNET_PQ_query_param_absolute_time (&change_date),
|
||||||
GNUNET_PQ_query_param_end
|
GNUNET_PQ_query_param_end
|
||||||
};
|
};
|
||||||
@ -11767,7 +11823,9 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
|||||||
plugin->get_latest_reserve_in_reference =
|
plugin->get_latest_reserve_in_reference =
|
||||||
&postgres_get_latest_reserve_in_reference;
|
&postgres_get_latest_reserve_in_reference;
|
||||||
plugin->get_withdraw_info = &postgres_get_withdraw_info;
|
plugin->get_withdraw_info = &postgres_get_withdraw_info;
|
||||||
plugin->insert_withdraw_info = &postgres_insert_withdraw_info;
|
// plugin->insert_withdraw_info = &postgres_insert_withdraw_info;
|
||||||
|
plugin->do_withdraw = &postgres_do_withdraw;
|
||||||
|
plugin->do_withdraw_limit_check = &postgres_do_withdraw_limit_check;
|
||||||
plugin->get_reserve_history = &postgres_get_reserve_history;
|
plugin->get_reserve_history = &postgres_get_reserve_history;
|
||||||
plugin->select_withdraw_amounts_by_account
|
plugin->select_withdraw_amounts_by_account
|
||||||
= &postgres_select_withdraw_amounts_by_account;
|
= &postgres_select_withdraw_amounts_by_account;
|
||||||
|
@ -1659,10 +1659,26 @@ run (void *cls)
|
|||||||
cbc.reserve_pub = reserve_pub;
|
cbc.reserve_pub = reserve_pub;
|
||||||
cbc.amount_with_fee = value;
|
cbc.amount_with_fee = value;
|
||||||
GNUNET_assert (GNUNET_OK ==
|
GNUNET_assert (GNUNET_OK ==
|
||||||
TALER_amount_set_zero (CURRENCY, &cbc.withdraw_fee));
|
TALER_amount_set_zero (CURRENCY,
|
||||||
|
&cbc.withdraw_fee));
|
||||||
|
{
|
||||||
|
bool found;
|
||||||
|
bool balance_ok;
|
||||||
|
struct TALER_EXCHANGEDB_KycStatus kyc;
|
||||||
|
uint64_t ruuid;
|
||||||
|
|
||||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||||
plugin->insert_withdraw_info (plugin->cls,
|
plugin->do_withdraw (plugin->cls,
|
||||||
&cbc));
|
&cbc,
|
||||||
|
now,
|
||||||
|
&found,
|
||||||
|
&balance_ok,
|
||||||
|
&kyc,
|
||||||
|
&ruuid));
|
||||||
|
GNUNET_assert (found);
|
||||||
|
GNUNET_assert (balance_ok);
|
||||||
|
GNUNET_assert (! kyc.ok);
|
||||||
|
}
|
||||||
FAILIF (GNUNET_OK !=
|
FAILIF (GNUNET_OK !=
|
||||||
check_reserve (&reserve_pub,
|
check_reserve (&reserve_pub,
|
||||||
value.value,
|
value.value,
|
||||||
|
@ -496,7 +496,7 @@ struct TALER_EXCHANGEDB_ClosingTransfer
|
|||||||
struct TALER_ReservePublicKeyP reserve_pub;
|
struct TALER_ReservePublicKeyP reserve_pub;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Amount that was transferred to the exchange.
|
* Amount that was transferred from the exchange.
|
||||||
*/
|
*/
|
||||||
struct TALER_Amount amount;
|
struct TALER_Amount amount;
|
||||||
|
|
||||||
@ -2512,23 +2512,70 @@ struct TALER_EXCHANGEDB_Plugin
|
|||||||
* @return statement execution status
|
* @return statement execution status
|
||||||
*/
|
*/
|
||||||
enum GNUNET_DB_QueryStatus
|
enum GNUNET_DB_QueryStatus
|
||||||
(*insert_withdraw_info)(
|
(*insert_withdraw_infoXX)(
|
||||||
void *cls,
|
void *cls,
|
||||||
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable);
|
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform withdraw operation, checking for sufficient balance
|
||||||
|
* and possibly persisting the withdrawal details.
|
||||||
|
*
|
||||||
|
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||||
|
* @param collectable corresponding collectable coin (blind signature)
|
||||||
|
* if a coin is found
|
||||||
|
* @param now current time (rounded)
|
||||||
|
* @param[out] found set to true if the reserve was found
|
||||||
|
* @param[out] balance_ok set to true if the balance was sufficient
|
||||||
|
* @param[out] kyc set to the KYC status of the reserve
|
||||||
|
* @param[out] reserve_uuid set to the UUID of the reserve
|
||||||
|
* @return query execution status
|
||||||
|
*/
|
||||||
|
enum GNUNET_DB_QueryStatus
|
||||||
|
(*do_withdraw)(
|
||||||
|
void *cls,
|
||||||
|
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
|
||||||
|
struct GNUNET_TIME_Absolute now,
|
||||||
|
bool *found,
|
||||||
|
bool *balance_ok,
|
||||||
|
struct TALER_EXCHANGEDB_KycStatus *kyc_ok,
|
||||||
|
uint64_t *reserve_uuid);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that reserve remains below threshold for KYC
|
||||||
|
* checks after withdraw operation.
|
||||||
|
*
|
||||||
|
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||||
|
* @param reserve_uuid reserve to check
|
||||||
|
* @param withdraw_start starting point to accumulate from
|
||||||
|
* @param upper_limit maximum amount allowed
|
||||||
|
* @param[out] below_limit set to true if the limit was not exceeded
|
||||||
|
* @return query execution status
|
||||||
|
*/
|
||||||
|
enum GNUNET_DB_QueryStatus
|
||||||
|
(*do_withdraw_limit_check)(
|
||||||
|
void *cls,
|
||||||
|
uint64_t reserve_uuid,
|
||||||
|
struct GNUNET_TIME_Absolute withdraw_start,
|
||||||
|
const struct TALER_Amount *upper_limit,
|
||||||
|
bool *below_limit);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all of the transaction history associated with the specified
|
* Get all of the transaction history associated with the specified
|
||||||
* reserve.
|
* reserve.
|
||||||
*
|
*
|
||||||
* @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 reserve
|
* @param reserve_pub public key of the reserve
|
||||||
|
* @param[out] balance set to the reserve balance
|
||||||
* @param[out] rhp set to known transaction history (NULL if reserve is unknown)
|
* @param[out] rhp set to known transaction history (NULL if reserve is unknown)
|
||||||
* @return transaction status
|
* @return transaction status
|
||||||
*/
|
*/
|
||||||
enum GNUNET_DB_QueryStatus
|
enum GNUNET_DB_QueryStatus
|
||||||
(*get_reserve_history)(void *cls,
|
(*get_reserve_history)(void *cls,
|
||||||
const struct TALER_ReservePublicKeyP *reserve_pub,
|
const struct TALER_ReservePublicKeyP *reserve_pub,
|
||||||
|
struct TALER_Amount *balance,
|
||||||
struct TALER_EXCHANGEDB_ReserveHistory **rhp);
|
struct TALER_EXCHANGEDB_ReserveHistory **rhp);
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ TES_transmit_raw (int sock,
|
|||||||
size_t end,
|
size_t end,
|
||||||
const void *pos)
|
const void *pos)
|
||||||
{
|
{
|
||||||
ssize_t off = 0;
|
size_t off = 0;
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
"Sending message of length %u\n",
|
"Sending message of length %u\n",
|
||||||
|
Loading…
Reference in New Issue
Block a user