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>

View File

@ -400,6 +400,148 @@ struct Transaction
}; };
/**
* Function called to clean up context of a connection.
*
* @param ctx context to clean up
*/
typedef void
(*ConnectionCleaner)(void *ctx);
/**
* Universal context we keep per connection.
*/
struct ConnectionContext
{
/**
* Function we call upon completion to clean up.
*/
ConnectionCleaner ctx_cleaner;
/**
* Request-handler specific context.
*/
void *ctx;
};
/**
* This is the "base" structure for both the /history and the
* /history-range API calls.
*/
struct HistoryArgs
{
/**
* Bank account number of the requesting client.
*/
uint64_t account_number;
/**
* Index of the starting transaction, exclusive (!).
*/
uint64_t start_idx;
/**
* Requested number of results and order
* (positive: ascending, negative: descending)
*/
int64_t delta;
/**
* Timeout for long polling.
*/
struct GNUNET_TIME_Relative lp_timeout;
/**
* true if starting point was given.
*/
bool have_start;
};
/**
* Context we keep per history request.
*/
struct HistoryContext
{
/**
* When does this request time out.
*/
struct GNUNET_TIME_Absolute timeout;
/**
* Client arguments for this request.
*/
struct HistoryArgs ha;
/**
* Account the request is about.
*/
struct Account *acc;
/**
* Payto URI of the account.
*/
char *payto_uri;
/**
* JSON object we are building to return.
*/
json_t *history;
};
/**
* Function called to clean up a history context.
*
* @param cls a `struct HistoryContext *`
*/
static void
history_cleanup (void *cls)
{
struct HistoryContext *hc = cls;
GNUNET_free (hc->payto_uri);
json_decref (hc->history);
GNUNET_free (hc);
}
/**
* Context we keep per get withdrawal operation request.
*/
struct WithdrawContext
{
/**
* When does this request time out.
*/
struct GNUNET_TIME_Absolute timeout;
/**
* The withdrawal operation this is about.
*/
struct WithdrawalOperation *wo;
};
/**
* Function called to clean up a withdraw context.
*
* @param cls a `struct WithdrawContext *`
*/
static void
withdraw_cleanup (void *cls)
{
struct WithdrawContext *wc = cls;
GNUNET_free (wc);
}
/** /**
* Handle for the fake bank. * Handle for the fake bank.
*/ */
@ -569,13 +711,6 @@ struct TALER_FAKEBANK_Handle
}; };
/**
* Special address "con_cls" can point to to indicate that the handler has
* been called more than once already (was previously suspended).
*/
static int special_ptr;
/** /**
* Task run whenever HTTP server operations are pending. * Task run whenever HTTP server operations are pending.
* *
@ -1583,15 +1718,14 @@ handle_mhd_completion_callback (void *cls,
enum MHD_RequestTerminationCode toe) enum MHD_RequestTerminationCode toe)
{ {
/* struct TALER_FAKEBANK_Handle *h = cls; */ /* struct TALER_FAKEBANK_Handle *h = cls; */
struct ConnectionContext *cc = *con_cls;
(void) cls; (void) cls;
(void) connection; (void) connection;
(void) toe; (void) toe;
if (NULL == *con_cls) if (NULL == cc)
return; return;
if (&special_ptr == *con_cls) cc->ctx_cleaner (cc->ctx);
return; GNUNET_free (cc);
GNUNET_JSON_post_parser_cleanup (*con_cls);
*con_cls = NULL;
} }
@ -1603,7 +1737,7 @@ handle_mhd_completion_callback (void *cls,
* @param account account into which to deposit the funds (credit) * @param account account into which to deposit the funds (credit)
* @param upload_data request data * @param upload_data request data
* @param upload_data_size size of @a upload_data in bytes * @param upload_data_size size of @a upload_data in bytes
* @param con_cls closure for request (a `struct Buffer *`) * @param con_cls closure for request (a `struct ConnectionContext *`)
* @return MHD result code * @return MHD result code
*/ */
static MHD_RESULT static MHD_RESULT
@ -1614,14 +1748,21 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size, size_t *upload_data_size,
void **con_cls) void **con_cls)
{ {
struct ConnectionContext *cc = *con_cls;
enum GNUNET_JSON_PostResult pr; enum GNUNET_JSON_PostResult pr;
json_t *json; json_t *json;
uint64_t row_id; uint64_t row_id;
struct GNUNET_TIME_Timestamp timestamp; struct GNUNET_TIME_Timestamp timestamp;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
*con_cls = cc;
}
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
connection, connection,
con_cls, &cc->ctx,
upload_data, upload_data,
upload_data_size, upload_data_size,
&json); &json);
@ -1736,7 +1877,7 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
* @param account account making the transfer * @param account account making the transfer
* @param upload_data request data * @param upload_data request data
* @param upload_data_size size of @a upload_data in bytes * @param upload_data_size size of @a upload_data in bytes
* @param con_cls closure for request (a `struct Buffer *`) * @param con_cls closure for request (a `struct ConnectionContext *`)
* @return MHD result code * @return MHD result code
*/ */
static MHD_RESULT static MHD_RESULT
@ -1747,14 +1888,21 @@ handle_transfer (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size, size_t *upload_data_size,
void **con_cls) void **con_cls)
{ {
struct ConnectionContext *cc = *con_cls;
enum GNUNET_JSON_PostResult pr; enum GNUNET_JSON_PostResult pr;
json_t *json; json_t *json;
uint64_t row_id; uint64_t row_id;
struct GNUNET_TIME_Timestamp ts; struct GNUNET_TIME_Timestamp ts;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
*con_cls = cc;
}
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
connection, connection,
con_cls, &cc->ctx,
upload_data, upload_data,
upload_data_size, upload_data_size,
&json); &json);
@ -1895,42 +2043,6 @@ handle_home_page (struct TALER_FAKEBANK_Handle *h,
} }
/**
* This is the "base" structure for both the /history and the
* /history-range API calls.
*/
struct HistoryArgs
{
/**
* Bank account number of the requesting client.
*/
uint64_t account_number;
/**
* Index of the starting transaction, exclusive (!).
*/
uint64_t start_idx;
/**
* Requested number of results and order
* (positive: ascending, negative: descending)
*/
int64_t delta;
/**
* Timeout for long polling.
*/
struct GNUNET_TIME_Relative lp_timeout;
/**
* true if starting point was given.
*/
bool have_start;
};
/** /**
* Parse URL history arguments, of _both_ APIs: * Parse URL history arguments, of _both_ APIs:
* /history/incoming and /history/outgoing. * /history/incoming and /history/outgoing.
@ -2176,7 +2288,7 @@ start_lp (struct TALER_FAKEBANK_Handle *h,
* @param h the fakebank handle * @param h the fakebank handle
* @param connection the connection * @param connection the connection
* @param account which account the request is about * @param account which account the request is about
* @param con_cls closure for request (NULL or &special_ptr) * @param con_cls closure for request
*/ */
static MHD_RESULT static MHD_RESULT
handle_debit_history (struct TALER_FAKEBANK_Handle *h, handle_debit_history (struct TALER_FAKEBANK_Handle *h,
@ -2184,87 +2296,106 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
const char *account, const char *account,
void **con_cls) void **con_cls)
{ {
struct HistoryArgs ha; struct ConnectionContext *cc = *con_cls;
struct Account *acc; struct HistoryContext *hc;
struct Transaction *pos; struct Transaction *pos;
json_t *history;
char *debit_payto;
enum GNUNET_GenericReturnValue ret; enum GNUNET_GenericReturnValue ret;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &history_cleanup;
*con_cls = cc;
hc = GNUNET_new (struct HistoryContext);
cc->ctx = hc;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Handling /history/outgoing connection %p\n", "Handling /history/outgoing connection %p\n",
connection); connection);
if (GNUNET_OK != if (GNUNET_OK !=
(ret = parse_history_common_args (h, (ret = parse_history_common_args (h,
connection, connection,
&ha))) &hc->ha)))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES;
} }
if (&special_ptr == *con_cls) GNUNET_assert (0 ==
ha.lp_timeout = GNUNET_TIME_UNIT_ZERO; pthread_mutex_lock (&h->big_lock));
acc = lookup_account (h, hc->acc = lookup_account (h,
account, account,
NULL); NULL);
if (NULL == acc) if (NULL == hc->acc)
{ {
GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock));
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_UNKNOWN_ACCOUNT, TALER_EC_BANK_UNKNOWN_ACCOUNT,
account); account);
} }
GNUNET_asprintf (&debit_payto, GNUNET_asprintf (&hc->payto_uri,
"payto://x-taler-bank/localhost/%s?receiver-name=%s", "payto://x-taler-bank/localhost/%s?receiver-name=%s",
account, account,
acc->receiver_name); hc->acc->receiver_name);
history = json_array (); /* New invariant: */
if (NULL == history) GNUNET_assert (0 == strcmp (hc->payto_uri,
hc->acc->payto_uri));
hc->history = json_array ();
if (NULL == hc->history)
{ {
GNUNET_break (0); GNUNET_break (0);
GNUNET_free (debit_payto); GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock));
return MHD_NO; return MHD_NO;
} }
GNUNET_assert (0 == hc->timeout = GNUNET_TIME_relative_to_absolute (hc->ha.lp_timeout);
pthread_mutex_lock (&h->big_lock));
if (! ha.have_start)
{
pos = (0 > ha.delta)
? acc->out_tail
: acc->out_head;
} }
else else
{ {
struct Transaction *t = h->transactions[ha.start_idx % h->ram_limit]; hc = cc->ctx;
GNUNET_assert (0 ==
pthread_mutex_lock (&h->big_lock));
}
if (! hc->ha.have_start)
{
pos = (0 > hc->ha.delta)
? hc->acc->out_tail
: hc->acc->out_head;
}
else
{
struct Transaction *t = h->transactions[hc->ha.start_idx % h->ram_limit];
bool overflow; bool overflow;
uint64_t dir; uint64_t dir;
bool skip = true; bool skip = true;
dir = (0 > ha.delta) ? (h->ram_limit - 1) : 1; dir = (0 > hc->ha.delta) ? (h->ram_limit - 1) : 1;
overflow = (t->row_id != ha.start_idx); overflow = (t->row_id != hc->ha.start_idx);
/* If account does not match, linear scan for /* If account does not match, linear scan for
first matching account. */ first matching account. */
while ( (! overflow) && while ( (! overflow) &&
(NULL != t) && (NULL != t) &&
(t->debit_account != acc) ) (t->debit_account != hc->acc) )
{ {
skip = false; skip = false;
t = h->transactions[(t->row_id + dir) % h->ram_limit]; t = h->transactions[(t->row_id + dir) % h->ram_limit];
if ( (NULL != t) && if ( (NULL != t) &&
(t->row_id == ha.start_idx) ) (t->row_id == hc->ha.start_idx) )
overflow = true; /* full circle, give up! */ overflow = true; /* full circle, give up! */
} }
if ( (NULL == t) || if ( (NULL == t) ||
overflow) overflow)
{ {
if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) && /* FIXME: these conditions are unclear to me. */
(0 < ha.delta)) if ( (GNUNET_TIME_relative_is_zero (hc->ha.lp_timeout)) &&
(0 < hc->ha.delta))
{ {
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
if (overflow) if (overflow)
{ {
GNUNET_free (debit_payto);
return TALER_MHD_reply_with_ec ( return TALER_MHD_reply_with_ec (
connection, connection,
TALER_EC_BANK_ANCIENT_TRANSACTION_GONE, TALER_EC_BANK_ANCIENT_TRANSACTION_GONE,
@ -2272,35 +2403,36 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
} }
goto finish; goto finish;
} }
*con_cls = &special_ptr; if (h->in_shutdown)
{
GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock));
goto finish;
}
start_lp (h, start_lp (h,
connection, connection,
acc, hc->acc,
ha.lp_timeout, GNUNET_TIME_absolute_get_remaining (hc->timeout),
LP_DEBIT, LP_DEBIT,
NULL); NULL);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
json_decref (history);
GNUNET_free (debit_payto);
return MHD_YES; return MHD_YES;
} }
if (t->debit_account != acc) if (t->debit_account != hc->acc)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Invalid start specified, transaction %llu not with account %s!\n", "Invalid start specified, transaction %llu not with account %s!\n",
(unsigned long long) ha.start_idx, (unsigned long long) hc->ha.start_idx,
account); account);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
GNUNET_free (debit_payto);
json_decref (history);
return MHD_NO; return MHD_NO;
} }
if (skip) if (skip)
{ {
/* range is exclusive, skip the matching entry */ /* range is exclusive, skip the matching entry */
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = t->prev_out; pos = t->prev_out;
else else
pos = t->next_out; pos = t->next_out;
@ -2313,9 +2445,9 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
if (NULL != pos) if (NULL != pos)
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Returning %lld debit transactions starting (inclusive) from %llu\n", "Returning %lld debit transactions starting (inclusive) from %llu\n",
(long long) ha.delta, (long long) hc->ha.delta,
(unsigned long long) pos->row_id); (unsigned long long) pos->row_id);
while ( (0 != ha.delta) && while ( (0 != hc->ha.delta) &&
(NULL != pos) ) (NULL != pos) )
{ {
json_t *trans; json_t *trans;
@ -2327,9 +2459,9 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
"Unexpected CREDIT transaction #%llu for account `%s'\n", "Unexpected CREDIT transaction #%llu for account `%s'\n",
(unsigned long long) pos->row_id, (unsigned long long) pos->row_id,
account); account);
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = pos->prev_in; pos = pos->prev_in;
if (0 < ha.delta) if (0 < hc->ha.delta)
pos = pos->next_in; pos = pos->next_in;
continue; continue;
} }
@ -2348,7 +2480,7 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
GNUNET_JSON_pack_string ("credit_account", GNUNET_JSON_pack_string ("credit_account",
credit_payto), credit_payto),
GNUNET_JSON_pack_string ("debit_account", GNUNET_JSON_pack_string ("debit_account",
debit_payto), // FIXME #7275: inefficient to return this here always! hc->payto_uri), // FIXME #7275: inefficient to return this here always!
GNUNET_JSON_pack_string ("exchange_base_url", GNUNET_JSON_pack_string ("exchange_base_url",
pos->subject.debit.exchange_base_url), pos->subject.debit.exchange_base_url),
GNUNET_JSON_pack_data_auto ("wtid", GNUNET_JSON_pack_data_auto ("wtid",
@ -2356,51 +2488,55 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
GNUNET_assert (NULL != trans); GNUNET_assert (NULL != trans);
GNUNET_free (credit_payto); GNUNET_free (credit_payto);
GNUNET_assert (0 == GNUNET_assert (0 ==
json_array_append_new (history, json_array_append_new (hc->history,
trans)); trans));
if (ha.delta > 0) if (hc->ha.delta > 0)
ha.delta--; hc->ha.delta--;
else else
ha.delta++; hc->ha.delta++;
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = pos->prev_out; pos = pos->prev_out;
if (0 < ha.delta) if (0 < hc->ha.delta)
pos = pos->next_out; pos = pos->next_out;
} }
if ( (0 == json_array_size (history)) && if ( (0 == json_array_size (hc->history)) &&
(! GNUNET_TIME_relative_is_zero (ha.lp_timeout)) && (! h->in_shutdown) &&
(0 < ha.delta)) (GNUNET_TIME_absolute_is_future (hc->timeout)) &&
(0 < hc->ha.delta))
{ {
*con_cls = &special_ptr;
start_lp (h, start_lp (h,
connection, connection,
acc, hc->acc,
ha.lp_timeout, GNUNET_TIME_absolute_get_remaining (hc->timeout),
LP_DEBIT, LP_DEBIT,
NULL); NULL);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
json_decref (history);
return MHD_YES; return MHD_YES;
} }
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
finish: finish:
if (0 == json_array_size (history)) if (0 == json_array_size (hc->history))
{ {
json_decref (history); GNUNET_break (h->in_shutdown ||
(! GNUNET_TIME_absolute_is_future (hc->timeout)));
return TALER_MHD_reply_static (connection, return TALER_MHD_reply_static (connection,
MHD_HTTP_NO_CONTENT, MHD_HTTP_NO_CONTENT,
NULL, NULL,
NULL, NULL,
0); 0);
} }
GNUNET_free (debit_payto); {
json_t *h = hc->history;
hc->history = NULL;
return TALER_MHD_REPLY_JSON_PACK (connection, return TALER_MHD_REPLY_JSON_PACK (connection,
MHD_HTTP_OK, MHD_HTTP_OK,
GNUNET_JSON_pack_array_steal ( GNUNET_JSON_pack_array_steal (
"outgoing_transactions", "outgoing_transactions",
history)); h));
}
} }
@ -2419,77 +2555,101 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
const char *account, const char *account,
void **con_cls) void **con_cls)
{ {
struct HistoryArgs ha; struct ConnectionContext *cc = *con_cls;
struct Account *acc; struct HistoryContext *hc;
const struct Transaction *pos; const struct Transaction *pos;
json_t *history;
const char *credit_payto;
enum GNUNET_GenericReturnValue ret; enum GNUNET_GenericReturnValue ret;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &history_cleanup;
*con_cls = cc;
hc = GNUNET_new (struct HistoryContext);
cc->ctx = hc;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Handling /history/incoming connection %p (%d)\n", "Handling /history/incoming connection %p\n",
connection, connection);
(*con_cls == &special_ptr));
if (GNUNET_OK != if (GNUNET_OK !=
(ret = parse_history_common_args (h, (ret = parse_history_common_args (h,
connection, connection,
&ha))) &hc->ha)))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES;
} }
if (&special_ptr == *con_cls) GNUNET_assert (0 ==
ha.lp_timeout = GNUNET_TIME_UNIT_ZERO; pthread_mutex_lock (&h->big_lock));
*con_cls = &special_ptr; hc->acc = lookup_account (h,
acc = lookup_account (h,
account, account,
NULL); NULL);
if (NULL == acc) if (NULL == hc->acc)
{ {
GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock));
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_UNKNOWN_ACCOUNT, TALER_EC_BANK_UNKNOWN_ACCOUNT,
account); account);
} }
history = json_array (); /* FIXME: was simply: acc->payto_uri -- same!? */
GNUNET_assert (NULL != history); GNUNET_asprintf (&hc->payto_uri,
credit_payto = acc->payto_uri; "payto://x-taler-bank/localhost/%s?receiver-name=%s",
GNUNET_assert (0 == account,
pthread_mutex_lock (&h->big_lock)); hc->acc->receiver_name);
if (! ha.have_start) GNUNET_assert (0 == strcmp (hc->payto_uri,
hc->acc->payto_uri));
hc->history = json_array ();
if (NULL == hc->history)
{ {
pos = (0 > ha.delta) GNUNET_break (0);
? acc->in_tail GNUNET_assert (0 ==
: acc->in_head; pthread_mutex_unlock (&h->big_lock));
return MHD_NO;
}
hc->timeout = GNUNET_TIME_relative_to_absolute (hc->ha.lp_timeout);
} }
else else
{ {
struct Transaction *t = h->transactions[ha.start_idx % h->ram_limit]; hc = cc->ctx;
GNUNET_assert (0 ==
pthread_mutex_lock (&h->big_lock));
}
if (! hc->ha.have_start)
{
pos = (0 > hc->ha.delta)
? hc->acc->in_tail
: hc->acc->in_head;
}
else
{
struct Transaction *t = h->transactions[hc->ha.start_idx % h->ram_limit];
bool overflow; bool overflow;
uint64_t dir; uint64_t dir;
bool skip = true; bool skip = true;
overflow = ( (NULL != t) && (t->row_id != ha.start_idx) ); overflow = ( (NULL != t) && (t->row_id != hc->ha.start_idx) );
dir = (0 > ha.delta) ? (h->ram_limit - 1) : 1; dir = (0 > hc->ha.delta) ? (h->ram_limit - 1) : 1;
/* If account does not match, linear scan for /* If account does not match, linear scan for
first matching account. */ first matching account. */
while ( (! overflow) && while ( (! overflow) &&
(NULL != t) && (NULL != t) &&
(t->credit_account != acc) ) (t->credit_account != hc->acc) )
{ {
skip = false; skip = false;
t = h->transactions[(t->row_id + dir) % h->ram_limit]; t = h->transactions[(t->row_id + dir) % h->ram_limit];
if ( (NULL != t) && if ( (NULL != t) &&
(t->row_id == ha.start_idx) ) (t->row_id == hc->ha.start_idx) )
overflow = true; /* full circle, give up! */ overflow = true; /* full circle, give up! */
} }
if ( (NULL == t) || if ( (NULL == t) ||
overflow) overflow)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, /* FIXME: these conditions are unclear to me. */
"No transactions available, suspending request\n"); if (GNUNET_TIME_relative_is_zero (hc->ha.lp_timeout) &&
if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) && (0 < hc->ha.delta))
(0 < ha.delta))
{ {
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
@ -2500,23 +2660,27 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
NULL); NULL);
goto finish; goto finish;
} }
*con_cls = &special_ptr; if (h->in_shutdown)
{
GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock));
goto finish;
}
start_lp (h, start_lp (h,
connection, connection,
acc, hc->acc,
ha.lp_timeout, GNUNET_TIME_absolute_get_remaining (hc->timeout),
LP_CREDIT, LP_CREDIT,
NULL); NULL);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
json_decref (history);
return MHD_YES; return MHD_YES;
} }
if (skip) if (skip)
{ {
/* range from application is exclusive, skip the /* range from application is exclusive, skip the
matching entry */ matching entry */
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = t->prev_in; pos = t->prev_in;
else else
pos = t->next_in; pos = t->next_in;
@ -2529,9 +2693,9 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
if (NULL != pos) if (NULL != pos)
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Returning %lld credit transactions starting (inclusive) from %llu\n", "Returning %lld credit transactions starting (inclusive) from %llu\n",
(long long) ha.delta, (long long) hc->ha.delta,
(unsigned long long) pos->row_id); (unsigned long long) pos->row_id);
while ( (0 != ha.delta) && while ( (0 != hc->ha.delta) &&
(NULL != pos) ) (NULL != pos) )
{ {
json_t *trans; json_t *trans;
@ -2542,9 +2706,9 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
"Unexpected DEBIT transaction #%llu for account `%s'\n", "Unexpected DEBIT transaction #%llu for account `%s'\n",
(unsigned long long) pos->row_id, (unsigned long long) pos->row_id,
account); account);
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = pos->prev_in; pos = pos->prev_in;
if (0 < ha.delta) if (0 < hc->ha.delta)
pos = pos->next_in; pos = pos->next_in;
continue; continue;
} }
@ -2556,57 +2720,62 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
TALER_JSON_pack_amount ("amount", TALER_JSON_pack_amount ("amount",
&pos->amount), &pos->amount),
GNUNET_JSON_pack_string ("credit_account", GNUNET_JSON_pack_string ("credit_account",
credit_payto), // FIXME #7275: inefficient to repeat this always here! hc->payto_uri), // FIXME #7275: inefficient to repeat this always here!
GNUNET_JSON_pack_string ("debit_account", GNUNET_JSON_pack_string ("debit_account",
pos->debit_account->payto_uri), pos->debit_account->payto_uri),
GNUNET_JSON_pack_data_auto ("reserve_pub", GNUNET_JSON_pack_data_auto ("reserve_pub",
&pos->subject.credit.reserve_pub)); &pos->subject.credit.reserve_pub));
GNUNET_assert (NULL != trans); GNUNET_assert (NULL != trans);
GNUNET_assert (0 == GNUNET_assert (0 ==
json_array_append_new (history, json_array_append_new (hc->history,
trans)); trans));
if (ha.delta > 0) if (hc->ha.delta > 0)
ha.delta--; hc->ha.delta--;
else else
ha.delta++; hc->ha.delta++;
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = pos->prev_in; pos = pos->prev_in;
if (0 < ha.delta) if (0 < hc->ha.delta)
pos = pos->next_in; pos = pos->next_in;
} }
if ( (0 == json_array_size (history)) && if ( (0 == json_array_size (hc->history)) &&
(! GNUNET_TIME_relative_is_zero (ha.lp_timeout)) && (! h->in_shutdown) &&
(0 < ha.delta)) (GNUNET_TIME_absolute_is_future (hc->timeout)) &&
(0 < hc->ha.delta))
{ {
*con_cls = &special_ptr;
start_lp (h, start_lp (h,
connection, connection,
acc, hc->acc,
ha.lp_timeout, GNUNET_TIME_absolute_get_remaining (hc->timeout),
LP_CREDIT, LP_CREDIT,
NULL); NULL);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
json_decref (history);
return MHD_YES; return MHD_YES;
} }
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
finish: finish:
if (0 == json_array_size (history)) if (0 == json_array_size (hc->history))
{ {
json_decref (history); GNUNET_break (h->in_shutdown ||
(! GNUNET_TIME_absolute_is_future (hc->timeout)));
return TALER_MHD_reply_static (connection, return TALER_MHD_reply_static (connection,
MHD_HTTP_NO_CONTENT, MHD_HTTP_NO_CONTENT,
NULL, NULL,
NULL, NULL,
0); 0);
} }
{
json_t *h = hc->history;
hc->history = NULL;
return TALER_MHD_REPLY_JSON_PACK (connection, return TALER_MHD_REPLY_JSON_PACK (connection,
MHD_HTTP_OK, MHD_HTTP_OK,
GNUNET_JSON_pack_array_steal ( GNUNET_JSON_pack_array_steal (
"incoming_transactions", "incoming_transactions",
history)); h));
}
} }
@ -2711,13 +2880,21 @@ get_withdrawal_operation (struct TALER_FAKEBANK_Handle *h,
struct GNUNET_TIME_Relative lp, struct GNUNET_TIME_Relative lp,
void **con_cls) void **con_cls)
{ {
struct WithdrawalOperation *wo; struct ConnectionContext *cc = *con_cls;
struct WithdrawContext *wc;
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_lock (&h->big_lock)); pthread_mutex_lock (&h->big_lock));
wo = lookup_withdrawal_operation (h, if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &withdraw_cleanup;
*con_cls = cc;
wc = GNUNET_new (struct WithdrawContext);
cc->ctx = wc;
wc->wo = lookup_withdrawal_operation (h,
wopid); wopid);
if (NULL == wo) if (NULL == wc->wo)
{ {
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
@ -2726,10 +2903,16 @@ get_withdrawal_operation (struct TALER_FAKEBANK_Handle *h,
TALER_EC_BANK_TRANSACTION_NOT_FOUND, TALER_EC_BANK_TRANSACTION_NOT_FOUND,
wopid); wopid);
} }
if ( (NULL != *con_cls) || wc->timeout = GNUNET_TIME_relative_to_absolute (lp);
(GNUNET_TIME_relative_is_zero (lp)) || }
wo->confirmation_done || else
wo->aborted) {
wc = cc->ctx;
}
if (GNUNET_TIME_absolute_is_past (wc->timeout) ||
h->in_shutdown ||
wc->wo->confirmation_done ||
wc->wo->aborted)
{ {
json_t *wt; json_t *wt;
@ -2744,27 +2927,26 @@ get_withdrawal_operation (struct TALER_FAKEBANK_Handle *h,
connection, connection,
MHD_HTTP_OK, MHD_HTTP_OK,
GNUNET_JSON_pack_bool ("aborted", GNUNET_JSON_pack_bool ("aborted",
wo->aborted), wc->wo->aborted),
GNUNET_JSON_pack_bool ("selection_done", GNUNET_JSON_pack_bool ("selection_done",
wo->selection_done), wc->wo->selection_done),
GNUNET_JSON_pack_bool ("transfer_done", GNUNET_JSON_pack_bool ("transfer_done",
wo->confirmation_done), wc->wo->confirmation_done),
GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("suggested_exchange", GNUNET_JSON_pack_string ("suggested_exchange",
h->exchange_url)), h->exchange_url)),
TALER_JSON_pack_amount ("amount", TALER_JSON_pack_amount ("amount",
&wo->amount), &wc->wo->amount),
GNUNET_JSON_pack_array_steal ("wire_types", GNUNET_JSON_pack_array_steal ("wire_types",
wt)); wt));
} }
*con_cls = &special_ptr;
start_lp (h, start_lp (h,
connection, connection,
wo->debit_account, wc->wo->debit_account,
lp, GNUNET_TIME_absolute_get_remaining (wc->timeout),
LP_WITHDRAW, LP_WITHDRAW,
wo); wc->wo);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
return MHD_YES; return MHD_YES;
@ -2903,13 +3085,20 @@ post_withdrawal_operation (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size, size_t *upload_data_size,
void **con_cls) void **con_cls)
{ {
struct ConnectionContext *cc = *con_cls;
enum GNUNET_JSON_PostResult pr; enum GNUNET_JSON_PostResult pr;
json_t *json; json_t *json;
MHD_RESULT res; MHD_RESULT res;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
*con_cls = cc;
}
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
connection, connection,
con_cls, &cc->ctx,
upload_data, upload_data,
upload_data_size, upload_data_size,
&json); &json);
@ -3294,13 +3483,20 @@ post_account_withdrawals_access (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size, size_t *upload_data_size,
void **con_cls) void **con_cls)
{ {
struct ConnectionContext *cc = *con_cls;
enum GNUNET_JSON_PostResult pr; enum GNUNET_JSON_PostResult pr;
json_t *json; json_t *json;
MHD_RESULT res; MHD_RESULT res;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
*con_cls = cc;
}
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
connection, connection,
con_cls, &cc->ctx,
upload_data, upload_data,
upload_data_size, upload_data_size,
&json); &json);
@ -3367,13 +3563,20 @@ post_testing_register (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size, size_t *upload_data_size,
void **con_cls) void **con_cls)
{ {
struct ConnectionContext *cc = *con_cls;
enum GNUNET_JSON_PostResult pr; enum GNUNET_JSON_PostResult pr;
json_t *json; json_t *json;
MHD_RESULT res; MHD_RESULT res;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
*con_cls = cc;
}
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
connection, connection,
con_cls, &cc->ctx,
upload_data, upload_data,
upload_data_size, upload_data_size,
&json); &json);

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.cs_values); &alg_values.details.
cs_values);
if (TALER_EC_NONE != ec) /* FIXME Handle error? */
{ 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) )
{ {
if (! check_request_idempotent (wc,
mhd_ret))
{
/* We do not support *some* of the coins of the request being
idempotent while others being fresh. */
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Idempotent coin in batch, not allowed. Aborting.\n"); "Idempotent coin in batch, not allowed. Aborting.\n");
*mhd_ret = TALER_MHD_reply_with_error (connection, *mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_CONFLICT, MHD_HTTP_CONFLICT,
TALER_EC_EXCHANGE_WITHDRAW_BATCH_IDEMPOTENT_PLANCHET, TALER_EC_EXCHANGE_WITHDRAW_BATCH_IDEMPOTENT_PLANCHET,
NULL); 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,85 +163,29 @@ 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 (NULL == rp)
{
struct GNUNET_TIME_Relative timeout
= GNUNET_TIME_UNIT_ZERO;
rp = GNUNET_new (struct ReservePoller);
rp->connection = rc->connection;
rc->rh_ctx = rp;
rc->rh_cleaner = &rp_cleanup;
GNUNET_CONTAINER_DLL_insert (rp_head,
rp_tail,
rp);
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[0], GNUNET_STRINGS_string_to_data (args[0],
strlen (args[0]), strlen (args[0]),
&rsc.reserve_pub, &rp->reserve_pub,
sizeof (rsc.reserve_pub))) sizeof (rp->reserve_pub)))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection, return TALER_MHD_reply_with_error (rc->connection,
@ -277,47 +220,58 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc,
timeout_ms); timeout_ms);
} }
} }
if ( (! GNUNET_TIME_relative_is_zero (timeout)) && rp->timeout = GNUNET_TIME_relative_to_absolute (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 (
TEH_plugin->cls,
GNUNET_TIME_absolute_get_remaining (rp->timeout),
&rep.header, &rep.header,
&db_event_cb, &db_event_cb,
rc); 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) case GNUNET_DB_STATUS_SOFT_ERROR:
TEH_plugin->event_listen_cancel (TEH_plugin->cls, GNUNET_break (0); /* single-shot query should never have soft-errors */
eh); return TALER_MHD_reply_with_error (rc->connection,
return mhd_ret; MHD_HTTP_INTERNAL_SERVER_ERROR,
} TALER_EC_GENERIC_DB_SOFT_FAILURE,
} "get_reserve_balance");
/* generate proper response */ case GNUNET_DB_STATUS_HARD_ERROR:
if (rsc.not_found) GNUNET_break (0);
{ return TALER_MHD_reply_with_error (rc->connection,
struct ReservePoller *rp = rc->rh_ctx; MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
if ( (NULL != rp) || "get_reserve_balance");
(GNUNET_TIME_relative_is_zero (timeout)) ) 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, return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_NOT_FOUND,
@ -326,29 +280,16 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc,
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Long-polling on reserve for %s\n", "Long-polling on reserve for %s\n",
GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_STRINGS_relative_time_to_string (
GNUNET_YES)); GNUNET_TIME_absolute_get_remaining (rp->timeout),
rp = GNUNET_new (struct ReservePoller); true));
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; rp->suspended = true;
GNUNET_CONTAINER_DLL_insert (rp_head,
rp_tail,
rp);
MHD_suspend_connection (rc->connection); MHD_suspend_connection (rc->connection);
return MHD_YES; return MHD_YES;
} }
if (NULL != eh) }
TEH_plugin->event_listen_cancel (TEH_plugin->cls, GNUNET_break (0);
eh); return MHD_NO;
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

@ -39,4 +39,5 @@ 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

@ -86,4 +86,3 @@ TEH_PG_add_denomination_key (
"denomination_insert", "denomination_insert",
iparams); iparams);
} }

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

@ -45,4 +45,5 @@ TEH_PG_begin_revolving_shard (void *cls,
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

@ -39,4 +39,5 @@ 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

@ -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

@ -75,4 +75,3 @@ TEH_PG_do_batch_withdraw (
params, params,
rs); rs);
} }

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

@ -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

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

View File

@ -26,7 +26,6 @@
#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)

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

@ -67,5 +67,3 @@ TEH_PG_get_coin_denomination (
params, params,
rs); rs);
} }

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

@ -38,4 +38,5 @@ 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

@ -121,7 +121,6 @@ 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,
@ -169,7 +168,3 @@ TEH_PG_get_global_fees (void *cls,
&global_fees_cb, &global_fees_cb,
&gctx); &gctx);
} }

View File

@ -37,4 +37,5 @@ 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

@ -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,

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

@ -80,4 +80,3 @@ TEH_PG_get_purse_request (
params, params,
rs); rs);
} }

View File

@ -133,9 +133,6 @@ 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,

View File

@ -92,8 +92,6 @@ 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,

View File

@ -55,7 +55,6 @@ 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",

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

@ -41,4 +41,5 @@ TEH_PG_insert_kyc_requirement_for_account (
const char *provider_section, const char *provider_section,
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
uint64_t *requirement_row); uint64_t *requirement_row);
#endif #endif

View File

@ -45,4 +45,5 @@ TEH_PG_insert_kyc_requirement_process (
const char *provider_account_id, const char *provider_account_id,
const char *provider_legitimization_id, const char *provider_legitimization_id,
uint64_t *process_row); uint64_t *process_row);
#endif #endif

View File

@ -1,6 +1,6 @@
/* /*
This file is part of GNUnet This file is part of GNUnet
Copyright (C) 2020, 2021, 2022 Taler Systems SA Copyright (C) 2020-2023 Taler Systems SA
GNUnet is free software: you can redistribute it and/or modify it GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published under the terms of the GNU Affero General Public License as published
@ -19,8 +19,9 @@
*/ */
/** /**
* @file exchangedb/pg_insert_records_by_table.c * @file exchangedb/pg_insert_records_by_table.c
* @brief insert_records_by_table implementation * @brief replicate_records_by_table implementation
* @author Christian Grothoff * @author Christian Grothoff
* @author Özgür Kesim
*/ */
#include "platform.h" #include "platform.h"
#include "taler_error_codes.h" #include "taler_error_codes.h"
@ -28,6 +29,7 @@
#include "taler_pq_lib.h" #include "taler_pq_lib.h"
#include "pg_insert_records_by_table.h" #include "pg_insert_records_by_table.h"
#include "pg_helper.h" #include "pg_helper.h"
#include <gnunet/gnunet_pq_lib.h>
/** /**
@ -1407,7 +1409,7 @@ irbt_cb_table_purse_decision (struct PostgresClosure *pg,
GNUNET_PQ_query_param_timestamp ( GNUNET_PQ_query_param_timestamp (
&td->details.purse_decision.action_timestamp), &td->details.purse_decision.action_timestamp),
GNUNET_PQ_query_param_bool ( GNUNET_PQ_query_param_bool (
&td->details.purse_decision.refunded), td->details.purse_decision.refunded),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
@ -1872,12 +1874,304 @@ irbt_cb_table_profit_drains (struct PostgresClosure *pg,
} }
/**
* Function called with aml_staff records to insert into table.
*
* @param pg plugin context
* @param td record to insert
*/
static enum GNUNET_DB_QueryStatus
irbt_cb_table_aml_staff (struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_TableData *td)
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_auto_from_type (
&td->details.aml_staff.decider_pub),
GNUNET_PQ_query_param_auto_from_type (
&td->details.aml_staff.master_sig),
GNUNET_PQ_query_param_string (
td->details.aml_staff.decider_name),
GNUNET_PQ_query_param_bool (
td->details.aml_staff.is_active),
GNUNET_PQ_query_param_bool (
td->details.aml_staff.read_only),
GNUNET_PQ_query_param_timestamp (
&td->details.aml_staff.last_change),
GNUNET_PQ_query_param_end
};
PREPARE (pg,
"insert_into_table_aml_staff",
"INSERT INTO aml_staff"
"(aml_staff_uuid"
",decider_pub"
",master_sig"
",decider_name"
",is_active"
",read_only"
",last_change"
") VALUES "
"($1, $2, $3, $4, $5, $6, $7);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_aml_staff",
params);
}
/**
* Function called with aml_history records to insert into table.
*
* @param pg plugin context
* @param td record to insert
*/
static enum GNUNET_DB_QueryStatus
irbt_cb_table_aml_history (struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_TableData *td)
{
uint32_t status32 = td->details.aml_history.new_status;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_auto_from_type (
&td->details.aml_history.h_payto),
TALER_PQ_query_param_amount (
&td->details.aml_history.new_threshold),
GNUNET_PQ_query_param_uint32 (
&status32),
GNUNET_PQ_query_param_timestamp (
&td->details.aml_history.decision_time),
GNUNET_PQ_query_param_string (
td->details.aml_history.justification),
(NULL == td->details.aml_history.kyc_requirements)
? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_string (
td->details.aml_history.kyc_requirements),
GNUNET_PQ_query_param_uint64 (
&td->details.aml_history.kyc_req_row),
GNUNET_PQ_query_param_auto_from_type (
&td->details.aml_history.decider_pub),
GNUNET_PQ_query_param_auto_from_type (
&td->details.aml_history.decider_sig),
GNUNET_PQ_query_param_end
};
PREPARE (pg,
"insert_into_table_aml_history",
"INSERT INTO aml_history"
"(aml_history_serial_id"
",h_payto"
",new_threshold_val"
",new_threshold_frac"
",new_status"
",decision_time"
",justification"
",kyc_requirements"
",kyc_req_row"
",decider_pub"
",decider_sig"
") VALUES "
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_aml_history",
params);
}
/**
* Function called with kyc_attributes records to insert into table.
*
* @param pg plugin context
* @param td record to insert
*/
static enum GNUNET_DB_QueryStatus
irbt_cb_table_kyc_attributes (struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_TableData *td)
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_auto_from_type (
&td->details.kyc_attributes.h_payto),
GNUNET_PQ_query_param_auto_from_type (
&td->details.kyc_attributes.kyc_prox),
GNUNET_PQ_query_param_string (
td->details.kyc_attributes.provider),
(NULL == td->details.kyc_attributes.birthdate)
? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_string (
td->details.kyc_attributes.birthdate),
GNUNET_PQ_query_param_timestamp (
&td->details.kyc_attributes.collection_time),
GNUNET_PQ_query_param_timestamp (
&td->details.kyc_attributes.expiration_time),
GNUNET_PQ_query_param_fixed_size (
&td->details.kyc_attributes.encrypted_attributes,
td->details.kyc_attributes.encrypted_attributes_size),
GNUNET_PQ_query_param_end
};
PREPARE (pg,
"insert_into_table_kyc_attributes",
"INSERT INTO kyc_attributes"
"(kyc_attributes_serial_id"
",h_payto"
",kyc_prox"
",provider"
",birthdate"
",collection_time"
",expiration_time"
",encrypted_attributes"
") VALUES "
"($1, $2, $3, $4, $5, $6, $7, $8);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_kyc_attributes",
params);
}
/**
* Function called with purse_deletion records to insert into table.
*
* @param pg plugin context
* @param td record to insert
*/
static enum GNUNET_DB_QueryStatus
irbt_cb_table_purse_deletion (struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_TableData *td)
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_auto_from_type (
&td->details.purse_deletion.purse_pub),
GNUNET_PQ_query_param_auto_from_type (
&td->details.purse_deletion.purse_sig),
GNUNET_PQ_query_param_end
};
PREPARE (pg,
"insert_into_table_purse_deletion",
"INSERT INTO purse_deletion"
"(purse_deletion_serial_id"
",purse_pub"
",purse_sig"
") VALUES "
"($1, $2, $3);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_purse_deletion",
params);
}
/**
* Function called with withdraw_age_commitments records to insert into table.
*
* @param pg plugin context
* @param td record to insert
*/
static enum GNUNET_DB_QueryStatus
irbt_cb_table_withdraw_age_commitments (struct PostgresClosure *pg,
const struct
TALER_EXCHANGEDB_TableData *td)
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_auto_from_type (
&td->details.withdraw_age_commitments.h_commitment),
TALER_PQ_query_param_amount (
&td->details.withdraw_age_commitments.amount_with_fee),
GNUNET_PQ_query_param_uint16 (
&td->details.withdraw_age_commitments.max_age),
GNUNET_PQ_query_param_auto_from_type (
&td->details.withdraw_age_commitments.reserve_pub),
GNUNET_PQ_query_param_auto_from_type (
&td->details.withdraw_age_commitments.reserve_sig),
GNUNET_PQ_query_param_uint32 (
&td->details.withdraw_age_commitments.noreveal_index),
GNUNET_PQ_query_param_absolute_time (
&td->details.withdraw_age_commitments.timestamp),
GNUNET_PQ_query_param_end
};
PREPARE (pg,
"insert_into_table_withdraw_age_commitments",
"INSERT INTO withdraw_age_commitments"
"(withdraw_age_commitment_id"
",h_commitment"
",amount_with_fee_val"
",amount_with_fee_frac"
",max_age"
",reserve_pub"
",reserve_sig"
",noreveal_index"
",timestamp"
") VALUES "
"($1, $2, $3, $4, $5, $6, $7, $8, $9);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_withdraw_age_commitments",
params);
}
/**
* Function called with withdraw_age_revealed_coins records to insert into table.
*
* @param pg plugin context
* @param td record to insert
*/
static enum GNUNET_DB_QueryStatus
irbt_cb_table_withdraw_age_revealed_coins (struct PostgresClosure *pg,
const struct
TALER_EXCHANGEDB_TableData *td)
{
struct GNUNET_HashCode h_coin_ev;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_auto_from_type (
&td->details.withdraw_age_revealed_coins.h_commitment),
GNUNET_PQ_query_param_uint32 (
&td->details.withdraw_age_revealed_coins.freshcoin_index),
GNUNET_PQ_query_param_uint64 (
&td->details.withdraw_age_revealed_coins.denominations_serial),
GNUNET_PQ_query_param_fixed_size (
td->details.withdraw_age_revealed_coins.coin_ev,
td->details.withdraw_age_revealed_coins.coin_ev_size),
GNUNET_PQ_query_param_auto_from_type (&h_coin_ev),
TALER_PQ_query_param_blinded_denom_sig (
&td->details.withdraw_age_revealed_coins.ev_sig),
TALER_PQ_query_param_exchange_withdraw_values (
&td->details.withdraw_age_revealed_coins.ewv),
GNUNET_PQ_query_param_end
};
PREPARE (pg,
"insert_into_table_withdraw_age_revealed_coins",
"INSERT INTO withdraw_age_revealed_coins"
"(withdraw_age_revealed_coins_id"
",h_commitment"
",freshcoin_index"
",denominations_serial"
",coin_ev"
",h_coin_ev"
",ev_sig"
",ewv"
") VALUES "
"($1, $2, $3, $4, $5, $6, $7, $8);");
GNUNET_CRYPTO_hash (td->details.withdraw_age_revealed_coins.coin_ev,
td->details.withdraw_age_revealed_coins.coin_ev_size,
&h_coin_ev);
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_withdraw_age_revealed_coins",
params);
}
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_insert_records_by_table (void *cls, TEH_PG_insert_records_by_table (void *cls,
const struct TALER_EXCHANGEDB_TableData *td) const struct TALER_EXCHANGEDB_TableData *td)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
InsertRecordCallback rh; InsertRecordCallback rh = NULL;
switch (td->table) switch (td->table)
{ {
@ -2007,7 +2301,27 @@ TEH_PG_insert_records_by_table (void *cls,
case TALER_EXCHANGEDB_RT_PROFIT_DRAINS: case TALER_EXCHANGEDB_RT_PROFIT_DRAINS:
rh = &irbt_cb_table_profit_drains; rh = &irbt_cb_table_profit_drains;
break; break;
default: case TALER_EXCHANGEDB_RT_AML_STAFF:
rh = &irbt_cb_table_aml_staff;
break;
case TALER_EXCHANGEDB_RT_AML_HISTORY:
rh = &irbt_cb_table_aml_history;
break;
case TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES:
rh = &irbt_cb_table_kyc_attributes;
break;
case TALER_EXCHANGEDB_RT_PURSE_DELETION:
rh = &irbt_cb_table_purse_deletion;
break;
case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_COMMITMENTS:
rh = &irbt_cb_table_withdraw_age_commitments;
break;
case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_REVEALED_COINS:
rh = &irbt_cb_table_withdraw_age_revealed_coins;
break;
}
if (NULL == rh)
{
GNUNET_break (0); GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
} }
@ -2016,4 +2330,4 @@ TEH_PG_insert_records_by_table (void *cls,
} }
/* end of irbt_callbacks.c */ /* end of pg_insert_records_by_table.c */

View File

@ -38,4 +38,5 @@ enum GNUNET_DB_QueryStatus
TEH_PG_iterate_active_auditors (void *cls, TEH_PG_iterate_active_auditors (void *cls,
TALER_EXCHANGEDB_AuditorsCallback cb, TALER_EXCHANGEDB_AuditorsCallback cb,
void *cb_cls); void *cb_cls);
#endif #endif

View File

@ -41,4 +41,5 @@ TEH_PG_iterate_auditor_denominations (
void *cls, void *cls,
TALER_EXCHANGEDB_AuditorDenominationsCallback cb, TALER_EXCHANGEDB_AuditorDenominationsCallback cb,
void *cb_cls); void *cb_cls);
#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_kyc_provider_account_lookup ( TEH_PG_kyc_provider_account_lookup (
void *cls, void *cls,

View File

@ -44,4 +44,5 @@ TEH_PG_kyc_provider_account_lookup (
const char *provider_legitimization_id, const char *provider_legitimization_id,
struct TALER_PaytoHashP *h_payto, struct TALER_PaytoHashP *h_payto,
uint64_t *process_row); uint64_t *process_row);
#endif #endif

View File

@ -48,4 +48,5 @@ TEH_PG_lookup_global_fee_by_time (
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);
#endif #endif

View File

@ -47,4 +47,5 @@ TEH_PG_lookup_kyc_process_by_account (
struct GNUNET_TIME_Absolute *expiration, struct GNUNET_TIME_Absolute *expiration,
char **provider_account_id, char **provider_account_id,
char **provider_legitimization_id); char **provider_legitimization_id);
#endif #endif

View File

@ -30,9 +30,11 @@ TEH_PG_lookup_kyc_requirement_by_row (
void *cls, void *cls,
uint64_t requirement_row, uint64_t requirement_row,
char **requirements, char **requirements,
enum TALER_AmlDecisionState *aml_status,
struct TALER_PaytoHashP *h_payto) struct TALER_PaytoHashP *h_payto)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
uint32_t status = TALER_AML_NORMAL;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&requirement_row), GNUNET_PQ_query_param_uint64 (&requirement_row),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
@ -42,19 +44,28 @@ TEH_PG_lookup_kyc_requirement_by_row (
requirements), requirements),
GNUNET_PQ_result_spec_auto_from_type ("h_payto", GNUNET_PQ_result_spec_auto_from_type ("h_payto",
h_payto), h_payto),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_uint32 ("status",
&status),
NULL),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
/* Used in #postgres_lookup_kyc_requirement_by_row() */ enum GNUNET_DB_QueryStatus qs;
PREPARE (pg, PREPARE (pg,
"lookup_legitimization_requirement_by_row", "lookup_legitimization_requirement_by_row",
"SELECT " "SELECT "
" required_checks" " lr.required_checks"
",h_payto" ",lr.h_payto"
" FROM legitimization_requirements" ",aml.status"
" FROM legitimization_requirements lr"
" LEFT JOIN aml_status aml USING (h_payto)"
" WHERE legitimization_requirement_serial_id=$1;"); " WHERE legitimization_requirement_serial_id=$1;");
return GNUNET_PQ_eval_prepared_singleton_select ( qs = GNUNET_PQ_eval_prepared_singleton_select (
pg->conn, pg->conn,
"lookup_legitimization_requirement_by_row", "lookup_legitimization_requirement_by_row",
params, params,
rs); rs);
*aml_status = (enum TALER_AmlDecisionState) status;
return qs;
} }

View File

@ -32,6 +32,7 @@
* @param cls closure * @param cls closure
* @param requirement_row identifies requirement to look up * @param requirement_row identifies requirement to look up
* @param[out] requirements provider that must be checked * @param[out] requirements provider that must be checked
* @param[out] aml_status set to the AML status of the account
* @param[out] h_payto account that must be KYC'ed * @param[out] h_payto account that must be KYC'ed
* @return database transaction status * @return database transaction status
*/ */
@ -40,5 +41,7 @@ TEH_PG_lookup_kyc_requirement_by_row (
void *cls, void *cls,
uint64_t requirement_row, uint64_t requirement_row,
char **requirements, char **requirements,
enum TALER_AmlDecisionState *aml_status,
struct TALER_PaytoHashP *h_payto); struct TALER_PaytoHashP *h_payto);
#endif #endif

View File

@ -1,6 +1,6 @@
/* /*
This file is part of GNUnet This file is part of GNUnet
Copyright (C) 2020, 2021, 2022 Taler Systems SA Copyright (C) 2020-2023 Taler Systems SA
GNUnet is free software: you can redistribute it and/or modify it GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published under the terms of the GNU Affero General Public License as published
@ -21,6 +21,7 @@
* @file exchangedb/pg_lookup_records_by_table.c * @file exchangedb/pg_lookup_records_by_table.c
* @brief implementation of lookup_records_by_table * @brief implementation of lookup_records_by_table
* @author Christian Grothoff * @author Christian Grothoff
* @author Özgür Kesim
*/ */
#include "platform.h" #include "platform.h"
#include "taler_error_codes.h" #include "taler_error_codes.h"
@ -231,6 +232,109 @@ lrbt_cb_table_wire_targets (void *cls,
} }
/**
* Function called with legitimization_processes table entries.
*
* @param cls closure
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
lrbt_cb_table_legitimization_processes (void *cls,
PGresult *result,
unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_LEGITIMIZATION_PROCESSES
};
for (unsigned int i = 0; i<num_results; i++)
{
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("serial",
&td.serial),
GNUNET_PQ_result_spec_auto_from_type (
"h_payto",
&td.details.legitimization_processes.h_payto),
GNUNET_PQ_result_spec_timestamp (
"expiration_time",
&td.details.legitimization_processes.expiration_time),
GNUNET_PQ_result_spec_string (
"provider_section",
&td.details.legitimization_processes.provider_section),
GNUNET_PQ_result_spec_string (
"provider_user_id",
&td.details.legitimization_processes.provider_user_id),
GNUNET_PQ_result_spec_string (
"provider_legitimization_id",
&td.details.legitimization_processes.provider_legitimization_id),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
ctx->error = true;
return;
}
ctx->cb (ctx->cb_cls,
&td);
GNUNET_PQ_cleanup_result (rs);
}
}
/**
* Function called with legitimization_requirements table entries.
*
* @param cls closure
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
lrbt_cb_table_legitimization_requirements (void *cls,
PGresult *result,
unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_LEGITIMIZATION_REQUIREMENTS
};
for (unsigned int i = 0; i<num_results; i++)
{
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("serial",
&td.serial),
GNUNET_PQ_result_spec_auto_from_type (
"h_payto",
&td.details.legitimization_requirements.h_payto),
GNUNET_PQ_result_spec_string (
"required_checks",
&td.details.legitimization_requirements.required_checks),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
ctx->error = true;
return;
}
ctx->cb (ctx->cb_cls,
&td);
GNUNET_PQ_cleanup_result (rs);
}
}
/** /**
* Function called with reserves table entries. * Function called with reserves table entries.
* *
@ -400,6 +504,123 @@ lrbt_cb_table_reserves_close (void *cls,
} }
/**
* Function called with reserves_open_requests table entries.
*
* @param cls closure
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
lrbt_cb_table_reserves_open_requests (void *cls,
PGresult *result,
unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
struct PostgresClosure *pg = ctx->pg;
struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_RESERVES_OPEN_REQUESTS
};
for (unsigned int i = 0; i<num_results; i++)
{
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("serial",
&td.serial),
GNUNET_PQ_result_spec_auto_from_type (
"reserve_pub",
&td.details.reserves_open_requests.reserve_pub),
GNUNET_PQ_result_spec_timestamp (
"request_timestamp",
&td.details.reserves_open_requests.request_timestamp),
GNUNET_PQ_result_spec_timestamp (
"expiration_date",
&td.details.reserves_open_requests.expiration_date),
GNUNET_PQ_result_spec_auto_from_type (
"reserve_sig",
&td.details.reserves_open_requests.reserve_sig),
TALER_PQ_RESULT_SPEC_AMOUNT (
"reserve_payment",
&td.details.reserves_open_requests.reserve_payment),
GNUNET_PQ_result_spec_uint32 (
"requested_purse_limit",
&td.details.reserves_open_requests.requested_purse_limit),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
ctx->error = true;
return;
}
ctx->cb (ctx->cb_cls,
&td);
GNUNET_PQ_cleanup_result (rs);
}
}
/**
* Function called with reserves_open_deposits table entries.
*
* @param cls closure
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
lrbt_cb_table_reserves_open_deposits (void *cls,
PGresult *result,
unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
struct PostgresClosure *pg = ctx->pg;
struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS
};
for (unsigned int i = 0; i<num_results; i++)
{
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("serial",
&td.serial),
GNUNET_PQ_result_spec_auto_from_type (
"reserve_sig",
&td.details.reserves_open_deposits.reserve_sig),
GNUNET_PQ_result_spec_auto_from_type (
"reserve_pub",
&td.details.reserves_open_deposits.reserve_pub),
GNUNET_PQ_result_spec_auto_from_type (
"coin_pub",
&td.details.reserves_open_deposits.coin_pub),
GNUNET_PQ_result_spec_auto_from_type (
"coin_sig",
&td.details.reserves_open_deposits.coin_sig),
TALER_PQ_RESULT_SPEC_AMOUNT (
"contribution",
&td.details.reserves_open_deposits.contribution),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
ctx->error = true;
return;
}
ctx->cb (ctx->cb_cls,
&td);
GNUNET_PQ_cleanup_result (rs);
}
}
/** /**
* Function called with reserves_out table entries. * Function called with reserves_out table entries.
* *
@ -2295,6 +2516,379 @@ lrbt_cb_table_profit_drains (void *cls,
} }
/**
* Function called with aml_staff table entries.
*
* @param cls closure
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
lrbt_cb_table_aml_staff (void *cls,
PGresult *result,
unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_AML_STAFF
};
for (unsigned int i = 0; i<num_results; i++)
{
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 (
"aml_staff_uuid",
&td.serial),
GNUNET_PQ_result_spec_auto_from_type (
"decider_pub",
&td.details.aml_staff.decider_pub),
GNUNET_PQ_result_spec_auto_from_type (
"master_sig",
&td.details.aml_staff.master_sig),
GNUNET_PQ_result_spec_string (
"decider_name",
&td.details.aml_staff.decider_name),
GNUNET_PQ_result_spec_bool (
"is_active",
&td.details.aml_staff.is_active),
GNUNET_PQ_result_spec_bool (
"read_only",
&td.details.aml_staff.read_only),
GNUNET_PQ_result_spec_timestamp (
"last_change",
&td.details.aml_staff.last_change),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
ctx->error = true;
return;
}
ctx->cb (ctx->cb_cls,
&td);
GNUNET_PQ_cleanup_result (rs);
}
}
/**
* Function called with aml_history table entries.
*
* @param cls closure
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
lrbt_cb_table_aml_history (void *cls,
PGresult *result,
unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
struct PostgresClosure *pg = ctx->pg;
struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_AML_HISTORY
};
for (unsigned int i = 0; i<num_results; i++)
{
uint32_t status32;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 (
"aml_history_serial_id",
&td.serial),
GNUNET_PQ_result_spec_auto_from_type (
"h_payto",
&td.details.aml_history.h_payto),
TALER_PQ_RESULT_SPEC_AMOUNT (
"new_threshold",
&td.details.aml_history.new_threshold),
GNUNET_PQ_result_spec_uint32 (
"new_status",
&status32),
GNUNET_PQ_result_spec_timestamp (
"decision_time",
&td.details.aml_history.decision_time),
GNUNET_PQ_result_spec_string (
"justification",
&td.details.aml_history.justification),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_string (
"kyc_requirements",
&td.details.aml_history.kyc_requirements),
NULL),
GNUNET_PQ_result_spec_uint64 (
"kyc_req_row",
&td.details.aml_history.kyc_req_row),
GNUNET_PQ_result_spec_auto_from_type (
"decider_pub",
&td.details.aml_history.decider_pub),
GNUNET_PQ_result_spec_auto_from_type (
"decider_sig",
&td.details.aml_history.decider_sig),
GNUNET_PQ_result_spec_end
};
td.details.aml_history.kyc_requirements = NULL;
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
ctx->error = true;
return;
}
td.details.aml_history.new_status
= (enum TALER_AmlDecisionState) status32;
ctx->cb (ctx->cb_cls,
&td);
GNUNET_PQ_cleanup_result (rs);
}
}
/**
* Function called with kyc_attributes table entries.
*
* @param cls closure
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
lrbt_cb_table_kyc_attributes (void *cls,
PGresult *result,
unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES
};
for (unsigned int i = 0; i<num_results; i++)
{
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 (
"kyc_attributes_serial_id",
&td.serial),
GNUNET_PQ_result_spec_auto_from_type (
"h_payto",
&td.details.kyc_attributes.h_payto),
GNUNET_PQ_result_spec_auto_from_type (
"kyc_prox",
&td.details.kyc_attributes.kyc_prox),
GNUNET_PQ_result_spec_string (
"provider",
&td.details.kyc_attributes.provider),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_string (
"birthdate",
&td.details.kyc_attributes.birthdate),
NULL),
GNUNET_PQ_result_spec_timestamp (
"collection_time",
&td.details.kyc_attributes.collection_time),
GNUNET_PQ_result_spec_timestamp (
"expiration_time",
&td.details.kyc_attributes.expiration_time),
GNUNET_PQ_result_spec_variable_size (
"encrypted_attributes",
&td.details.kyc_attributes.encrypted_attributes,
&td.details.kyc_attributes.encrypted_attributes_size),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
ctx->error = true;
return;
}
ctx->cb (ctx->cb_cls,
&td);
GNUNET_PQ_cleanup_result (rs);
}
}
/**
* Function called with purse_deletion table entries.
*
* @param cls closure
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
lrbt_cb_table_purse_deletion (void *cls,
PGresult *result,
unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_PURSE_DELETION
};
for (unsigned int i = 0; i<num_results; i++)
{
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 (
"purse_deletion_serial_id",
&td.serial),
GNUNET_PQ_result_spec_auto_from_type (
"purse_sig",
&td.details.purse_deletion.purse_sig),
GNUNET_PQ_result_spec_auto_from_type (
"purse_pub",
&td.details.purse_deletion.purse_pub),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
ctx->error = true;
return;
}
ctx->cb (ctx->cb_cls,
&td);
GNUNET_PQ_cleanup_result (rs);
}
}
/**
* Function called with withdraw_age_commitments table entries.
*
* @param cls closure
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
lrbt_cb_table_withdraw_age_commitments (void *cls,
PGresult *result,
unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
struct PostgresClosure *pg = ctx->pg;
struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_WITHDRAW_AGE_COMMITMENTS
};
for (unsigned int i = 0; i<num_results; i++)
{
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 (
"withdraw_age_commitment_id",
&td.serial),
GNUNET_PQ_result_spec_auto_from_type (
"h_commitment",
&td.details.withdraw_age_commitments.h_commitment),
GNUNET_PQ_result_spec_uint16 (
"max_age",
&td.details.withdraw_age_commitments.max_age),
TALER_PQ_RESULT_SPEC_AMOUNT (
"amount_with_fee",
&td.details.withdraw_age_commitments.amount_with_fee),
GNUNET_PQ_result_spec_auto_from_type (
"reserve_pub",
&td.details.withdraw_age_commitments.reserve_pub),
GNUNET_PQ_result_spec_auto_from_type (
"reserve_sig",
&td.details.withdraw_age_commitments.reserve_sig),
GNUNET_PQ_result_spec_uint32 (
"noreveal_index",
&td.details.withdraw_age_commitments.noreveal_index),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
ctx->error = true;
return;
}
ctx->cb (ctx->cb_cls,
&td);
GNUNET_PQ_cleanup_result (rs);
}
}
/**
* Function called with withdraw_age_revealed_coins table entries.
*
* @param cls closure
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
lrbt_cb_table_withdraw_age_revealed_coins (void *cls,
PGresult *result,
unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_WITHDRAW_AGE_REVEALED_COINS
};
for (unsigned int i = 0; i<num_results; i++)
{
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 (
"withdraw_age_revealed_coins_id",
&td.serial),
GNUNET_PQ_result_spec_auto_from_type (
"h_commitment",
&td.details.withdraw_age_revealed_coins.h_commitment),
GNUNET_PQ_result_spec_uint32 (
"freshcoin_index",
&td.details.withdraw_age_revealed_coins.freshcoin_index),
GNUNET_PQ_result_spec_uint64 (
"denominations_serial",
&td.details.withdraw_age_revealed_coins.denominations_serial),
/* Note: h_coin_ev is recalculated */
GNUNET_PQ_result_spec_variable_size (
"coin_ev",
(void **) &td.details.withdraw_age_revealed_coins.coin_ev,
&td.details.withdraw_age_revealed_coins.coin_ev_size),
TALER_PQ_result_spec_blinded_denom_sig (
"ev_sig",
&td.details.refresh_revealed_coins.ev_sig),
TALER_PQ_result_spec_exchange_withdraw_values (
"ewv",
&td.details.refresh_revealed_coins.ewv),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
i))
{
GNUNET_break (0);
ctx->error = true;
return;
}
ctx->cb (ctx->cb_cls,
&td);
GNUNET_PQ_cleanup_result (rs);
}
}
/** /**
* Assign statement to @a n and PREPARE * Assign statement to @a n and PREPARE
* @a sql under name @a n. * @a sql under name @a n.
@ -2321,8 +2915,8 @@ TEH_PG_lookup_records_by_table (void *cls,
.cb = cb, .cb = cb,
.cb_cls = cb_cls .cb_cls = cb_cls
}; };
GNUNET_PQ_PostgresResultHandler rh; GNUNET_PQ_PostgresResultHandler rh = NULL;
const char *statement; const char *statement = NULL;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
switch (table) switch (table)
@ -2375,6 +2969,31 @@ TEH_PG_lookup_records_by_table (void *cls,
" ORDER BY wire_target_serial_id ASC;"); " ORDER BY wire_target_serial_id ASC;");
rh = &lrbt_cb_table_wire_targets; rh = &lrbt_cb_table_wire_targets;
break; break;
case TALER_EXCHANGEDB_RT_LEGITIMIZATION_PROCESSES:
XPREPARE ("select_above_serial_by_table_legitimization_processes",
"SELECT"
" legitimization_process_serial_id AS serial"
",h_payto"
",expiration_time"
",provider_section"
",provider_user_id"
",provider_legitimization_id"
" FROM legitimization_processes"
" WHERE legitimization_process_serial_id > $1"
" ORDER BY legitimization_process_serial_id ASC;");
rh = &lrbt_cb_table_legitimization_processes;
break;
case TALER_EXCHANGEDB_RT_LEGITIMIZATION_REQUIREMENTS:
XPREPARE ("select_above_serial_by_table_legitimization_requirements",
"SELECT"
" legitimization_requirement_serial_id AS serial"
",h_payto"
",required_checks"
" FROM legitimization_requirements"
" WHERE legitimization_requirement_serial_id > $1"
" ORDER BY legitimization_requirement_serial_id ASC;");
rh = &lrbt_cb_table_legitimization_requirements;
break;
case TALER_EXCHANGEDB_RT_RESERVES: case TALER_EXCHANGEDB_RT_RESERVES:
XPREPARE ("select_above_serial_by_table_reserves", XPREPARE ("select_above_serial_by_table_reserves",
"SELECT" "SELECT"
@ -2420,6 +3039,37 @@ TEH_PG_lookup_records_by_table (void *cls,
" ORDER BY close_uuid ASC;"); " ORDER BY close_uuid ASC;");
rh = &lrbt_cb_table_reserves_close; rh = &lrbt_cb_table_reserves_close;
break; break;
case TALER_EXCHANGEDB_RT_RESERVES_OPEN_REQUESTS:
XPREPARE ("select_above_serial_by_table_reserves_open_requests",
"SELECT"
" open_request_uuid AS serial"
",reserve_pub"
",request_timestamp"
",expiration_date"
",reserve_sig"
",reserve_payment_val"
",reserve_payment_frac"
",requested_purse_limit"
" FROM reserves_open_requests"
" WHERE open_request_uuid > $1"
" ORDER BY open_request_uuid ASC;");
rh = &lrbt_cb_table_reserves_open_requests;
break;
case TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS:
XPREPARE ("select_above_serial_by_table_reserves_open_deposits",
"SELECT"
" reserves_open_deposit_uuid AS serial"
",reserve_sig"
",reserve_pub"
",coin_pub"
",coin_sig"
",contribution_val"
",contribution_frac"
" FROM reserves_open_deposits"
" WHERE reserves_open_deposit_uuid > $1"
" ORDER BY reserves_open_deposit_uuid ASC;");
rh = &lrbt_cb_table_reserves_open_deposits;
break;
case TALER_EXCHANGEDB_RT_RESERVES_OUT: case TALER_EXCHANGEDB_RT_RESERVES_OUT:
XPREPARE ("select_above_serial_by_table_reserves_out", XPREPARE ("select_above_serial_by_table_reserves_out",
"SELECT" "SELECT"
@ -2885,7 +3535,103 @@ TEH_PG_lookup_records_by_table (void *cls,
" ORDER BY profit_drain_serial_id ASC;"); " ORDER BY profit_drain_serial_id ASC;");
rh = &lrbt_cb_table_profit_drains; rh = &lrbt_cb_table_profit_drains;
break; break;
default:
case TALER_EXCHANGEDB_RT_AML_STAFF:
XPREPARE ("select_above_serial_by_table_aml_staff",
"SELECT"
" aml_staff_uuid"
",decider_pub"
",master_sig"
",decider_name"
",is_active"
",read_only"
",last_change"
" FROM aml_staff"
" WHERE aml_staff_uuid > $1"
" ORDER BY aml_staff_uuid ASC;");
rh = &lrbt_cb_table_aml_staff;
break;
case TALER_EXCHANGEDB_RT_AML_HISTORY:
XPREPARE ("select_above_serial_by_table_aml_history",
"SELECT"
" aml_history_serial_id"
",h_payto"
",new_threshold_val"
",new_threshold_frac"
",new_status"
",decision_time"
",justification"
",kyc_requirements"
",kyc_req_row"
",decider_pub"
",decider_sig"
" FROM aml_history"
" WHERE aml_history_serial_id > $1"
" ORDER BY aml_history_serial_id ASC;");
rh = &lrbt_cb_table_aml_history;
break;
case TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES:
XPREPARE ("select_above_serial_by_table_kyc_attributes",
"SELECT"
" kyc_attributes_serial_id"
",h_payto"
",kyc_prox"
",provider"
",birthdate"
",collection_time"
",expiration_time"
",encrypted_attributes"
" FROM kyc_attributes"
" WHERE kyc_attributes_serial_id > $1"
" ORDER BY kyc_attributes_serial_id ASC;");
rh = &lrbt_cb_table_kyc_attributes;
break;
case TALER_EXCHANGEDB_RT_PURSE_DELETION:
XPREPARE ("select_above_serial_by_table_purse_deletion",
"SELECT"
" purse_deletion_serial_id"
",purse_pub"
",purse_sig"
" FROM purse_deletion"
" WHERE purse_deletion_serial_id > $1"
" ORDER BY purse_deletion_serial_id ASC;");
rh = &lrbt_cb_table_purse_deletion;
break;
case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_COMMITMENTS:
XPREPARE ("select_above_serial_by_table_withdraw_age_commitments",
"SELECT"
" withdraw_age_commitment_id"
",h_commitment"
",amount_with_fee_val"
",amount_with_fee_frac"
",max_age"
",reserve_pub"
",reserve_sig"
",noreveal_index"
" FROM withdraw_age_commitments"
" WHERE withdraw_age_commitment_id > $1"
" ORDER BY withdraw_age_commitment_id ASC;");
rh = &lrbt_cb_table_withdraw_age_commitments;
break;
case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_REVEALED_COINS:
XPREPARE ("select_above_serial_by_table_withdraw_age_revealed_coins",
"SELECT"
" withdraw_age_revealed_coins_serial_id"
",h_commitment"
",freshcoin_index"
",denominations_serial"
",coin_ev"
",h_coin_ev"
",ev_sig"
",ewv"
" FROM withdraw_age_revealed_coins"
" WHERE withdraw_age_revealed_coins_serial_id > $1"
" ORDER BY withdraw_age_revealed_coins_serial_id ASC;");
rh = &lrbt_cb_table_withdraw_age_revealed_coins;
break;
}
if (NULL == rh)
{
GNUNET_break (0); GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
} }

View File

@ -390,6 +390,60 @@ TEH_PG_lookup_serial_by_table (void *cls,
" LIMIT 1;"); " LIMIT 1;");
statement = "select_serial_by_table_profit_drains"; statement = "select_serial_by_table_profit_drains";
break; break;
case TALER_EXCHANGEDB_RT_AML_STAFF:
XPREPARE ("select_serial_by_table_aml_staff",
"SELECT"
" aml_staff_uuid AS serial"
" FROM aml_staff"
" ORDER BY aml_staff_uuid DESC"
" LIMIT 1;");
statement = "select_serial_by_table_aml_staff";
break;
case TALER_EXCHANGEDB_RT_AML_HISTORY:
XPREPARE ("select_serial_by_table_aml_history",
"SELECT"
" aml_history_serial_id AS serial"
" FROM aml_history"
" ORDER BY aml_history_serial_id DESC"
" LIMIT 1;");
statement = "select_serial_by_table_aml_history";
break;
case TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES:
XPREPARE ("select_serial_by_table_kyc_attributes",
"SELECT"
" kyc_attributes_serial_id AS serial"
" FROM kyc_attributes"
" ORDER BY kyc_attributes_serial_id DESC"
" LIMIT 1;");
statement = "select_serial_by_table_kyc_attributes";
break;
case TALER_EXCHANGEDB_RT_PURSE_DELETION:
XPREPARE ("select_serial_by_table_purse_deletion",
"SELECT"
" purse_deletion_serial_id AS serial"
" FROM purse_deletion"
" ORDER BY purse_deletion_serial_id DESC"
" LIMIT 1;");
statement = "select_serial_by_table_purse_deletion";
break;
case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_COMMITMENTS:
XPREPARE ("select_serial_by_table_withdraw_age_commitments",
"SELECT"
" withdraw_age_commitment_id AS serial"
" FROM withdraw_age_commitments"
" ORDER BY withdraw_age_commitment_id DESC"
" LIMIT 1;");
statement = "select_serial_by_table_withdraw_age_commitments";
break;
case TALER_EXCHANGEDB_RT_WITHDRAW_AGE_REVEALED_COINS:
XPREPARE ("select_serial_by_table_withdraw_age_revealed_coins",
"SELECT"
" withdraw_age_revealed_coins_id AS serial"
" FROM withdraw_age_revealed_coins"
" ORDER BY withdraw_age_revealed_coins_id DESC"
" LIMIT 1;");
statement = "select_serial_by_table_withdraw_age_revealed_coins";
break;
} }
if (NULL == statement) if (NULL == statement)
{ {

View File

@ -62,4 +62,3 @@ TEH_PG_lookup_signing_key (
params, params,
rs); rs);
} }

View File

@ -47,9 +47,3 @@ TEH_PG_profit_drains_set_finished (
"drain_profit_set_finished", "drain_profit_set_finished",
params); params);
} }

File diff suppressed because it is too large Load Diff

View File

@ -26,8 +26,6 @@
#include "pg_helper.h" #include "pg_helper.h"
/** /**
* Closure for #get_kyc_amounts_cb(). * Closure for #get_kyc_amounts_cb().
*/ */
@ -112,7 +110,6 @@ get_kyc_amounts_cb (void *cls,
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_select_aggregation_amounts_for_kyc_check ( TEH_PG_select_aggregation_amounts_for_kyc_check (
void *cls, void *cls,

View File

@ -44,4 +44,5 @@ TEH_PG_select_aggregation_amounts_for_kyc_check (
struct GNUNET_TIME_Absolute time_limit, struct GNUNET_TIME_Absolute time_limit,
TALER_EXCHANGEDB_KycAmountCallback kac, TALER_EXCHANGEDB_KycAmountCallback kac,
void *kac_cls); void *kac_cls);
#endif #endif

View File

@ -56,6 +56,7 @@ TEH_PG_select_aml_threshold (
"SELECT" "SELECT"
" threshold_val" " threshold_val"
",threshold_frac" ",threshold_frac"
",status"
",kyc_requirement" ",kyc_requirement"
" FROM aml_status" " FROM aml_status"
" WHERE h_payto=$1;"); " WHERE h_payto=$1;");

View File

@ -64,4 +64,3 @@ TEH_PG_select_auditor_denom_sig (
params, params,
rs); rs);
} }

View File

@ -164,7 +164,6 @@ TEH_PG_select_deposits_missing_wire (void *cls,
" ORDER BY wire_deadline ASC"); " ORDER BY wire_deadline ASC");
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"deposits_get_overdue", "deposits_get_overdue",
params, params,

View File

@ -113,8 +113,6 @@ history_request_serial_helper_cb (void *cls,
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_select_history_requests_above_serial_id ( TEH_PG_select_history_requests_above_serial_id (
void *cls, void *cls,

View File

@ -26,7 +26,6 @@
#include "pg_helper.h" #include "pg_helper.h"
/** /**
* Closure for #get_kyc_amounts_cb(). * Closure for #get_kyc_amounts_cb().
*/ */
@ -157,4 +156,3 @@ TEH_PG_select_merge_amounts_for_kyc_check (
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
return qs; return qs;
} }

View File

@ -112,7 +112,6 @@ purse_decision_serial_helper_cb (void *cls,
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_select_purse_decisions_above_serial_id ( TEH_PG_select_purse_decisions_above_serial_id (
void *cls, void *cls,

View File

@ -43,4 +43,5 @@ TEH_PG_select_purse_decisions_above_serial_id (
bool refunded, bool refunded,
TALER_EXCHANGEDB_PurseDecisionCallback cb, TALER_EXCHANGEDB_PurseDecisionCallback cb,
void *cb_cls); void *cb_cls);
#endif #endif

View File

@ -26,7 +26,6 @@
#include "pg_helper.h" #include "pg_helper.h"
/** /**
* Closure for #recoup_serial_helper_cb(). * Closure for #recoup_serial_helper_cb().
*/ */
@ -137,6 +136,7 @@ recoup_serial_helper_cb (void *cls,
} }
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_select_recoup_above_serial_id ( TEH_PG_select_recoup_above_serial_id (
void *cls, void *cls,

View File

@ -141,7 +141,6 @@ recoup_refresh_serial_helper_cb (void *cls,
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_select_recoup_refresh_above_serial_id ( TEH_PG_select_recoup_refresh_above_serial_id (
void *cls, void *cls,

View File

@ -130,10 +130,6 @@ refreshs_serial_helper_cb (void *cls,
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_select_refreshes_above_serial_id ( TEH_PG_select_refreshes_above_serial_id (
void *cls, void *cls,

View File

@ -44,4 +44,5 @@ TEH_PG_select_refunds_by_coin (
const struct TALER_PrivateContractHashP *h_contract, const struct TALER_PrivateContractHashP *h_contract,
TALER_EXCHANGEDB_RefundCoinCallback cb, TALER_EXCHANGEDB_RefundCoinCallback cb,
void *cb_cls); void *cb_cls);
#endif #endif

View File

@ -113,7 +113,6 @@ wire_out_serial_helper_cb (void *cls,
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_select_wire_out_above_serial_id ( TEH_PG_select_wire_out_above_serial_id (
void *cls, void *cls,

View File

@ -112,6 +112,7 @@ wire_out_serial_helper_cb (void *cls,
} }
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_select_wire_out_above_serial_id_by_account ( TEH_PG_select_wire_out_above_serial_id_by_account (
void *cls, void *cls,

View File

@ -43,4 +43,5 @@ TEH_PG_select_wire_out_above_serial_id_by_account (
uint64_t serial_id, uint64_t serial_id,
TALER_EXCHANGEDB_WireTransferOutCallback cb, TALER_EXCHANGEDB_WireTransferOutCallback cb,
void *cb_cls); void *cb_cls);
#endif #endif

View File

@ -44,4 +44,5 @@ TEH_PG_select_withdraw_amounts_for_kyc_check (
struct GNUNET_TIME_Absolute time_limit, struct GNUNET_TIME_Absolute time_limit,
TALER_EXCHANGEDB_KycAmountCallback kac, TALER_EXCHANGEDB_KycAmountCallback kac,
void *kac_cls); void *kac_cls);
#endif #endif

View File

@ -121,7 +121,6 @@ reserves_out_serial_helper_cb (void *cls,
} }
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_select_withdrawals_above_serial_id ( TEH_PG_select_withdrawals_above_serial_id (
void *cls, void *cls,

View File

@ -41,4 +41,5 @@ TEH_PG_select_withdrawals_above_serial_id (
uint64_t serial_id, uint64_t serial_id,
TALER_EXCHANGEDB_WithdrawCallback cb, TALER_EXCHANGEDB_WithdrawCallback cb,
void *cb_cls); void *cb_cls);
#endif #endif

View File

@ -50,6 +50,3 @@ TEH_PG_set_purse_balance (
"set_purse_balance", "set_purse_balance",
params); params);
} }

View File

@ -26,7 +26,6 @@
#include "pg_helper.h" #include "pg_helper.h"
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_update_aggregation_transient ( TEH_PG_update_aggregation_transient (
void *cls, void *cls,

View File

@ -42,4 +42,5 @@ TEH_PG_wire_prepare_data_get (void *cls,
uint64_t limit, uint64_t limit,
TALER_EXCHANGEDB_WirePreparationIterator cb, TALER_EXCHANGEDB_WirePreparationIterator cb,
void *cb_cls); void *cb_cls);
#endif #endif

View File

@ -39,4 +39,5 @@ TEH_PG_wire_prepare_data_insert (void *cls,
const char *type, const char *type,
const char *buf, const char *buf,
size_t buf_size); size_t buf_size);
#endif #endif

View File

@ -36,4 +36,5 @@ enum GNUNET_DB_QueryStatus
TEH_PG_wire_prepare_data_mark_failed ( TEH_PG_wire_prepare_data_mark_failed (
void *cls, void *cls,
uint64_t rowid); uint64_t rowid);
#endif #endif

View File

@ -36,4 +36,5 @@ enum GNUNET_DB_QueryStatus
TEH_PG_wire_prepare_data_mark_finished ( TEH_PG_wire_prepare_data_mark_finished (
void *cls, void *cls,
uint64_t rowid); uint64_t rowid);
#endif #endif

View File

@ -21,6 +21,7 @@
* @author Christian Grothoff * @author Christian Grothoff
* @author Sree Harsha Totakura * @author Sree Harsha Totakura
* @author Marcello Stanisci * @author Marcello Stanisci
* @author Özgür Kesim
*/ */
#include "platform.h" #include "platform.h"
#include <poll.h> #include <poll.h>
@ -216,7 +217,7 @@
#include "pg_select_aml_process.h" #include "pg_select_aml_process.h"
#include "pg_select_aml_history.h" #include "pg_select_aml_history.h"
#include "pg_insert_aml_decision.h" #include "pg_insert_aml_decision.h"
#include "pg_batch_ensure_coin_known.h"
/** /**
* Set to 1 to enable Postgres auto_explain module. This will * Set to 1 to enable Postgres auto_explain module. This will
@ -773,6 +774,10 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_select_aml_history; = &TEH_PG_select_aml_history;
plugin->insert_aml_decision plugin->insert_aml_decision
= &TEH_PG_insert_aml_decision; = &TEH_PG_insert_aml_decision;
plugin->batch_ensure_coin_known
= &TEH_PG_batch_ensure_coin_known;
return plugin; return plugin;
} }

View File

@ -39,13 +39,11 @@ SET search_path TO exchange;
#include "exchange_do_insert_or_update_policy_details.sql" #include "exchange_do_insert_or_update_policy_details.sql"
#include "exchange_do_insert_aml_decision.sql" #include "exchange_do_insert_aml_decision.sql"
#include "exchange_do_insert_aml_officer.sql" #include "exchange_do_insert_aml_officer.sql"
#include "exchange_do_batch_reserves_in_insert.sql" #include "exchange_do_reserves_in_insert.sql"
#include "exchange_do_batch_reserves_update.sql" #include "exchange_do_batch_reserves_update.sql"
#include "exchange_do_batch2_reserves_in_insert.sql"
#include "exchange_do_batch4_reserves_in_insert.sql"
#include "exchange_do_batch8_reserves_in_insert.sql"
#include "exchange_do_refund_by_coin.sql" #include "exchange_do_refund_by_coin.sql"
#include "exchange_do_get_ready_deposit.sql" #include "exchange_do_get_ready_deposit.sql"
#include "exchange_do_get_link_data.sql" #include "exchange_do_get_link_data.sql"
#include "exchange_do_batch_coin_known.sql"
COMMIT; COMMIT;

View File

@ -0,0 +1,9 @@
EXTENSION = own_test
MODULES = own_test
DATA = own_test.sql
PG_CPPFLAGS = -I /usr/include/postgresql
# postgresql build stuff
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)

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