Compare commits

...

53 Commits

Author SHA1 Message Date
ed57e6dc86
-typo 2023-04-22 16:05:34 +02:00
4a4da26e77
Merge branch 'master' into age-withdraw 2023-04-22 15:53:49 +02:00
89a9224c3b
Merge branch 'master' of ssh://git.taler.net/exchange 2023-04-22 15:39:14 +02:00
12681dfa1a
WiP: age-withdraw, adjust schema and DB-handlers, cleanup FIXME's, 8/n 2023-04-22 15:39:02 +02:00
37dd5bed20
-added FIXME 2023-04-22 15:06:44 +02:00
Christian Grothoff
acbee86745
simplify batch insert: no cursor where not required, replace out_reserve_found with ruuid being allowed to remain NULL 2023-04-22 15:02:47 +02:00
Christian Grothoff
c3fc8c5e55
fix fakebank long polling 2023-04-22 14:43:26 +02:00
Christian Grothoff
76b934b219
-misc fixes 2023-04-22 02:54:55 +02:00
Christian Grothoff
be1d8afaec
-misc fixes 2023-04-22 02:33:18 +02:00
Christian Grothoff
0236caf354
-misc fixes 2023-04-22 02:30:02 +02:00
Christian Grothoff
9e61579c8b
-misc fixes 2023-04-22 02:26:44 +02:00
Christian Grothoff
89c5a3eca9
-misc bugs 2023-04-22 01:53:41 +02:00
Christian Grothoff
53157062cb
-misc bugs 2023-04-22 01:40:53 +02:00
Christian Grothoff
2dab1fac1c
misc bugfixes in reserves_in batch logic 2023-04-22 01:20:41 +02:00
Christian Grothoff
5290453e36
clean up reserve_get logic 2023-04-21 22:30:37 +02:00
Christian Grothoff
03deaeb108
-fix doxygen 2023-04-21 10:54:50 +02:00
Christian Grothoff
ee6ec1f55d
-fix bug in sync 2023-04-21 10:50:35 +02:00
Christian Grothoff
44e0e00595
fix some major bugs in pg_reserves_in_insert 2023-04-18 20:44:33 +02:00
Christian Grothoff
8952a87b85
avoid overloading of global variable 2023-04-18 20:24:10 +02:00
Christian Grothoff
8463572bea
fix SPI build 2023-04-16 22:07:36 +02:00
Christian Grothoff
ade7586c30
add missing resource 2023-04-16 21:26:01 +02:00
Christian Grothoff
10c779bbc6
add FIXME 2023-04-16 21:25:48 +02:00
Christian Grothoff
5121c6b1cf
work on lookup_records_by_table 2023-04-16 10:05:38 +02:00
Christian Grothoff
2906ded1a6
work on insert_records_by_table 2023-04-16 09:41:37 +02:00
Christian Grothoff
136d2b2e70
implement more of lookup_records_by_table 2023-04-15 23:43:20 +02:00
Christian Grothoff
376de032b5
create warnings on missing table syncs 2023-04-15 23:11:36 +02:00
Christian Grothoff
32c6999a83
update gana 2023-04-15 22:19:33 +02:00
Christian Grothoff
eec4dc80ef
always check for the entire batch being idempotent, not only when it is too late to repeat the request 2023-04-15 19:53:38 +02:00
Christian Grothoff
2c28f7ebd0
reduce max requests limit per default 2023-04-15 15:14:05 +02:00
Christian Grothoff
07a089f4f1
-fix memory leak 2023-04-15 14:38:32 +02:00
Christian Grothoff
eb2b4a131b
add logic to check signature over fees in /wire response (fixes #7802) 2023-04-13 17:30:53 +02:00
Christian Grothoff
4e9c43954e
-fix SQL query 2023-04-10 23:28:40 +02:00
Christian Grothoff
122c926493
avoid crashing, fail test instead 2023-04-10 13:51:36 +02:00
Christian Grothoff
27c9fef5ea
use LEFT JOIN as aml_status table may be empty 2023-04-10 10:52:45 +02:00
Christian Grothoff
090c532b3a
return AML status together with KYC status 2023-04-10 10:48:32 +02:00
Christian Grothoff
677ac4a5c8
return text/plain by default (fixes #7747) 2023-04-08 09:46:00 +02:00
Christian Grothoff
cbabddf013
fix #7792 2023-04-08 08:29:30 +02:00
Christian Grothoff
3137d8dc13
adding FIXME 2023-04-08 08:11:27 +02:00
Christian Grothoff
36b2cbb47e
modify logic to match
https://datatracker.ietf.org/doc/draft-nottingham-http-availability-hints/
2023-04-06 23:46:39 +02:00
Christian Grothoff
d4f9417d8c
-spelling, typos, indentation 2023-04-04 17:26:51 +02:00
Christian Grothoff
979ec38ec4
left-pad TOTP code with 0s 2023-04-02 14:12:13 +02:00
Christian Grothoff
e99450e2e2
-fix missing comments 2023-03-31 14:04:04 +02:00
Christian Grothoff
a30827fcef
-fix missing comments 2023-03-31 14:03:12 +02:00
Christian Grothoff
6eed8917c3
fix exchangedb build errors 2023-03-31 13:50:32 +02:00
Joseph
9cce35d270
New sql code for batch ensure coin known 2023-03-29 11:18:20 -04:00
Joseph
0c2d5bba55
Remove binary files 2023-03-27 10:19:44 -04:00
Joseph
6af9fd66fb
New spi files 2023-03-27 09:55:00 -04:00
Joseph
cb87b6f646
New spi files 2023-03-27 09:55:00 -04:00
Joseph
d83c2539bc
some changes for known coins 2023-03-27 09:54:59 -04:00
Joseph
fb70814d46
some changes for ensure known coin 2023-03-27 09:54:59 -04:00
Joseph
42258d5778
nothing to update 2023-03-27 09:54:59 -04:00
Joseph
39f2d441f7
Spi files 2023-03-27 09:53:51 -04:00
Joseph
5dfa56727e
New spi files 2023-03-27 09:51:09 -04:00
210 changed files with 6795 additions and 3056 deletions

@ -1 +1 @@
Subproject commit 59de2acb7c716c816ed15786b5369e56c325770c Subproject commit bf43b20a0362ac19bcf1bab9c33215e55d8d9f36

View File

@ -46,6 +46,12 @@
<anchorfile>microhttpd.h</anchorfile> <anchorfile>microhttpd.h</anchorfile>
<arglist></arglist> <arglist></arglist>
</member> </member>
<member kind="define">
<type>#define</type>
<name>MHD_HTTP_CONTENT_TOO_LARGE</name>
<anchorfile>microhttpd.h</anchorfile>
<arglist></arglist>
</member>
<member kind="define"> <member kind="define">
<type>#define</type> <type>#define</type>
<name>MHD_HTTP_REQUEST_TIMEOUT</name> <name>MHD_HTTP_REQUEST_TIMEOUT</name>

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,7 @@ DB = postgres
# exchange (or the twister) is actually listening. # exchange (or the twister) is actually listening.
base_url = "http://localhost:8081/" base_url = "http://localhost:8081/"
WIREWATCH_IDLE_SLEEP_INTERVAL = 1500 ms WIREWATCH_IDLE_SLEEP_INTERVAL = 500 ms
[exchange-offline] [exchange-offline]
MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv
@ -51,11 +51,11 @@ MAX_DEBT = EUR:100000000000.0
MAX_DEBT_BANK = EUR:1000000000000000.0 MAX_DEBT_BANK = EUR:1000000000000000.0
[benchmark] [benchmark]
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42 USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42?receiver-name=user42
[exchange-account-2] [exchange-account-2]
# What is the payto://-URL of the exchange (to generate wire response) # What is the payto://-URL of the exchange (to generate wire response)
PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange" PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange?receiver-name=Exchange"
enable_debit = YES enable_debit = YES
enable_credit = YES enable_credit = YES

View File

@ -689,6 +689,8 @@ parallel_benchmark (void)
} }
/* But be extra sure we did finish all shards by doing one more */ /* But be extra sure we did finish all shards by doing one more */
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"Shard check phase\n");
wirewatch[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, wirewatch[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL, NULL, NULL, NULL,
"taler-exchange-wirewatch", "taler-exchange-wirewatch",

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
(C) 2014-2020 Taler Systems SA (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as under the terms of the GNU Affero General Public License as

View File

@ -19,7 +19,7 @@ MAX_KEYS_CACHING = forever
# After how many requests should the exchange auto-restart # After how many requests should the exchange auto-restart
# (to address potential issues with memory fragmentation)? # (to address potential issues with memory fragmentation)?
# If this option is not specified, auto-restarting is disabled. # If this option is not specified, auto-restarting is disabled.
# MAX_REQUESTS = 10000000 # MAX_REQUESTS = 100000
# How to access our database # How to access our database
DB = postgres DB = postgres

View File

@ -222,7 +222,6 @@ age_withdraw_transaction (void *cls,
awc->kyc.ok = true; awc->kyc.ok = true;
qs = TEH_plugin->do_age_withdraw (TEH_plugin->cls, qs = TEH_plugin->do_age_withdraw (TEH_plugin->cls,
&awc->commitment, &awc->commitment,
awc->now,
&found, &found,
&balance_ok, &balance_ok,
&ruuid); &ruuid);
@ -312,7 +311,7 @@ TEH_handler_age_withdraw (struct TEH_RequestContext *rc,
const json_t *root) const json_t *root)
{ {
MHD_RESULT mhd_ret; MHD_RESULT mhd_ret;
struct AgeWithdrawContext awc; struct AgeWithdrawContext awc = {0};
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("reserve_sig", GNUNET_JSON_spec_fixed_auto ("reserve_sig",
&awc.commitment.reserve_sig), &awc.commitment.reserve_sig),
@ -321,12 +320,11 @@ TEH_handler_age_withdraw (struct TEH_RequestContext *rc,
TALER_JSON_spec_amount ("amount", TALER_JSON_spec_amount ("amount",
TEH_currency, TEH_currency,
&awc.commitment.amount_with_fee), &awc.commitment.amount_with_fee),
GNUNET_JSON_spec_uint32 ("max_age", GNUNET_JSON_spec_uint16 ("max_age",
&awc.commitment.max_age), &awc.commitment.max_age),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
memset (&awc, 0, sizeof (awc));
awc.commitment.reserve_pub = *reserve_pub; awc.commitment.reserve_pub = *reserve_pub;

View File

@ -347,6 +347,15 @@ find_original_commitment (
NULL); NULL);
break; break;
case GNUNET_DB_STATUS_HARD_ERROR:
*result = TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
"get_age_withdraw_info");
break;
case GNUNET_DB_STATUS_SOFT_ERROR:
/* FIXME oec: Do we queue a result in this case or retry? */
default: default:
GNUNET_break (0); GNUNET_break (0);
*result = TALER_MHD_reply_with_error (connection, *result = TALER_MHD_reply_with_error (connection,
@ -616,7 +625,7 @@ verify_commitment_and_max_age (
{ {
size_t k = 0; /* either 0 or 1, to index into coin_evs */ size_t k = 0; /* either 0 or 1, to index into coin_evs */
for (size_t idx = 0; idx<3; idx++) for (size_t idx = 0; idx<TALER_CNC_KAPPA; idx++)
{ {
if (idx == (size_t) noreveal_idx) if (idx == (size_t) noreveal_idx)
{ {
@ -628,12 +637,13 @@ verify_commitment_and_max_age (
{ {
/* FIXME:oec: Refactor this block out into its own function */ /* FIXME:oec: Refactor this block out into its own function */
size_t j = 2 * c + k; /* Index into disclosed_coin_secrets[] */ size_t j = (TALER_CNC_KAPPA - 1) * c + k; /* Index into disclosed_coin_secrets[] */
const struct TALER_PlanchetMasterSecretP *secret; const struct TALER_PlanchetMasterSecretP *secret;
struct TALER_AgeCommitmentHash ach; struct TALER_AgeCommitmentHash ach;
struct TALER_BlindedCoinHashP bch;
GNUNET_assert (k<2); GNUNET_assert (k<2);
GNUNET_assert (num_coins * (TALER_CNC_KAPPA - 1) > j); GNUNET_assert ((TALER_CNC_KAPPA - 1) * num_coins > j);
secret = &disclosed_coin_secrets[j]; secret = &disclosed_coin_secrets[j];
k++; k++;
@ -666,7 +676,6 @@ verify_commitment_and_max_age (
{ {
struct TALER_CoinPubHashP c_hash; struct TALER_CoinPubHashP c_hash;
struct TALER_PlanchetDetail detail; struct TALER_PlanchetDetail detail;
struct TALER_BlindedCoinHashP bch;
struct TALER_CoinSpendPrivateKeyP coin_priv; struct TALER_CoinSpendPrivateKeyP coin_priv;
union TALER_DenominationBlindingKeyP bks; union TALER_DenominationBlindingKeyP bks;
struct TALER_ExchangeWithdrawValues alg_values = { struct TALER_ExchangeWithdrawValues alg_values = {
@ -688,19 +697,12 @@ verify_commitment_and_max_age (
.nonce = &nonce, .nonce = &nonce,
}; };
ec = TEH_keys_denomination_cs_r_pub ( ec = TEH_keys_denomination_cs_r_pub (&cdd,
&cdd, false,
false, &alg_values.details.
&alg_values.details.cs_values); cs_values);
/* FIXME Handle error? */
if (TALER_EC_NONE != ec) GNUNET_assert (TALER_EC_NONE == ec);
{
GNUNET_break_op (0);
*result = TALER_MHD_reply_with_ec (connection,
ec,
NULL);
return GNUNET_SYSERR;
}
} }
} }
@ -749,10 +751,13 @@ verify_commitment_and_max_age (
return ret; return ret;
} }
GNUNET_CRYPTO_hash_context_read (hash_context,
&detail.blinded_planchet,
sizeof(detail.blinded_planchet));
} }
/* Continue the running hash of all coin hashes with the calculated
* hash-value of the current, disclosed coin */
GNUNET_CRYPTO_hash_context_read (hash_context,
&bch,
sizeof(bch));
} }
} }
} }
@ -780,61 +785,35 @@ verify_commitment_and_max_age (
/** /**
* @brief Executes the database transaction for the withdraw of coins and signs * @brief Signs and persists the undisclosed coins
* the blinded coins
* *
* @param connection The HTTP-connection to the client * @param connection HTTP-connection to the client
* @param h_commitment_orig The commitment from the age-withdraw request * @param h_commitment_orig Original commitment
* @param num_coins The number of coins (and also denominations) * @param num_coins Number of coins
* @param coin_evs The blinded planchets of the coins * @param coin_evs The Hashes of the undisclosed, blinded coins, @a num_coins many
* @param denom_keys The corresponding denominations * @param denom_keys The array of denomination keys, @a num_coins. Needed to detect Clause-Schnorr-based denominations
* @param[out] result On error, a HTTP-response will be queued and result set accordingly * @param[out] result On error, a HTTP-response will be queued and result set accordingly
* @return GNUNET_OK on success, GNUNET_SYSERR otherwise * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
*/ */
enum GNUNET_GenericReturnValue static enum GNUNET_GenericReturnValue
finalize_withdraw_and_sign ( sign_and_persist_blinded_coins (
struct MHD_Connection *connection, struct MHD_Connection *connection,
const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, const struct TALER_AgeWithdrawCommitmentHashP *h_commitment_orig,
const uint32_t num_coins, const uint32_t num_coins,
const struct TALER_BlindedPlanchet *coin_evs, const struct TALER_BlindedPlanchet *coin_evs,
const struct TEH_DenominationKey *denom_keys, const struct TEH_DenominationKey *denom_keys,
MHD_RESULT *result) MHD_RESULT *result)
{ {
enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
struct TEH_CoinSignData csds[num_coins];
struct TALER_BlindedDenominationSignature bss[num_coins];
for (uint32_t i = 0; i<num_coins; i++)
{
csds[i].h_denom_pub = &denom_keys[i].h_denom_pub;
csds[i].bp = &coin_evs[i];
}
/* First, sign the keys */
{
enum TALER_ErrorCode ec;
ec = TEH_keys_denomination_batch_sign (csds,
num_coins,
false,
bss);
if (TALER_EC_NONE != ec)
{
GNUNET_break (0);
*result = TALER_MHD_reply_with_ec (connection,
ec,
NULL);
return GNUNET_SYSERR;
}
}
/* Then, execute the transaction */
#pragma message ("FIXME:oec implement finalize_withdraw_and_sign()")
/* TODO[oec]:
* - sign the planchets
* - in a transaction: save the coins.
*/
#pragma message "FIXME[oec]: implement sign_and_persist_blinded_coins"
return ret; return ret;
} }
MHD_RESULT MHD_RESULT
TEH_handler_age_withdraw_reveal ( TEH_handler_age_withdraw_reveal (
struct TEH_RequestContext *rc, struct TEH_RequestContext *rc,
@ -915,8 +894,8 @@ TEH_handler_age_withdraw_reveal (
&result)) &result))
break; break;
/* Do the withdraw in the DB and sign the coins */ /* Finally, sign and persist the coins */
if (GNUNET_OK != finalize_withdraw_and_sign ( if (GNUNET_OK != sign_and_persist_blinded_coins (
rc->connection, rc->connection,
&actx.commitment.h_commitment, &actx.commitment.h_commitment,
actx.num_coins, actx.num_coins,

View File

@ -77,6 +77,11 @@ struct BatchWithdrawContext
*/ */
const struct TALER_ReservePublicKeyP *reserve_pub; const struct TALER_ReservePublicKeyP *reserve_pub;
/**
* request context
*/
const struct TEH_RequestContext *rc;
/** /**
* KYC status of the reserve used for the operation. * KYC status of the reserve used for the operation.
*/ */
@ -183,6 +188,99 @@ aml_amount_cb (
} }
/**
* Generates our final (successful) response.
*
* @param rc request context
* @param wc operation context
* @return MHD queue status
*/
static MHD_RESULT
generate_reply_success (const struct TEH_RequestContext *rc,
const struct BatchWithdrawContext *wc)
{
json_t *sigs;
if (! wc->kyc.ok)
{
/* KYC required */
return TEH_RESPONSE_reply_kyc_required (rc->connection,
&wc->h_payto,
&wc->kyc);
}
if (TALER_AML_NORMAL != wc->aml_decision)
return TEH_RESPONSE_reply_aml_blocked (rc->connection,
wc->aml_decision);
sigs = json_array ();
GNUNET_assert (NULL != sigs);
for (unsigned int i = 0; i<wc->planchets_length; i++)
{
struct PlanchetContext *pc = &wc->planchets[i];
GNUNET_assert (
0 ==
json_array_append_new (
sigs,
GNUNET_JSON_PACK (
TALER_JSON_pack_blinded_denom_sig (
"ev_sig",
&pc->collectable.sig))));
}
TEH_METRICS_batch_withdraw_num_coins += wc->planchets_length;
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_array_steal ("ev_sigs",
sigs));
}
/**
* Check if the @a wc is replayed and we already have an
* answer. If so, replay the existing answer and return the
* HTTP response.
*
* @param wc parsed request data
* @param[out] mret HTTP status, set if we return true
* @return true if the request is idempotent with an existing request
* false if we did not find the request in the DB and did not set @a mret
*/
static bool
check_request_idempotent (const struct BatchWithdrawContext *wc,
MHD_RESULT *mret)
{
const struct TEH_RequestContext *rc = wc->rc;
for (unsigned int i = 0; i<wc->planchets_length; i++)
{
struct PlanchetContext *pc = &wc->planchets[i];
enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->get_withdraw_info (TEH_plugin->cls,
&pc->h_coin_envelope,
&pc->collectable);
if (0 > qs)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
*mret = TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
"get_withdraw_info");
return true; /* well, kind-of */
}
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
return false;
}
/* generate idempotent reply */
TEH_METRICS_num_requests[TEH_MT_REQUEST_IDEMPOTENT_BATCH_WITHDRAW]++;
*mret = generate_reply_success (rc,
wc);
return true;
}
/** /**
* 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
@ -448,12 +546,18 @@ batch_withdraw_transaction (void *cls,
if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) || if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) ||
(conflict) ) (conflict) )
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, if (! check_request_idempotent (wc,
"Idempotent coin in batch, not allowed. Aborting.\n"); mhd_ret))
*mhd_ret = TALER_MHD_reply_with_error (connection, {
MHD_HTTP_CONFLICT, /* We do not support *some* of the coins of the request being
TALER_EC_EXCHANGE_WITHDRAW_BATCH_IDEMPOTENT_PLANCHET, idempotent while others being fresh. */
NULL); GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Idempotent coin in batch, not allowed. Aborting.\n");
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_CONFLICT,
TALER_EC_EXCHANGE_WITHDRAW_BATCH_IDEMPOTENT_PLANCHET,
NULL);
}
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
} }
if (nonce_reuse) if (nonce_reuse)
@ -471,99 +575,6 @@ batch_withdraw_transaction (void *cls,
} }
/**
* Generates our final (successful) response.
*
* @param rc request context
* @param wc operation context
* @return MHD queue status
*/
static MHD_RESULT
generate_reply_success (const struct TEH_RequestContext *rc,
const struct BatchWithdrawContext *wc)
{
json_t *sigs;
if (! wc->kyc.ok)
{
/* KYC required */
return TEH_RESPONSE_reply_kyc_required (rc->connection,
&wc->h_payto,
&wc->kyc);
}
if (TALER_AML_NORMAL != wc->aml_decision)
return TEH_RESPONSE_reply_aml_blocked (rc->connection,
wc->aml_decision);
sigs = json_array ();
GNUNET_assert (NULL != sigs);
for (unsigned int i = 0; i<wc->planchets_length; i++)
{
struct PlanchetContext *pc = &wc->planchets[i];
GNUNET_assert (
0 ==
json_array_append_new (
sigs,
GNUNET_JSON_PACK (
TALER_JSON_pack_blinded_denom_sig (
"ev_sig",
&pc->collectable.sig))));
}
TEH_METRICS_batch_withdraw_num_coins += wc->planchets_length;
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_array_steal ("ev_sigs",
sigs));
}
/**
* Check if the @a rc is replayed and we already have an
* answer. If so, replay the existing answer and return the
* HTTP response.
*
* @param rc request context
* @param wc parsed request data
* @param[out] mret HTTP status, set if we return true
* @return true if the request is idempotent with an existing request
* false if we did not find the request in the DB and did not set @a mret
*/
static bool
check_request_idempotent (const struct TEH_RequestContext *rc,
const struct BatchWithdrawContext *wc,
MHD_RESULT *mret)
{
for (unsigned int i = 0; i<wc->planchets_length; i++)
{
struct PlanchetContext *pc = &wc->planchets[i];
enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->get_withdraw_info (TEH_plugin->cls,
&pc->h_coin_envelope,
&pc->collectable);
if (0 > qs)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
*mret = TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
"get_withdraw_info");
return true; /* well, kind-of */
}
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
return false;
}
/* generate idempotent reply */
TEH_METRICS_num_requests[TEH_MT_REQUEST_IDEMPOTENT_BATCH_WITHDRAW]++;
*mret = generate_reply_success (rc,
wc);
return true;
}
/** /**
* The request was parsed successfully. Prepare * The request was parsed successfully. Prepare
* our side for the main DB transaction. * our side for the main DB transaction.
@ -691,8 +702,7 @@ parse_planchets (const struct TEH_RequestContext *rc,
ksh = TEH_keys_get_state (); ksh = TEH_keys_get_state ();
if (NULL == ksh) if (NULL == ksh)
{ {
if (! check_request_idempotent (rc, if (! check_request_idempotent (wc,
wc,
&mret)) &mret))
{ {
return TALER_MHD_reply_with_error (rc->connection, return TALER_MHD_reply_with_error (rc->connection,
@ -713,8 +723,7 @@ parse_planchets (const struct TEH_RequestContext *rc,
NULL); NULL);
if (NULL == dk) if (NULL == dk)
{ {
if (! check_request_idempotent (rc, if (! check_request_idempotent (wc,
wc,
&mret)) &mret))
{ {
return TEH_RESPONSE_reply_unknown_denom_pub_hash ( return TEH_RESPONSE_reply_unknown_denom_pub_hash (
@ -726,8 +735,7 @@ parse_planchets (const struct TEH_RequestContext *rc,
if (GNUNET_TIME_absolute_is_past (dk->meta.expire_withdraw.abs_time)) if (GNUNET_TIME_absolute_is_past (dk->meta.expire_withdraw.abs_time))
{ {
/* This denomination is past the expiration time for withdraws */ /* This denomination is past the expiration time for withdraws */
if (! check_request_idempotent (rc, if (! check_request_idempotent (wc,
wc,
&mret)) &mret))
{ {
return TEH_RESPONSE_reply_expired_denom_pub_hash ( return TEH_RESPONSE_reply_expired_denom_pub_hash (
@ -751,8 +759,7 @@ parse_planchets (const struct TEH_RequestContext *rc,
if (dk->recoup_possible) if (dk->recoup_possible)
{ {
/* This denomination has been revoked */ /* This denomination has been revoked */
if (! check_request_idempotent (rc, if (! check_request_idempotent (wc,
wc,
&mret)) &mret))
{ {
return TEH_RESPONSE_reply_expired_denom_pub_hash ( return TEH_RESPONSE_reply_expired_denom_pub_hash (
@ -832,7 +839,10 @@ TEH_handler_batch_withdraw (struct TEH_RequestContext *rc,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const json_t *root) const json_t *root)
{ {
struct BatchWithdrawContext wc; struct BatchWithdrawContext wc = {
.reserve_pub = reserve_pub,
.rc = rc
};
json_t *planchets; json_t *planchets;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("planchets", GNUNET_JSON_spec_json ("planchets",
@ -840,13 +850,9 @@ TEH_handler_batch_withdraw (struct TEH_RequestContext *rc,
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
memset (&wc,
0,
sizeof (wc));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TEH_currency, TALER_amount_set_zero (TEH_currency,
&wc.batch_total)); &wc.batch_total));
wc.reserve_pub = reserve_pub;
{ {
enum GNUNET_GenericReturnValue res; enum GNUNET_GenericReturnValue res;

View File

@ -112,6 +112,11 @@ struct KycPoller
*/ */
const char *section_name; const char *section_name;
/**
* Set to AML status of the account.
*/
enum TALER_AmlDecisionState aml_status;
/** /**
* Set to error encountered with KYC logic, if any. * Set to error encountered with KYC logic, if any.
*/ */
@ -303,6 +308,7 @@ kyc_check (void *cls,
TEH_plugin->cls, TEH_plugin->cls,
kyp->requirement_row, kyp->requirement_row,
&requirements, &requirements,
&kyp->aml_status,
&h_payto); &h_payto);
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
{ {
@ -580,6 +586,17 @@ TEH_handler_kyc_check (
if ( (NULL == kyp->ih) && if ( (NULL == kyp->ih) &&
(! kyp->kyc_required) ) (! kyp->kyc_required) )
{ {
if (TALER_AML_NORMAL != kyp->aml_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"KYC is OK, but AML active: %d\n",
(int) kyp->aml_status);
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
GNUNET_JSON_pack_uint64 ("aml_status",
kyp->aml_status));
}
/* KYC not required */ /* KYC not required */
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"KYC not required %llu\n", "KYC not required %llu\n",
@ -628,6 +645,8 @@ TEH_handler_kyc_check (
return TALER_MHD_REPLY_JSON_PACK ( return TALER_MHD_REPLY_JSON_PACK (
rc->connection, rc->connection,
MHD_HTTP_ACCEPTED, MHD_HTTP_ACCEPTED,
GNUNET_JSON_pack_uint64 ("aml_status",
kyp->aml_status),
GNUNET_JSON_pack_string ("kyc_url", GNUNET_JSON_pack_string ("kyc_url",
kyp->kyc_url)); kyp->kyc_url));
} }
@ -665,6 +684,8 @@ TEH_handler_kyc_check (
&sig), &sig),
GNUNET_JSON_pack_data_auto ("exchange_pub", GNUNET_JSON_pack_data_auto ("exchange_pub",
&pub), &pub),
GNUNET_JSON_pack_uint64 ("aml_status",
kyp->aml_status),
GNUNET_JSON_pack_object_incref ("kyc_details", GNUNET_JSON_pack_object_incref ("kyc_details",
kyp->kyc_details), kyp->kyc_details),
GNUNET_JSON_pack_timestamp ("now", GNUNET_JSON_pack_timestamp ("now",

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2022 Taler Systems SA Copyright (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software terms of the GNU Affero General Public License as published by the Free Software
@ -62,6 +62,16 @@ struct ReservePoller
*/ */
struct GNUNET_TIME_Absolute timeout; struct GNUNET_TIME_Absolute timeout;
/**
* Public key of the reserve the inquiry is about.
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* Balance of the reserve, set in the callback.
*/
struct TALER_Amount balance;
/** /**
* True if we are still suspended. * True if we are still suspended.
*/ */
@ -84,13 +94,10 @@ static struct ReservePoller *rp_tail;
void void
TEH_reserves_get_cleanup () TEH_reserves_get_cleanup ()
{ {
struct ReservePoller *rp; for (struct ReservePoller *rp = rp_head;
NULL != rp;
while (NULL != (rp = rp_head)) rp = rp->next)
{ {
GNUNET_CONTAINER_DLL_remove (rp_head,
rp_tail,
rp);
if (rp->suspended) if (rp->suspended)
{ {
rp->suspended = false; rp->suspended = false;
@ -115,11 +122,14 @@ rp_cleanup (struct TEH_RequestContext *rc)
if (NULL != rp->eh) if (NULL != rp->eh)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Cancelling DB event listening\n"); "Cancelling DB event listening on cleanup (odd unless during shutdown)\n");
TEH_plugin->event_listen_cancel (TEH_plugin->cls, TEH_plugin->event_listen_cancel (TEH_plugin->cls,
rp->eh); rp->eh);
rp->eh = NULL; rp->eh = NULL;
} }
GNUNET_CONTAINER_DLL_remove (rp_head,
rp_tail,
rp);
GNUNET_free (rp); GNUNET_free (rp);
} }
@ -137,26 +147,15 @@ db_event_cb (void *cls,
const void *extra, const void *extra,
size_t extra_size) size_t extra_size)
{ {
struct TEH_RequestContext *rc = cls; struct ReservePoller *rp = cls;
struct ReservePoller *rp = rc->rh_ctx;
struct GNUNET_AsyncScopeSave old_scope; struct GNUNET_AsyncScopeSave old_scope;
(void) extra; (void) extra;
(void) extra_size; (void) extra_size;
if (NULL == rp)
return; /* event triggered while main transaction
was still running */
if (! rp->suspended) if (! rp->suspended)
return; /* might get multiple wake-up events */ return; /* might get multiple wake-up events */
rp->suspended = false;
GNUNET_async_scope_enter (&rc->async_scope_id,
&old_scope);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Resuming from long-polling on reserve\n");
TEH_check_invariants (); TEH_check_invariants ();
GNUNET_CONTAINER_DLL_remove (rp_head, rp->suspended = false;
rp_tail,
rp);
MHD_resume_connection (rp->connection); MHD_resume_connection (rp->connection);
TALER_MHD_daemon_trigger (); TALER_MHD_daemon_trigger ();
TEH_check_invariants (); TEH_check_invariants ();
@ -164,191 +163,133 @@ db_event_cb (void *cls,
} }
/**
* Closure for #reserve_history_transaction.
*/
struct ReserveHistoryContext
{
/**
* Public key of the reserve the inquiry is about.
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* Balance of the reserve, set in the callback.
*/
struct TALER_Amount balance;
/**
* Set to true if we did not find the reserve.
*/
bool not_found;
};
/**
* Function implementing /reserves/ GET transaction.
* Execute a /reserves/ GET. Given the public key of a reserve,
* return the associated transaction history. Runs the
* transaction logic; IF it returns a non-error code, the transaction
* logic MUST NOT queue a MHD response. IF it returns an hard error,
* the transaction logic MUST queue a MHD response and set @a mhd_ret.
* IF it returns the soft error code, the function MAY be called again
* to retry and MUST not queue a MHD response.
*
* @param cls a `struct ReserveHistoryContext *`
* @param connection MHD request which triggered the transaction
* @param[out] mhd_ret set to MHD response status for @a connection,
* if transaction failed (!)
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
reserve_balance_transaction (void *cls,
struct MHD_Connection *connection,
MHD_RESULT *mhd_ret)
{
struct ReserveHistoryContext *rsc = cls;
enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls,
&rsc->reserve_pub,
&rsc->balance);
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,
"get_reserve_balance");
}
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
rsc->not_found = true;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
rsc->not_found = false;
return qs;
}
MHD_RESULT MHD_RESULT
TEH_handler_reserves_get (struct TEH_RequestContext *rc, TEH_handler_reserves_get (struct TEH_RequestContext *rc,
const char *const args[1]) const char *const args[1])
{ {
struct ReserveHistoryContext rsc; struct ReservePoller *rp = rc->rh_ctx;
struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_ZERO;
struct GNUNET_DB_EventHandler *eh = NULL;
if (GNUNET_OK != if (NULL == rp)
GNUNET_STRINGS_string_to_data (args[0],
strlen (args[0]),
&rsc.reserve_pub,
sizeof (rsc.reserve_pub)))
{ {
GNUNET_break_op (0); struct GNUNET_TIME_Relative timeout
return TALER_MHD_reply_with_error (rc->connection, = GNUNET_TIME_UNIT_ZERO;
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_RESERVE_PUB_MALFORMED,
args[0]);
}
{
const char *long_poll_timeout_ms;
long_poll_timeout_ms rp = GNUNET_new (struct ReservePoller);
= MHD_lookup_connection_value (rc->connection, rp->connection = rc->connection;
MHD_GET_ARGUMENT_KIND, rc->rh_ctx = rp;
"timeout_ms"); rc->rh_cleaner = &rp_cleanup;
if (NULL != long_poll_timeout_ms) GNUNET_CONTAINER_DLL_insert (rp_head,
rp_tail,
rp);
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[0],
strlen (args[0]),
&rp->reserve_pub,
sizeof (rp->reserve_pub)))
{ {
unsigned int timeout_ms; GNUNET_break_op (0);
char dummy; return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
if (1 != sscanf (long_poll_timeout_ms, TALER_EC_GENERIC_RESERVE_PUB_MALFORMED,
"%u%c", args[0]);
&timeout_ms,
&dummy))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"timeout_ms (must be non-negative number)");
}
timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
timeout_ms);
} }
{
const char *long_poll_timeout_ms;
long_poll_timeout_ms
= MHD_lookup_connection_value (rc->connection,
MHD_GET_ARGUMENT_KIND,
"timeout_ms");
if (NULL != long_poll_timeout_ms)
{
unsigned int timeout_ms;
char dummy;
if (1 != sscanf (long_poll_timeout_ms,
"%u%c",
&timeout_ms,
&dummy))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"timeout_ms (must be non-negative number)");
}
timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
timeout_ms);
}
}
rp->timeout = GNUNET_TIME_relative_to_absolute (timeout);
} }
if ( (! GNUNET_TIME_relative_is_zero (timeout)) &&
(NULL == rc->rh_ctx) ) if ( (GNUNET_TIME_absolute_is_future (rp->timeout)) &&
(NULL == rp->eh) )
{ {
struct TALER_ReserveEventP rep = { struct TALER_ReserveEventP rep = {
.header.size = htons (sizeof (rep)), .header.size = htons (sizeof (rep)),
.header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING), .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING),
.reserve_pub = rsc.reserve_pub .reserve_pub = rp->reserve_pub
}; };
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Starting DB event listening\n"); "Starting DB event listening until %s\n",
eh = TEH_plugin->event_listen (TEH_plugin->cls, GNUNET_TIME_absolute2s (rp->timeout));
timeout, rp->eh = TEH_plugin->event_listen (
&rep.header, TEH_plugin->cls,
&db_event_cb, GNUNET_TIME_absolute_get_remaining (rp->timeout),
rc); &rep.header,
&db_event_cb,
rp);
} }
{ {
MHD_RESULT mhd_ret; enum GNUNET_DB_QueryStatus qs;
if (GNUNET_OK != qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls,
TEH_DB_run_transaction (rc->connection, &rp->reserve_pub,
"get reserve balance", &rp->balance);
TEH_MT_REQUEST_OTHER, switch (qs)
&mhd_ret,
&reserve_balance_transaction,
&rsc))
{
if (NULL != eh)
TEH_plugin->event_listen_cancel (TEH_plugin->cls,
eh);
return mhd_ret;
}
}
/* generate proper response */
if (rsc.not_found)
{
struct ReservePoller *rp = rc->rh_ctx;
if ( (NULL != rp) ||
(GNUNET_TIME_relative_is_zero (timeout)) )
{ {
case GNUNET_DB_STATUS_SOFT_ERROR:
GNUNET_break (0); /* single-shot query should never have soft-errors */
return TALER_MHD_reply_with_error (rc->connection, return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN, TALER_EC_GENERIC_DB_SOFT_FAILURE,
args[0]); "get_reserve_balance");
case GNUNET_DB_STATUS_HARD_ERROR:
GNUNET_break (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
"get_reserve_balance");
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got reserve balance of %s\n",
TALER_amount2s (&rp->balance));
return TALER_MHD_REPLY_JSON_PACK (rc->connection,
MHD_HTTP_OK,
TALER_JSON_pack_amount ("balance",
&rp->balance));
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
if (! GNUNET_TIME_absolute_is_future (rp->timeout))
{
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN,
args[0]);
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Long-polling on reserve for %s\n",
GNUNET_STRINGS_relative_time_to_string (
GNUNET_TIME_absolute_get_remaining (rp->timeout),
true));
rp->suspended = true;
MHD_suspend_connection (rc->connection);
return MHD_YES;
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Long-polling on reserve for %s\n",
GNUNET_STRINGS_relative_time_to_string (timeout,
GNUNET_YES));
rp = GNUNET_new (struct ReservePoller);
rp->connection = rc->connection;
rp->timeout = GNUNET_TIME_relative_to_absolute (timeout);
rp->eh = eh;
rc->rh_ctx = rp;
rc->rh_cleaner = &rp_cleanup;
rp->suspended = true;
GNUNET_CONTAINER_DLL_insert (rp_head,
rp_tail,
rp);
MHD_suspend_connection (rc->connection);
return MHD_YES;
} }
if (NULL != eh) GNUNET_break (0);
TEH_plugin->event_listen_cancel (TEH_plugin->cls, return MHD_NO;
eh);
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_OK,
TALER_JSON_pack_amount ("balance",
&rsc.balance));
} }

View File

@ -57,6 +57,12 @@ static struct TALER_BANK_CreditHistoryHandle *hh;
*/ */
static bool hh_returned_data; static bool hh_returned_data;
/**
* Set to true if the request for history did not
* succeed because the account was unknown.
*/
static bool hh_account_404;
/** /**
* When did we start the last @e hh request? * When did we start the last @e hh request?
*/ */
@ -472,9 +478,9 @@ transaction_completed (void)
GNUNET_SCHEDULER_shutdown (); GNUNET_SCHEDULER_shutdown ();
return; return;
} }
if (! hh_returned_data) if (! (hh_returned_data || hh_account_404) )
{ {
/* Enforce long polling delay even if the server ignored it /* Enforce long-polling delay even if the server ignored it
and returned earlier */ and returned earlier */
struct GNUNET_TIME_Relative latency; struct GNUNET_TIME_Relative latency;
struct GNUNET_TIME_Relative left; struct GNUNET_TIME_Relative left;
@ -482,8 +488,17 @@ transaction_completed (void)
latency = GNUNET_TIME_absolute_get_duration (hh_start_time); latency = GNUNET_TIME_absolute_get_duration (hh_start_time);
left = GNUNET_TIME_relative_subtract (longpoll_timeout, left = GNUNET_TIME_relative_subtract (longpoll_timeout,
latency); latency);
if (! (test_mode ||
GNUNET_TIME_relative_is_zero (left)) )
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, // WARNING,
"Server did not respect long-polling, enforcing client-side by sleeping for %s\n",
GNUNET_TIME_relative2s (left,
true));
delayed_until = GNUNET_TIME_relative_to_absolute (left); delayed_until = GNUNET_TIME_relative_to_absolute (left);
} }
if (hh_account_404)
delayed_until = GNUNET_TIME_relative_to_absolute (
GNUNET_TIME_UNIT_MILLISECONDS);
if (test_mode) if (test_mode)
delayed_until = GNUNET_TIME_UNIT_ZERO_ABS; delayed_until = GNUNET_TIME_UNIT_ZERO_ABS;
GNUNET_assert (NULL == task); GNUNET_assert (NULL == task);
@ -495,12 +510,12 @@ transaction_completed (void)
* We got incoming transaction details from the bank. Add them * We got incoming transaction details from the bank. Add them
* to the database. * to the database.
* *
* @param batch_size desired batch size * @param wrap_size desired bulk insert size
* @param details array of transaction details * @param details array of transaction details
* @param details_length length of the @a details array * @param details_length length of the @a details array
*/ */
static void static void
process_reply (unsigned int batch_size, process_reply (unsigned int wrap_size,
const struct TALER_BANK_CreditDetails *details, const struct TALER_BANK_CreditDetails *details,
unsigned int details_length) unsigned int details_length)
{ {
@ -570,7 +585,7 @@ process_reply (unsigned int batch_size,
qs = db_plugin->reserves_in_insert (db_plugin->cls, qs = db_plugin->reserves_in_insert (db_plugin->cls,
reserves, reserves,
details_length, details_length,
batch_size, wrap_size,
qss); qss);
switch (qs) switch (qs)
{ {
@ -581,7 +596,7 @@ process_reply (unsigned int batch_size,
case GNUNET_DB_STATUS_SOFT_ERROR: case GNUNET_DB_STATUS_SOFT_ERROR:
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got DB soft error for batch2_reserves_in_insert (%u). Rolling back.\n", "Got DB soft error for batch2_reserves_in_insert (%u). Rolling back.\n",
batch_size); wrap_size);
handle_soft_error (); handle_soft_error ();
return; return;
default: default:
@ -686,36 +701,36 @@ static void
history_cb (void *cls, history_cb (void *cls,
const struct TALER_BANK_CreditHistoryResponse *reply) const struct TALER_BANK_CreditHistoryResponse *reply)
{ {
static int batch_mode = -2; static int wrap_size = -2;
(void) cls; (void) cls;
if (-2 == batch_mode) if (-2 == wrap_size)
{ {
const char *mode = getenv ("TALER_WIREWATCH_BATCH_SIZE"); const char *mode = getenv ("TALER_WIREWATCH_WARP_SIZE");
char dummy; char dummy;
if ( (NULL == mode) || if ( (NULL == mode) ||
(1 != sscanf (mode, (1 != sscanf (mode,
"%d%c", "%d%c",
&batch_mode, &wrap_size,
&dummy)) ) &dummy)) )
{ {
if (NULL != mode) if (NULL != mode)
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Bad batch mode `%s' specified\n", "Bad batch mode `%s' specified\n",
mode); mode);
batch_mode = 8; /* maximum supported is currently 8 */ wrap_size = 8; /* maximum supported is currently 8 */
} }
} }
GNUNET_assert (NULL == task); GNUNET_assert (NULL == task);
hh = NULL; hh = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"History request returned with HTTP status %u\n", "History request returned with HTTP status %u\n",
reply->http_status); reply->http_status);
switch (reply->http_status) switch (reply->http_status)
{ {
case MHD_HTTP_OK: case MHD_HTTP_OK:
process_reply (batch_mode, process_reply (wrap_size,
reply->details.success.details, reply->details.success.details,
reply->details.success.details_length); reply->details.success.details_length);
return; return;
@ -723,6 +738,7 @@ history_cb (void *cls,
transaction_completed (); transaction_completed ();
return; return;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
hh_account_404 = true;
if (ignore_account_404) if (ignore_account_404)
{ {
transaction_completed (); transaction_completed ();
@ -761,6 +777,7 @@ continue_with_shard (void *cls)
(unsigned long long) latest_row_off); (unsigned long long) latest_row_off);
hh_start_time = GNUNET_TIME_absolute_get (); hh_start_time = GNUNET_TIME_absolute_get ();
hh_returned_data = false; hh_returned_data = false;
hh_account_404 = false;
hh = TALER_BANK_credit_history (ctx, hh = TALER_BANK_credit_history (ctx,
ai->auth, ai->auth,
latest_row_off, latest_row_off,
@ -857,6 +874,17 @@ lock_shard (void *cls)
job_name, job_name,
GNUNET_STRINGS_relative_time_to_string (rdelay, GNUNET_STRINGS_relative_time_to_string (rdelay,
true)); true));
#if 1
if (GNUNET_TIME_relative_cmp (rdelay,
>,
GNUNET_TIME_UNIT_SECONDS))
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Delay would have been for %s\n",
GNUNET_TIME_relative2s (rdelay,
true));
rdelay = GNUNET_TIME_relative_min (rdelay,
GNUNET_TIME_UNIT_SECONDS);
#endif
delayed_until = GNUNET_TIME_relative_to_absolute (rdelay); delayed_until = GNUNET_TIME_relative_to_absolute (rdelay);
} }
GNUNET_assert (NULL == task); GNUNET_assert (NULL == task);
@ -869,7 +897,7 @@ lock_shard (void *cls)
job_name, job_name,
GNUNET_STRINGS_relative_time_to_string ( GNUNET_STRINGS_relative_time_to_string (
wirewatch_idle_sleep_interval, wirewatch_idle_sleep_interval,
GNUNET_YES)); true));
delayed_until = GNUNET_TIME_relative_to_absolute ( delayed_until = GNUNET_TIME_relative_to_absolute (
wirewatch_idle_sleep_interval); wirewatch_idle_sleep_interval);
shard_open = false; shard_open = false;

View File

@ -7,3 +7,9 @@ perf_select_refunds_by_coin-postgres
exchange-0002.sql exchange-0002.sql
procedures.sql procedures.sql
exchange-0003.sql exchange-0003.sql
perf-exchangedb-reserves-in-insert-postgres
test-exchangedb-batch-reserves-in-insert-postgres
test-exchangedb-by-j-postgres
test-exchangedb-populate-link-data-postgres
test-exchangedb-populate-ready-deposit-postgres
test-exchangedb-populate-select-refunds-by-coin-postgres

View File

@ -62,6 +62,9 @@ BEGIN
,table_name ,table_name
,partition_suffix ,partition_suffix
); );
--
-- FIXME: Add comment for link_sig
--
PERFORM comment_partitioned_column( PERFORM comment_partitioned_column(
'envelope of the new coin to be signed' 'envelope of the new coin to be signed'
,'coin_ev' ,'coin_ev'

View File

@ -33,7 +33,6 @@ BEGIN
',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)' ',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)'
',reserve_sig BYTEA CHECK (LENGTH(reserve_sig)=64)' ',reserve_sig BYTEA CHECK (LENGTH(reserve_sig)=64)'
',noreveal_index INT4 NOT NULL' ',noreveal_index INT4 NOT NULL'
',timestamp INT8 NOT NULL'
') %s ;' ') %s ;'
,table_name ,table_name
,'PARTITION BY HASH (reserve_pub)' ,'PARTITION BY HASH (reserve_pub)'
@ -51,7 +50,7 @@ BEGIN
,partition_suffix ,partition_suffix
); );
PERFORM comment_partitioned_column( PERFORM comment_partitioned_column(
'The maximum age that the client commits to with this request' 'The maximum age (in years) that the client commits to with this request'
,'max_age' ,'max_age'
,table_name ,table_name
,partition_suffix ,partition_suffix
@ -74,12 +73,6 @@ BEGIN
,table_name ,table_name
,partition_suffix ,partition_suffix
); );
PERFORM comment_partitioned_column(
'Timestamp with the time when the withdraw-age request was received by the exchange'
,'timestamp'
,table_name
,partition_suffix
);
END END
$$; $$;

View File

@ -14,22 +14,25 @@
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-- --
CREATE FUNCTION create_table_withdraw_age_reveals( CREATE FUNCTION create_table_withdraw_age_revealed_coins(
IN partition_suffix VARCHAR DEFAULT NULL IN partition_suffix VARCHAR DEFAULT NULL
) )
RETURNS VOID RETURNS VOID
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
DECLARE DECLARE
table_name VARCHAR DEFAULT 'withdraw_age_reveals'; table_name VARCHAR DEFAULT 'withdraw_age_revealed_coins';
BEGIN BEGIN
PERFORM create_partitioned_table( PERFORM create_partitioned_table(
'CREATE TABLE %I' 'CREATE TABLE %I'
'(withdraw_age_reveals_id BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE '(withdraw_age_revealed_coins_id BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE
',h_commitment BYTEA NOT NULL CHECK (LENGTH(h_commitment)=32)' ',h_commitment BYTEA NOT NULL CHECK (LENGTH(h_commitment)=64)'
',freshcoin_index INT4 NOT NULL' ',freshcoin_index INT4 NOT NULL'
',denominations_serial INT8 NOT NULL' ',denominations_serial INT8 NOT NULL'
',h_coin_ev BYTEA CHECK (LENGTH(h_coin_ev)=32)' ',coin_ev BYTEA NOT NULL'
',h_coin_ev BYTEA CHECK (LENGTH(h_coin_ev)=64)'
',ev_sig BYTEA NOT NULL'
',ewv BYTEA NOT NULL'
') %s ;' ') %s ;'
,table_name ,table_name
,'PARTITION BY HASH (h_commitment)' ,'PARTITION BY HASH (h_commitment)'
@ -59,29 +62,47 @@ BEGIN
,partition_suffix ,partition_suffix
); );
PERFORM comment_partitioned_column( PERFORM comment_partitioned_column(
'Hash of the blinded coins' 'Envelope of the new coin to be signed'
,'coin_ev'
,table_name
,partition_suffix
);
PERFORM comment_partitioned_column(
'Hash of the envelope of the new coin to be signed (for lookups)'
,'h_coin_ev' ,'h_coin_ev'
,table_name ,table_name
,partition_suffix ,partition_suffix
); );
PERFORM comment_partitioned_column(
'Exchange signature over the envelope'
,'ev_sig'
,table_name
,partition_suffix
);
PERFORM comment_partitioned_column(
'Exchange contributed values in the creation of the fresh coin (see /csr)'
,'ewv'
,table_name
,partition_suffix
);
END END
$$; $$;
CREATE FUNCTION constrain_table_withdraw_age_reveals( CREATE FUNCTION constrain_table_withdraw_age_revealed_coins(
IN partition_suffix VARCHAR IN partition_suffix VARCHAR
) )
RETURNS void RETURNS void
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
DECLARE DECLARE
table_name VARCHAR DEFAULT 'withdraw_age_reveals'; table_name VARCHAR DEFAULT 'withdraw_age_revealed_coins';
BEGIN BEGIN
table_name = concat_ws('_', table_name, partition_suffix); table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT ( EXECUTE FORMAT (
'ALTER TABLE ' || table_name || 'ALTER TABLE ' || table_name ||
' ADD CONSTRAINT ' || table_name || '_withdraw_age_reveals_id_key' ' ADD CONSTRAINT ' || table_name || '_withdraw_age_revealed_coins_id_key'
' UNIQUE (withdraw_age_reveals_id);' ' UNIQUE (withdraw_age_revealed_coins_id);'
); );
EXECUTE FORMAT ( EXECUTE FORMAT (
'ALTER TABLE ' || table_name || 'ALTER TABLE ' || table_name ||
@ -91,12 +112,12 @@ BEGIN
END END
$$; $$;
CREATE FUNCTION foreign_table_withdraw_age_reveals() CREATE FUNCTION foreign_table_withdraw_age_revealed_coins()
RETURNS void RETURNS void
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
DECLARE DECLARE
table_name VARCHAR DEFAULT 'withdraw_age_reveals'; table_name VARCHAR DEFAULT 'withdraw_age_revealed_coins';
BEGIN BEGIN
EXECUTE FORMAT ( EXECUTE FORMAT (
'ALTER TABLE ' || table_name || 'ALTER TABLE ' || table_name ||
@ -121,17 +142,17 @@ INSERT INTO exchange_tables
,partitioned ,partitioned
,by_range) ,by_range)
VALUES VALUES
('withdraw_age_reveals' ('withdraw_age_revealed_coins'
,'exchange-0003' ,'exchange-0003'
,'create' ,'create'
,TRUE ,TRUE
,FALSE), ,FALSE),
('withdraw_age_reveals' ('withdraw_age_revealed_coins'
,'exchange-0003' ,'exchange-0003'
,'constrain' ,'constrain'
,TRUE ,TRUE
,FALSE), ,FALSE),
('withdraw_age_reveals' ('withdraw_age_revealed_coins'
,'exchange-0003' ,'exchange-0003'
,'foreign' ,'foreign'
,TRUE ,TRUE

View File

@ -116,6 +116,7 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_reserves_in_insert.h pg_reserves_in_insert.c \ pg_reserves_in_insert.h pg_reserves_in_insert.c \
pg_get_withdraw_info.h pg_get_withdraw_info.c \ pg_get_withdraw_info.h pg_get_withdraw_info.c \
pg_get_age_withdraw_info.c pg_get_age_withdraw_info.h \ pg_get_age_withdraw_info.c pg_get_age_withdraw_info.h \
pg_batch_ensure_coin_known.h pg_batch_ensure_coin_known.c \
pg_do_batch_withdraw.h pg_do_batch_withdraw.c \ pg_do_batch_withdraw.h pg_do_batch_withdraw.c \
pg_get_policy_details.h pg_get_policy_details.c \ pg_get_policy_details.h pg_get_policy_details.c \
pg_persist_policy_details.h pg_persist_policy_details.c \ pg_persist_policy_details.h pg_persist_policy_details.c \

View File

@ -1,186 +0,0 @@
--
-- This file is part of TALER
-- Copyright (C) 2014--2022 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/>
--
DROP FUNCTION IF EXISTS exchange_do_batch2_reserves_insert;
CREATE OR REPLACE FUNCTION exchange_do_batch2_reserves_insert(
IN in_reserve_pub BYTEA,
IN in_expiration_date INT8,
IN in_gc_date INT8,
IN in_wire_ref INT8,
IN in_credit_val INT8,
IN in_credit_frac INT4,
IN in_exchange_account_name VARCHAR,
IN in_execution_date INT8,
IN in_wire_source_h_payto BYTEA, ---h_payto
IN in_payto_uri VARCHAR,
IN in_reserve_expiration INT8,
IN in_notify text,
IN in2_notify text,
IN in2_reserve_pub BYTEA,
IN in2_wire_ref INT8,
IN in2_credit_val INT8,
IN in2_credit_frac INT4,
IN in2_exchange_account_name VARCHAR,
IN in2_execution_date INT8,
IN in2_wire_source_h_payto BYTEA, ---h_payto
IN in2_payto_uri VARCHAR,
IN in2_reserve_expiration INT8,
OUT out_reserve_found BOOLEAN,
OUT out_reserve_found2 BOOLEAN,
OUT transaction_duplicate BOOLEAN,
OUT transaction_duplicate2 BOOLEAN,
OUT ruuid INT8,
OUT ruuid2 INT8)
LANGUAGE plpgsql
AS $$
DECLARE
curs_reserve_exist REFCURSOR;
DECLARE
curs_transaction_exist refcursor;
DECLARE
i RECORD;
DECLARE
r RECORD;
DECLARE
k INT8;
BEGIN
transaction_duplicate=TRUE;
transaction_duplicate2=TRUE;
out_reserve_found = TRUE;
out_reserve_found2 = TRUE;
ruuid=0;
ruuid2=0;
k=0;
INSERT INTO wire_targets
(wire_target_h_payto
,payto_uri)
VALUES
(in_wire_source_h_payto
,in_payto_uri),
(in2_wire_source_h_payto
,in2_payto_uri)
ON CONFLICT DO NOTHING;
OPEN curs_reserve_exist FOR
WITH reserve_changes AS (
INSERT INTO reserves
(reserve_pub
,current_balance_val
,current_balance_frac
,expiration_date
,gc_date)
VALUES
(in_reserve_pub
,in_credit_val
,in_credit_frac
,in_expiration_date
,in_gc_date),
(in2_reserve_pub
,in2_credit_val
,in2_credit_frac
,in_expiration_date
,in_gc_date)
ON CONFLICT DO NOTHING
RETURNING reserve_uuid,reserve_pub)
SELECT * FROM reserve_changes;
WHILE k < 2 LOOP
FETCH FROM curs_reserve_exist INTO i;
IF FOUND
THEN
IF in_reserve_pub = i.reserve_pub
THEN
ruuid = i.reserve_uuid;
IF in_reserve_pub <> in2_reserve_pub
THEN
out_reserve_found = FALSE;
END IF;
END IF;
IF in2_reserve_pub = i.reserve_pub
THEN
out_reserve_found2 = FALSE;
ruuid2 = i.reserve_uuid;
END IF;
END IF;
k=k+1;
END LOOP;
CLOSE curs_reserve_exist;
-- FIXME: must be changed to EXECUTE FORMAT!
PERFORM pg_notify(in_notify, NULL);
PERFORM pg_notify(in2_notify, NULL);
OPEN curs_transaction_exist FOR
WITH reserve_in_exist AS (
INSERT INTO reserves_in
(reserve_pub
,wire_reference
,credit_val
,credit_frac
,exchange_account_section
,wire_source_h_payto
,execution_date)
VALUES
(in_reserve_pub
,in_wire_ref
,in_credit_val
,in_credit_frac
,in_exchange_account_name
,in_wire_source_h_payto
,in_execution_date),
(in2_reserve_pub
,in2_wire_ref
,in2_credit_val
,in2_credit_frac
,in2_exchange_account_name
,in2_wire_source_h_payto
,in_execution_date)
ON CONFLICT DO NOTHING
RETURNING reserve_pub)
SELECT * FROM reserve_in_exist;
FETCH FROM curs_transaction_exist INTO r;
IF FOUND
THEN
IF in_reserve_pub = r.reserve_pub
THEN
transaction_duplicate = FALSE;
END IF;
IF in2_reserve_pub = r.reserve_pub
THEN
transaction_duplicate2 = FALSE;
END IF;
FETCH FROM curs_transaction_exist INTO r;
IF FOUND
THEN
IF in_reserve_pub = r.reserve_pub
THEN
transaction_duplicate = FALSE;
END IF;
IF in2_reserve_pub = r.reserve_pub
THEN
transaction_duplicate2 = FALSE;
END IF;
END IF;
END IF;
/* IF transaction_duplicate
OR transaction_duplicate2
THEN
CLOSE curs_transaction_exist;
ROLLBACK;
RETURN;
END IF;*/
CLOSE curs_transaction_exist;
RETURN;
END $$;

View File

@ -1,287 +0,0 @@
--
-- This file is part of TALER
-- Copyright (C) 2014--2022 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/>
--
DROP FUNCTION IF EXISTS exchange_do_batch4_reserves_insert;
CREATE OR REPLACE FUNCTION exchange_do_batch4_reserves_insert(
IN in_reserve_pub BYTEA,
IN in_expiration_date INT8,
IN in_gc_date INT8,
IN in_wire_ref INT8,
IN in_credit_val INT8,
IN in_credit_frac INT4,
IN in_exchange_account_name VARCHAR,
IN in_execution_date INT8,
IN in_wire_source_h_payto BYTEA, ---h_payto
IN in_payto_uri VARCHAR,
IN in_reserve_expiration INT8,
IN in_notify text,
IN in2_notify text,
IN in3_notify text,
IN in4_notify text,
IN in2_reserve_pub BYTEA,
IN in2_wire_ref INT8,
IN in2_credit_val INT8,
IN in2_credit_frac INT4,
IN in2_exchange_account_name VARCHAR,
IN in2_execution_date INT8,
IN in2_wire_source_h_payto BYTEA, ---h_payto
IN in2_payto_uri VARCHAR,
IN in2_reserve_expiration INT8,
IN in3_reserve_pub BYTEA,
IN in3_wire_ref INT8,
IN in3_credit_val INT8,
IN in3_credit_frac INT4,
IN in3_exchange_account_name VARCHAR,
IN in3_execution_date INT8,
IN in3_wire_source_h_payto BYTEA, ---h_payto
IN in3_payto_uri VARCHAR,
IN in3_reserve_expiration INT8,
IN in4_reserve_pub BYTEA,
IN in4_wire_ref INT8,
IN in4_credit_val INT8,
IN in4_credit_frac INT4,
IN in4_exchange_account_name VARCHAR,
IN in4_execution_date INT8,
IN in4_wire_source_h_payto BYTEA, ---h_payto
IN in4_payto_uri VARCHAR,
IN in4_reserve_expiration INT8,
OUT out_reserve_found BOOLEAN,
OUT out_reserve_found2 BOOLEAN,
OUT out_reserve_found3 BOOLEAN,
OUT out_reserve_found4 BOOLEAN,
OUT transaction_duplicate BOOLEAN,
OUT transaction_duplicate2 BOOLEAN,
OUT transaction_duplicate3 BOOLEAN,
OUT transaction_duplicate4 BOOLEAN,
OUT ruuid INT8,
OUT ruuid2 INT8,
OUT ruuid3 INT8,
OUT ruuid4 INT8)
LANGUAGE plpgsql
AS $$
DECLARE
curs_reserve_exist refcursor;
DECLARE
k INT8;
DECLARE
curs_transaction_exist refcursor;
DECLARE
i RECORD;
BEGIN
--INITIALIZATION
transaction_duplicate=TRUE;
transaction_duplicate2=TRUE;
transaction_duplicate3=TRUE;
transaction_duplicate4=TRUE;
out_reserve_found = TRUE;
out_reserve_found2 = TRUE;
out_reserve_found3 = TRUE;
out_reserve_found4 = TRUE;
ruuid=0;
ruuid2=0;
ruuid3=0;
ruuid4=0;
k=0;
--SIMPLE INSERT ON CONFLICT DO NOTHING
INSERT INTO wire_targets
(wire_target_h_payto
,payto_uri)
VALUES
(in_wire_source_h_payto
,in_payto_uri),
(in2_wire_source_h_payto
,in2_payto_uri),
(in3_wire_source_h_payto
,in3_payto_uri),
(in4_wire_source_h_payto
,in4_payto_uri)
ON CONFLICT DO NOTHING;
OPEN curs_reserve_exist FOR
WITH reserve_changes AS (
INSERT INTO reserves
(reserve_pub
,current_balance_val
,current_balance_frac
,expiration_date
,gc_date)
VALUES
(in_reserve_pub
,in_credit_val
,in_credit_frac
,in_expiration_date
,in_gc_date),
(in2_reserve_pub
,in2_credit_val
,in2_credit_frac
,in_expiration_date
,in_gc_date),
(in3_reserve_pub
,in3_credit_val
,in3_credit_frac
,in_expiration_date
,in_gc_date),
(in4_reserve_pub
,in4_credit_val
,in4_credit_frac
,in_expiration_date
,in_gc_date)
ON CONFLICT DO NOTHING
RETURNING reserve_uuid,reserve_pub)
SELECT * FROM reserve_changes;
WHILE k < 4 LOOP
FETCH FROM curs_reserve_exist INTO i;
IF FOUND
THEN
IF in_reserve_pub = i.reserve_pub
THEN
ruuid = i.reserve_uuid;
IF in_reserve_pub
NOT IN (in2_reserve_pub
,in3_reserve_pub
,in4_reserve_pub)
THEN
out_reserve_found = FALSE;
END IF;
END IF;
IF in2_reserve_pub = i.reserve_pub
THEN
ruuid2 = i.reserve_uuid;
IF in2_reserve_pub
NOT IN (in_reserve_pub
,in3_reserve_pub
,in4_reserve_pub)
THEN
out_reserve_found2 = FALSE;
END IF;
END IF;
IF in3_reserve_pub = i.reserve_pub
THEN
ruuid3 = i.reserve_uuid;
IF in3_reserve_pub
NOT IN (in_reserve_pub
,in2_reserve_pub
,in4_reserve_pub)
THEN
out_reserve_found3 = FALSE;
END IF;
END IF;
IF in4_reserve_pub = i.reserve_pub
THEN
ruuid4 = i.reserve_uuid;
IF in4_reserve_pub
NOT IN (in_reserve_pub
,in2_reserve_pub
,in3_reserve_pub)
THEN
out_reserve_found4 = FALSE;
END IF;
END IF;
END IF;
k=k+1;
END LOOP;
CLOSE curs_reserve_exist;
-- FIXME: must be changed to EXECUTE FORMAT!
PERFORM pg_notify(in_notify, NULL);
PERFORM pg_notify(in2_notify, NULL);
PERFORM pg_notify(in3_notify, NULL);
PERFORM pg_notify(in4_notify, NULL);
k=0;
OPEN curs_transaction_exist FOR
WITH reserve_in_changes AS (
INSERT INTO reserves_in
(reserve_pub
,wire_reference
,credit_val
,credit_frac
,exchange_account_section
,wire_source_h_payto
,execution_date)
VALUES
(in_reserve_pub
,in_wire_ref
,in_credit_val
,in_credit_frac
,in_exchange_account_name
,in_wire_source_h_payto
,in_execution_date),
(in2_reserve_pub
,in2_wire_ref
,in2_credit_val
,in2_credit_frac
,in2_exchange_account_name
,in2_wire_source_h_payto
,in_execution_date),
(in3_reserve_pub
,in3_wire_ref
,in3_credit_val
,in3_credit_frac
,in3_exchange_account_name
,in3_wire_source_h_payto
,in_execution_date),
(in4_reserve_pub
,in4_wire_ref
,in4_credit_val
,in4_credit_frac
,in4_exchange_account_name
,in4_wire_source_h_payto
,in_execution_date)
ON CONFLICT DO NOTHING
RETURNING reserve_pub)
SELECT * FROM reserve_in_changes;
WHILE k < 4 LOOP
FETCH FROM curs_transaction_exist INTO i;
IF FOUND
THEN
IF in_reserve_pub = i.reserve_pub
THEN
transaction_duplicate = FALSE;
END IF;
IF in2_reserve_pub = i.reserve_pub
THEN
transaction_duplicate2 = FALSE;
END IF;
IF in3_reserve_pub = i.reserve_pub
THEN
transaction_duplicate3 = FALSE;
END IF;
IF in4_reserve_pub = i.reserve_pub
THEN
transaction_duplicate4 = FALSE;
END IF;
END IF;
k=k+1;
END LOOP;
/**ROLLBACK TRANSACTION IN SORTED PROCEDURE IS IT PROSSIBLE ?**/
/*IF transaction_duplicate
OR transaction_duplicate2
OR transaction_duplicate3
OR transaction_duplicate4
THEN
RAISE EXCEPTION 'Reserve did not exist, but INSERT into reserves_in gave conflict';
ROLLBACK;
CLOSE curs_transaction_exist;
RETURN;
END IF;*/
CLOSE curs_transaction_exist;
RETURN;
END $$;

View File

@ -1,509 +0,0 @@
--
-- This file is part of TALER
-- Copyright (C) 2014--2022 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/>
--
DROP FUNCTION IF EXISTS exchange_do_batch8_reserves_insert;
CREATE OR REPLACE FUNCTION exchange_do_batch8_reserves_insert(
IN in_reserve_pub BYTEA,
IN in_expiration_date INT8,
IN in_gc_date INT8,
IN in_wire_ref INT8,
IN in_credit_val INT8,
IN in_credit_frac INT4,
IN in_exchange_account_name VARCHAR,
IN in_execution_date INT8,
IN in_wire_source_h_payto BYTEA, ---h_payto
IN in_payto_uri VARCHAR,
IN in_reserve_expiration INT8,
IN in_notify text,
IN in2_notify text,
IN in3_notify text,
IN in4_notify text,
IN in5_notify text,
IN in6_notify text,
IN in7_notify text,
IN in8_notify text,
IN in2_reserve_pub BYTEA,
IN in2_wire_ref INT8,
IN in2_credit_val INT8,
IN in2_credit_frac INT4,
IN in2_exchange_account_name VARCHAR,
IN in2_execution_date INT8,
IN in2_wire_source_h_payto BYTEA, ---h_payto
IN in2_payto_uri VARCHAR,
IN in2_reserve_expiration INT8,
IN in3_reserve_pub BYTEA,
IN in3_wire_ref INT8,
IN in3_credit_val INT8,
IN in3_credit_frac INT4,
IN in3_exchange_account_name VARCHAR,
IN in3_execution_date INT8,
IN in3_wire_source_h_payto BYTEA, ---h_payto
IN in3_payto_uri VARCHAR,
IN in3_reserve_expiration INT8,
IN in4_reserve_pub BYTEA,
IN in4_wire_ref INT8,
IN in4_credit_val INT8,
IN in4_credit_frac INT4,
IN in4_exchange_account_name VARCHAR,
IN in4_execution_date INT8,
IN in4_wire_source_h_payto BYTEA, ---h_payto
IN in4_payto_uri VARCHAR,
IN in4_reserve_expiration INT8,
IN in5_reserve_pub BYTEA,
IN in5_wire_ref INT8,
IN in5_credit_val INT8,
IN in5_credit_frac INT4,
IN in5_exchange_account_name VARCHAR,
IN in5_execution_date INT8,
IN in5_wire_source_h_payto BYTEA, ---h_payto
IN in5_payto_uri VARCHAR,
IN in5_reserve_expiration INT8,
IN in6_reserve_pub BYTEA,
IN in6_wire_ref INT8,
IN in6_credit_val INT8,
IN in6_credit_frac INT4,
IN in6_exchange_account_name VARCHAR,
IN in6_execution_date INT8,
IN in6_wire_source_h_payto BYTEA, ---h_payto
IN in6_payto_uri VARCHAR,
IN in6_reserve_expiration INT8,
IN in7_reserve_pub BYTEA,
IN in7_wire_ref INT8,
IN in7_credit_val INT8,
IN in7_credit_frac INT4,
IN in7_exchange_account_name VARCHAR,
IN in7_execution_date INT8,
IN in7_wire_source_h_payto BYTEA, ---h_payto
IN in7_payto_uri VARCHAR,
IN in7_reserve_expiration INT8,
IN in8_reserve_pub BYTEA,
IN in8_wire_ref INT8,
IN in8_credit_val INT8,
IN in8_credit_frac INT4,
IN in8_exchange_account_name VARCHAR,
IN in8_execution_date INT8,
IN in8_wire_source_h_payto BYTEA, ---h_payto
IN in8_payto_uri VARCHAR,
IN in8_reserve_expiration INT8,
OUT out_reserve_found BOOLEAN,
OUT out_reserve_found2 BOOLEAN,
OUT out_reserve_found3 BOOLEAN,
OUT out_reserve_found4 BOOLEAN,
OUT out_reserve_found5 BOOLEAN,
OUT out_reserve_found6 BOOLEAN,
OUT out_reserve_found7 BOOLEAN,
OUT out_reserve_found8 BOOLEAN,
OUT transaction_duplicate BOOLEAN,
OUT transaction_duplicate2 BOOLEAN,
OUT transaction_duplicate3 BOOLEAN,
OUT transaction_duplicate4 BOOLEAN,
OUT transaction_duplicate5 BOOLEAN,
OUT transaction_duplicate6 BOOLEAN,
OUT transaction_duplicate7 BOOLEAN,
OUT transaction_duplicate8 BOOLEAN,
OUT ruuid INT8,
OUT ruuid2 INT8,
OUT ruuid3 INT8,
OUT ruuid4 INT8,
OUT ruuid5 INT8,
OUT ruuid6 INT8,
OUT ruuid7 INT8,
OUT ruuid8 INT8)
LANGUAGE plpgsql
AS $$
DECLARE
curs_reserve_existed refcursor;
DECLARE
k INT8;
DECLARE
curs_transaction_existed refcursor;
DECLARE
i RECORD;
DECLARE
r RECORD;
BEGIN
--INITIALIZATION
transaction_duplicate=TRUE;
transaction_duplicate2=TRUE;
transaction_duplicate3=TRUE;
transaction_duplicate4=TRUE;
transaction_duplicate5=TRUE;
transaction_duplicate6=TRUE;
transaction_duplicate7=TRUE;
transaction_duplicate8=TRUE;
out_reserve_found = TRUE;
out_reserve_found2 = TRUE;
out_reserve_found3 = TRUE;
out_reserve_found4 = TRUE;
out_reserve_found5 = TRUE;
out_reserve_found6 = TRUE;
out_reserve_found7 = TRUE;
out_reserve_found8 = TRUE;
ruuid=0;
ruuid2=0;
ruuid3=0;
ruuid4=0;
ruuid5=0;
ruuid6=0;
ruuid7=0;
ruuid8=0;
k=0;
--SIMPLE INSERT ON CONFLICT DO NOTHING
INSERT INTO wire_targets
(wire_target_h_payto
,payto_uri)
VALUES
(in_wire_source_h_payto
,in_payto_uri),
(in2_wire_source_h_payto
,in2_payto_uri),
(in3_wire_source_h_payto
,in3_payto_uri),
(in4_wire_source_h_payto
,in4_payto_uri),
(in5_wire_source_h_payto
,in5_payto_uri),
(in6_wire_source_h_payto
,in6_payto_uri),
(in7_wire_source_h_payto
,in7_payto_uri),
(in8_wire_source_h_payto
,in8_payto_uri)
ON CONFLICT DO NOTHING;
OPEN curs_reserve_existed FOR
WITH reserve_changes AS (
INSERT INTO reserves
(reserve_pub
,current_balance_val
,current_balance_frac
,expiration_date
,gc_date)
VALUES
(in_reserve_pub
,in_credit_val
,in_credit_frac
,in_expiration_date
,in_gc_date),
(in2_reserve_pub
,in2_credit_val
,in2_credit_frac
,in_expiration_date
,in_gc_date),
(in3_reserve_pub
,in3_credit_val
,in3_credit_frac
,in_expiration_date
,in_gc_date),
(in4_reserve_pub
,in4_credit_val
,in4_credit_frac
,in_expiration_date
,in_gc_date),
(in5_reserve_pub
,in5_credit_val
,in5_credit_frac
,in_expiration_date
,in_gc_date),
(in6_reserve_pub
,in6_credit_val
,in6_credit_frac
,in_expiration_date
,in_gc_date),
(in7_reserve_pub
,in7_credit_val
,in7_credit_frac
,in_expiration_date
,in_gc_date),
(in8_reserve_pub
,in8_credit_val
,in8_credit_frac
,in_expiration_date
,in_gc_date)
ON CONFLICT DO NOTHING
RETURNING reserve_uuid,reserve_pub)
SELECT * FROM reserve_changes;
WHILE k < 8 LOOP
FETCH FROM curs_reserve_existed INTO i;
IF FOUND
THEN
IF in_reserve_pub = i.reserve_pub
THEN
ruuid = i.reserve_uuid;
IF in_reserve_pub
NOT IN (in2_reserve_pub
,in3_reserve_pub
,in4_reserve_pub
,in5_reserve_pub
,in6_reserve_pub
,in7_reserve_pub
,in8_reserve_pub)
THEN
out_reserve_found = FALSE;
END IF;
END IF;
IF in2_reserve_pub = i.reserve_pub
THEN
ruuid2 = i.reserve_uuid;
IF in2_reserve_pub
NOT IN (in_reserve_pub
,in3_reserve_pub
,in4_reserve_pub
,in5_reserve_pub
,in6_reserve_pub
,in7_reserve_pub
,in8_reserve_pub)
THEN
out_reserve_found2 = FALSE;
END IF;
END IF;
IF in3_reserve_pub = i.reserve_pub
THEN
ruuid3 = i.reserve_uuid;
IF in3_reserve_pub
NOT IN (in_reserve_pub
,in2_reserve_pub
,in4_reserve_pub
,in5_reserve_pub
,in6_reserve_pub
,in7_reserve_pub
,in8_reserve_pub)
THEN
out_reserve_found3 = FALSE;
END IF;
END IF;
IF in4_reserve_pub = i.reserve_pub
THEN
ruuid4 = i.reserve_uuid;
IF in4_reserve_pub
NOT IN (in_reserve_pub
,in2_reserve_pub
,in3_reserve_pub
,in5_reserve_pub
,in6_reserve_pub
,in7_reserve_pub
,in8_reserve_pub)
THEN
out_reserve_found4 = FALSE;
END IF;
END IF;
IF in5_reserve_pub = i.reserve_pub
THEN
ruuid5 = i.reserve_uuid;
IF in5_reserve_pub
NOT IN (in_reserve_pub
,in2_reserve_pub
,in3_reserve_pub
,in4_reserve_pub
,in6_reserve_pub
,in7_reserve_pub
,in8_reserve_pub)
THEN
out_reserve_found5 = FALSE;
END IF;
END IF;
IF in6_reserve_pub = i.reserve_pub
THEN
ruuid6 = i.reserve_uuid;
IF in6_reserve_pub
NOT IN (in_reserve_pub
,in2_reserve_pub
,in3_reserve_pub
,in4_reserve_pub
,in5_reserve_pub
,in7_reserve_pub
,in8_reserve_pub)
THEN
out_reserve_found6 = FALSE;
END IF;
END IF;
IF in7_reserve_pub = i.reserve_pub
THEN
ruuid7 = i.reserve_uuid;
IF in7_reserve_pub
NOT IN (in_reserve_pub
,in2_reserve_pub
,in3_reserve_pub
,in4_reserve_pub
,in5_reserve_pub
,in6_reserve_pub
,in8_reserve_pub)
THEN
out_reserve_found7 = FALSE;
END IF;
END IF;
IF in8_reserve_pub = i.reserve_pub
THEN
ruuid8 = i.reserve_uuid;
IF in8_reserve_pub
NOT IN (in_reserve_pub
,in2_reserve_pub
,in3_reserve_pub
,in4_reserve_pub
,in5_reserve_pub
,in6_reserve_pub
,in7_reserve_pub)
THEN
out_reserve_found8 = FALSE;
END IF;
END IF;
END IF;
k=k+1;
END LOOP;
CLOSE curs_reserve_existed;
-- FIXME: must be changed to EXECUTE FORMAT!
PERFORM pg_notify(in_notify, NULL);
PERFORM pg_notify(in2_notify, NULL);
PERFORM pg_notify(in3_notify, NULL);
PERFORM pg_notify(in4_notify, NULL);
PERFORM pg_notify(in5_notify, NULL);
PERFORM pg_notify(in6_notify, NULL);
PERFORM pg_notify(in7_notify, NULL);
PERFORM pg_notify(in8_notify, NULL);
k=0;
OPEN curs_transaction_existed FOR
WITH reserve_in_changes AS (
INSERT INTO reserves_in
(reserve_pub
,wire_reference
,credit_val
,credit_frac
,exchange_account_section
,wire_source_h_payto
,execution_date)
VALUES
(in_reserve_pub
,in_wire_ref
,in_credit_val
,in_credit_frac
,in_exchange_account_name
,in_wire_source_h_payto
,in_execution_date),
(in2_reserve_pub
,in2_wire_ref
,in2_credit_val
,in2_credit_frac
,in2_exchange_account_name
,in2_wire_source_h_payto
,in_execution_date),
(in3_reserve_pub
,in3_wire_ref
,in3_credit_val
,in3_credit_frac
,in3_exchange_account_name
,in3_wire_source_h_payto
,in_execution_date),
(in4_reserve_pub
,in4_wire_ref
,in4_credit_val
,in4_credit_frac
,in4_exchange_account_name
,in4_wire_source_h_payto
,in_execution_date),
(in5_reserve_pub
,in5_wire_ref
,in5_credit_val
,in5_credit_frac
,in5_exchange_account_name
,in5_wire_source_h_payto
,in_execution_date),
(in6_reserve_pub
,in6_wire_ref
,in6_credit_val
,in6_credit_frac
,in6_exchange_account_name
,in6_wire_source_h_payto
,in_execution_date),
(in7_reserve_pub
,in7_wire_ref
,in7_credit_val
,in7_credit_frac
,in7_exchange_account_name
,in7_wire_source_h_payto
,in_execution_date),
(in8_reserve_pub
,in8_wire_ref
,in8_credit_val
,in8_credit_frac
,in8_exchange_account_name
,in8_wire_source_h_payto
,in_execution_date)
ON CONFLICT DO NOTHING
RETURNING reserve_pub)
SELECT * FROM reserve_in_changes;
WHILE k < 8 LOOP
FETCH FROM curs_transaction_existed INTO r;
IF FOUND
THEN
IF in_reserve_pub = r.reserve_pub
THEN
transaction_duplicate = FALSE;
END IF;
IF in2_reserve_pub = r.reserve_pub
THEN
transaction_duplicate2 = FALSE;
END IF;
IF in3_reserve_pub = r.reserve_pub
THEN
transaction_duplicate3 = FALSE;
END IF;
IF in4_reserve_pub = r.reserve_pub
THEN
transaction_duplicate4 = FALSE;
END IF;
IF in5_reserve_pub = r.reserve_pub
THEN
transaction_duplicate5 = FALSE;
END IF;
IF in6_reserve_pub = r.reserve_pub
THEN
transaction_duplicate6 = FALSE;
END IF;
IF in7_reserve_pub = r.reserve_pub
THEN
transaction_duplicate7 = FALSE;
END IF;
IF in8_reserve_pub = r.reserve_pub
THEN
transaction_duplicate8 = FALSE;
END IF;
END IF;
k=k+1;
END LOOP;
/* IF transaction_duplicate
OR transaction_duplicate2
OR transaction_duplicate3
OR transaction_duplicate4
OR transaction_duplicate5
OR transaction_duplicate6
OR transaction_duplicate7
OR transaction_duplicate8
THEN
CLOSE curs_transaction_existed;
ROLLBACK;
RETURN;
END IF;*/
CLOSE curs_transaction_existed;
RETURN;
END $$;

View File

@ -0,0 +1,477 @@
--
-- This file is part of TALER
-- Copyright (C) 2014--2022 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/>
--
CREATE OR REPLACE FUNCTION exchange_do_batch4_known_coin(
IN in_coin_pub1 BYTEA,
IN in_denom_pub_hash1 BYTEA,
IN in_h_age_commitment1 BYTEA,
IN in_denom_sig1 BYTEA,
IN in_coin_pub2 BYTEA,
IN in_denom_pub_hash2 BYTEA,
IN in_h_age_commitment2 BYTEA,
IN in_denom_sig2 BYTEA,
IN in_coin_pub3 BYTEA,
IN in_denom_pub_hash3 BYTEA,
IN in_h_age_commitment3 BYTEA,
IN in_denom_sig3 BYTEA,
IN in_coin_pub4 BYTEA,
IN in_denom_pub_hash4 BYTEA,
IN in_h_age_commitment4 BYTEA,
IN in_denom_sig4 BYTEA,
OUT existed1 BOOLEAN,
OUT existed2 BOOLEAN,
OUT existed3 BOOLEAN,
OUT existed4 BOOLEAN,
OUT known_coin_id1 INT8,
OUT known_coin_id2 INT8,
OUT known_coin_id3 INT8,
OUT known_coin_id4 INT8,
OUT denom_pub_hash1 BYTEA,
OUT denom_pub_hash2 BYTEA,
OUT denom_pub_hash3 BYTEA,
OUT denom_pub_hash4 BYTEA,
OUT age_commitment_hash1 BYTEA,
OUT age_commitment_hash2 BYTEA,
OUT age_commitment_hash3 BYTEA,
OUT age_commitment_hash4 BYTEA)
LANGUAGE plpgsql
AS $$
BEGIN
WITH dd AS (
SELECT
denominations_serial,
coin_val, coin_frac
FROM denominations
WHERE denom_pub_hash
IN
(in_denom_pub_hash1,
in_denom_pub_hash2,
in_denom_pub_hash3,
in_denom_pub_hash4)
),--dd
input_rows AS (
VALUES
(in_coin_pub1,
in_denom_pub_hash1,
in_h_age_commitment1,
in_denom_sig1),
(in_coin_pub2,
in_denom_pub_hash2,
in_h_age_commitment2,
in_denom_sig2),
(in_coin_pub3,
in_denom_pub_hash3,
in_h_age_commitment3,
in_denom_sig3),
(in_coin_pub4,
in_denom_pub_hash4,
in_h_age_commitment4,
in_denom_sig4)
),--ir
ins AS (
INSERT INTO known_coins (
coin_pub,
denominations_serial,
age_commitment_hash,
denom_sig,
remaining_val,
remaining_frac
)
SELECT
ir.coin_pub,
dd.denominations_serial,
ir.age_commitment_hash,
ir.denom_sig,
dd.coin_val,
dd.coin_frac
FROM input_rows ir
JOIN dd
ON dd.denom_pub_hash = ir.denom_pub_hash
ON CONFLICT DO NOTHING
RETURNING known_coin_id
),--kc
exists AS (
SELECT
CASE
WHEN
ins.known_coin_id IS NOT NULL
THEN
FALSE
ELSE
TRUE
END AS existed,
ins.known_coin_id,
dd.denom_pub_hash,
kc.age_commitment_hash
FROM input_rows ir
LEFT JOIN ins
ON ins.coin_pub = ir.coin_pub
LEFT JOIN known_coins kc
ON kc.coin_pub = ir.coin_pub
LEFT JOIN dd
ON dd.denom_pub_hash = ir.denom_pub_hash
)--exists
SELECT
exists.existed AS existed1,
exists.known_coin_id AS known_coin_id1,
exists.denom_pub_hash AS denom_pub_hash1,
exists.age_commitment_hash AS age_commitment_hash1,
(
SELECT exists.existed
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash2
) AS existed2,
(
SELECT exists.known_coin_id
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash2
) AS known_coin_id2,
(
SELECT exists.denom_pub_hash
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash2
) AS denom_pub_hash2,
(
SELECT exists.age_commitment_hash
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash2
)AS age_commitment_hash2,
(
SELECT exists.existed
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash3
) AS existed3,
(
SELECT exists.known_coin_id
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash3
) AS known_coin_id3,
(
SELECT exists.denom_pub_hash
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash3
) AS denom_pub_hash3,
(
SELECT exists.age_commitment_hash
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash3
)AS age_commitment_hash3,
(
SELECT exists.existed
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash4
) AS existed4,
(
SELECT exists.known_coin_id
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash4
) AS known_coin_id4,
(
SELECT exists.denom_pub_hash
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash4
) AS denom_pub_hash4,
(
SELECT exists.age_commitment_hash
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash4
)AS age_commitment_hash4
FROM exists;
RETURN;
END $$;
CREATE OR REPLACE FUNCTION exchange_do_batch2_known_coin(
IN in_coin_pub1 BYTEA,
IN in_denom_pub_hash1 BYTEA,
IN in_h_age_commitment1 BYTEA,
IN in_denom_sig1 BYTEA,
IN in_coin_pub2 BYTEA,
IN in_denom_pub_hash2 BYTEA,
IN in_h_age_commitment2 BYTEA,
IN in_denom_sig2 BYTEA,
OUT existed1 BOOLEAN,
OUT existed2 BOOLEAN,
OUT known_coin_id1 INT8,
OUT known_coin_id2 INT8,
OUT denom_pub_hash1 BYTEA,
OUT denom_pub_hash2 BYTEA,
OUT age_commitment_hash1 BYTEA,
OUT age_commitment_hash2 BYTEA)
LANGUAGE plpgsql
AS $$
BEGIN
WITH dd AS (
SELECT
denominations_serial,
coin_val, coin_frac
FROM denominations
WHERE denom_pub_hash
IN
(in_denom_pub_hash1,
in_denom_pub_hash2)
),--dd
input_rows AS (
VALUES
(in_coin_pub1,
in_denom_pub_hash1,
in_h_age_commitment1,
in_denom_sig1),
(in_coin_pub2,
in_denom_pub_hash2,
in_h_age_commitment2,
in_denom_sig2)
),--ir
ins AS (
INSERT INTO known_coins (
coin_pub,
denominations_serial,
age_commitment_hash,
denom_sig,
remaining_val,
remaining_frac
)
SELECT
ir.coin_pub,
dd.denominations_serial,
ir.age_commitment_hash,
ir.denom_sig,
dd.coin_val,
dd.coin_frac
FROM input_rows ir
JOIN dd
ON dd.denom_pub_hash = ir.denom_pub_hash
ON CONFLICT DO NOTHING
RETURNING known_coin_id
),--kc
exists AS (
SELECT
CASE
WHEN ins.known_coin_id IS NOT NULL
THEN
FALSE
ELSE
TRUE
END AS existed,
ins.known_coin_id,
dd.denom_pub_hash,
kc.age_commitment_hash
FROM input_rows ir
LEFT JOIN ins
ON ins.coin_pub = ir.coin_pub
LEFT JOIN known_coins kc
ON kc.coin_pub = ir.coin_pub
LEFT JOIN dd
ON dd.denom_pub_hash = ir.denom_pub_hash
)--exists
SELECT
exists.existed AS existed1,
exists.known_coin_id AS known_coin_id1,
exists.denom_pub_hash AS denom_pub_hash1,
exists.age_commitment_hash AS age_commitment_hash1,
(
SELECT exists.existed
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash2
) AS existed2,
(
SELECT exists.known_coin_id
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash2
) AS known_coin_id2,
(
SELECT exists.denom_pub_hash
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash2
) AS denom_pub_hash2,
(
SELECT exists.age_commitment_hash
FROM exists
WHERE exists.denom_pub_hash = in_denom_pub_hash2
)AS age_commitment_hash2
FROM exists;
RETURN;
END $$;
CREATE OR REPLACE FUNCTION exchange_do_batch1_known_coin(
IN in_coin_pub1 BYTEA,
IN in_denom_pub_hash1 BYTEA,
IN in_h_age_commitment1 BYTEA,
IN in_denom_sig1 BYTEA,
OUT existed1 BOOLEAN,
OUT known_coin_id1 INT8,
OUT denom_pub_hash1 BYTEA,
OUT age_commitment_hash1 BYTEA)
LANGUAGE plpgsql
AS $$
BEGIN
WITH dd AS (
SELECT
denominations_serial,
coin_val, coin_frac
FROM denominations
WHERE denom_pub_hash
IN
(in_denom_pub_hash1,
in_denom_pub_hash2)
),--dd
input_rows AS (
VALUES
(in_coin_pub1,
in_denom_pub_hash1,
in_h_age_commitment1,
in_denom_sig1)
),--ir
ins AS (
INSERT INTO known_coins (
coin_pub,
denominations_serial,
age_commitment_hash,
denom_sig,
remaining_val,
remaining_frac
)
SELECT
ir.coin_pub,
dd.denominations_serial,
ir.age_commitment_hash,
ir.denom_sig,
dd.coin_val,
dd.coin_frac
FROM input_rows ir
JOIN dd
ON dd.denom_pub_hash = ir.denom_pub_hash
ON CONFLICT DO NOTHING
RETURNING known_coin_id
),--kc
exists AS (
SELECT
CASE
WHEN ins.known_coin_id IS NOT NULL
THEN
FALSE
ELSE
TRUE
END AS existed,
ins.known_coin_id,
dd.denom_pub_hash,
kc.age_commitment_hash
FROM input_rows ir
LEFT JOIN ins
ON ins.coin_pub = ir.coin_pub
LEFT JOIN known_coins kc
ON kc.coin_pub = ir.coin_pub
LEFT JOIN dd
ON dd.denom_pub_hash = ir.denom_pub_hash
)--exists
SELECT
exists.existed AS existed1,
exists.known_coin_id AS known_coin_id1,
exists.denom_pub_hash AS denom_pub_hash1,
exists.age_commitment_hash AS age_commitment_hash1
FROM exists;
RETURN;
END $$;
/*** Experiment using a loop ***/
/*
CREATE OR REPLACE FUNCTION exchange_do_batch2_known_coin(
IN in_coin_pub1 BYTEA,
IN in_denom_pub_hash1 TEXT,
IN in_h_age_commitment1 TEXT,
IN in_denom_sig1 TEXT,
IN in_coin_pub2 BYTEA,
IN in_denom_pub_hash2 TEXT,
IN in_h_age_commitment2 TEXT,
IN in_denom_sig2 TEXT,
OUT existed1 BOOLEAN,
OUT existed2 BOOLEAN,
OUT known_coin_id1 INT8,
OUT known_coin_id2 INT8,
OUT denom_pub_hash1 TEXT,
OUT denom_pub_hash2 TEXT,
OUT age_commitment_hash1 TEXT,
OUT age_commitment_hash2 TEXT)
LANGUAGE plpgsql
AS $$
DECLARE
ins_values RECORD;
BEGIN
FOR i IN 1..2 LOOP
ins_values := (
SELECT
in_coin_pub1 AS coin_pub,
in_denom_pub_hash1 AS denom_pub_hash,
in_h_age_commitment1 AS age_commitment_hash,
in_denom_sig1 AS denom_sig
WHERE i = 1
UNION
SELECT
in_coin_pub2 AS coin_pub,
in_denom_pub_hash2 AS denom_pub_hash,
in_h_age_commitment2 AS age_commitment_hash,
in_denom_sig2 AS denom_sig
WHERE i = 2
);
WITH dd (denominations_serial, coin_val, coin_frac) AS (
SELECT denominations_serial, coin_val, coin_frac
FROM denominations
WHERE denom_pub_hash = ins_values.denom_pub_hash
),
input_rows(coin_pub) AS (
VALUES (ins_values.coin_pub)
),
ins AS (
INSERT INTO known_coins (
coin_pub,
denominations_serial,
age_commitment_hash,
denom_sig,
remaining_val,
remaining_frac
) SELECT
input_rows.coin_pub,
dd.denominations_serial,
ins_values.age_commitment_hash,
ins_values.denom_sig,
coin_val,
coin_frac
FROM dd
CROSS JOIN input_rows
ON CONFLICT DO NOTHING
RETURNING known_coin_id, denom_pub_hash
)
SELECT
CASE i
WHEN 1 THEN
COALESCE(ins.known_coin_id, 0) <> 0 AS existed1,
ins.known_coin_id AS known_coin_id1,
ins.denom_pub_hash AS denom_pub_hash1,
ins.age_commitment_hash AS age_commitment_hash1
WHEN 2 THEN
COALESCE(ins.known_coin_id, 0) <> 0 AS existed2,
ins.known_coin_id AS known_coin_id2,
ins.denom_pub_hash AS denom_pub_hash2,
ins.age_commitment_hash AS age_commitment_hash2
END
FROM ins;
END LOOP;
END;
$$;*/

View File

@ -1,120 +0,0 @@
--
-- This file is part of TALER
-- Copyright (C) 2014--2022 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/>
--
DROP FUNCTION IF EXISTS exchange_do_batch_reserves_in_insert;
CREATE OR REPLACE FUNCTION exchange_do_batch_reserves_in_insert(
IN in_reserve_pub BYTEA,
IN in_expiration_date INT8,
IN in_gc_date INT8,
IN in_wire_ref INT8,
IN in_credit_val INT8,
IN in_credit_frac INT4,
IN in_exchange_account_name VARCHAR,
IN in_execution_date INT8,
IN in_wire_source_h_payto BYTEA, ---h_payto
IN in_payto_uri VARCHAR,
IN in_reserve_expiration INT8,
IN in_notify text,
OUT out_reserve_found BOOLEAN,
OUT transaction_duplicate BOOLEAN,
OUT ruuid INT8)
LANGUAGE plpgsql
AS $$
DECLARE
curs refcursor;
DECLARE
i RECORD;
DECLARE
curs_trans refcursor;
BEGIN
ruuid = 0;
out_reserve_found = TRUE;
transaction_duplicate = TRUE;
--SIMPLE INSERT ON CONFLICT DO NOTHING
INSERT INTO wire_targets
(wire_target_h_payto
,payto_uri)
VALUES
(in_wire_source_h_payto
,in_payto_uri)
ON CONFLICT DO NOTHING;
OPEN curs FOR
WITH reserve_changes AS (
INSERT INTO reserves
(reserve_pub
,current_balance_val
,current_balance_frac
,expiration_date
,gc_date)
VALUES
(in_reserve_pub
,in_credit_val
,in_credit_frac
,in_expiration_date
,in_gc_date)
ON CONFLICT DO NOTHING
RETURNING reserve_uuid, reserve_pub)
SELECT * FROM reserve_changes;
FETCH FROM curs INTO i;
IF FOUND
THEN
-- We made a change, so the reserve did not previously exist.
IF in_reserve_pub = i.reserve_pub
THEN
out_reserve_found = FALSE;
ruuid = i.reserve_uuid;
END IF;
END IF;
CLOSE curs;
OPEN curs_trans FOR
WITH reserve_transaction AS(
INSERT INTO reserves_in
(reserve_pub
,wire_reference
,credit_val
,credit_frac
,exchange_account_section
,wire_source_h_payto
,execution_date)
VALUES
(in_reserve_pub
,in_wire_ref
,in_credit_val
,in_credit_frac
,in_exchange_account_name
,in_wire_source_h_payto
,in_execution_date)
ON CONFLICT DO NOTHING
RETURNING reserve_pub)
SELECT * FROM reserve_transaction;
FETCH FROM curs_trans INTO i;
IF FOUND
THEN
IF i.reserve_pub = in_reserve_pub
THEN
-- HAPPY PATH THERE IS NO DUPLICATE TRANS
transaction_duplicate = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in_notify);
END IF;
END IF;
CLOSE curs_trans;
RETURN;
END $$;

View File

@ -123,6 +123,7 @@ THEN
-- Deposit exists, but with differences. Not allowed. -- Deposit exists, but with differences. Not allowed.
out_balance_ok=FALSE; out_balance_ok=FALSE;
out_conflict=TRUE; out_conflict=TRUE;
out_exchange_timestamp=0;
RETURN; RETURN;
END IF; END IF;

View File

@ -0,0 +1,965 @@
--
-- This file is part of TALER
-- Copyright (C) 2014--2023 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/>
--
CREATE OR REPLACE FUNCTION exchange_do_batch_reserves_in_insert(
IN in_gc_date INT8,
IN in_reserve_expiration INT8,
IN in_reserve_pub BYTEA,
IN in_wire_ref INT8,
IN in_credit_val INT8,
IN in_credit_frac INT4,
IN in_exchange_account_name VARCHAR,
IN in_execution_date INT8,
IN in_wire_source_h_payto BYTEA,
IN in_payto_uri VARCHAR,
IN in_notify TEXT,
OUT transaction_duplicate0 BOOLEAN,
OUT ruuid0 INT8)
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO wire_targets
(wire_target_h_payto
,payto_uri)
VALUES
(in_wire_source_h_payto
,in_payto_uri)
ON CONFLICT DO NOTHING;
INSERT INTO reserves
(reserve_pub
,current_balance_val
,current_balance_frac
,expiration_date
,gc_date)
VALUES
(in_reserve_pub
,in_credit_val
,in_credit_frac
,in_reserve_expiration
,in_gc_date)
ON CONFLICT DO NOTHING
RETURNING reserve_uuid
INTO ruuid0;
INSERT INTO reserves_in
(reserve_pub
,wire_reference
,credit_val
,credit_frac
,exchange_account_section
,wire_source_h_payto
,execution_date)
VALUES
(in_reserve_pub
,in_wire_ref
,in_credit_val
,in_credit_frac
,in_exchange_account_name
,in_wire_source_h_payto
,in_execution_date)
ON CONFLICT DO NOTHING;
transaction_duplicate0 = NOT FOUND;
IF FOUND
THEN
EXECUTE FORMAT (
'NOTIFY %s'
,in_notify);
END IF;
RETURN;
END $$;
CREATE OR REPLACE FUNCTION exchange_do_batch2_reserves_insert(
IN in_gc_date INT8,
IN in_reserve_expiration INT8,
IN in0_reserve_pub BYTEA,
IN in0_wire_ref INT8,
IN in0_credit_val INT8,
IN in0_credit_frac INT4,
IN in0_exchange_account_name VARCHAR,
IN in0_execution_date INT8,
IN in0_wire_source_h_payto BYTEA,
IN in0_payto_uri VARCHAR,
IN in0_notify TEXT,
IN in1_reserve_pub BYTEA,
IN in1_wire_ref INT8,
IN in1_credit_val INT8,
IN in1_credit_frac INT4,
IN in1_exchange_account_name VARCHAR,
IN in1_execution_date INT8,
IN in1_wire_source_h_payto BYTEA,
IN in1_payto_uri VARCHAR,
IN in1_notify TEXT,
OUT transaction_duplicate0 BOOLEAN,
OUT transaction_duplicate1 BOOLEAN,
OUT ruuid0 INT8,
OUT ruuid1 INT8)
LANGUAGE plpgsql
AS $$
DECLARE
curs_reserve_exist REFCURSOR;
DECLARE
k INT8;
DECLARE
curs_transaction_exist REFCURSOR;
DECLARE
i RECORD;
BEGIN
transaction_duplicate0 = TRUE;
transaction_duplicate1 = TRUE;
INSERT INTO wire_targets
(wire_target_h_payto
,payto_uri)
VALUES
(in0_wire_source_h_payto
,in0_payto_uri),
(in1_wire_source_h_payto
,in1_payto_uri)
ON CONFLICT DO NOTHING;
OPEN curs_reserve_exist FOR
WITH reserve_changes AS (
INSERT INTO reserves
(reserve_pub
,current_balance_val
,current_balance_frac
,expiration_date
,gc_date)
VALUES
(in0_reserve_pub
,in0_credit_val
,in0_credit_frac
,in_reserve_expiration
,in_gc_date),
(in1_reserve_pub
,in1_credit_val
,in1_credit_frac
,in_reserve_expiration
,in_gc_date)
ON CONFLICT DO NOTHING
RETURNING reserve_uuid, reserve_pub)
SELECT reserve_uuid, reserve_pub FROM reserve_changes;
k=0;
<<loop_reserve>> LOOP
FETCH FROM curs_reserve_exist INTO i;
IF NOT FOUND
THEN
EXIT loop_reserve;
END IF;
<<loop_k>> LOOP
CASE k
WHEN 0 THEN
k = k + 1;
IF in0_reserve_pub = i.reserve_pub
THEN
ruuid0 = i.reserve_uuid;
CONTINUE loop_reserve;
END IF;
CONTINUE loop_k;
WHEN 1 THEN
IF in1_reserve_pub = i.reserve_pub
THEN
ruuid1 = i.reserve_uuid;
END IF;
EXIT loop_reserve;
END CASE;
END LOOP loop_k;
END LOOP loop_reserve;
CLOSE curs_reserve_exist;
OPEN curs_transaction_exist FOR
WITH reserve_transaction AS (
INSERT INTO reserves_in
(reserve_pub
,wire_reference
,credit_val
,credit_frac
,exchange_account_section
,wire_source_h_payto
,execution_date)
VALUES
(in0_reserve_pub
,in0_wire_ref
,in0_credit_val
,in0_credit_frac
,in0_exchange_account_name
,in0_wire_source_h_payto
,in0_execution_date),
(in1_reserve_pub
,in1_wire_ref
,in1_credit_val
,in1_credit_frac
,in1_exchange_account_name
,in1_wire_source_h_payto
,in1_execution_date)
ON CONFLICT DO NOTHING
RETURNING reserve_pub)
SELECT reserve_pub FROM reserve_transaction;
k=0;
<<loop_transaction>> LOOP
FETCH FROM curs_transaction_exist INTO i;
IF NOT FOUND
THEN
EXIT loop_transaction;
END IF;
<<loop2_k>> LOOP
CASE k
WHEN 0 THEN
k = k + 1;
IF in0_reserve_pub = i.reserve_pub
THEN
transaction_duplicate0 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in0_notify);
CONTINUE loop_transaction;
END IF;
CONTINUE loop2_k;
WHEN 1 THEN
IF in1_reserve_pub = i.reserve_pub
THEN
transaction_duplicate1 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in1_notify);
END IF;
EXIT loop_transaction;
END CASE;
END LOOP loop2_k;
END LOOP loop_transaction;
CLOSE curs_transaction_exist;
RETURN;
END $$;
CREATE OR REPLACE FUNCTION exchange_do_batch4_reserves_insert(
IN in_gc_date INT8,
IN in_reserve_expiration INT8,
IN in0_reserve_pub BYTEA,
IN in0_wire_ref INT8,
IN in0_credit_val INT8,
IN in0_credit_frac INT4,
IN in0_exchange_account_name VARCHAR,
IN in0_execution_date INT8,
IN in0_wire_source_h_payto BYTEA,
IN in0_payto_uri VARCHAR,
IN in0_notify TEXT,
IN in1_reserve_pub BYTEA,
IN in1_wire_ref INT8,
IN in1_credit_val INT8,
IN in1_credit_frac INT4,
IN in1_exchange_account_name VARCHAR,
IN in1_execution_date INT8,
IN in1_wire_source_h_payto BYTEA,
IN in1_payto_uri VARCHAR,
IN in1_notify TEXT,
IN in2_reserve_pub BYTEA,
IN in2_wire_ref INT8,
IN in2_credit_val INT8,
IN in2_credit_frac INT4,
IN in2_exchange_account_name VARCHAR,
IN in2_execution_date INT8,
IN in2_wire_source_h_payto BYTEA,
IN in2_payto_uri VARCHAR,
IN in2_notify TEXT,
IN in3_reserve_pub BYTEA,
IN in3_wire_ref INT8,
IN in3_credit_val INT8,
IN in3_credit_frac INT4,
IN in3_exchange_account_name VARCHAR,
IN in3_execution_date INT8,
IN in3_wire_source_h_payto BYTEA,
IN in3_payto_uri VARCHAR,
IN in3_notify TEXT,
OUT transaction_duplicate0 BOOLEAN,
OUT transaction_duplicate1 BOOLEAN,
OUT transaction_duplicate2 BOOLEAN,
OUT transaction_duplicate3 BOOLEAN,
OUT ruuid0 INT8,
OUT ruuid1 INT8,
OUT ruuid2 INT8,
OUT ruuid3 INT8)
LANGUAGE plpgsql
AS $$
DECLARE
curs_reserve_exist REFCURSOR;
DECLARE
k INT8;
DECLARE
curs_transaction_exist REFCURSOR;
DECLARE
i RECORD;
BEGIN
transaction_duplicate0=TRUE;
transaction_duplicate1=TRUE;
transaction_duplicate2=TRUE;
transaction_duplicate3=TRUE;
INSERT INTO wire_targets
(wire_target_h_payto
,payto_uri)
VALUES
(in0_wire_source_h_payto
,in0_payto_uri),
(in1_wire_source_h_payto
,in1_payto_uri),
(in2_wire_source_h_payto
,in2_payto_uri),
(in3_wire_source_h_payto
,in3_payto_uri)
ON CONFLICT DO NOTHING;
OPEN curs_reserve_exist FOR
WITH reserve_changes AS (
INSERT INTO reserves
(reserve_pub
,current_balance_val
,current_balance_frac
,expiration_date
,gc_date)
VALUES
(in0_reserve_pub
,in0_credit_val
,in0_credit_frac
,in_reserve_expiration
,in_gc_date),
(in1_reserve_pub
,in1_credit_val
,in1_credit_frac
,in_reserve_expiration
,in_gc_date),
(in2_reserve_pub
,in2_credit_val
,in2_credit_frac
,in_reserve_expiration
,in_gc_date),
(in3_reserve_pub
,in3_credit_val
,in3_credit_frac
,in_reserve_expiration
,in_gc_date)
ON CONFLICT DO NOTHING
RETURNING reserve_uuid,reserve_pub)
SELECT reserve_uuid, reserve_pub FROM reserve_changes;
k=0;
<<loop_reserve>> LOOP
FETCH FROM curs_reserve_exist INTO i;
IF NOT FOUND
THEN
EXIT loop_reserve;
END IF;
<<loop_k>> LOOP
CASE k
WHEN 0 THEN
k = k + 1;
IF in0_reserve_pub = i.reserve_pub
THEN
ruuid0 = i.reserve_uuid;
CONTINUE loop_reserve;
END IF;
CONTINUE loop_k;
WHEN 1 THEN
k = k + 1;
IF in1_reserve_pub = i.reserve_pub
THEN
ruuid1 = i.reserve_uuid;
CONTINUE loop_reserve;
END IF;
CONTINUE loop_k;
WHEN 2 THEN
k = k + 1;
IF in2_reserve_pub = i.reserve_pub
THEN
ruuid2 = i.reserve_uuid;
CONTINUE loop_reserve;
END IF;
CONTINUE loop_k;
WHEN 3 THEN
IF in3_reserve_pub = i.reserve_pub
THEN
ruuid3 = i.reserve_uuid;
END IF;
EXIT loop_reserve;
END CASE;
END LOOP loop_k;
END LOOP loop_reserve;
CLOSE curs_reserve_exist;
OPEN curs_transaction_exist FOR
WITH reserve_transaction AS (
INSERT INTO reserves_in
(reserve_pub
,wire_reference
,credit_val
,credit_frac
,exchange_account_section
,wire_source_h_payto
,execution_date)
VALUES
(in0_reserve_pub
,in0_wire_ref
,in0_credit_val
,in0_credit_frac
,in0_exchange_account_name
,in0_wire_source_h_payto
,in0_execution_date),
(in1_reserve_pub
,in1_wire_ref
,in1_credit_val
,in1_credit_frac
,in1_exchange_account_name
,in1_wire_source_h_payto
,in1_execution_date),
(in2_reserve_pub
,in2_wire_ref
,in2_credit_val
,in2_credit_frac
,in2_exchange_account_name
,in2_wire_source_h_payto
,in2_execution_date),
(in3_reserve_pub
,in3_wire_ref
,in3_credit_val
,in3_credit_frac
,in3_exchange_account_name
,in3_wire_source_h_payto
,in3_execution_date)
ON CONFLICT DO NOTHING
RETURNING reserve_pub)
SELECT reserve_pub FROM reserve_transaction;
k=0;
<<loop_transaction>> LOOP
FETCH FROM curs_transaction_exist INTO i;
IF NOT FOUND
THEN
EXIT loop_transaction;
END IF;
<<loop2_k>> LOOP
CASE k
WHEN 0 THEN
k = k + 1;
IF in0_reserve_pub = i.reserve_pub
THEN
transaction_duplicate0 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in0_notify);
CONTINUE loop_transaction;
END IF;
CONTINUE loop2_k;
WHEN 1 THEN
k = k + 1;
IF in1_reserve_pub = i.reserve_pub
THEN
transaction_duplicate1 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in1_notify);
CONTINUE loop_transaction;
END IF;
CONTINUE loop2_k;
WHEN 2 THEN
k = k + 1;
IF in2_reserve_pub = i.reserve_pub
THEN
transaction_duplicate2 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in2_notify);
CONTINUE loop_transaction;
END IF;
CONTINUE loop2_k;
WHEN 3 THEN
IF in3_reserve_pub = i.reserve_pub
THEN
transaction_duplicate3 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in3_notify);
END IF;
EXIT loop_transaction;
END CASE;
END LOOP loop2_k;
END LOOP loop_transaction;
CLOSE curs_transaction_exist;
RETURN;
END $$;
CREATE OR REPLACE FUNCTION exchange_do_batch8_reserves_insert(
IN in_gc_date INT8,
IN in_reserve_expiration INT8,
IN in0_reserve_pub BYTEA,
IN in0_wire_ref INT8,
IN in0_credit_val INT8,
IN in0_credit_frac INT4,
IN in0_exchange_account_name VARCHAR,
IN in0_execution_date INT8,
IN in0_wire_source_h_payto BYTEA,
IN in0_payto_uri VARCHAR,
IN in0_notify TEXT,
IN in1_reserve_pub BYTEA,
IN in1_wire_ref INT8,
IN in1_credit_val INT8,
IN in1_credit_frac INT4,
IN in1_exchange_account_name VARCHAR,
IN in1_execution_date INT8,
IN in1_wire_source_h_payto BYTEA,
IN in1_payto_uri VARCHAR,
IN in1_notify TEXT,
IN in2_reserve_pub BYTEA,
IN in2_wire_ref INT8,
IN in2_credit_val INT8,
IN in2_credit_frac INT4,
IN in2_exchange_account_name VARCHAR,
IN in2_execution_date INT8,
IN in2_wire_source_h_payto BYTEA,
IN in2_payto_uri VARCHAR,
IN in2_notify TEXT,
IN in3_reserve_pub BYTEA,
IN in3_wire_ref INT8,
IN in3_credit_val INT8,
IN in3_credit_frac INT4,
IN in3_exchange_account_name VARCHAR,
IN in3_execution_date INT8,
IN in3_wire_source_h_payto BYTEA,
IN in3_payto_uri VARCHAR,
IN in3_notify TEXT,
IN in4_reserve_pub BYTEA,
IN in4_wire_ref INT8,
IN in4_credit_val INT8,
IN in4_credit_frac INT4,
IN in4_exchange_account_name VARCHAR,
IN in4_execution_date INT8,
IN in4_wire_source_h_payto BYTEA,
IN in4_payto_uri VARCHAR,
IN in4_notify TEXT,
IN in5_reserve_pub BYTEA,
IN in5_wire_ref INT8,
IN in5_credit_val INT8,
IN in5_credit_frac INT4,
IN in5_exchange_account_name VARCHAR,
IN in5_execution_date INT8,
IN in5_wire_source_h_payto BYTEA,
IN in5_payto_uri VARCHAR,
IN in5_notify TEXT,
IN in6_reserve_pub BYTEA,
IN in6_wire_ref INT8,
IN in6_credit_val INT8,
IN in6_credit_frac INT4,
IN in6_exchange_account_name VARCHAR,
IN in6_execution_date INT8,
IN in6_wire_source_h_payto BYTEA,
IN in6_payto_uri VARCHAR,
IN in6_notify TEXT,
IN in7_reserve_pub BYTEA,
IN in7_wire_ref INT8,
IN in7_credit_val INT8,
IN in7_credit_frac INT4,
IN in7_exchange_account_name VARCHAR,
IN in7_execution_date INT8,
IN in7_wire_source_h_payto BYTEA,
IN in7_payto_uri VARCHAR,
IN in7_notify TEXT,
OUT transaction_duplicate0 BOOLEAN,
OUT transaction_duplicate1 BOOLEAN,
OUT transaction_duplicate2 BOOLEAN,
OUT transaction_duplicate3 BOOLEAN,
OUT transaction_duplicate4 BOOLEAN,
OUT transaction_duplicate5 BOOLEAN,
OUT transaction_duplicate6 BOOLEAN,
OUT transaction_duplicate7 BOOLEAN,
OUT ruuid0 INT8,
OUT ruuid1 INT8,
OUT ruuid2 INT8,
OUT ruuid3 INT8,
OUT ruuid4 INT8,
OUT ruuid5 INT8,
OUT ruuid6 INT8,
OUT ruuid7 INT8)
LANGUAGE plpgsql
AS $$
DECLARE
curs_reserve_exist REFCURSOR;
DECLARE
k INT8;
DECLARE
curs_transaction_exist REFCURSOR;
DECLARE
i RECORD;
DECLARE
r RECORD;
BEGIN
transaction_duplicate0=TRUE;
transaction_duplicate1=TRUE;
transaction_duplicate2=TRUE;
transaction_duplicate3=TRUE;
transaction_duplicate4=TRUE;
transaction_duplicate5=TRUE;
transaction_duplicate6=TRUE;
transaction_duplicate7=TRUE;
INSERT INTO wire_targets
(wire_target_h_payto
,payto_uri)
VALUES
(in0_wire_source_h_payto
,in0_payto_uri),
(in1_wire_source_h_payto
,in1_payto_uri),
(in2_wire_source_h_payto
,in2_payto_uri),
(in3_wire_source_h_payto
,in3_payto_uri),
(in4_wire_source_h_payto
,in4_payto_uri),
(in5_wire_source_h_payto
,in5_payto_uri),
(in6_wire_source_h_payto
,in6_payto_uri),
(in7_wire_source_h_payto
,in7_payto_uri)
ON CONFLICT DO NOTHING;
OPEN curs_reserve_exist FOR
WITH reserve_changes AS (
INSERT INTO reserves
(reserve_pub
,current_balance_val
,current_balance_frac
,expiration_date
,gc_date)
VALUES
(in0_reserve_pub
,in0_credit_val
,in0_credit_frac
,in_reserve_expiration
,in_gc_date),
(in1_reserve_pub
,in1_credit_val
,in1_credit_frac
,in_reserve_expiration
,in_gc_date),
(in2_reserve_pub
,in2_credit_val
,in2_credit_frac
,in_reserve_expiration
,in_gc_date),
(in3_reserve_pub
,in3_credit_val
,in3_credit_frac
,in_reserve_expiration
,in_gc_date),
(in4_reserve_pub
,in4_credit_val
,in4_credit_frac
,in_reserve_expiration
,in_gc_date),
(in5_reserve_pub
,in5_credit_val
,in5_credit_frac
,in_reserve_expiration
,in_gc_date),
(in6_reserve_pub
,in6_credit_val
,in6_credit_frac
,in_reserve_expiration
,in_gc_date),
(in7_reserve_pub
,in7_credit_val
,in7_credit_frac
,in_reserve_expiration
,in_gc_date)
ON CONFLICT DO NOTHING
RETURNING
reserve_uuid
,reserve_pub)
SELECT
reserve_uuid
,reserve_pub
FROM reserve_changes;
k=0;
<<loop_reserve>> LOOP
FETCH FROM curs_reserve_exist INTO i;
IF NOT FOUND
THEN
EXIT loop_reserve;
END IF;
<<loop_k>> LOOP
CASE k
WHEN 0 THEN
k = k + 1;
IF in0_reserve_pub = i.reserve_pub
THEN
ruuid0 = i.reserve_uuid;
CONTINUE loop_reserve;
END IF;
CONTINUE loop_k;
WHEN 1 THEN
k = k + 1;
IF in1_reserve_pub = i.reserve_pub
THEN
ruuid1 = i.reserve_uuid;
CONTINUE loop_reserve;
END IF;
CONTINUE loop_k;
WHEN 2 THEN
k = k + 1;
IF in2_reserve_pub = i.reserve_pub
THEN
ruuid2 = i.reserve_uuid;
CONTINUE loop_reserve;
END IF;
CONTINUE loop_k;
WHEN 3 THEN
k = k + 1;
IF in3_reserve_pub = i.reserve_pub
THEN
ruuid3 = i.reserve_uuid;
CONTINUE loop_reserve;
END IF;
CONTINUE loop_k;
WHEN 4 THEN
k = k + 1;
IF in4_reserve_pub = i.reserve_pub
THEN
ruuid4 = i.reserve_uuid;
CONTINUE loop_reserve;
END IF;
CONTINUE loop_k;
WHEN 5 THEN
k = k + 1;
IF in5_reserve_pub = i.reserve_pub
THEN
ruuid5 = i.reserve_uuid;
CONTINUE loop_reserve;
END IF;
CONTINUE loop_k;
WHEN 6 THEN
k = k + 1;
IF in6_reserve_pub = i.reserve_pub
THEN
ruuid6 = i.reserve_uuid;
CONTINUE loop_reserve;
END IF;
CONTINUE loop_k;
WHEN 7 THEN
IF in7_reserve_pub = i.reserve_pub
THEN
ruuid7 = i.reserve_uuid;
END IF;
EXIT loop_reserve;
END CASE;
END LOOP loop_k;
END LOOP loop_reserve;
CLOSE curs_reserve_exist;
OPEN curs_transaction_exist FOR
WITH reserve_transaction AS (
INSERT INTO reserves_in
(reserve_pub
,wire_reference
,credit_val
,credit_frac
,exchange_account_section
,wire_source_h_payto
,execution_date)
VALUES
(in0_reserve_pub
,in0_wire_ref
,in0_credit_val
,in0_credit_frac
,in0_exchange_account_name
,in0_wire_source_h_payto
,in0_execution_date),
(in1_reserve_pub
,in1_wire_ref
,in1_credit_val
,in1_credit_frac
,in1_exchange_account_name
,in1_wire_source_h_payto
,in1_execution_date),
(in2_reserve_pub
,in2_wire_ref
,in2_credit_val
,in2_credit_frac
,in2_exchange_account_name
,in2_wire_source_h_payto
,in2_execution_date),
(in3_reserve_pub
,in3_wire_ref
,in3_credit_val
,in3_credit_frac
,in3_exchange_account_name
,in3_wire_source_h_payto
,in3_execution_date),
(in4_reserve_pub
,in4_wire_ref
,in4_credit_val
,in4_credit_frac
,in4_exchange_account_name
,in4_wire_source_h_payto
,in4_execution_date),
(in5_reserve_pub
,in5_wire_ref
,in5_credit_val
,in5_credit_frac
,in5_exchange_account_name
,in5_wire_source_h_payto
,in5_execution_date),
(in6_reserve_pub
,in6_wire_ref
,in6_credit_val
,in6_credit_frac
,in6_exchange_account_name
,in6_wire_source_h_payto
,in6_execution_date),
(in7_reserve_pub
,in7_wire_ref
,in7_credit_val
,in7_credit_frac
,in7_exchange_account_name
,in7_wire_source_h_payto
,in7_execution_date)
ON CONFLICT DO NOTHING
RETURNING reserve_pub)
SELECT reserve_pub FROM reserve_transaction;
k=0;
<<loop_transaction>> LOOP
FETCH FROM curs_transaction_exist INTO i;
IF NOT FOUND
THEN
EXIT loop_transaction;
END IF;
<<loop2_k>> LOOP
CASE k
WHEN 0 THEN
k = k + 1;
IF in0_reserve_pub = i.reserve_pub
THEN
transaction_duplicate0 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in0_notify);
CONTINUE loop_transaction;
END IF;
CONTINUE loop2_k;
WHEN 1 THEN
k = k + 1;
IF in1_reserve_pub = i.reserve_pub
THEN
transaction_duplicate1 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in1_notify);
CONTINUE loop_transaction;
END IF;
CONTINUE loop2_k;
WHEN 2 THEN
k = k + 1;
IF in2_reserve_pub = i.reserve_pub
THEN
transaction_duplicate2 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in2_notify);
CONTINUE loop_transaction;
END IF;
CONTINUE loop2_k;
WHEN 3 THEN
k = k + 1;
IF in3_reserve_pub = i.reserve_pub
THEN
transaction_duplicate3 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in3_notify);
CONTINUE loop_transaction;
END IF;
CONTINUE loop2_k;
WHEN 4 THEN
k = k + 1;
IF in4_reserve_pub = i.reserve_pub
THEN
transaction_duplicate4 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in4_notify);
CONTINUE loop_transaction;
END IF;
CONTINUE loop2_k;
WHEN 5 THEN
k = k + 1;
IF in5_reserve_pub = i.reserve_pub
THEN
transaction_duplicate5 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in5_notify);
CONTINUE loop_transaction;
END IF;
CONTINUE loop2_k;
WHEN 6 THEN
k = k + 1;
IF in6_reserve_pub = i.reserve_pub
THEN
transaction_duplicate6 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in6_notify);
CONTINUE loop_transaction;
END IF;
CONTINUE loop2_k;
WHEN 7 THEN
IF in7_reserve_pub = i.reserve_pub
THEN
transaction_duplicate7 = FALSE;
EXECUTE FORMAT (
'NOTIFY %s'
,in7_notify);
END IF;
EXIT loop_transaction;
END CASE;
END LOOP loop2_k;
END LOOP loop_transaction;
CLOSE curs_transaction_exist;
RETURN;
END $$;

View File

@ -0,0 +1,60 @@
--
-- This file is part of TALER
-- Copyright (C) 2014--2022 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/>
--
CREATE OR REPLACE FUNCTION exchange_do_get_ready_deposit(
IN in_now INT8,
IN in_start_shard_now INT8,
IN in_end_shard_now INT8,
OUT out_payto_uri VARCHAR,
OUT out_merchant_pub BYTEA
)
LANGUAGE plpgsql
AS $$
DECLARE
curs CURSOR
FOR
SELECT
coin_pub
,deposit_serial_id
,wire_deadline
,shard
FROM deposits_by_ready dbr
WHERE wire_deadline <= in_now
AND shard >= in_start_shard_now
AND shard <=in_end_shard_now
ORDER BY
wire_deadline ASC
,shard ASC
LIMIT 1;
DECLARE
i RECORD;
BEGIN
OPEN curs;
FETCH FROM curs INTO i;
SELECT
payto_uri
,merchant_pub
INTO
out_payto_uri
,out_merchant_pub
FROM deposits
JOIN wire_targets wt
USING (wire_target_h_payto)
WHERE
i.coin_pub = coin_pub
AND i.deposit_serial_id=deposit_serial_id;
CLOSE curs;
RETURN;
END $$;

View File

@ -36,7 +36,8 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_abort_shard (void *cls, TEH_PG_abort_shard (void *cls,
const char *job_name, const char *job_name,
uint64_t start_row, uint64_t start_row,
uint64_t end_row); uint64_t end_row);
#endif #endif

View File

@ -56,8 +56,8 @@ TEH_PG_add_denomination_key (
GNUNET_assert (GNUNET_YES == GNUNET_assert (GNUNET_YES ==
TALER_denom_fee_check_currency (meta->value.currency, TALER_denom_fee_check_currency (meta->value.currency,
&meta->fees)); &meta->fees));
/* Used in #postgres_insert_denomination_info() and /* Used in #postgres_insert_denomination_info() and
#postgres_add_denomination_key() */ #postgres_add_denomination_key() */
PREPARE (pg, PREPARE (pg,
"denomination_insert", "denomination_insert",
"INSERT INTO denominations " "INSERT INTO denominations "
@ -86,4 +86,3 @@ TEH_PG_add_denomination_key (
"denomination_insert", "denomination_insert",
iparams); iparams);
} }

View File

@ -94,7 +94,7 @@ TEH_PG_add_policy_fulfillment_proof (
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"insert_proof_into_policy_fulfillments", "insert_proof_into_policy_fulfillments",
params, params,

View File

@ -0,0 +1,470 @@
/*
This file is part of TALER
Copyright (C) 2022 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 exchangedb/pg_batch_ensure_coin_known.c
* @brief Implementation of the batch_ensure_coin_known function for Postgres
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_error_codes.h"
#include "taler_dbevents.h"
#include "taler_pq_lib.h"
#include "pg_batch_ensure_coin_known.h"
#include "pg_helper.h"
static enum GNUNET_DB_QueryStatus
insert1 (struct PostgresClosure *pg,
const struct TALER_CoinPublicInfo coin[1],
struct TALER_EXCHANGEDB_CoinInfo result[1])
{
enum GNUNET_DB_QueryStatus qs;
bool is_denom_pub_hash_null = false;
bool is_age_hash_null = false;
PREPARE (pg,
"batch1_known_coin",
"SELECT"
" existed1 AS existed"
",known_coin_id1 AS known_coin_id"
",denom_pub_hash1 AS denom_hash"
",age_commitment_hash1 AS h_age_commitment"
" FROM exchange_do_batch1_known_coin"
" ($1, $2, $3, $4);"
);
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub),
GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash),
GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment),
TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("existed",
&result[0].existed),
GNUNET_PQ_result_spec_uint64 ("known_coin_id",
&result[0].known_coin_id),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
&result[0].denom_hash),
&is_denom_pub_hash_null),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
&result[0].h_age_commitment),
&is_age_hash_null),
GNUNET_PQ_result_spec_end
};
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"batch1_known_coin",
params,
rs);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
GNUNET_break (0);
return qs;
case GNUNET_DB_STATUS_SOFT_ERROR:
return qs;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
GNUNET_break (0); /* should be impossible */
return GNUNET_DB_STATUS_HARD_ERROR;
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
break; /* continued below */
}
if ( (! is_denom_pub_hash_null) &&
(0 != GNUNET_memcmp (&result[0].denom_hash,
&coin->denom_pub_hash)) )
{
GNUNET_break_op (0);
result[0].denom_conflict = true;
}
if ( (! is_age_hash_null) &&
(0 != GNUNET_memcmp (&result[0].h_age_commitment,
&coin->h_age_commitment)) )
{
GNUNET_break (GNUNET_is_zero (&result[0].h_age_commitment));
GNUNET_break_op (0);
result[0].age_conflict = true;
}
return qs;
}
static enum GNUNET_DB_QueryStatus
insert2 (struct PostgresClosure *pg,
const struct TALER_CoinPublicInfo coin[2],
struct TALER_EXCHANGEDB_CoinInfo result[2])
{
enum GNUNET_DB_QueryStatus qs;
bool is_denom_pub_hash_null = false;
bool is_age_hash_null = false;
bool is_denom_pub_hash_null2 = false;
bool is_age_hash_null2 = false;
PREPARE (pg,
"batch2_known_coin",
"SELECT"
" existed1 AS existed"
",known_coin_id1 AS known_coin_id"
",denom_pub_hash1 AS denom_hash"
",age_commitment_hash1 AS h_age_commitment"
",existed2 AS existed2"
",known_coin_id2 AS known_coin_id2"
",denom_pub_hash2 AS denom_hash2"
",age_commitment_hash2 AS h_age_commitment2"
" FROM exchange_do_batch2_known_coin"
" ($1, $2, $3, $4, $5, $6, $7, $8);"
);
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub),
GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash),
GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment),
TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
GNUNET_PQ_query_param_auto_from_type (&coin[1].coin_pub),
GNUNET_PQ_query_param_auto_from_type (&coin[1].denom_pub_hash),
GNUNET_PQ_query_param_auto_from_type (&coin[1].h_age_commitment),
TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("existed",
&result[0].existed),
GNUNET_PQ_result_spec_uint64 ("known_coin_id",
&result[0].known_coin_id),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
&result[0].denom_hash),
&is_denom_pub_hash_null),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
&result[0].h_age_commitment),
&is_age_hash_null),
GNUNET_PQ_result_spec_bool ("existed2",
&result[1].existed),
GNUNET_PQ_result_spec_uint64 ("known_coin_id2",
&result[1].known_coin_id),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash2",
&result[1].denom_hash),
&is_denom_pub_hash_null2),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash2",
&result[1].h_age_commitment),
&is_age_hash_null2),
GNUNET_PQ_result_spec_end
};
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"batch2_known_coin",
params,
rs);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
GNUNET_break (0);
return qs;
case GNUNET_DB_STATUS_SOFT_ERROR:
return qs;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
GNUNET_break (0); /* should be impossible */
return GNUNET_DB_STATUS_HARD_ERROR;
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
break; /* continued below */
}
if ( (! is_denom_pub_hash_null) &&
(0 != GNUNET_memcmp (&result[0].denom_hash,
&coin[0].denom_pub_hash)) )
{
GNUNET_break_op (0);
result[0].denom_conflict = true;
}
if ( (! is_age_hash_null) &&
(0 != GNUNET_memcmp (&result[0].h_age_commitment,
&coin[0].h_age_commitment)) )
{
GNUNET_break (GNUNET_is_zero (&result[0].h_age_commitment));
GNUNET_break_op (0);
result[0].age_conflict = true;
}
if ( (! is_denom_pub_hash_null2) &&
(0 != GNUNET_memcmp (&result[1].denom_hash,
&coin[1].denom_pub_hash)) )
{
GNUNET_break_op (0);
result[1].denom_conflict = true;
}
if ( (! is_age_hash_null) &&
(0 != GNUNET_memcmp (&result[1].h_age_commitment,
&coin[1].h_age_commitment)) )
{
GNUNET_break (GNUNET_is_zero (&result[1].h_age_commitment));
GNUNET_break_op (0);
result[1].age_conflict = true;
}
return qs;
}
static enum GNUNET_DB_QueryStatus
insert4 (struct PostgresClosure *pg,
const struct TALER_CoinPublicInfo coin[4],
struct TALER_EXCHANGEDB_CoinInfo result[4])
{
enum GNUNET_DB_QueryStatus qs;
bool is_denom_pub_hash_null = false;
bool is_age_hash_null = false;
bool is_denom_pub_hash_null2 = false;
bool is_age_hash_null2 = false;
bool is_denom_pub_hash_null3 = false;
bool is_age_hash_null3 = false;
bool is_denom_pub_hash_null4 = false;
bool is_age_hash_null4 = false;
PREPARE (pg,
"batch4_known_coin",
"SELECT"
" existed1 AS existed"
",known_coin_id1 AS known_coin_id"
",denom_pub_hash1 AS denom_hash"
",age_commitment_hash1 AS h_age_commitment"
",existed2 AS existed2"
",known_coin_id2 AS known_coin_id2"
",denom_pub_hash2 AS denom_hash2"
",age_commitment_hash2 AS h_age_commitment2"
",existed3 AS existed3"
",known_coin_id3 AS known_coin_id3"
",denom_pub_hash3 AS denom_hash3"
",age_commitment_hash3 AS h_age_commitment3"
",existed4 AS existed4"
",known_coin_id4 AS known_coin_id4"
",denom_pub_hash4 AS denom_hash4"
",age_commitment_hash4 AS h_age_commitment4"
" FROM exchange_do_batch2_known_coin"
" ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16);"
);
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub),
GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash),
GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment),
TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
GNUNET_PQ_query_param_auto_from_type (&coin[1].coin_pub),
GNUNET_PQ_query_param_auto_from_type (&coin[1].denom_pub_hash),
GNUNET_PQ_query_param_auto_from_type (&coin[1].h_age_commitment),
TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
GNUNET_PQ_query_param_auto_from_type (&coin[2].coin_pub),
GNUNET_PQ_query_param_auto_from_type (&coin[2].denom_pub_hash),
GNUNET_PQ_query_param_auto_from_type (&coin[2].h_age_commitment),
TALER_PQ_query_param_denom_sig (&coin[2].denom_sig),
GNUNET_PQ_query_param_auto_from_type (&coin[3].coin_pub),
GNUNET_PQ_query_param_auto_from_type (&coin[3].denom_pub_hash),
GNUNET_PQ_query_param_auto_from_type (&coin[3].h_age_commitment),
TALER_PQ_query_param_denom_sig (&coin[3].denom_sig),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("existed",
&result[0].existed),
GNUNET_PQ_result_spec_uint64 ("known_coin_id",
&result[0].known_coin_id),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
&result[0].denom_hash),
&is_denom_pub_hash_null),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
&result[0].h_age_commitment),
&is_age_hash_null),
GNUNET_PQ_result_spec_bool ("existed2",
&result[1].existed),
GNUNET_PQ_result_spec_uint64 ("known_coin_id2",
&result[1].known_coin_id),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash2",
&result[1].denom_hash),
&is_denom_pub_hash_null2),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash2",
&result[1].h_age_commitment),
&is_age_hash_null2),
GNUNET_PQ_result_spec_bool ("existed3",
&result[2].existed),
GNUNET_PQ_result_spec_uint64 ("known_coin_id3",
&result[2].known_coin_id),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash3",
&result[2].denom_hash),
&is_denom_pub_hash_null3),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash3",
&result[2].h_age_commitment),
&is_age_hash_null3),
GNUNET_PQ_result_spec_bool ("existed4",
&result[3].existed),
GNUNET_PQ_result_spec_uint64 ("known_coin_id4",
&result[3].known_coin_id),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash4",
&result[3].denom_hash),
&is_denom_pub_hash_null4),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash4",
&result[3].h_age_commitment),
&is_age_hash_null4),
GNUNET_PQ_result_spec_end
};
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"batch4_known_coin",
params,
rs);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
GNUNET_break (0);
return qs;
case GNUNET_DB_STATUS_SOFT_ERROR:
return qs;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
GNUNET_break (0); /* should be impossible */
return GNUNET_DB_STATUS_HARD_ERROR;
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
break; /* continued below */
}
if ( (! is_denom_pub_hash_null) &&
(0 != GNUNET_memcmp (&result[0].denom_hash,
&coin[0].denom_pub_hash)) )
{
GNUNET_break_op (0);
result[0].denom_conflict = true;
}
if ( (! is_age_hash_null) &&
(0 != GNUNET_memcmp (&result[0].h_age_commitment,
&coin[0].h_age_commitment)) )
{
GNUNET_break (GNUNET_is_zero (&result[0].h_age_commitment));
GNUNET_break_op (0);
result[0].age_conflict = true;
}
if ( (! is_denom_pub_hash_null2) &&
(0 != GNUNET_memcmp (&result[1].denom_hash,
&coin[1].denom_pub_hash)) )
{
GNUNET_break_op (0);
result[1].denom_conflict = true;
}
if ( (! is_age_hash_null2) &&
(0 != GNUNET_memcmp (&result[1].h_age_commitment,
&coin[1].h_age_commitment)) )
{
GNUNET_break (GNUNET_is_zero (&result[1].h_age_commitment));
GNUNET_break_op (0);
result[1].age_conflict = true;
}
if ( (! is_denom_pub_hash_null3) &&
(0 != GNUNET_memcmp (&result[2].denom_hash,
&coin[2].denom_pub_hash)) )
{
GNUNET_break_op (0);
result[2].denom_conflict = true;
}
if ( (! is_age_hash_null3) &&
(0 != GNUNET_memcmp (&result[2].h_age_commitment,
&coin[2].h_age_commitment)) )
{
GNUNET_break (GNUNET_is_zero (&result[2].h_age_commitment));
GNUNET_break_op (0);
result[2].age_conflict = true;
}
if ( (! is_denom_pub_hash_null4) &&
(0 != GNUNET_memcmp (&result[3].denom_hash,
&coin[3].denom_pub_hash)) )
{
GNUNET_break_op (0);
result[3].denom_conflict = true;
}
if ( (! is_age_hash_null4) &&
(0 != GNUNET_memcmp (&result[3].h_age_commitment,
&coin[3].h_age_commitment)) )
{
GNUNET_break (GNUNET_is_zero (&result[3].h_age_commitment));
GNUNET_break_op (0);
result[3].age_conflict = true;
}
return qs;
}
enum GNUNET_DB_QueryStatus
TEH_PG_batch_ensure_coin_known (
void *cls,
const struct TALER_CoinPublicInfo *coin,
struct TALER_EXCHANGEDB_CoinInfo *result,
unsigned int coin_length,
unsigned int batch_size)
{
struct PostgresClosure *pg = cls;
enum GNUNET_DB_QueryStatus qs = 0;
unsigned int i = 0;
while ( (qs >= 0) &&
(i < coin_length) )
{
unsigned int bs = GNUNET_MIN (batch_size,
coin_length - i);
if (bs >= 4)
{
qs = insert4 (pg,
&coin[i],
&result[i]);
i += 4;
continue;
}
switch (bs)
{
case 3:
case 2:
qs = insert2 (pg,
&coin[i],
&result[i]);
i += 2;
break;
case 1:
qs = insert1 (pg,
&coin[i],
&result[i]);
i += 1;
break;
case 0:
GNUNET_assert (0);
break;
}
} /* end while */
if (qs < 0)
return qs;
return i;
}

View File

@ -0,0 +1,47 @@
/*
This file is part of TALER
Copyright (C) 2022, 2023 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 exchangedb/pg_batch_ensure_coin_known.h
* @brief implementation of the batch_ensure_coin_known function for Postgres
* @author Christian Grothoff
*/
#ifndef PG_BATCH_ENSURE_COIN_KNOWN_H
#define PG_BATCH_ENSURE_COIN_KNOWN_H
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
/**
* Make sure the array of given @a coin is known to the database.
*
* @param cls database connection plugin state
* @param coin array of coins that must be made known
* @param[out] result array where to store information about each coin
* @param coin_length length of the @a coin and @a result arraysf
* @param batch_size desired (maximum) batch size
* @return database transaction status, non-negative on success
*/
enum GNUNET_DB_QueryStatus
TEH_PG_batch_ensure_coin_known (
void *cls,
const struct TALER_CoinPublicInfo *coin,
struct TALER_EXCHANGEDB_CoinInfo *result,
unsigned int coin_length,
unsigned int batch_size);
#endif

View File

@ -30,11 +30,11 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_begin_revolving_shard (void *cls, TEH_PG_begin_revolving_shard (void *cls,
const char *job_name, const char *job_name,
uint32_t shard_size, uint32_t shard_size,
uint32_t shard_limit, uint32_t shard_limit,
uint32_t *start_row, uint32_t *start_row,
uint32_t *end_row) uint32_t *end_row)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
@ -45,7 +45,7 @@ TEH_PG_begin_revolving_shard (void *cls,
{ {
if (GNUNET_OK != if (GNUNET_OK !=
TEH_PG_start (pg, TEH_PG_start (pg,
"begin_revolving_shard")) "begin_revolving_shard"))
{ {
GNUNET_break (0); GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
@ -64,15 +64,15 @@ TEH_PG_begin_revolving_shard (void *cls,
&last_end), &last_end),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
/* Used in #postgres_begin_revolving_shard() */ /* Used in #postgres_begin_revolving_shard() */
PREPARE(pg, PREPARE (pg,
"get_last_revolving_shard", "get_last_revolving_shard",
"SELECT" "SELECT"
" end_row" " end_row"
" FROM revolving_work_shards" " FROM revolving_work_shards"
" WHERE job_name=$1" " WHERE job_name=$1"
" ORDER BY end_row DESC" " ORDER BY end_row DESC"
" LIMIT 1;"); " LIMIT 1;");
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_last_revolving_shard", "get_last_revolving_shard",
params, params,
@ -116,7 +116,7 @@ TEH_PG_begin_revolving_shard (void *cls,
(unsigned long long) *start_row, (unsigned long long) *start_row,
(unsigned long long) *end_row); (unsigned long long) *end_row);
/* Used in #postgres_claim_revolving_shard() */ /* Used in #postgres_claim_revolving_shard() */
PREPARE (pg, PREPARE (pg,
"create_revolving_shard", "create_revolving_shard",
"INSERT INTO revolving_work_shards" "INSERT INTO revolving_work_shards"
@ -164,7 +164,7 @@ TEH_PG_begin_revolving_shard (void *cls,
end_row), end_row),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
/* Used in #postgres_begin_revolving_shard() */ /* Used in #postgres_begin_revolving_shard() */
PREPARE (pg, PREPARE (pg,
"get_open_revolving_shard", "get_open_revolving_shard",
"SELECT" "SELECT"
@ -206,7 +206,7 @@ TEH_PG_begin_revolving_shard (void *cls,
now = GNUNET_TIME_timestamp_get (); now = GNUNET_TIME_timestamp_get ();
/* Used in #postgres_begin_revolving_shard() */ /* Used in #postgres_begin_revolving_shard() */
PREPARE (pg, PREPARE (pg,
"reclaim_revolving_shard", "reclaim_revolving_shard",
"UPDATE revolving_work_shards" "UPDATE revolving_work_shards"

View File

@ -40,9 +40,10 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_begin_revolving_shard (void *cls, TEH_PG_begin_revolving_shard (void *cls,
const char *job_name, const char *job_name,
uint32_t shard_size, uint32_t shard_size,
uint32_t shard_limit, uint32_t shard_limit,
uint32_t *start_row, uint32_t *start_row,
uint32_t *end_row); uint32_t *end_row);
#endif #endif

View File

@ -38,10 +38,10 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_begin_shard (void *cls, TEH_PG_begin_shard (void *cls,
const char *job_name, const char *job_name,
struct GNUNET_TIME_Relative delay, struct GNUNET_TIME_Relative delay,
uint64_t shard_size, uint64_t shard_size,
uint64_t *start_row, uint64_t *start_row,
uint64_t *end_row); uint64_t *end_row);
#endif #endif

View File

@ -45,7 +45,7 @@ TEH_PG_commit (void *cls)
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Committing transaction `%s'\n", "Committing transaction `%s'\n",
pg->transaction_name); pg->transaction_name);
/* used in #postgres_commit */ /* used in #postgres_commit */
PREPARE (pg, PREPARE (pg,
"do_commit", "do_commit",
"COMMIT"); "COMMIT");

View File

@ -36,7 +36,8 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_complete_shard (void *cls, TEH_PG_complete_shard (void *cls,
const char *job_name, const char *job_name,
uint64_t start_row, uint64_t start_row,
uint64_t end_row); uint64_t end_row);
#endif #endif

View File

@ -27,8 +27,8 @@
long long long long
TEH_PG_count_known_coins (void *cls, TEH_PG_count_known_coins (void *cls,
const struct const struct
TALER_DenominationHashP *denom_pub_hash) TALER_DenominationHashP *denom_pub_hash)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
uint64_t count; uint64_t count;

View File

@ -33,7 +33,7 @@
*/ */
long long long long
TEH_PG_count_known_coins (void *cls, TEH_PG_count_known_coins (void *cls,
const struct const struct
TALER_DenominationHashP *denom_pub_hash); TALER_DenominationHashP *denom_pub_hash);
#endif #endif

View File

@ -46,18 +46,18 @@ TEH_PG_create_aggregation_transient (
GNUNET_PQ_query_param_auto_from_type (wtid), GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
/* Used in #postgres_create_aggregation_transient() */ /* Used in #postgres_create_aggregation_transient() */
PREPARE (pg, PREPARE (pg,
"create_aggregation_transient", "create_aggregation_transient",
"INSERT INTO aggregation_transient" "INSERT INTO aggregation_transient"
" (amount_val" " (amount_val"
" ,amount_frac" " ,amount_frac"
" ,merchant_pub" " ,merchant_pub"
" ,wire_target_h_payto" " ,wire_target_h_payto"
" ,legitimization_requirement_serial_id" " ,legitimization_requirement_serial_id"
" ,exchange_account_section" " ,exchange_account_section"
" ,wtid_raw)" " ,wtid_raw)"
" VALUES ($1, $2, $3, $4, $5, $6, $7);"); " VALUES ($1, $2, $3, $4, $5, $6, $7);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn, return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"create_aggregation_transient", "create_aggregation_transient",
params); params);

View File

@ -48,5 +48,3 @@ TEH_PG_delete_aggregation_transient (
"delete_aggregation_transient", "delete_aggregation_transient",
params); params);
} }

View File

@ -39,4 +39,3 @@ TEH_PG_delete_shard_locks (void *cls)
return GNUNET_PQ_exec_statements (pg->conn, return GNUNET_PQ_exec_statements (pg->conn,
es); es);
} }

View File

@ -60,8 +60,8 @@ TEH_PG_do_batch_withdraw (
pg->legal_reserve_expiration_time)); pg->legal_reserve_expiration_time));
/* Used in #postgres_do_batch_withdraw() to /* Used in #postgres_do_batch_withdraw() to
update the reserve balance and check its status */ update the reserve balance and check its status */
PREPARE (pg, PREPARE (pg,
"call_batch_withdraw", "call_batch_withdraw",
"SELECT " "SELECT "
@ -75,4 +75,3 @@ TEH_PG_do_batch_withdraw (
params, params,
rs); rs);
} }

View File

@ -59,9 +59,9 @@ TEH_PG_do_batch_withdraw_insert (
nonce_reuse), nonce_reuse),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
/* Used in #postgres_do_batch_withdraw_insert() to store /* Used in #postgres_do_batch_withdraw_insert() 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. */ details. */
PREPARE (pg, PREPARE (pg,
"call_batch_withdraw_insert", "call_batch_withdraw_insert",
"SELECT " "SELECT "

View File

@ -25,6 +25,8 @@
#include "pg_do_deposit.h" #include "pg_do_deposit.h"
#include "pg_helper.h" #include "pg_helper.h"
#include "pg_compute_shard.h" #include "pg_compute_shard.h"
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_do_deposit ( TEH_PG_do_deposit (
void *cls, void *cls,
@ -69,8 +71,6 @@ TEH_PG_do_deposit (
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
/* Used in #postgres_do_deposit() to execute a deposit,
checking the coin's balance in the process as needed. */
PREPARE (pg, PREPARE (pg,
"call_deposit", "call_deposit",
"SELECT " "SELECT "

View File

@ -63,7 +63,7 @@ TEH_PG_do_melt (
}; };
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
/* Used in #postgres_do_melt() to melt a coin. */ /* Used in #postgres_do_melt() to melt a coin. */
PREPARE (pg, PREPARE (pg,
"call_melt", "call_melt",
"SELECT " "SELECT "

View File

@ -75,7 +75,7 @@ TEH_PG_do_purse_merge (
&h_payto); &h_payto);
GNUNET_free (payto_uri); GNUNET_free (payto_uri);
} }
/* Used in #postgres_do_purse_merge() */ /* Used in #postgres_do_purse_merge() */
PREPARE (pg, PREPARE (pg,
"call_purse_merge", "call_purse_merge",
"SELECT" "SELECT"

View File

@ -70,7 +70,6 @@ TEH_PG_do_recoup (
}; };
PREPARE (pg, PREPARE (pg,
"call_recoup", "call_recoup",
"SELECT " "SELECT "

View File

@ -53,4 +53,5 @@ TEH_PG_do_recoup_refresh (
struct GNUNET_TIME_Timestamp *recoup_timestamp, struct GNUNET_TIME_Timestamp *recoup_timestamp,
bool *recoup_ok, bool *recoup_ok,
bool *internal_failure); bool *internal_failure);
#endif #endif

View File

@ -72,7 +72,7 @@ TEH_PG_do_refund (
GNUNET_break (0); GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
} }
/* Used in #postgres_do_refund() to refund a deposit. */ /* Used in #postgres_do_refund() to refund a deposit. */
PREPARE (pg, PREPARE (pg,
"call_refund", "call_refund",
"SELECT " "SELECT "

View File

@ -82,5 +82,3 @@ TEH_PG_do_withdraw (
params, params,
rs); rs);
} }

View File

@ -28,8 +28,8 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_drain_kyc_alert (void *cls, TEH_PG_drain_kyc_alert (void *cls,
uint32_t trigger_type, uint32_t trigger_type,
struct TALER_PaytoHashP *h_payto) struct TALER_PaytoHashP *h_payto)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {

View File

@ -34,7 +34,7 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_drain_kyc_alert (void *cls, TEH_PG_drain_kyc_alert (void *cls,
uint32_t trigger_type, uint32_t trigger_type,
struct TALER_PaytoHashP *h_payto); struct TALER_PaytoHashP *h_payto);
#endif #endif

View File

@ -28,10 +28,10 @@
enum TALER_EXCHANGEDB_CoinKnownStatus enum TALER_EXCHANGEDB_CoinKnownStatus
TEH_PG_ensure_coin_known (void *cls, TEH_PG_ensure_coin_known (void *cls,
const struct TALER_CoinPublicInfo *coin, const struct TALER_CoinPublicInfo *coin,
uint64_t *known_coin_id, uint64_t *known_coin_id,
struct TALER_DenominationHashP *denom_hash, struct TALER_DenominationHashP *denom_hash,
struct TALER_AgeCommitmentHash *h_age_commitment) struct TALER_AgeCommitmentHash *h_age_commitment)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;

View File

@ -37,9 +37,9 @@
*/ */
enum TALER_EXCHANGEDB_CoinKnownStatus enum TALER_EXCHANGEDB_CoinKnownStatus
TEH_PG_ensure_coin_known (void *cls, TEH_PG_ensure_coin_known (void *cls,
const struct TALER_CoinPublicInfo *coin, const struct TALER_CoinPublicInfo *coin,
uint64_t *known_coin_id, uint64_t *known_coin_id,
struct TALER_DenominationHashP *denom_hash, struct TALER_DenominationHashP *denom_hash,
struct TALER_AgeCommitmentHash *h_age_commitment); struct TALER_AgeCommitmentHash *h_age_commitment);
#endif #endif

View File

@ -38,10 +38,10 @@
*/ */
struct GNUNET_DB_EventHandler * struct GNUNET_DB_EventHandler *
TEH_PG_event_listen (void *cls, TEH_PG_event_listen (void *cls,
struct GNUNET_TIME_Relative timeout, struct GNUNET_TIME_Relative timeout,
const struct GNUNET_DB_EventHeaderP *es, const struct GNUNET_DB_EventHeaderP *es,
GNUNET_DB_EventCallback cb, GNUNET_DB_EventCallback cb,
void *cb_cls) void *cb_cls)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;

View File

@ -37,9 +37,9 @@
*/ */
struct GNUNET_DB_EventHandler * struct GNUNET_DB_EventHandler *
TEH_PG_event_listen (void *cls, TEH_PG_event_listen (void *cls,
struct GNUNET_TIME_Relative timeout, struct GNUNET_TIME_Relative timeout,
const struct GNUNET_DB_EventHeaderP *es, const struct GNUNET_DB_EventHeaderP *es,
GNUNET_DB_EventCallback cb, GNUNET_DB_EventCallback cb,
void *cb_cls); void *cb_cls);
#endif #endif

View File

@ -26,10 +26,9 @@
#include "pg_helper.h" #include "pg_helper.h"
void void
TEH_PG_event_listen_cancel (void *cls, TEH_PG_event_listen_cancel (void *cls,
struct GNUNET_DB_EventHandler *eh) struct GNUNET_DB_EventHandler *eh)
{ {
(void) cls; (void) cls;

View File

@ -28,9 +28,9 @@
void void
TEH_PG_event_notify (void *cls, TEH_PG_event_notify (void *cls,
const struct GNUNET_DB_EventHeaderP *es, const struct GNUNET_DB_EventHeaderP *es,
const void *extra, const void *extra,
size_t extra_size) size_t extra_size)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;

View File

@ -35,8 +35,8 @@
*/ */
void void
TEH_PG_event_notify (void *cls, TEH_PG_event_notify (void *cls,
const struct GNUNET_DB_EventHeaderP *es, const struct GNUNET_DB_EventHeaderP *es,
const void *extra, const void *extra,
size_t extra_size); size_t extra_size);
#endif #endif

View File

@ -128,7 +128,7 @@ TEH_PG_find_aggregation_transient (
.pg = pg, .pg = pg,
.status = GNUNET_OK .status = GNUNET_OK
}; };
/* Used in #postgres_find_aggregation_transient() */ /* Used in #postgres_find_aggregation_transient() */
PREPARE (pg, PREPARE (pg,
"find_transient_aggregations", "find_transient_aggregations",
"SELECT" "SELECT"

View File

@ -35,4 +35,5 @@
*/ */
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TEH_PG_gc (void *cls); TEH_PG_gc (void *cls);
#endif #endif

View File

@ -35,6 +35,7 @@ TEH_PG_get_age_withdraw_info (
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
GNUNET_PQ_query_param_auto_from_type (ach), GNUNET_PQ_query_param_auto_from_type (ach),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
@ -45,14 +46,12 @@ TEH_PG_get_age_withdraw_info (
&awc->reserve_sig), &awc->reserve_sig),
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
&awc->reserve_pub), &awc->reserve_pub),
GNUNET_PQ_result_spec_uint32 ("max_age", GNUNET_PQ_result_spec_uint16 ("max_age",
&awc->max_age), &awc->max_age),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
&awc->amount_with_fee), &awc->amount_with_fee),
GNUNET_PQ_result_spec_uint32 ("noreveal_index", GNUNET_PQ_result_spec_uint32 ("noreveal_index",
&awc->noreveal_index), &awc->noreveal_index),
GNUNET_PQ_result_spec_timestamp ("timtestamp",
&awc->timestamp),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
@ -70,9 +69,8 @@ TEH_PG_get_age_withdraw_info (
",amount_with_fee_val" ",amount_with_fee_val"
",amount_with_fee_frac" ",amount_with_fee_frac"
",noreveal_index" ",noreveal_index"
",timestamp"
" FROM withdraw_age_commitments" " FROM withdraw_age_commitments"
" WHERE h_commitment=$1;"); " WHERE reserve_pub=$1 and h_commitment=$2;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_age_withdraw_info", "get_age_withdraw_info",
params, params,

View File

@ -49,9 +49,9 @@ TEH_PG_get_coin_denomination (
"Getting coin denomination of coin %s\n", "Getting coin denomination of coin %s\n",
TALER_B2S (coin_pub)); TALER_B2S (coin_pub));
/* Used in #postgres_get_coin_denomination() to fetch /* Used in #postgres_get_coin_denomination() to fetch
the denomination public key hash for the denomination public key hash for
a coin known to the exchange. */ a coin known to the exchange. */
PREPARE (pg, PREPARE (pg,
"get_coin_denomination", "get_coin_denomination",
"SELECT" "SELECT"
@ -67,5 +67,3 @@ TEH_PG_get_coin_denomination (
params, params,
rs); rs);
} }

View File

@ -46,15 +46,15 @@ TEH_PG_get_denomination_revocation (
}; };
PREPARE (pg, PREPARE (pg,
"denomination_revocation_get", "denomination_revocation_get",
"SELECT" "SELECT"
" master_sig" " master_sig"
",denom_revocations_serial_id" ",denom_revocations_serial_id"
" FROM denomination_revocations" " FROM denomination_revocations"
" WHERE denominations_serial=" " WHERE denominations_serial="
" (SELECT denominations_serial" " (SELECT denominations_serial"
" FROM denominations" " FROM denominations"
" WHERE denom_pub_hash=$1);"); " WHERE denom_pub_hash=$1);");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"denomination_revocation_get", "denomination_revocation_get",

View File

@ -41,4 +41,5 @@ TEH_PG_get_denomination_revocation (
const struct TALER_DenominationHashP *denom_pub_hash, const struct TALER_DenominationHashP *denom_pub_hash,
struct TALER_MasterSignatureP *master_sig, struct TALER_MasterSignatureP *master_sig,
uint64_t *rowid); uint64_t *rowid);
#endif #endif

View File

@ -36,6 +36,7 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_extension_manifest (void *cls, TEH_PG_get_extension_manifest (void *cls,
const char *extension_name, const char *extension_name,
char **manifest); char **manifest);
#endif #endif

View File

@ -28,14 +28,14 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_global_fee (void *cls, TEH_PG_get_global_fee (void *cls,
struct GNUNET_TIME_Timestamp date, struct GNUNET_TIME_Timestamp date,
struct GNUNET_TIME_Timestamp *start_date, struct GNUNET_TIME_Timestamp *start_date,
struct GNUNET_TIME_Timestamp *end_date, struct GNUNET_TIME_Timestamp *end_date,
struct TALER_GlobalFeeSet *fees, struct TALER_GlobalFeeSet *fees,
struct GNUNET_TIME_Relative *purse_timeout, struct GNUNET_TIME_Relative *purse_timeout,
struct GNUNET_TIME_Relative *history_expiration, struct GNUNET_TIME_Relative *history_expiration,
uint32_t *purse_account_limit, uint32_t *purse_account_limit,
struct TALER_MasterSignatureP *master_sig) struct TALER_MasterSignatureP *master_sig)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
@ -65,25 +65,25 @@ TEH_PG_get_global_fee (void *cls,
}; };
/* Used in #postgres_get_global_fee() */ /* Used in #postgres_get_global_fee() */
PREPARE(pg, PREPARE (pg,
"get_global_fee", "get_global_fee",
"SELECT " "SELECT "
" start_date" " start_date"
",end_date" ",end_date"
",history_fee_val" ",history_fee_val"
",history_fee_frac" ",history_fee_frac"
",account_fee_val" ",account_fee_val"
",account_fee_frac" ",account_fee_frac"
",purse_fee_val" ",purse_fee_val"
",purse_fee_frac" ",purse_fee_frac"
",purse_timeout" ",purse_timeout"
",history_expiration" ",history_expiration"
",purse_account_limit" ",purse_account_limit"
",master_sig" ",master_sig"
" FROM global_fee" " FROM global_fee"
" WHERE start_date <= $1" " WHERE start_date <= $1"
" AND end_date > $1;"); " AND end_date > $1;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_global_fee", "get_global_fee",
params, params,

View File

@ -40,13 +40,13 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_global_fee (void *cls, TEH_PG_get_global_fee (void *cls,
struct GNUNET_TIME_Timestamp date, struct GNUNET_TIME_Timestamp date,
struct GNUNET_TIME_Timestamp *start_date, struct GNUNET_TIME_Timestamp *start_date,
struct GNUNET_TIME_Timestamp *end_date, struct GNUNET_TIME_Timestamp *end_date,
struct TALER_GlobalFeeSet *fees, struct TALER_GlobalFeeSet *fees,
struct GNUNET_TIME_Relative *purse_timeout, struct GNUNET_TIME_Relative *purse_timeout,
struct GNUNET_TIME_Relative *history_expiration, struct GNUNET_TIME_Relative *history_expiration,
uint32_t *purse_account_limit, uint32_t *purse_account_limit,
struct TALER_MasterSignatureP *master_sig); struct TALER_MasterSignatureP *master_sig);
#endif #endif

View File

@ -121,11 +121,10 @@ global_fees_cb (void *cls,
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_global_fees (void *cls, TEH_PG_get_global_fees (void *cls,
TALER_EXCHANGEDB_GlobalFeeCallback cb, TALER_EXCHANGEDB_GlobalFeeCallback cb,
void *cb_cls) void *cb_cls)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_TIME_Timestamp date struct GNUNET_TIME_Timestamp date
@ -144,7 +143,7 @@ TEH_PG_get_global_fees (void *cls,
.status = GNUNET_OK .status = GNUNET_OK
}; };
/* Used in #postgres_get_global_fees() */ /* Used in #postgres_get_global_fees() */
PREPARE (pg, PREPARE (pg,
"get_global_fees", "get_global_fees",
"SELECT " "SELECT "
@ -169,7 +168,3 @@ TEH_PG_get_global_fees (void *cls,
&global_fees_cb, &global_fees_cb,
&gctx); &gctx);
} }

View File

@ -35,6 +35,7 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_global_fees (void *cls, TEH_PG_get_global_fees (void *cls,
TALER_EXCHANGEDB_GlobalFeeCallback cb, TALER_EXCHANGEDB_GlobalFeeCallback cb,
void *cb_cls); void *cb_cls);
#endif #endif

View File

@ -27,8 +27,8 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_known_coin (void *cls, TEH_PG_get_known_coin (void *cls,
const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub,
struct TALER_CoinPublicInfo *coin_info) struct TALER_CoinPublicInfo *coin_info)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
@ -51,9 +51,9 @@ TEH_PG_get_known_coin (void *cls,
"Getting known coin data for coin %s\n", "Getting known coin data for coin %s\n",
TALER_B2S (coin_pub)); TALER_B2S (coin_pub));
coin_info->coin_pub = *coin_pub; coin_info->coin_pub = *coin_pub;
/* Used in #postgres_get_known_coin() to fetch /* Used in #postgres_get_known_coin() to fetch
the denomination public key and signature for the denomination public key and signature for
a coin known to the exchange. */ a coin known to the exchange. */
PREPARE (pg, PREPARE (pg,
"get_known_coin", "get_known_coin",
"SELECT" "SELECT"

View File

@ -34,7 +34,7 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_known_coin (void *cls, TEH_PG_get_known_coin (void *cls,
const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub,
struct TALER_CoinPublicInfo *coin_info); struct TALER_CoinPublicInfo *coin_info);
#endif #endif

View File

@ -28,9 +28,9 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_melt (void *cls, TEH_PG_get_melt (void *cls,
const struct TALER_RefreshCommitmentP *rc, const struct TALER_RefreshCommitmentP *rc,
struct TALER_EXCHANGEDB_Melt *melt, struct TALER_EXCHANGEDB_Melt *melt,
uint64_t *melt_serial_id) uint64_t *melt_serial_id)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
bool h_age_commitment_is_null; bool h_age_commitment_is_null;
@ -66,8 +66,8 @@ TEH_PG_get_melt (void *cls,
0, 0,
sizeof (melt->session.coin.denom_sig)); sizeof (melt->session.coin.denom_sig));
/* Used in #postgres_get_melt() to fetch /* Used in #postgres_get_melt() to fetch
high-level information about a melt operation */ high-level information about a melt operation */
PREPARE (pg, PREPARE (pg,
"get_melt", "get_melt",
/* "SELECT" /* "SELECT"

View File

@ -37,8 +37,8 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_melt (void *cls, TEH_PG_get_melt (void *cls,
const struct TALER_RefreshCommitmentP *rc, const struct TALER_RefreshCommitmentP *rc,
struct TALER_EXCHANGEDB_Melt *melt, struct TALER_EXCHANGEDB_Melt *melt,
uint64_t *melt_serial_id); uint64_t *melt_serial_id);
#endif #endif

View File

@ -26,7 +26,6 @@
#include "pg_helper.h" #include "pg_helper.h"
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_old_coin_by_h_blind ( TEH_PG_get_old_coin_by_h_blind (
void *cls, void *cls,
@ -47,7 +46,7 @@ TEH_PG_get_old_coin_by_h_blind (
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
/* Used in #postgres_get_old_coin_by_h_blind() */ /* Used in #postgres_get_old_coin_by_h_blind() */
PREPARE (pg, PREPARE (pg,
"old_coin_by_h_blind", "old_coin_by_h_blind",
"SELECT" "SELECT"

View File

@ -41,4 +41,5 @@ TEH_PG_get_old_coin_by_h_blind (
const struct TALER_BlindedCoinHashP *h_blind_ev, const struct TALER_BlindedCoinHashP *h_blind_ev,
struct TALER_CoinSpendPublicKeyP *old_coin_pub, struct TALER_CoinSpendPublicKeyP *old_coin_pub,
uint64_t *rrc_serial); uint64_t *rrc_serial);
#endif #endif

View File

@ -57,7 +57,6 @@ TEH_PG_get_policy_details (
}; };
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_policy_details", "get_policy_details",
params, params,

View File

@ -61,7 +61,7 @@ TEH_PG_get_purse_deposit (
*partner_url = NULL; *partner_url = NULL;
/* Used in #postgres_get_purse_deposit */ /* Used in #postgres_get_purse_deposit */
PREPARE (pg, PREPARE (pg,
"select_purse_deposit_by_coin_pub", "select_purse_deposit_by_coin_pub",
"SELECT " "SELECT "

View File

@ -59,7 +59,7 @@ TEH_PG_get_purse_request (
purse_sig), purse_sig),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
PREPARE (pg, PREPARE (pg,
"get_purse_request", "get_purse_request",
"SELECT " "SELECT "
@ -80,4 +80,3 @@ TEH_PG_get_purse_request (
params, params,
rs); rs);
} }

View File

@ -38,9 +38,9 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_ready_deposit (void *cls, TEH_PG_get_ready_deposit (void *cls,
uint64_t start_shard_row, uint64_t start_shard_row,
uint64_t end_shard_row, uint64_t end_shard_row,
struct TALER_MerchantPublicKeyP *merchant_pub, struct TALER_MerchantPublicKeyP *merchant_pub,
char **payto_uri); char **payto_uri);
#endif #endif

View File

@ -133,14 +133,11 @@ add_revealed_coins (void *cls,
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_refresh_reveal (void *cls, TEH_PG_get_refresh_reveal (void *cls,
const struct TALER_RefreshCommitmentP *rc, const struct TALER_RefreshCommitmentP *rc,
TALER_EXCHANGEDB_RefreshCallback cb, TALER_EXCHANGEDB_RefreshCallback cb,
void *cb_cls) void *cb_cls)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GetRevealContext grctx; struct GetRevealContext grctx;
@ -154,8 +151,8 @@ TEH_PG_get_refresh_reveal (void *cls,
0, 0,
sizeof (grctx)); sizeof (grctx));
/* Obtain information about the coins created in a refresh /* Obtain information about the coins created in a refresh
operation, used in #postgres_get_refresh_reveal() */ operation, used in #postgres_get_refresh_reveal() */
PREPARE (pg, PREPARE (pg,
"get_refresh_revealed_coins", "get_refresh_revealed_coins",
"SELECT " "SELECT "

View File

@ -37,8 +37,8 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_refresh_reveal (void *cls, TEH_PG_get_refresh_reveal (void *cls,
const struct TALER_RefreshCommitmentP *rc, const struct TALER_RefreshCommitmentP *rc,
TALER_EXCHANGEDB_RefreshCallback cb, TALER_EXCHANGEDB_RefreshCallback cb,
void *cb_cls); void *cb_cls);
#endif #endif

View File

@ -27,8 +27,8 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_reserve_balance (void *cls, TEH_PG_get_reserve_balance (void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
struct TALER_Amount *balance) struct TALER_Amount *balance)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {

View File

@ -34,7 +34,7 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_reserve_balance (void *cls, TEH_PG_get_reserve_balance (void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
struct TALER_Amount *balance); struct TALER_Amount *balance);
#endif #endif

View File

@ -45,7 +45,7 @@ TEH_PG_get_reserve_by_h_blind (
reserve_out_serial_id), reserve_out_serial_id),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
/* Used in #postgres_get_reserve_by_h_blind() */ /* Used in #postgres_get_reserve_by_h_blind() */
PREPARE (pg, PREPARE (pg,
"reserve_by_h_blind", "reserve_by_h_blind",
"SELECT" "SELECT"

View File

@ -92,12 +92,10 @@ get_wire_accounts_cb (void *cls,
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_accounts (void *cls, TEH_PG_get_wire_accounts (void *cls,
TALER_EXCHANGEDB_WireAccountCallback cb, TALER_EXCHANGEDB_WireAccountCallback cb,
void *cb_cls) void *cb_cls)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GetWireAccountsContext ctx = { struct GetWireAccountsContext ctx = {
@ -111,12 +109,12 @@ TEH_PG_get_wire_accounts (void *cls,
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
PREPARE (pg, PREPARE (pg,
"get_wire_accounts", "get_wire_accounts",
"SELECT" "SELECT"
" payto_uri" " payto_uri"
",master_sig" ",master_sig"
" FROM wire_accounts" " FROM wire_accounts"
" WHERE is_active"); " WHERE is_active");
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"get_wire_accounts", "get_wire_accounts",
params, params,

View File

@ -36,7 +36,7 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_accounts (void *cls, TEH_PG_get_wire_accounts (void *cls,
TALER_EXCHANGEDB_WireAccountCallback cb, TALER_EXCHANGEDB_WireAccountCallback cb,
void *cb_cls); void *cb_cls);
#endif #endif

View File

@ -27,12 +27,12 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_fee (void *cls, TEH_PG_get_wire_fee (void *cls,
const char *type, const char *type,
struct GNUNET_TIME_Timestamp date, struct GNUNET_TIME_Timestamp date,
struct GNUNET_TIME_Timestamp *start_date, struct GNUNET_TIME_Timestamp *start_date,
struct GNUNET_TIME_Timestamp *end_date, struct GNUNET_TIME_Timestamp *end_date,
struct TALER_WireFeeSet *fees, struct TALER_WireFeeSet *fees,
struct TALER_MasterSignatureP *master_sig) struct TALER_MasterSignatureP *master_sig)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
@ -55,22 +55,21 @@ TEH_PG_get_wire_fee (void *cls,
}; };
/* Used in #postgres_get_wire_fee() */
/* Used in #postgres_get_wire_fee() */ PREPARE (pg,
PREPARE(pg, "get_wire_fee",
"get_wire_fee", "SELECT "
"SELECT " " start_date"
" start_date" ",end_date"
",end_date" ",wire_fee_val"
",wire_fee_val" ",wire_fee_frac"
",wire_fee_frac" ",closing_fee_val"
",closing_fee_val" ",closing_fee_frac"
",closing_fee_frac" ",master_sig"
",master_sig" " FROM wire_fee"
" FROM wire_fee" " WHERE wire_method=$1"
" WHERE wire_method=$1" " AND start_date <= $2"
" AND start_date <= $2" " AND end_date > $2;");
" AND end_date > $2;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_wire_fee", "get_wire_fee",
params, params,

View File

@ -39,11 +39,11 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_fee (void *cls, TEH_PG_get_wire_fee (void *cls,
const char *type, const char *type,
struct GNUNET_TIME_Timestamp date, struct GNUNET_TIME_Timestamp date,
struct GNUNET_TIME_Timestamp *start_date, struct GNUNET_TIME_Timestamp *start_date,
struct GNUNET_TIME_Timestamp *end_date, struct GNUNET_TIME_Timestamp *end_date,
struct TALER_WireFeeSet *fees, struct TALER_WireFeeSet *fees,
struct TALER_MasterSignatureP *master_sig); struct TALER_MasterSignatureP *master_sig);
#endif #endif

View File

@ -109,9 +109,9 @@ get_wire_fees_cb (void *cls,
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_fees (void *cls, TEH_PG_get_wire_fees (void *cls,
const char *wire_method, const char *wire_method,
TALER_EXCHANGEDB_WireFeeCallback cb, TALER_EXCHANGEDB_WireFeeCallback cb,
void *cb_cls) void *cb_cls)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {

View File

@ -37,8 +37,8 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_fees (void *cls, TEH_PG_get_wire_fees (void *cls,
const char *wire_method, const char *wire_method,
TALER_EXCHANGEDB_WireFeeCallback cb, TALER_EXCHANGEDB_WireFeeCallback cb,
void *cb_cls); void *cb_cls);
#endif #endif

View File

@ -55,10 +55,10 @@ TEH_PG_get_withdraw_info (
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
/* Used in #postgres_get_withdraw_info() to /* Used in #postgres_get_withdraw_info() to
locate the response for a /reserve/withdraw request locate the response for a /reserve/withdraw request
using the hash of the blinded message. Used to using the hash of the blinded message. Used to
make sure /reserve/withdraw requests are idempotent. */ make sure /reserve/withdraw requests are idempotent. */
PREPARE (pg, PREPARE (pg,
"get_withdraw_info", "get_withdraw_info",
"SELECT" "SELECT"

View File

@ -71,29 +71,29 @@ TEH_PG_have_deposit2 (
"Getting deposits for coin %s\n", "Getting deposits for coin %s\n",
TALER_B2S (coin_pub)); TALER_B2S (coin_pub));
/* Fetch an existing deposit request, used to ensure idempotency /* Fetch an existing deposit request, used to ensure idempotency
during /deposit processing. Used in #postgres_have_deposit(). */ during /deposit processing. Used in #postgres_have_deposit(). */
PREPARE (pg, PREPARE (pg,
"get_deposit", "get_deposit",
"SELECT" "SELECT"
" dep.amount_with_fee_val" " dep.amount_with_fee_val"
",dep.amount_with_fee_frac" ",dep.amount_with_fee_frac"
",denominations.fee_deposit_val" ",denominations.fee_deposit_val"
",denominations.fee_deposit_frac" ",denominations.fee_deposit_frac"
",dep.wallet_timestamp" ",dep.wallet_timestamp"
",dep.exchange_timestamp" ",dep.exchange_timestamp"
",dep.refund_deadline" ",dep.refund_deadline"
",dep.wire_deadline" ",dep.wire_deadline"
",dep.h_contract_terms" ",dep.h_contract_terms"
",dep.wire_salt" ",dep.wire_salt"
",wt.payto_uri AS receiver_wire_account" ",wt.payto_uri AS receiver_wire_account"
" FROM deposits dep" " FROM deposits dep"
" JOIN known_coins kc ON (kc.coin_pub = dep.coin_pub)" " JOIN known_coins kc ON (kc.coin_pub = dep.coin_pub)"
" JOIN denominations USING (denominations_serial)" " JOIN denominations USING (denominations_serial)"
" JOIN wire_targets wt USING (wire_target_h_payto)" " JOIN wire_targets wt USING (wire_target_h_payto)"
" WHERE dep.coin_pub=$1" " WHERE dep.coin_pub=$1"
" AND dep.merchant_pub=$3" " AND dep.merchant_pub=$3"
" AND dep.h_contract_terms=$2;"); " AND dep.h_contract_terms=$2;");
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_deposit", "get_deposit",

View File

@ -51,4 +51,3 @@ TEH_PG_insert_aggregation_tracking (
"insert_aggregation_tracking", "insert_aggregation_tracking",
params); params);
} }

View File

@ -40,4 +40,3 @@ TEH_PG_insert_aggregation_tracking (
unsigned long long deposit_serial_id); unsigned long long deposit_serial_id);
#endif #endif

View File

@ -27,10 +27,10 @@
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_insert_auditor (void *cls, TEH_PG_insert_auditor (void *cls,
const struct TALER_AuditorPublicKeyP *auditor_pub, const struct TALER_AuditorPublicKeyP *auditor_pub,
const char *auditor_url, const char *auditor_url,
const char *auditor_name, const char *auditor_name,
struct GNUNET_TIME_Timestamp start_date) struct GNUNET_TIME_Timestamp start_date)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
@ -41,7 +41,7 @@ TEH_PG_insert_auditor (void *cls,
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
/* used in #postgres_insert_auditor() */ /* used in #postgres_insert_auditor() */
PREPARE (pg, PREPARE (pg,
"insert_auditor", "insert_auditor",
"INSERT INTO auditors " "INSERT INTO auditors "

View File

@ -38,8 +38,8 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_insert_auditor (void *cls, TEH_PG_insert_auditor (void *cls,
const struct TALER_AuditorPublicKeyP *auditor_pub, const struct TALER_AuditorPublicKeyP *auditor_pub,
const char *auditor_url, const char *auditor_url,
const char *auditor_name, const char *auditor_name,
struct GNUNET_TIME_Timestamp start_date); struct GNUNET_TIME_Timestamp start_date);
#endif #endif

View File

@ -45,20 +45,20 @@ TEH_PG_insert_contract (
}; };
*in_conflict = false; *in_conflict = false;
/* Used in #postgres_insert_contract() */ /* Used in #postgres_insert_contract() */
PREPARE (pg, PREPARE (pg,
"insert_contract", "insert_contract",
"INSERT INTO contracts" "INSERT INTO contracts"
" (purse_pub" " (purse_pub"
" ,pub_ckey" " ,pub_ckey"
" ,e_contract" " ,e_contract"
" ,contract_sig" " ,contract_sig"
" ,purse_expiration" " ,purse_expiration"
" ) SELECT " " ) SELECT "
" $1, $2, $3, $4, purse_expiration" " $1, $2, $3, $4, purse_expiration"
" FROM purse_requests" " FROM purse_requests"
" WHERE purse_pub=$1" " WHERE purse_pub=$1"
" ON CONFLICT DO NOTHING;"); " ON CONFLICT DO NOTHING;");
qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_contract", "insert_contract",
params); params);
@ -68,8 +68,8 @@ TEH_PG_insert_contract (
struct TALER_EncryptedContract econtract2; struct TALER_EncryptedContract econtract2;
qs = TEH_PG_select_contract_by_purse (pg, qs = TEH_PG_select_contract_by_purse (pg,
purse_pub, purse_pub,
&econtract2); &econtract2);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{ {
GNUNET_break (0); GNUNET_break (0);

View File

@ -39,7 +39,7 @@ TEH_PG_insert_denomination_revocation (
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
/* Used in #postgres_insert_denomination_revocation() */ /* Used in #postgres_insert_denomination_revocation() */
PREPARE (pg, PREPARE (pg,
"denomination_revocation_insert", "denomination_revocation_insert",
"INSERT INTO denomination_revocations " "INSERT INTO denomination_revocations "

View File

@ -34,7 +34,7 @@
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_insert_deposit (void *cls, TEH_PG_insert_deposit (void *cls,
struct GNUNET_TIME_Timestamp exchange_timestamp, struct GNUNET_TIME_Timestamp exchange_timestamp,
const struct TALER_EXCHANGEDB_Deposit *deposit); const struct TALER_EXCHANGEDB_Deposit *deposit);
#endif #endif

Some files were not shown because too many files have changed in this diff Show More