diff --git a/contrib/gana b/contrib/gana index 59de2acb7..bf43b20a0 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 59de2acb7c716c816ed15786b5369e56c325770c +Subproject commit bf43b20a0362ac19bcf1bab9c33215e55d8d9f36 diff --git a/contrib/microhttpd.tag b/contrib/microhttpd.tag index d80405036..5156a1a3a 100644 --- a/contrib/microhttpd.tag +++ b/contrib/microhttpd.tag @@ -46,6 +46,12 @@ microhttpd.h + + #define + MHD_HTTP_CONTENT_TOO_LARGE + microhttpd.h + + #define MHD_HTTP_REQUEST_TIMEOUT diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index 76e4db70a..60492e50f 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c @@ -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. */ @@ -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. * @@ -1583,15 +1718,14 @@ handle_mhd_completion_callback (void *cls, enum MHD_RequestTerminationCode toe) { /* struct TALER_FAKEBANK_Handle *h = cls; */ + struct ConnectionContext *cc = *con_cls; (void) cls; (void) connection; (void) toe; - if (NULL == *con_cls) + if (NULL == cc) return; - if (&special_ptr == *con_cls) - return; - GNUNET_JSON_post_parser_cleanup (*con_cls); - *con_cls = NULL; + cc->ctx_cleaner (cc->ctx); + GNUNET_free (cc); } @@ -1603,7 +1737,7 @@ handle_mhd_completion_callback (void *cls, * @param account account into which to deposit the funds (credit) * @param upload_data request data * @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 */ static MHD_RESULT @@ -1614,14 +1748,21 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h, size_t *upload_data_size, void **con_cls) { + struct ConnectionContext *cc = *con_cls; enum GNUNET_JSON_PostResult pr; json_t *json; uint64_t row_id; 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, connection, - con_cls, + &cc->ctx, upload_data, upload_data_size, &json); @@ -1736,7 +1877,7 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h, * @param account account making the transfer * @param upload_data request data * @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 */ static MHD_RESULT @@ -1747,14 +1888,21 @@ handle_transfer (struct TALER_FAKEBANK_Handle *h, size_t *upload_data_size, void **con_cls) { + struct ConnectionContext *cc = *con_cls; enum GNUNET_JSON_PostResult pr; json_t *json; uint64_t row_id; 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, connection, - con_cls, + &cc->ctx, upload_data, upload_data_size, &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: * /history/incoming and /history/outgoing. @@ -2176,7 +2288,7 @@ start_lp (struct TALER_FAKEBANK_Handle *h, * @param h the fakebank handle * @param connection the connection * @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 handle_debit_history (struct TALER_FAKEBANK_Handle *h, @@ -2184,87 +2296,106 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, const char *account, void **con_cls) { - struct HistoryArgs ha; - struct Account *acc; + struct ConnectionContext *cc = *con_cls; + struct HistoryContext *hc; struct Transaction *pos; - json_t *history; - char *debit_payto; enum GNUNET_GenericReturnValue ret; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Handling /history/outgoing connection %p\n", - connection); - if (GNUNET_OK != - (ret = parse_history_common_args (h, - connection, - &ha))) + if (NULL == cc) { - GNUNET_break_op (0); - return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; - } - if (&special_ptr == *con_cls) - ha.lp_timeout = GNUNET_TIME_UNIT_ZERO; - acc = lookup_account (h, - account, - NULL); - if (NULL == acc) - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_BANK_UNKNOWN_ACCOUNT, - account); - } - GNUNET_asprintf (&debit_payto, - "payto://x-taler-bank/localhost/%s?receiver-name=%s", - account, - acc->receiver_name); - history = json_array (); - if (NULL == history) - { - GNUNET_break (0); - GNUNET_free (debit_payto); - return MHD_NO; - } - GNUNET_assert (0 == - pthread_mutex_lock (&h->big_lock)); - if (! ha.have_start) - { - pos = (0 > ha.delta) - ? acc->out_tail - : acc->out_head; + 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, + "Handling /history/outgoing connection %p\n", + connection); + if (GNUNET_OK != + (ret = parse_history_common_args (h, + connection, + &hc->ha))) + { + GNUNET_break_op (0); + return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; + } + GNUNET_assert (0 == + pthread_mutex_lock (&h->big_lock)); + hc->acc = lookup_account (h, + account, + NULL); + if (NULL == hc->acc) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_BANK_UNKNOWN_ACCOUNT, + account); + } + GNUNET_asprintf (&hc->payto_uri, + "payto://x-taler-bank/localhost/%s?receiver-name=%s", + account, + hc->acc->receiver_name); + /* New invariant: */ + GNUNET_assert (0 == strcmp (hc->payto_uri, + hc->acc->payto_uri)); + hc->history = json_array (); + if (NULL == hc->history) + { + GNUNET_break (0); + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return MHD_NO; + } + hc->timeout = GNUNET_TIME_relative_to_absolute (hc->ha.lp_timeout); } 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; uint64_t dir; bool skip = true; - dir = (0 > ha.delta) ? (h->ram_limit - 1) : 1; - overflow = (t->row_id != ha.start_idx); + dir = (0 > hc->ha.delta) ? (h->ram_limit - 1) : 1; + overflow = (t->row_id != hc->ha.start_idx); /* If account does not match, linear scan for first matching account. */ while ( (! overflow) && - (NULL != t) && - (t->debit_account != acc) ) + (NULL != t) && + (t->debit_account != hc->acc) ) { skip = false; t = h->transactions[(t->row_id + dir) % h->ram_limit]; if ( (NULL != t) && - (t->row_id == ha.start_idx) ) + (t->row_id == hc->ha.start_idx) ) overflow = true; /* full circle, give up! */ } if ( (NULL == t) || overflow) { - if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) && - (0 < ha.delta)) + /* FIXME: these conditions are unclear to me. */ + if ( (GNUNET_TIME_relative_is_zero (hc->ha.lp_timeout)) && + (0 < hc->ha.delta)) { GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); if (overflow) { - GNUNET_free (debit_payto); return TALER_MHD_reply_with_ec ( connection, TALER_EC_BANK_ANCIENT_TRANSACTION_GONE, @@ -2272,35 +2403,36 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, } goto finish; } - *con_cls = &special_ptr; + if (h->in_shutdown) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + goto finish; + } start_lp (h, connection, - acc, - ha.lp_timeout, + hc->acc, + GNUNET_TIME_absolute_get_remaining (hc->timeout), LP_DEBIT, NULL); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); - json_decref (history); - GNUNET_free (debit_payto); return MHD_YES; } - if (t->debit_account != acc) + if (t->debit_account != hc->acc) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid start specified, transaction %llu not with account %s!\n", - (unsigned long long) ha.start_idx, + (unsigned long long) hc->ha.start_idx, account); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); - GNUNET_free (debit_payto); - json_decref (history); return MHD_NO; } if (skip) { /* range is exclusive, skip the matching entry */ - if (0 > ha.delta) + if (0 > hc->ha.delta) pos = t->prev_out; else pos = t->next_out; @@ -2313,9 +2445,9 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, if (NULL != pos) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Returning %lld debit transactions starting (inclusive) from %llu\n", - (long long) ha.delta, + (long long) hc->ha.delta, (unsigned long long) pos->row_id); - while ( (0 != ha.delta) && + while ( (0 != hc->ha.delta) && (NULL != pos) ) { json_t *trans; @@ -2327,9 +2459,9 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, "Unexpected CREDIT transaction #%llu for account `%s'\n", (unsigned long long) pos->row_id, account); - if (0 > ha.delta) + if (0 > hc->ha.delta) pos = pos->prev_in; - if (0 < ha.delta) + if (0 < hc->ha.delta) pos = pos->next_in; continue; } @@ -2348,7 +2480,7 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, GNUNET_JSON_pack_string ("credit_account", credit_payto), 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", pos->subject.debit.exchange_base_url), GNUNET_JSON_pack_data_auto ("wtid", @@ -2356,51 +2488,55 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, GNUNET_assert (NULL != trans); GNUNET_free (credit_payto); GNUNET_assert (0 == - json_array_append_new (history, + json_array_append_new (hc->history, trans)); - if (ha.delta > 0) - ha.delta--; + if (hc->ha.delta > 0) + hc->ha.delta--; else - ha.delta++; - if (0 > ha.delta) + hc->ha.delta++; + if (0 > hc->ha.delta) pos = pos->prev_out; - if (0 < ha.delta) + if (0 < hc->ha.delta) pos = pos->next_out; } - if ( (0 == json_array_size (history)) && - (! GNUNET_TIME_relative_is_zero (ha.lp_timeout)) && - (0 < ha.delta)) + if ( (0 == json_array_size (hc->history)) && + (! h->in_shutdown) && + (GNUNET_TIME_absolute_is_future (hc->timeout)) && + (0 < hc->ha.delta)) { - *con_cls = &special_ptr; start_lp (h, connection, - acc, - ha.lp_timeout, + hc->acc, + GNUNET_TIME_absolute_get_remaining (hc->timeout), LP_DEBIT, NULL); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); - json_decref (history); return MHD_YES; } GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); 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, MHD_HTTP_NO_CONTENT, NULL, NULL, 0); } - GNUNET_free (debit_payto); - return TALER_MHD_REPLY_JSON_PACK (connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_array_steal ( - "outgoing_transactions", - history)); + { + json_t *h = hc->history; + + hc->history = NULL; + return TALER_MHD_REPLY_JSON_PACK (connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ( + "outgoing_transactions", + h)); + } } @@ -2419,77 +2555,101 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, const char *account, void **con_cls) { - struct HistoryArgs ha; - struct Account *acc; + struct ConnectionContext *cc = *con_cls; + struct HistoryContext *hc; const struct Transaction *pos; - json_t *history; - const char *credit_payto; enum GNUNET_GenericReturnValue ret; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Handling /history/incoming connection %p (%d)\n", - connection, - (*con_cls == &special_ptr)); - if (GNUNET_OK != - (ret = parse_history_common_args (h, - connection, - &ha))) + if (NULL == cc) { - GNUNET_break_op (0); - return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; - } - if (&special_ptr == *con_cls) - ha.lp_timeout = GNUNET_TIME_UNIT_ZERO; - *con_cls = &special_ptr; - acc = lookup_account (h, - account, - NULL); - if (NULL == acc) - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_BANK_UNKNOWN_ACCOUNT, - account); - } - history = json_array (); - GNUNET_assert (NULL != history); - credit_payto = acc->payto_uri; - GNUNET_assert (0 == - pthread_mutex_lock (&h->big_lock)); - if (! ha.have_start) - { - pos = (0 > ha.delta) - ? acc->in_tail - : acc->in_head; + 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, + "Handling /history/incoming connection %p\n", + connection); + if (GNUNET_OK != + (ret = parse_history_common_args (h, + connection, + &hc->ha))) + { + GNUNET_break_op (0); + return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; + } + GNUNET_assert (0 == + pthread_mutex_lock (&h->big_lock)); + hc->acc = lookup_account (h, + account, + NULL); + if (NULL == hc->acc) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_BANK_UNKNOWN_ACCOUNT, + account); + } + /* FIXME: was simply: acc->payto_uri -- same!? */ + GNUNET_asprintf (&hc->payto_uri, + "payto://x-taler-bank/localhost/%s?receiver-name=%s", + account, + hc->acc->receiver_name); + GNUNET_assert (0 == strcmp (hc->payto_uri, + hc->acc->payto_uri)); + hc->history = json_array (); + if (NULL == hc->history) + { + GNUNET_break (0); + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return MHD_NO; + } + hc->timeout = GNUNET_TIME_relative_to_absolute (hc->ha.lp_timeout); } 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; uint64_t dir; bool skip = true; - overflow = ( (NULL != t) && (t->row_id != ha.start_idx) ); - dir = (0 > ha.delta) ? (h->ram_limit - 1) : 1; + overflow = ( (NULL != t) && (t->row_id != hc->ha.start_idx) ); + dir = (0 > hc->ha.delta) ? (h->ram_limit - 1) : 1; /* If account does not match, linear scan for first matching account. */ while ( (! overflow) && (NULL != t) && - (t->credit_account != acc) ) + (t->credit_account != hc->acc) ) { skip = false; t = h->transactions[(t->row_id + dir) % h->ram_limit]; if ( (NULL != t) && - (t->row_id == ha.start_idx) ) + (t->row_id == hc->ha.start_idx) ) overflow = true; /* full circle, give up! */ } if ( (NULL == t) || overflow) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "No transactions available, suspending request\n"); - if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) && - (0 < ha.delta)) + /* FIXME: these conditions are unclear to me. */ + if (GNUNET_TIME_relative_is_zero (hc->ha.lp_timeout) && + (0 < hc->ha.delta)) { GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); @@ -2500,23 +2660,27 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, NULL); goto finish; } - *con_cls = &special_ptr; + if (h->in_shutdown) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + goto finish; + } start_lp (h, connection, - acc, - ha.lp_timeout, + hc->acc, + GNUNET_TIME_absolute_get_remaining (hc->timeout), LP_CREDIT, NULL); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); - json_decref (history); return MHD_YES; } if (skip) { /* range from application is exclusive, skip the matching entry */ - if (0 > ha.delta) + if (0 > hc->ha.delta) pos = t->prev_in; else pos = t->next_in; @@ -2529,9 +2693,9 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, if (NULL != pos) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Returning %lld credit transactions starting (inclusive) from %llu\n", - (long long) ha.delta, + (long long) hc->ha.delta, (unsigned long long) pos->row_id); - while ( (0 != ha.delta) && + while ( (0 != hc->ha.delta) && (NULL != pos) ) { json_t *trans; @@ -2542,9 +2706,9 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, "Unexpected DEBIT transaction #%llu for account `%s'\n", (unsigned long long) pos->row_id, account); - if (0 > ha.delta) + if (0 > hc->ha.delta) pos = pos->prev_in; - if (0 < ha.delta) + if (0 < hc->ha.delta) pos = pos->next_in; continue; } @@ -2556,57 +2720,62 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, TALER_JSON_pack_amount ("amount", &pos->amount), 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", pos->debit_account->payto_uri), GNUNET_JSON_pack_data_auto ("reserve_pub", &pos->subject.credit.reserve_pub)); GNUNET_assert (NULL != trans); GNUNET_assert (0 == - json_array_append_new (history, + json_array_append_new (hc->history, trans)); - if (ha.delta > 0) - ha.delta--; + if (hc->ha.delta > 0) + hc->ha.delta--; else - ha.delta++; - if (0 > ha.delta) + hc->ha.delta++; + if (0 > hc->ha.delta) pos = pos->prev_in; - if (0 < ha.delta) + if (0 < hc->ha.delta) pos = pos->next_in; } - if ( (0 == json_array_size (history)) && - (! GNUNET_TIME_relative_is_zero (ha.lp_timeout)) && - (0 < ha.delta)) + if ( (0 == json_array_size (hc->history)) && + (! h->in_shutdown) && + (GNUNET_TIME_absolute_is_future (hc->timeout)) && + (0 < hc->ha.delta)) { - *con_cls = &special_ptr; start_lp (h, connection, - acc, - ha.lp_timeout, + hc->acc, + GNUNET_TIME_absolute_get_remaining (hc->timeout), LP_CREDIT, NULL); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); - json_decref (history); return MHD_YES; } GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); 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, MHD_HTTP_NO_CONTENT, NULL, NULL, 0); } - return TALER_MHD_REPLY_JSON_PACK (connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_array_steal ( - "incoming_transactions", - history)); + { + json_t *h = hc->history; + + hc->history = NULL; + return TALER_MHD_REPLY_JSON_PACK (connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ( + "incoming_transactions", + h)); + } } @@ -2711,25 +2880,39 @@ get_withdrawal_operation (struct TALER_FAKEBANK_Handle *h, struct GNUNET_TIME_Relative lp, void **con_cls) { - struct WithdrawalOperation *wo; + struct ConnectionContext *cc = *con_cls; + struct WithdrawContext *wc; GNUNET_assert (0 == pthread_mutex_lock (&h->big_lock)); - wo = lookup_withdrawal_operation (h, - wopid); - if (NULL == wo) + if (NULL == cc) { - GNUNET_assert (0 == - pthread_mutex_unlock (&h->big_lock)); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_BANK_TRANSACTION_NOT_FOUND, - wopid); + 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); + if (NULL == wc->wo) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_BANK_TRANSACTION_NOT_FOUND, + wopid); + } + wc->timeout = GNUNET_TIME_relative_to_absolute (lp); } - if ( (NULL != *con_cls) || - (GNUNET_TIME_relative_is_zero (lp)) || - wo->confirmation_done || - wo->aborted) + else + { + wc = cc->ctx; + } + if (GNUNET_TIME_absolute_is_past (wc->timeout) || + h->in_shutdown || + wc->wo->confirmation_done || + wc->wo->aborted) { json_t *wt; @@ -2744,27 +2927,26 @@ get_withdrawal_operation (struct TALER_FAKEBANK_Handle *h, connection, MHD_HTTP_OK, GNUNET_JSON_pack_bool ("aborted", - wo->aborted), + wc->wo->aborted), GNUNET_JSON_pack_bool ("selection_done", - wo->selection_done), + wc->wo->selection_done), GNUNET_JSON_pack_bool ("transfer_done", - wo->confirmation_done), + wc->wo->confirmation_done), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_string ("suggested_exchange", h->exchange_url)), TALER_JSON_pack_amount ("amount", - &wo->amount), + &wc->wo->amount), GNUNET_JSON_pack_array_steal ("wire_types", wt)); } - *con_cls = &special_ptr; start_lp (h, connection, - wo->debit_account, - lp, + wc->wo->debit_account, + GNUNET_TIME_absolute_get_remaining (wc->timeout), LP_WITHDRAW, - wo); + wc->wo); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); return MHD_YES; @@ -2903,13 +3085,20 @@ post_withdrawal_operation (struct TALER_FAKEBANK_Handle *h, size_t *upload_data_size, void **con_cls) { + struct ConnectionContext *cc = *con_cls; enum GNUNET_JSON_PostResult pr; json_t *json; 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, connection, - con_cls, + &cc->ctx, upload_data, upload_data_size, &json); @@ -3294,13 +3483,20 @@ post_account_withdrawals_access (struct TALER_FAKEBANK_Handle *h, size_t *upload_data_size, void **con_cls) { + struct ConnectionContext *cc = *con_cls; enum GNUNET_JSON_PostResult pr; json_t *json; 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, connection, - con_cls, + &cc->ctx, upload_data, upload_data_size, &json); @@ -3367,13 +3563,20 @@ post_testing_register (struct TALER_FAKEBANK_Handle *h, size_t *upload_data_size, void **con_cls) { + struct ConnectionContext *cc = *con_cls; enum GNUNET_JSON_PostResult pr; json_t *json; 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, connection, - con_cls, + &cc->ctx, upload_data, upload_data_size, &json); diff --git a/src/benchmark/bank-benchmark-cs.conf b/src/benchmark/bank-benchmark-cs.conf index d012f0faa..e32370f89 100644 --- a/src/benchmark/bank-benchmark-cs.conf +++ b/src/benchmark/bank-benchmark-cs.conf @@ -28,7 +28,7 @@ DB = postgres # exchange (or the twister) is actually listening. base_url = "http://localhost:8081/" -WIREWATCH_IDLE_SLEEP_INTERVAL = 1500 ms +WIREWATCH_IDLE_SLEEP_INTERVAL = 500 ms [exchange-offline] 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 [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] # 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_credit = YES diff --git a/src/benchmark/taler-bank-benchmark.c b/src/benchmark/taler-bank-benchmark.c index b17bb9411..584df4896 100644 --- a/src/benchmark/taler-bank-benchmark.c +++ b/src/benchmark/taler-bank-benchmark.c @@ -689,6 +689,8 @@ parallel_benchmark (void) } /* 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, NULL, NULL, NULL, "taler-exchange-wirewatch", diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 77ef94ebc..fd7553813 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -1,6 +1,6 @@ /* 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 under the terms of the GNU Affero General Public License as diff --git a/src/exchange/exchange.conf b/src/exchange/exchange.conf index 750e71724..38e5816ff 100644 --- a/src/exchange/exchange.conf +++ b/src/exchange/exchange.conf @@ -19,7 +19,7 @@ MAX_KEYS_CACHING = forever # After how many requests should the exchange auto-restart # (to address potential issues with memory fragmentation)? # If this option is not specified, auto-restarting is disabled. -# MAX_REQUESTS = 10000000 +# MAX_REQUESTS = 100000 # How to access our database DB = postgres diff --git a/src/exchange/taler-exchange-httpd_age-withdraw.c b/src/exchange/taler-exchange-httpd_age-withdraw.c index 170cd06a5..0978421a4 100644 --- a/src/exchange/taler-exchange-httpd_age-withdraw.c +++ b/src/exchange/taler-exchange-httpd_age-withdraw.c @@ -222,7 +222,6 @@ age_withdraw_transaction (void *cls, awc->kyc.ok = true; qs = TEH_plugin->do_age_withdraw (TEH_plugin->cls, &awc->commitment, - awc->now, &found, &balance_ok, &ruuid); @@ -312,7 +311,7 @@ TEH_handler_age_withdraw (struct TEH_RequestContext *rc, const json_t *root) { MHD_RESULT mhd_ret; - struct AgeWithdrawContext awc; + struct AgeWithdrawContext awc = {0}; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("reserve_sig", &awc.commitment.reserve_sig), @@ -321,12 +320,11 @@ TEH_handler_age_withdraw (struct TEH_RequestContext *rc, TALER_JSON_spec_amount ("amount", TEH_currency, &awc.commitment.amount_with_fee), - GNUNET_JSON_spec_uint32 ("max_age", + GNUNET_JSON_spec_uint16 ("max_age", &awc.commitment.max_age), GNUNET_JSON_spec_end () }; - memset (&awc, 0, sizeof (awc)); awc.commitment.reserve_pub = *reserve_pub; diff --git a/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c b/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c index 1bf87342f..a1ae3a6b0 100644 --- a/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c +++ b/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c @@ -347,6 +347,15 @@ find_original_commitment ( NULL); 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: GNUNET_break (0); *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 */ - for (size_t idx = 0; idx<3; idx++) + for (size_t idx = 0; idx j); + GNUNET_assert ((TALER_CNC_KAPPA - 1) * num_coins > j); secret = &disclosed_coin_secrets[j]; k++; @@ -666,7 +676,6 @@ verify_commitment_and_max_age ( { struct TALER_CoinPubHashP c_hash; struct TALER_PlanchetDetail detail; - struct TALER_BlindedCoinHashP bch; struct TALER_CoinSpendPrivateKeyP coin_priv; union TALER_DenominationBlindingKeyP bks; struct TALER_ExchangeWithdrawValues alg_values = { @@ -688,19 +697,12 @@ verify_commitment_and_max_age ( .nonce = &nonce, }; - ec = TEH_keys_denomination_cs_r_pub ( - &cdd, - false, - &alg_values.details.cs_values); - - if (TALER_EC_NONE != ec) - { - GNUNET_break_op (0); - *result = TALER_MHD_reply_with_ec (connection, - ec, - NULL); - return GNUNET_SYSERR; - } + ec = TEH_keys_denomination_cs_r_pub (&cdd, + false, + &alg_values.details. + cs_values); + /* FIXME Handle error? */ + GNUNET_assert (TALER_EC_NONE == ec); } } @@ -749,10 +751,13 @@ verify_commitment_and_max_age ( 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 - * the blinded coins + * @brief Signs and persists the undisclosed coins * - * @param connection The HTTP-connection to the client - * @param h_commitment_orig The commitment from the age-withdraw request - * @param num_coins The number of coins (and also denominations) - * @param coin_evs The blinded planchets of the coins - * @param denom_keys The corresponding denominations + * @param connection HTTP-connection to the client + * @param h_commitment_orig Original commitment + * @param num_coins Number of coins + * @param coin_evs The Hashes of the undisclosed, blinded coins, @a num_coins many + * @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 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ -enum GNUNET_GenericReturnValue -finalize_withdraw_and_sign ( +static enum GNUNET_GenericReturnValue +sign_and_persist_blinded_coins ( struct MHD_Connection *connection, - const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, + const struct TALER_AgeWithdrawCommitmentHashP *h_commitment_orig, const uint32_t num_coins, const struct TALER_BlindedPlanchet *coin_evs, const struct TEH_DenominationKey *denom_keys, MHD_RESULT *result) { enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; - struct TEH_CoinSignData csds[num_coins]; - struct TALER_BlindedDenominationSignature bss[num_coins]; - - for (uint32_t i = 0; iconnection, &actx.commitment.h_commitment, actx.num_coins, diff --git a/src/exchange/taler-exchange-httpd_batch-withdraw.c b/src/exchange/taler-exchange-httpd_batch-withdraw.c index 6cd467d51..c3065e1df 100644 --- a/src/exchange/taler-exchange-httpd_batch-withdraw.c +++ b/src/exchange/taler-exchange-httpd_batch-withdraw.c @@ -77,6 +77,11 @@ struct BatchWithdrawContext */ const struct TALER_ReservePublicKeyP *reserve_pub; + /** + * request context + */ + const struct TEH_RequestContext *rc; + /** * 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; iplanchets_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; iplanchets_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 * 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) || (conflict) ) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Idempotent coin in batch, not allowed. Aborting.\n"); - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_CONFLICT, - TALER_EC_EXCHANGE_WITHDRAW_BATCH_IDEMPOTENT_PLANCHET, - NULL); + 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, + "Idempotent coin in batch, not allowed. Aborting.\n"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_CONFLICT, + TALER_EC_EXCHANGE_WITHDRAW_BATCH_IDEMPOTENT_PLANCHET, + NULL); + } return GNUNET_DB_STATUS_HARD_ERROR; } 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; iplanchets_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; iplanchets_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 * our side for the main DB transaction. @@ -691,8 +702,7 @@ parse_planchets (const struct TEH_RequestContext *rc, ksh = TEH_keys_get_state (); if (NULL == ksh) { - if (! check_request_idempotent (rc, - wc, + if (! check_request_idempotent (wc, &mret)) { return TALER_MHD_reply_with_error (rc->connection, @@ -713,8 +723,7 @@ parse_planchets (const struct TEH_RequestContext *rc, NULL); if (NULL == dk) { - if (! check_request_idempotent (rc, - wc, + if (! check_request_idempotent (wc, &mret)) { 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)) { /* This denomination is past the expiration time for withdraws */ - if (! check_request_idempotent (rc, - wc, + if (! check_request_idempotent (wc, &mret)) { return TEH_RESPONSE_reply_expired_denom_pub_hash ( @@ -751,8 +759,7 @@ parse_planchets (const struct TEH_RequestContext *rc, if (dk->recoup_possible) { /* This denomination has been revoked */ - if (! check_request_idempotent (rc, - wc, + if (! check_request_idempotent (wc, &mret)) { 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 json_t *root) { - struct BatchWithdrawContext wc; + struct BatchWithdrawContext wc = { + .reserve_pub = reserve_pub, + .rc = rc + }; json_t *planchets; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_json ("planchets", @@ -840,13 +850,9 @@ TEH_handler_batch_withdraw (struct TEH_RequestContext *rc, GNUNET_JSON_spec_end () }; - memset (&wc, - 0, - sizeof (wc)); GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (TEH_currency, &wc.batch_total)); - wc.reserve_pub = reserve_pub; { enum GNUNET_GenericReturnValue res; diff --git a/src/exchange/taler-exchange-httpd_kyc-check.c b/src/exchange/taler-exchange-httpd_kyc-check.c index c88859268..bf4e4dea1 100644 --- a/src/exchange/taler-exchange-httpd_kyc-check.c +++ b/src/exchange/taler-exchange-httpd_kyc-check.c @@ -112,6 +112,11 @@ struct KycPoller */ 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. */ @@ -303,6 +308,7 @@ kyc_check (void *cls, TEH_plugin->cls, kyp->requirement_row, &requirements, + &kyp->aml_status, &h_payto); if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { @@ -580,6 +586,17 @@ TEH_handler_kyc_check ( if ( (NULL == kyp->ih) && (! 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 */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "KYC not required %llu\n", @@ -628,6 +645,8 @@ TEH_handler_kyc_check ( return TALER_MHD_REPLY_JSON_PACK ( rc->connection, MHD_HTTP_ACCEPTED, + GNUNET_JSON_pack_uint64 ("aml_status", + kyp->aml_status), GNUNET_JSON_pack_string ("kyc_url", kyp->kyc_url)); } @@ -665,6 +684,8 @@ TEH_handler_kyc_check ( &sig), GNUNET_JSON_pack_data_auto ("exchange_pub", &pub), + GNUNET_JSON_pack_uint64 ("aml_status", + kyp->aml_status), GNUNET_JSON_pack_object_incref ("kyc_details", kyp->kyc_details), GNUNET_JSON_pack_timestamp ("now", diff --git a/src/exchange/taler-exchange-httpd_reserves_get.c b/src/exchange/taler-exchange-httpd_reserves_get.c index 88f7aca9c..c22e62bf5 100644 --- a/src/exchange/taler-exchange-httpd_reserves_get.c +++ b/src/exchange/taler-exchange-httpd_reserves_get.c @@ -1,6 +1,6 @@ /* 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 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; + /** + * 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. */ @@ -84,13 +94,10 @@ static struct ReservePoller *rp_tail; void TEH_reserves_get_cleanup () { - struct ReservePoller *rp; - - while (NULL != (rp = rp_head)) + for (struct ReservePoller *rp = rp_head; + NULL != rp; + rp = rp->next) { - GNUNET_CONTAINER_DLL_remove (rp_head, - rp_tail, - rp); if (rp->suspended) { rp->suspended = false; @@ -115,11 +122,14 @@ rp_cleanup (struct TEH_RequestContext *rc) if (NULL != rp->eh) { 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, rp->eh); rp->eh = NULL; } + GNUNET_CONTAINER_DLL_remove (rp_head, + rp_tail, + rp); GNUNET_free (rp); } @@ -137,26 +147,15 @@ db_event_cb (void *cls, const void *extra, size_t extra_size) { - struct TEH_RequestContext *rc = cls; - struct ReservePoller *rp = rc->rh_ctx; + struct ReservePoller *rp = cls; struct GNUNET_AsyncScopeSave old_scope; (void) extra; (void) extra_size; - if (NULL == rp) - return; /* event triggered while main transaction - was still running */ if (! rp->suspended) 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 (); - GNUNET_CONTAINER_DLL_remove (rp_head, - rp_tail, - rp); + rp->suspended = false; MHD_resume_connection (rp->connection); TALER_MHD_daemon_trigger (); TEH_check_invariants (); @@ -164,191 +163,133 @@ db_event_cb (void *cls, } -/** - * Closure for #reserve_history_transaction. - */ -struct ReserveHistoryContext -{ - /** - * Public key of the reserve the inquiry is about. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Balance of the reserve, set in the callback. - */ - struct TALER_Amount balance; - - /** - * Set to true if we did not find the reserve. - */ - bool not_found; -}; - - -/** - * Function implementing /reserves/ GET transaction. - * Execute a /reserves/ GET. Given the public key of a reserve, - * return the associated transaction history. Runs the - * transaction logic; IF it returns a non-error code, the transaction - * logic MUST NOT queue a MHD response. IF it returns an hard error, - * the transaction logic MUST queue a MHD response and set @a mhd_ret. - * IF it returns the soft error code, the function MAY be called again - * to retry and MUST not queue a MHD response. - * - * @param cls a `struct ReserveHistoryContext *` - * @param connection MHD request which triggered the transaction - * @param[out] mhd_ret set to MHD response status for @a connection, - * if transaction failed (!) - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -reserve_balance_transaction (void *cls, - struct MHD_Connection *connection, - MHD_RESULT *mhd_ret) -{ - struct ReserveHistoryContext *rsc = cls; - enum GNUNET_DB_QueryStatus qs; - - qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls, - &rsc->reserve_pub, - &rsc->balance); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - GNUNET_break (0); - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_reserve_balance"); - } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) - rsc->not_found = true; - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) - rsc->not_found = false; - return qs; -} - - MHD_RESULT TEH_handler_reserves_get (struct TEH_RequestContext *rc, const char *const args[1]) { - struct ReserveHistoryContext rsc; - struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_ZERO; - struct GNUNET_DB_EventHandler *eh = NULL; + struct ReservePoller *rp = rc->rh_ctx; - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (args[0], - strlen (args[0]), - &rsc.reserve_pub, - sizeof (rsc.reserve_pub))) + if (NULL == rp) { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, - args[0]); - } - { - const char *long_poll_timeout_ms; + struct GNUNET_TIME_Relative timeout + = GNUNET_TIME_UNIT_ZERO; - long_poll_timeout_ms - = MHD_lookup_connection_value (rc->connection, - MHD_GET_ARGUMENT_KIND, - "timeout_ms"); - if (NULL != long_poll_timeout_ms) + 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 != + GNUNET_STRINGS_string_to_data (args[0], + strlen (args[0]), + &rp->reserve_pub, + sizeof (rp->reserve_pub))) { - unsigned int timeout_ms; - char dummy; - - if (1 != sscanf (long_poll_timeout_ms, - "%u%c", - &timeout_ms, - &dummy)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "timeout_ms (must be non-negative number)"); - } - timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, - timeout_ms); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, + args[0]); } + { + const char *long_poll_timeout_ms; + + long_poll_timeout_ms + = MHD_lookup_connection_value (rc->connection, + MHD_GET_ARGUMENT_KIND, + "timeout_ms"); + if (NULL != long_poll_timeout_ms) + { + unsigned int timeout_ms; + char dummy; + + if (1 != sscanf (long_poll_timeout_ms, + "%u%c", + &timeout_ms, + &dummy)) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "timeout_ms (must be non-negative number)"); + } + timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + timeout_ms); + } + } + rp->timeout = GNUNET_TIME_relative_to_absolute (timeout); } - if ( (! GNUNET_TIME_relative_is_zero (timeout)) && - (NULL == rc->rh_ctx) ) + + if ( (GNUNET_TIME_absolute_is_future (rp->timeout)) && + (NULL == rp->eh) ) { struct TALER_ReserveEventP rep = { .header.size = htons (sizeof (rep)), .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING), - .reserve_pub = rsc.reserve_pub + .reserve_pub = rp->reserve_pub }; GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Starting DB event listening\n"); - eh = TEH_plugin->event_listen (TEH_plugin->cls, - timeout, - &rep.header, - &db_event_cb, - rc); + "Starting DB event listening until %s\n", + GNUNET_TIME_absolute2s (rp->timeout)); + rp->eh = TEH_plugin->event_listen ( + TEH_plugin->cls, + GNUNET_TIME_absolute_get_remaining (rp->timeout), + &rep.header, + &db_event_cb, + rp); } { - MHD_RESULT mhd_ret; + enum GNUNET_DB_QueryStatus qs; - if (GNUNET_OK != - TEH_DB_run_transaction (rc->connection, - "get reserve balance", - TEH_MT_REQUEST_OTHER, - &mhd_ret, - &reserve_balance_transaction, - &rsc)) - { - if (NULL != eh) - TEH_plugin->event_listen_cancel (TEH_plugin->cls, - eh); - return mhd_ret; - } - } - /* generate proper response */ - if (rsc.not_found) - { - struct ReservePoller *rp = rc->rh_ctx; - - if ( (NULL != rp) || - (GNUNET_TIME_relative_is_zero (timeout)) ) + qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls, + &rp->reserve_pub, + &rp->balance); + switch (qs) { + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); /* single-shot query should never have soft-errors */ return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN, - args[0]); + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_SOFT_FAILURE, + "get_reserve_balance"); + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "get_reserve_balance"); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Got reserve balance of %s\n", + TALER_amount2s (&rp->balance)); + return TALER_MHD_REPLY_JSON_PACK (rc->connection, + MHD_HTTP_OK, + TALER_JSON_pack_amount ("balance", + &rp->balance)); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + if (! GNUNET_TIME_absolute_is_future (rp->timeout)) + { + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN, + args[0]); + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Long-polling on reserve for %s\n", + GNUNET_STRINGS_relative_time_to_string ( + GNUNET_TIME_absolute_get_remaining (rp->timeout), + true)); + rp->suspended = true; + MHD_suspend_connection (rc->connection); + return MHD_YES; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Long-polling on reserve for %s\n", - GNUNET_STRINGS_relative_time_to_string (timeout, - GNUNET_YES)); - rp = GNUNET_new (struct ReservePoller); - rp->connection = rc->connection; - rp->timeout = GNUNET_TIME_relative_to_absolute (timeout); - rp->eh = eh; - rc->rh_ctx = rp; - rc->rh_cleaner = &rp_cleanup; - rp->suspended = true; - GNUNET_CONTAINER_DLL_insert (rp_head, - rp_tail, - rp); - MHD_suspend_connection (rc->connection); - return MHD_YES; } - if (NULL != eh) - TEH_plugin->event_listen_cancel (TEH_plugin->cls, - eh); - return TALER_MHD_REPLY_JSON_PACK ( - rc->connection, - MHD_HTTP_OK, - TALER_JSON_pack_amount ("balance", - &rsc.balance)); + GNUNET_break (0); + return MHD_NO; } diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c index 168e7b9b7..235c0153f 100644 --- a/src/exchange/taler-exchange-wirewatch.c +++ b/src/exchange/taler-exchange-wirewatch.c @@ -57,6 +57,12 @@ static struct TALER_BANK_CreditHistoryHandle *hh; */ 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? */ @@ -472,9 +478,9 @@ transaction_completed (void) GNUNET_SCHEDULER_shutdown (); 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 */ struct GNUNET_TIME_Relative latency; struct GNUNET_TIME_Relative left; @@ -482,8 +488,17 @@ transaction_completed (void) latency = GNUNET_TIME_absolute_get_duration (hh_start_time); left = GNUNET_TIME_relative_subtract (longpoll_timeout, 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); } + if (hh_account_404) + delayed_until = GNUNET_TIME_relative_to_absolute ( + GNUNET_TIME_UNIT_MILLISECONDS); if (test_mode) delayed_until = GNUNET_TIME_UNIT_ZERO_ABS; GNUNET_assert (NULL == task); @@ -495,12 +510,12 @@ transaction_completed (void) * We got incoming transaction details from the bank. Add them * to the database. * - * @param batch_size desired batch size + * @param wrap_size desired bulk insert size * @param details array of transaction details * @param details_length length of the @a details array */ static void -process_reply (unsigned int batch_size, +process_reply (unsigned int wrap_size, const struct TALER_BANK_CreditDetails *details, unsigned int details_length) { @@ -570,7 +585,7 @@ process_reply (unsigned int batch_size, qs = db_plugin->reserves_in_insert (db_plugin->cls, reserves, details_length, - batch_size, + wrap_size, qss); switch (qs) { @@ -581,7 +596,7 @@ process_reply (unsigned int batch_size, case GNUNET_DB_STATUS_SOFT_ERROR: GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got DB soft error for batch2_reserves_in_insert (%u). Rolling back.\n", - batch_size); + wrap_size); handle_soft_error (); return; default: @@ -686,36 +701,36 @@ static void history_cb (void *cls, const struct TALER_BANK_CreditHistoryResponse *reply) { - static int batch_mode = -2; + static int wrap_size = -2; (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; if ( (NULL == mode) || (1 != sscanf (mode, "%d%c", - &batch_mode, + &wrap_size, &dummy)) ) { if (NULL != mode) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Bad batch mode `%s' specified\n", mode); - batch_mode = 8; /* maximum supported is currently 8 */ + wrap_size = 8; /* maximum supported is currently 8 */ } } GNUNET_assert (NULL == task); hh = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "History request returned with HTTP status %u\n", reply->http_status); switch (reply->http_status) { case MHD_HTTP_OK: - process_reply (batch_mode, + process_reply (wrap_size, reply->details.success.details, reply->details.success.details_length); return; @@ -723,6 +738,7 @@ history_cb (void *cls, transaction_completed (); return; case MHD_HTTP_NOT_FOUND: + hh_account_404 = true; if (ignore_account_404) { transaction_completed (); @@ -761,6 +777,7 @@ continue_with_shard (void *cls) (unsigned long long) latest_row_off); hh_start_time = GNUNET_TIME_absolute_get (); hh_returned_data = false; + hh_account_404 = false; hh = TALER_BANK_credit_history (ctx, ai->auth, latest_row_off, @@ -857,6 +874,17 @@ lock_shard (void *cls) job_name, GNUNET_STRINGS_relative_time_to_string (rdelay, 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); } GNUNET_assert (NULL == task); @@ -869,7 +897,7 @@ lock_shard (void *cls) job_name, GNUNET_STRINGS_relative_time_to_string ( wirewatch_idle_sleep_interval, - GNUNET_YES)); + true)); delayed_until = GNUNET_TIME_relative_to_absolute ( wirewatch_idle_sleep_interval); shard_open = false; diff --git a/src/exchangedb/.gitignore b/src/exchangedb/.gitignore index 264217a3d..fa833d81f 100644 --- a/src/exchangedb/.gitignore +++ b/src/exchangedb/.gitignore @@ -7,3 +7,9 @@ perf_select_refunds_by_coin-postgres exchange-0002.sql procedures.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 \ No newline at end of file diff --git a/src/exchangedb/0002-refresh_revealed_coins.sql b/src/exchangedb/0002-refresh_revealed_coins.sql index 912e4bbbd..5fd315ba3 100644 --- a/src/exchangedb/0002-refresh_revealed_coins.sql +++ b/src/exchangedb/0002-refresh_revealed_coins.sql @@ -62,6 +62,9 @@ BEGIN ,table_name ,partition_suffix ); + -- + -- FIXME: Add comment for link_sig + -- PERFORM comment_partitioned_column( 'envelope of the new coin to be signed' ,'coin_ev' diff --git a/src/exchangedb/0003-withdraw_age_commitments.sql b/src/exchangedb/0003-withdraw_age_commitments.sql index 6c153598d..b8451129a 100644 --- a/src/exchangedb/0003-withdraw_age_commitments.sql +++ b/src/exchangedb/0003-withdraw_age_commitments.sql @@ -33,7 +33,6 @@ BEGIN ',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)' ',reserve_sig BYTEA CHECK (LENGTH(reserve_sig)=64)' ',noreveal_index INT4 NOT NULL' - ',timestamp INT8 NOT NULL' ') %s ;' ,table_name ,'PARTITION BY HASH (reserve_pub)' @@ -51,7 +50,7 @@ BEGIN ,partition_suffix ); 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' ,table_name ,partition_suffix @@ -74,12 +73,6 @@ BEGIN ,table_name ,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 $$; diff --git a/src/exchangedb/0003-withdraw_age_reveals.sql b/src/exchangedb/0003-withdraw_age_reveals.sql index 3353d9367..af66eab75 100644 --- a/src/exchangedb/0003-withdraw_age_reveals.sql +++ b/src/exchangedb/0003-withdraw_age_reveals.sql @@ -14,22 +14,25 @@ -- TALER; see the file COPYING. If not, see -- -CREATE FUNCTION create_table_withdraw_age_reveals( +CREATE FUNCTION create_table_withdraw_age_revealed_coins( IN partition_suffix VARCHAR DEFAULT NULL ) RETURNS VOID LANGUAGE plpgsql AS $$ DECLARE - table_name VARCHAR DEFAULT 'withdraw_age_reveals'; + table_name VARCHAR DEFAULT 'withdraw_age_revealed_coins'; BEGIN PERFORM create_partitioned_table( 'CREATE TABLE %I' - '(withdraw_age_reveals_id BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE - ',h_commitment BYTEA NOT NULL CHECK (LENGTH(h_commitment)=32)' + '(withdraw_age_revealed_coins_id BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE + ',h_commitment BYTEA NOT NULL CHECK (LENGTH(h_commitment)=64)' ',freshcoin_index INT4 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 ;' ,table_name ,'PARTITION BY HASH (h_commitment)' @@ -59,29 +62,47 @@ BEGIN ,partition_suffix ); 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' ,table_name ,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 $$; -CREATE FUNCTION constrain_table_withdraw_age_reveals( +CREATE FUNCTION constrain_table_withdraw_age_revealed_coins( IN partition_suffix VARCHAR ) RETURNS void LANGUAGE plpgsql AS $$ DECLARE - table_name VARCHAR DEFAULT 'withdraw_age_reveals'; + table_name VARCHAR DEFAULT 'withdraw_age_revealed_coins'; BEGIN table_name = concat_ws('_', table_name, partition_suffix); EXECUTE FORMAT ( 'ALTER TABLE ' || table_name || - ' ADD CONSTRAINT ' || table_name || '_withdraw_age_reveals_id_key' - ' UNIQUE (withdraw_age_reveals_id);' + ' ADD CONSTRAINT ' || table_name || '_withdraw_age_revealed_coins_id_key' + ' UNIQUE (withdraw_age_revealed_coins_id);' ); EXECUTE FORMAT ( 'ALTER TABLE ' || table_name || @@ -91,12 +112,12 @@ BEGIN END $$; -CREATE FUNCTION foreign_table_withdraw_age_reveals() +CREATE FUNCTION foreign_table_withdraw_age_revealed_coins() RETURNS void LANGUAGE plpgsql AS $$ DECLARE - table_name VARCHAR DEFAULT 'withdraw_age_reveals'; + table_name VARCHAR DEFAULT 'withdraw_age_revealed_coins'; BEGIN EXECUTE FORMAT ( 'ALTER TABLE ' || table_name || @@ -121,17 +142,17 @@ INSERT INTO exchange_tables ,partitioned ,by_range) VALUES - ('withdraw_age_reveals' + ('withdraw_age_revealed_coins' ,'exchange-0003' ,'create' ,TRUE ,FALSE), - ('withdraw_age_reveals' + ('withdraw_age_revealed_coins' ,'exchange-0003' ,'constrain' ,TRUE ,FALSE), - ('withdraw_age_reveals' + ('withdraw_age_revealed_coins' ,'exchange-0003' ,'foreign' ,TRUE diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index 9757aefff..de76997cb 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -116,6 +116,7 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \ pg_reserves_in_insert.h pg_reserves_in_insert.c \ pg_get_withdraw_info.h pg_get_withdraw_info.c \ 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_get_policy_details.h pg_get_policy_details.c \ pg_persist_policy_details.h pg_persist_policy_details.c \ diff --git a/src/exchangedb/exchange_do_batch2_reserves_in_insert.sql b/src/exchangedb/exchange_do_batch2_reserves_in_insert.sql deleted file mode 100644 index 6df8b7554..000000000 --- a/src/exchangedb/exchange_do_batch2_reserves_in_insert.sql +++ /dev/null @@ -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 --- - -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 $$; diff --git a/src/exchangedb/exchange_do_batch4_reserves_in_insert.sql b/src/exchangedb/exchange_do_batch4_reserves_in_insert.sql deleted file mode 100644 index 6a5707109..000000000 --- a/src/exchangedb/exchange_do_batch4_reserves_in_insert.sql +++ /dev/null @@ -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 --- - -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 $$; diff --git a/src/exchangedb/exchange_do_batch8_reserves_in_insert.sql b/src/exchangedb/exchange_do_batch8_reserves_in_insert.sql deleted file mode 100644 index a9f34b897..000000000 --- a/src/exchangedb/exchange_do_batch8_reserves_in_insert.sql +++ /dev/null @@ -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 --- - -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 $$; diff --git a/src/exchangedb/exchange_do_batch_coin_known.sql b/src/exchangedb/exchange_do_batch_coin_known.sql new file mode 100644 index 000000000..f6a14cfab --- /dev/null +++ b/src/exchangedb/exchange_do_batch_coin_known.sql @@ -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 +-- + +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; +$$;*/ diff --git a/src/exchangedb/exchange_do_batch_reserves_in_insert.sql b/src/exchangedb/exchange_do_batch_reserves_in_insert.sql deleted file mode 100644 index 5ee819229..000000000 --- a/src/exchangedb/exchange_do_batch_reserves_in_insert.sql +++ /dev/null @@ -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 --- - -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 $$; diff --git a/src/exchangedb/exchange_do_deposit.sql b/src/exchangedb/exchange_do_deposit.sql index a2f5ba53a..6e522b354 100644 --- a/src/exchangedb/exchange_do_deposit.sql +++ b/src/exchangedb/exchange_do_deposit.sql @@ -123,6 +123,7 @@ THEN -- Deposit exists, but with differences. Not allowed. out_balance_ok=FALSE; out_conflict=TRUE; + out_exchange_timestamp=0; RETURN; END IF; diff --git a/src/exchangedb/exchange_do_reserves_in_insert.sql b/src/exchangedb/exchange_do_reserves_in_insert.sql new file mode 100644 index 000000000..dffcd8b55 --- /dev/null +++ b/src/exchangedb/exchange_do_reserves_in_insert.sql @@ -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 +-- + +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 + FETCH FROM curs_reserve_exist INTO i; + IF NOT FOUND + THEN + EXIT loop_reserve; + END IF; + + <> 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 + FETCH FROM curs_transaction_exist INTO i; + IF NOT FOUND + THEN + EXIT loop_transaction; + END IF; + + <> 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 + FETCH FROM curs_reserve_exist INTO i; + IF NOT FOUND + THEN + EXIT loop_reserve; + END IF; + + <> 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 + FETCH FROM curs_transaction_exist INTO i; + IF NOT FOUND + THEN + EXIT loop_transaction; + END IF; + + <> 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 + FETCH FROM curs_reserve_exist INTO i; + IF NOT FOUND + THEN + EXIT loop_reserve; + END IF; + + <> 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 + FETCH FROM curs_transaction_exist INTO i; + IF NOT FOUND + THEN + EXIT loop_transaction; + END IF; + + <> 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 $$; diff --git a/src/exchangedb/exchange_get_ready_deposit.sql b/src/exchangedb/exchange_get_ready_deposit.sql new file mode 100644 index 000000000..4f76463fc --- /dev/null +++ b/src/exchangedb/exchange_get_ready_deposit.sql @@ -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 +-- +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 $$; diff --git a/src/exchangedb/pg_abort_shard.h b/src/exchangedb/pg_abort_shard.h index 070b48dab..e52ace5f6 100644 --- a/src/exchangedb/pg_abort_shard.h +++ b/src/exchangedb/pg_abort_shard.h @@ -36,7 +36,8 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_abort_shard (void *cls, - const char *job_name, - uint64_t start_row, + const char *job_name, + uint64_t start_row, uint64_t end_row); + #endif diff --git a/src/exchangedb/pg_add_denomination_key.c b/src/exchangedb/pg_add_denomination_key.c index e115a44ec..fa6d92ed6 100644 --- a/src/exchangedb/pg_add_denomination_key.c +++ b/src/exchangedb/pg_add_denomination_key.c @@ -56,8 +56,8 @@ TEH_PG_add_denomination_key ( GNUNET_assert (GNUNET_YES == TALER_denom_fee_check_currency (meta->value.currency, &meta->fees)); - /* Used in #postgres_insert_denomination_info() and - #postgres_add_denomination_key() */ + /* Used in #postgres_insert_denomination_info() and + #postgres_add_denomination_key() */ PREPARE (pg, "denomination_insert", "INSERT INTO denominations " @@ -86,4 +86,3 @@ TEH_PG_add_denomination_key ( "denomination_insert", iparams); } - diff --git a/src/exchangedb/pg_add_policy_fulfillment_proof.c b/src/exchangedb/pg_add_policy_fulfillment_proof.c index bb06206ae..103de7ad2 100644 --- a/src/exchangedb/pg_add_policy_fulfillment_proof.c +++ b/src/exchangedb/pg_add_policy_fulfillment_proof.c @@ -94,7 +94,7 @@ TEH_PG_add_policy_fulfillment_proof ( GNUNET_PQ_result_spec_end }; - + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "insert_proof_into_policy_fulfillments", params, diff --git a/src/exchangedb/pg_batch_ensure_coin_known.c b/src/exchangedb/pg_batch_ensure_coin_known.c new file mode 100644 index 000000000..e49813064 --- /dev/null +++ b/src/exchangedb/pg_batch_ensure_coin_known.c @@ -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 + */ +/** + * @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; +} diff --git a/src/exchangedb/pg_batch_ensure_coin_known.h b/src/exchangedb/pg_batch_ensure_coin_known.h new file mode 100644 index 000000000..2c53676d9 --- /dev/null +++ b/src/exchangedb/pg_batch_ensure_coin_known.h @@ -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 + */ +/** + * @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 diff --git a/src/exchangedb/pg_begin_revolving_shard.c b/src/exchangedb/pg_begin_revolving_shard.c index 888d7fd20..86cdf80fd 100644 --- a/src/exchangedb/pg_begin_revolving_shard.c +++ b/src/exchangedb/pg_begin_revolving_shard.c @@ -30,11 +30,11 @@ enum GNUNET_DB_QueryStatus TEH_PG_begin_revolving_shard (void *cls, - const char *job_name, - uint32_t shard_size, - uint32_t shard_limit, - uint32_t *start_row, - uint32_t *end_row) + const char *job_name, + uint32_t shard_size, + uint32_t shard_limit, + uint32_t *start_row, + uint32_t *end_row) { struct PostgresClosure *pg = cls; @@ -45,7 +45,7 @@ TEH_PG_begin_revolving_shard (void *cls, { if (GNUNET_OK != TEH_PG_start (pg, - "begin_revolving_shard")) + "begin_revolving_shard")) { GNUNET_break (0); return GNUNET_DB_STATUS_HARD_ERROR; @@ -64,15 +64,15 @@ TEH_PG_begin_revolving_shard (void *cls, &last_end), GNUNET_PQ_result_spec_end }; - /* Used in #postgres_begin_revolving_shard() */ - PREPARE(pg, - "get_last_revolving_shard", - "SELECT" - " end_row" - " FROM revolving_work_shards" - " WHERE job_name=$1" - " ORDER BY end_row DESC" - " LIMIT 1;"); + /* Used in #postgres_begin_revolving_shard() */ + PREPARE (pg, + "get_last_revolving_shard", + "SELECT" + " end_row" + " FROM revolving_work_shards" + " WHERE job_name=$1" + " ORDER BY end_row DESC" + " LIMIT 1;"); qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "get_last_revolving_shard", params, @@ -116,7 +116,7 @@ TEH_PG_begin_revolving_shard (void *cls, (unsigned long long) *start_row, (unsigned long long) *end_row); - /* Used in #postgres_claim_revolving_shard() */ + /* Used in #postgres_claim_revolving_shard() */ PREPARE (pg, "create_revolving_shard", "INSERT INTO revolving_work_shards" @@ -164,7 +164,7 @@ TEH_PG_begin_revolving_shard (void *cls, end_row), GNUNET_PQ_result_spec_end }; - /* Used in #postgres_begin_revolving_shard() */ + /* Used in #postgres_begin_revolving_shard() */ PREPARE (pg, "get_open_revolving_shard", "SELECT" @@ -206,7 +206,7 @@ TEH_PG_begin_revolving_shard (void *cls, now = GNUNET_TIME_timestamp_get (); - /* Used in #postgres_begin_revolving_shard() */ + /* Used in #postgres_begin_revolving_shard() */ PREPARE (pg, "reclaim_revolving_shard", "UPDATE revolving_work_shards" diff --git a/src/exchangedb/pg_begin_revolving_shard.h b/src/exchangedb/pg_begin_revolving_shard.h index bdbca4f11..0755f886b 100644 --- a/src/exchangedb/pg_begin_revolving_shard.h +++ b/src/exchangedb/pg_begin_revolving_shard.h @@ -40,9 +40,10 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_begin_revolving_shard (void *cls, - const char *job_name, - uint32_t shard_size, - uint32_t shard_limit, - uint32_t *start_row, + const char *job_name, + uint32_t shard_size, + uint32_t shard_limit, + uint32_t *start_row, uint32_t *end_row); + #endif diff --git a/src/exchangedb/pg_begin_shard.h b/src/exchangedb/pg_begin_shard.h index 39bd834e9..16f19491d 100644 --- a/src/exchangedb/pg_begin_shard.h +++ b/src/exchangedb/pg_begin_shard.h @@ -38,10 +38,10 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_begin_shard (void *cls, - const char *job_name, - struct GNUNET_TIME_Relative delay, - uint64_t shard_size, - uint64_t *start_row, + const char *job_name, + struct GNUNET_TIME_Relative delay, + uint64_t shard_size, + uint64_t *start_row, uint64_t *end_row); #endif diff --git a/src/exchangedb/pg_commit.c b/src/exchangedb/pg_commit.c index f1e61ee34..8c4f87c90 100644 --- a/src/exchangedb/pg_commit.c +++ b/src/exchangedb/pg_commit.c @@ -45,7 +45,7 @@ TEH_PG_commit (void *cls) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Committing transaction `%s'\n", pg->transaction_name); - /* used in #postgres_commit */ + /* used in #postgres_commit */ PREPARE (pg, "do_commit", "COMMIT"); diff --git a/src/exchangedb/pg_complete_shard.h b/src/exchangedb/pg_complete_shard.h index 8693f402e..f06c0483b 100644 --- a/src/exchangedb/pg_complete_shard.h +++ b/src/exchangedb/pg_complete_shard.h @@ -36,7 +36,8 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_complete_shard (void *cls, - const char *job_name, - uint64_t start_row, + const char *job_name, + uint64_t start_row, uint64_t end_row); + #endif diff --git a/src/exchangedb/pg_count_known_coins.c b/src/exchangedb/pg_count_known_coins.c index 28c4612fc..872965ac9 100644 --- a/src/exchangedb/pg_count_known_coins.c +++ b/src/exchangedb/pg_count_known_coins.c @@ -27,8 +27,8 @@ long long TEH_PG_count_known_coins (void *cls, - const struct - TALER_DenominationHashP *denom_pub_hash) + const struct + TALER_DenominationHashP *denom_pub_hash) { struct PostgresClosure *pg = cls; uint64_t count; diff --git a/src/exchangedb/pg_count_known_coins.h b/src/exchangedb/pg_count_known_coins.h index f5dd4f27f..69f07bdf4 100644 --- a/src/exchangedb/pg_count_known_coins.h +++ b/src/exchangedb/pg_count_known_coins.h @@ -33,7 +33,7 @@ */ long long TEH_PG_count_known_coins (void *cls, - const struct + const struct TALER_DenominationHashP *denom_pub_hash); #endif diff --git a/src/exchangedb/pg_create_aggregation_transient.c b/src/exchangedb/pg_create_aggregation_transient.c index 4ced9da04..80fba8bf4 100644 --- a/src/exchangedb/pg_create_aggregation_transient.c +++ b/src/exchangedb/pg_create_aggregation_transient.c @@ -46,18 +46,18 @@ TEH_PG_create_aggregation_transient ( GNUNET_PQ_query_param_auto_from_type (wtid), GNUNET_PQ_query_param_end }; - /* Used in #postgres_create_aggregation_transient() */ + /* Used in #postgres_create_aggregation_transient() */ PREPARE (pg, - "create_aggregation_transient", - "INSERT INTO aggregation_transient" - " (amount_val" - " ,amount_frac" - " ,merchant_pub" - " ,wire_target_h_payto" - " ,legitimization_requirement_serial_id" - " ,exchange_account_section" - " ,wtid_raw)" - " VALUES ($1, $2, $3, $4, $5, $6, $7);"); + "create_aggregation_transient", + "INSERT INTO aggregation_transient" + " (amount_val" + " ,amount_frac" + " ,merchant_pub" + " ,wire_target_h_payto" + " ,legitimization_requirement_serial_id" + " ,exchange_account_section" + " ,wtid_raw)" + " VALUES ($1, $2, $3, $4, $5, $6, $7);"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "create_aggregation_transient", params); diff --git a/src/exchangedb/pg_delete_aggregation_transient.c b/src/exchangedb/pg_delete_aggregation_transient.c index d0622c0f7..63c5c0a23 100644 --- a/src/exchangedb/pg_delete_aggregation_transient.c +++ b/src/exchangedb/pg_delete_aggregation_transient.c @@ -48,5 +48,3 @@ TEH_PG_delete_aggregation_transient ( "delete_aggregation_transient", params); } - - diff --git a/src/exchangedb/pg_delete_shard_locks.c b/src/exchangedb/pg_delete_shard_locks.c index e55cf25ff..dbb0f29ac 100644 --- a/src/exchangedb/pg_delete_shard_locks.c +++ b/src/exchangedb/pg_delete_shard_locks.c @@ -39,4 +39,3 @@ TEH_PG_delete_shard_locks (void *cls) return GNUNET_PQ_exec_statements (pg->conn, es); } - diff --git a/src/exchangedb/pg_do_batch_withdraw.c b/src/exchangedb/pg_do_batch_withdraw.c index 8ef1be268..3dee20d22 100644 --- a/src/exchangedb/pg_do_batch_withdraw.c +++ b/src/exchangedb/pg_do_batch_withdraw.c @@ -60,8 +60,8 @@ TEH_PG_do_batch_withdraw ( pg->legal_reserve_expiration_time)); - /* Used in #postgres_do_batch_withdraw() to - update the reserve balance and check its status */ + /* Used in #postgres_do_batch_withdraw() to + update the reserve balance and check its status */ PREPARE (pg, "call_batch_withdraw", "SELECT " @@ -75,4 +75,3 @@ TEH_PG_do_batch_withdraw ( params, rs); } - diff --git a/src/exchangedb/pg_do_batch_withdraw_insert.c b/src/exchangedb/pg_do_batch_withdraw_insert.c index 8d3aac688..8be18f7cc 100644 --- a/src/exchangedb/pg_do_batch_withdraw_insert.c +++ b/src/exchangedb/pg_do_batch_withdraw_insert.c @@ -59,9 +59,9 @@ TEH_PG_do_batch_withdraw_insert ( nonce_reuse), GNUNET_PQ_result_spec_end }; - /* Used in #postgres_do_batch_withdraw_insert() to store - the signature of a blinded coin with the blinded coin's - details. */ + /* Used in #postgres_do_batch_withdraw_insert() to store + the signature of a blinded coin with the blinded coin's + details. */ PREPARE (pg, "call_batch_withdraw_insert", "SELECT " diff --git a/src/exchangedb/pg_do_deposit.c b/src/exchangedb/pg_do_deposit.c index c8f25e5bc..f3d0856ac 100644 --- a/src/exchangedb/pg_do_deposit.c +++ b/src/exchangedb/pg_do_deposit.c @@ -25,6 +25,8 @@ #include "pg_do_deposit.h" #include "pg_helper.h" #include "pg_compute_shard.h" + + enum GNUNET_DB_QueryStatus TEH_PG_do_deposit ( void *cls, @@ -69,8 +71,6 @@ TEH_PG_do_deposit ( 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, "call_deposit", "SELECT " diff --git a/src/exchangedb/pg_do_melt.c b/src/exchangedb/pg_do_melt.c index 6f81ff38b..40a54d43b 100644 --- a/src/exchangedb/pg_do_melt.c +++ b/src/exchangedb/pg_do_melt.c @@ -63,7 +63,7 @@ TEH_PG_do_melt ( }; enum GNUNET_DB_QueryStatus qs; - /* Used in #postgres_do_melt() to melt a coin. */ + /* Used in #postgres_do_melt() to melt a coin. */ PREPARE (pg, "call_melt", "SELECT " diff --git a/src/exchangedb/pg_do_purse_merge.c b/src/exchangedb/pg_do_purse_merge.c index 518b66bf6..5d11b0565 100644 --- a/src/exchangedb/pg_do_purse_merge.c +++ b/src/exchangedb/pg_do_purse_merge.c @@ -75,7 +75,7 @@ TEH_PG_do_purse_merge ( &h_payto); GNUNET_free (payto_uri); } - /* Used in #postgres_do_purse_merge() */ + /* Used in #postgres_do_purse_merge() */ PREPARE (pg, "call_purse_merge", "SELECT" diff --git a/src/exchangedb/pg_do_recoup.c b/src/exchangedb/pg_do_recoup.c index 00f7bdd8b..1f74104ed 100644 --- a/src/exchangedb/pg_do_recoup.c +++ b/src/exchangedb/pg_do_recoup.c @@ -70,7 +70,6 @@ TEH_PG_do_recoup ( }; - PREPARE (pg, "call_recoup", "SELECT " diff --git a/src/exchangedb/pg_do_recoup_refresh.h b/src/exchangedb/pg_do_recoup_refresh.h index 3ac0f0a07..fbd791d44 100644 --- a/src/exchangedb/pg_do_recoup_refresh.h +++ b/src/exchangedb/pg_do_recoup_refresh.h @@ -53,4 +53,5 @@ TEH_PG_do_recoup_refresh ( struct GNUNET_TIME_Timestamp *recoup_timestamp, bool *recoup_ok, bool *internal_failure); + #endif diff --git a/src/exchangedb/pg_do_refund.c b/src/exchangedb/pg_do_refund.c index 1059f9cbb..0b9665c48 100644 --- a/src/exchangedb/pg_do_refund.c +++ b/src/exchangedb/pg_do_refund.c @@ -72,7 +72,7 @@ TEH_PG_do_refund ( GNUNET_break (0); return GNUNET_DB_STATUS_HARD_ERROR; } - /* Used in #postgres_do_refund() to refund a deposit. */ + /* Used in #postgres_do_refund() to refund a deposit. */ PREPARE (pg, "call_refund", "SELECT " diff --git a/src/exchangedb/pg_do_withdraw.c b/src/exchangedb/pg_do_withdraw.c index 87e4dd1d0..01bbfff5b 100644 --- a/src/exchangedb/pg_do_withdraw.c +++ b/src/exchangedb/pg_do_withdraw.c @@ -82,5 +82,3 @@ TEH_PG_do_withdraw ( params, rs); } - - diff --git a/src/exchangedb/pg_drain_kyc_alert.c b/src/exchangedb/pg_drain_kyc_alert.c index d635d95e9..4388334e9 100644 --- a/src/exchangedb/pg_drain_kyc_alert.c +++ b/src/exchangedb/pg_drain_kyc_alert.c @@ -28,8 +28,8 @@ enum GNUNET_DB_QueryStatus TEH_PG_drain_kyc_alert (void *cls, - uint32_t trigger_type, - struct TALER_PaytoHashP *h_payto) + uint32_t trigger_type, + struct TALER_PaytoHashP *h_payto) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { diff --git a/src/exchangedb/pg_drain_kyc_alert.h b/src/exchangedb/pg_drain_kyc_alert.h index bfaf04892..7425f472d 100644 --- a/src/exchangedb/pg_drain_kyc_alert.h +++ b/src/exchangedb/pg_drain_kyc_alert.h @@ -34,7 +34,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_drain_kyc_alert (void *cls, - uint32_t trigger_type, + uint32_t trigger_type, struct TALER_PaytoHashP *h_payto); #endif diff --git a/src/exchangedb/pg_ensure_coin_known.c b/src/exchangedb/pg_ensure_coin_known.c index 7ad37bf1d..721123fd3 100644 --- a/src/exchangedb/pg_ensure_coin_known.c +++ b/src/exchangedb/pg_ensure_coin_known.c @@ -28,10 +28,10 @@ enum TALER_EXCHANGEDB_CoinKnownStatus TEH_PG_ensure_coin_known (void *cls, - const struct TALER_CoinPublicInfo *coin, - uint64_t *known_coin_id, - struct TALER_DenominationHashP *denom_hash, - struct TALER_AgeCommitmentHash *h_age_commitment) + const struct TALER_CoinPublicInfo *coin, + uint64_t *known_coin_id, + struct TALER_DenominationHashP *denom_hash, + struct TALER_AgeCommitmentHash *h_age_commitment) { struct PostgresClosure *pg = cls; enum GNUNET_DB_QueryStatus qs; diff --git a/src/exchangedb/pg_ensure_coin_known.h b/src/exchangedb/pg_ensure_coin_known.h index 76581d4b7..68c101735 100644 --- a/src/exchangedb/pg_ensure_coin_known.h +++ b/src/exchangedb/pg_ensure_coin_known.h @@ -37,9 +37,9 @@ */ enum TALER_EXCHANGEDB_CoinKnownStatus TEH_PG_ensure_coin_known (void *cls, - const struct TALER_CoinPublicInfo *coin, - uint64_t *known_coin_id, - struct TALER_DenominationHashP *denom_hash, + const struct TALER_CoinPublicInfo *coin, + uint64_t *known_coin_id, + struct TALER_DenominationHashP *denom_hash, struct TALER_AgeCommitmentHash *h_age_commitment); #endif diff --git a/src/exchangedb/pg_event_listen.c b/src/exchangedb/pg_event_listen.c index c557ed3c5..6e1d32843 100644 --- a/src/exchangedb/pg_event_listen.c +++ b/src/exchangedb/pg_event_listen.c @@ -38,10 +38,10 @@ */ struct GNUNET_DB_EventHandler * TEH_PG_event_listen (void *cls, - struct GNUNET_TIME_Relative timeout, - const struct GNUNET_DB_EventHeaderP *es, - GNUNET_DB_EventCallback cb, - void *cb_cls) + struct GNUNET_TIME_Relative timeout, + const struct GNUNET_DB_EventHeaderP *es, + GNUNET_DB_EventCallback cb, + void *cb_cls) { struct PostgresClosure *pg = cls; diff --git a/src/exchangedb/pg_event_listen.h b/src/exchangedb/pg_event_listen.h index 1be140776..7e1e83a0e 100644 --- a/src/exchangedb/pg_event_listen.h +++ b/src/exchangedb/pg_event_listen.h @@ -37,9 +37,9 @@ */ struct GNUNET_DB_EventHandler * TEH_PG_event_listen (void *cls, - struct GNUNET_TIME_Relative timeout, - const struct GNUNET_DB_EventHeaderP *es, - GNUNET_DB_EventCallback cb, + struct GNUNET_TIME_Relative timeout, + const struct GNUNET_DB_EventHeaderP *es, + GNUNET_DB_EventCallback cb, void *cb_cls); #endif diff --git a/src/exchangedb/pg_event_listen_cancel.c b/src/exchangedb/pg_event_listen_cancel.c index 5d65827c2..9d776684d 100644 --- a/src/exchangedb/pg_event_listen_cancel.c +++ b/src/exchangedb/pg_event_listen_cancel.c @@ -26,10 +26,9 @@ #include "pg_helper.h" - void TEH_PG_event_listen_cancel (void *cls, - struct GNUNET_DB_EventHandler *eh) + struct GNUNET_DB_EventHandler *eh) { (void) cls; diff --git a/src/exchangedb/pg_event_notify.c b/src/exchangedb/pg_event_notify.c index 577f4acb8..188855775 100644 --- a/src/exchangedb/pg_event_notify.c +++ b/src/exchangedb/pg_event_notify.c @@ -28,9 +28,9 @@ void TEH_PG_event_notify (void *cls, - const struct GNUNET_DB_EventHeaderP *es, - const void *extra, - size_t extra_size) + const struct GNUNET_DB_EventHeaderP *es, + const void *extra, + size_t extra_size) { struct PostgresClosure *pg = cls; diff --git a/src/exchangedb/pg_event_notify.h b/src/exchangedb/pg_event_notify.h index 3b937cbab..85069659b 100644 --- a/src/exchangedb/pg_event_notify.h +++ b/src/exchangedb/pg_event_notify.h @@ -35,8 +35,8 @@ */ void TEH_PG_event_notify (void *cls, - const struct GNUNET_DB_EventHeaderP *es, - const void *extra, + const struct GNUNET_DB_EventHeaderP *es, + const void *extra, size_t extra_size); #endif diff --git a/src/exchangedb/pg_find_aggregation_transient.c b/src/exchangedb/pg_find_aggregation_transient.c index a5f367b5f..ecc6362cf 100644 --- a/src/exchangedb/pg_find_aggregation_transient.c +++ b/src/exchangedb/pg_find_aggregation_transient.c @@ -128,7 +128,7 @@ TEH_PG_find_aggregation_transient ( .pg = pg, .status = GNUNET_OK }; - /* Used in #postgres_find_aggregation_transient() */ + /* Used in #postgres_find_aggregation_transient() */ PREPARE (pg, "find_transient_aggregations", "SELECT" diff --git a/src/exchangedb/pg_gc.h b/src/exchangedb/pg_gc.h index 9e6ffbc3d..803581488 100644 --- a/src/exchangedb/pg_gc.h +++ b/src/exchangedb/pg_gc.h @@ -35,4 +35,5 @@ */ enum GNUNET_GenericReturnValue TEH_PG_gc (void *cls); + #endif diff --git a/src/exchangedb/pg_get_age_withdraw_info.c b/src/exchangedb/pg_get_age_withdraw_info.c index 02ccc84ac..754b572c9 100644 --- a/src/exchangedb/pg_get_age_withdraw_info.c +++ b/src/exchangedb/pg_get_age_withdraw_info.c @@ -35,6 +35,7 @@ TEH_PG_get_age_withdraw_info ( { struct PostgresClosure *pg = cls; 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_end }; @@ -45,14 +46,12 @@ TEH_PG_get_age_withdraw_info ( &awc->reserve_sig), GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", &awc->reserve_pub), - GNUNET_PQ_result_spec_uint32 ("max_age", + GNUNET_PQ_result_spec_uint16 ("max_age", &awc->max_age), TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", &awc->amount_with_fee), GNUNET_PQ_result_spec_uint32 ("noreveal_index", &awc->noreveal_index), - GNUNET_PQ_result_spec_timestamp ("timtestamp", - &awc->timestamp), GNUNET_PQ_result_spec_end }; @@ -70,9 +69,8 @@ TEH_PG_get_age_withdraw_info ( ",amount_with_fee_val" ",amount_with_fee_frac" ",noreveal_index" - ",timestamp" " 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, "get_age_withdraw_info", params, diff --git a/src/exchangedb/pg_get_coin_denomination.c b/src/exchangedb/pg_get_coin_denomination.c index e82b86aa9..9f9256f6f 100644 --- a/src/exchangedb/pg_get_coin_denomination.c +++ b/src/exchangedb/pg_get_coin_denomination.c @@ -49,9 +49,9 @@ TEH_PG_get_coin_denomination ( "Getting coin denomination of coin %s\n", TALER_B2S (coin_pub)); - /* Used in #postgres_get_coin_denomination() to fetch - the denomination public key hash for - a coin known to the exchange. */ + /* Used in #postgres_get_coin_denomination() to fetch + the denomination public key hash for + a coin known to the exchange. */ PREPARE (pg, "get_coin_denomination", "SELECT" @@ -67,5 +67,3 @@ TEH_PG_get_coin_denomination ( params, rs); } - - diff --git a/src/exchangedb/pg_get_denomination_revocation.c b/src/exchangedb/pg_get_denomination_revocation.c index 4d29d88c4..5e7a3a322 100644 --- a/src/exchangedb/pg_get_denomination_revocation.c +++ b/src/exchangedb/pg_get_denomination_revocation.c @@ -46,15 +46,15 @@ TEH_PG_get_denomination_revocation ( }; PREPARE (pg, - "denomination_revocation_get", - "SELECT" - " master_sig" - ",denom_revocations_serial_id" - " FROM denomination_revocations" - " WHERE denominations_serial=" - " (SELECT denominations_serial" - " FROM denominations" - " WHERE denom_pub_hash=$1);"); + "denomination_revocation_get", + "SELECT" + " master_sig" + ",denom_revocations_serial_id" + " FROM denomination_revocations" + " WHERE denominations_serial=" + " (SELECT denominations_serial" + " FROM denominations" + " WHERE denom_pub_hash=$1);"); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "denomination_revocation_get", diff --git a/src/exchangedb/pg_get_denomination_revocation.h b/src/exchangedb/pg_get_denomination_revocation.h index d022c822d..5f7f27227 100644 --- a/src/exchangedb/pg_get_denomination_revocation.h +++ b/src/exchangedb/pg_get_denomination_revocation.h @@ -41,4 +41,5 @@ TEH_PG_get_denomination_revocation ( const struct TALER_DenominationHashP *denom_pub_hash, struct TALER_MasterSignatureP *master_sig, uint64_t *rowid); + #endif diff --git a/src/exchangedb/pg_get_extension_manifest.h b/src/exchangedb/pg_get_extension_manifest.h index 3756b7f4c..e8331ad9b 100644 --- a/src/exchangedb/pg_get_extension_manifest.h +++ b/src/exchangedb/pg_get_extension_manifest.h @@ -36,6 +36,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_get_extension_manifest (void *cls, - const char *extension_name, + const char *extension_name, char **manifest); + #endif diff --git a/src/exchangedb/pg_get_global_fee.c b/src/exchangedb/pg_get_global_fee.c index 6f6bbafef..990113fed 100644 --- a/src/exchangedb/pg_get_global_fee.c +++ b/src/exchangedb/pg_get_global_fee.c @@ -28,14 +28,14 @@ enum GNUNET_DB_QueryStatus TEH_PG_get_global_fee (void *cls, - struct GNUNET_TIME_Timestamp date, - struct GNUNET_TIME_Timestamp *start_date, - struct GNUNET_TIME_Timestamp *end_date, - struct TALER_GlobalFeeSet *fees, - struct GNUNET_TIME_Relative *purse_timeout, - struct GNUNET_TIME_Relative *history_expiration, - uint32_t *purse_account_limit, - struct TALER_MasterSignatureP *master_sig) + struct GNUNET_TIME_Timestamp date, + struct GNUNET_TIME_Timestamp *start_date, + struct GNUNET_TIME_Timestamp *end_date, + struct TALER_GlobalFeeSet *fees, + struct GNUNET_TIME_Relative *purse_timeout, + struct GNUNET_TIME_Relative *history_expiration, + uint32_t *purse_account_limit, + struct TALER_MasterSignatureP *master_sig) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -65,25 +65,25 @@ TEH_PG_get_global_fee (void *cls, }; - /* Used in #postgres_get_global_fee() */ - PREPARE(pg, - "get_global_fee", - "SELECT " - " start_date" - ",end_date" - ",history_fee_val" - ",history_fee_frac" - ",account_fee_val" - ",account_fee_frac" - ",purse_fee_val" - ",purse_fee_frac" - ",purse_timeout" - ",history_expiration" - ",purse_account_limit" - ",master_sig" - " FROM global_fee" - " WHERE start_date <= $1" - " AND end_date > $1;"); + /* Used in #postgres_get_global_fee() */ + PREPARE (pg, + "get_global_fee", + "SELECT " + " start_date" + ",end_date" + ",history_fee_val" + ",history_fee_frac" + ",account_fee_val" + ",account_fee_frac" + ",purse_fee_val" + ",purse_fee_frac" + ",purse_timeout" + ",history_expiration" + ",purse_account_limit" + ",master_sig" + " FROM global_fee" + " WHERE start_date <= $1" + " AND end_date > $1;"); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "get_global_fee", params, diff --git a/src/exchangedb/pg_get_global_fee.h b/src/exchangedb/pg_get_global_fee.h index 0887d54d2..1e7c9e94b 100644 --- a/src/exchangedb/pg_get_global_fee.h +++ b/src/exchangedb/pg_get_global_fee.h @@ -40,13 +40,13 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_get_global_fee (void *cls, - struct GNUNET_TIME_Timestamp date, - struct GNUNET_TIME_Timestamp *start_date, - struct GNUNET_TIME_Timestamp *end_date, - struct TALER_GlobalFeeSet *fees, - struct GNUNET_TIME_Relative *purse_timeout, - struct GNUNET_TIME_Relative *history_expiration, - uint32_t *purse_account_limit, + struct GNUNET_TIME_Timestamp date, + struct GNUNET_TIME_Timestamp *start_date, + struct GNUNET_TIME_Timestamp *end_date, + struct TALER_GlobalFeeSet *fees, + struct GNUNET_TIME_Relative *purse_timeout, + struct GNUNET_TIME_Relative *history_expiration, + uint32_t *purse_account_limit, struct TALER_MasterSignatureP *master_sig); #endif diff --git a/src/exchangedb/pg_get_global_fees.c b/src/exchangedb/pg_get_global_fees.c index 0e1736bd4..e01eb2dab 100644 --- a/src/exchangedb/pg_get_global_fees.c +++ b/src/exchangedb/pg_get_global_fees.c @@ -121,11 +121,10 @@ global_fees_cb (void *cls, } - enum GNUNET_DB_QueryStatus TEH_PG_get_global_fees (void *cls, - TALER_EXCHANGEDB_GlobalFeeCallback cb, - void *cb_cls) + TALER_EXCHANGEDB_GlobalFeeCallback cb, + void *cb_cls) { struct PostgresClosure *pg = cls; struct GNUNET_TIME_Timestamp date @@ -144,7 +143,7 @@ TEH_PG_get_global_fees (void *cls, .status = GNUNET_OK }; - /* Used in #postgres_get_global_fees() */ + /* Used in #postgres_get_global_fees() */ PREPARE (pg, "get_global_fees", "SELECT " @@ -169,7 +168,3 @@ TEH_PG_get_global_fees (void *cls, &global_fees_cb, &gctx); } - - - - diff --git a/src/exchangedb/pg_get_global_fees.h b/src/exchangedb/pg_get_global_fees.h index c8f6f02c2..80c9b812f 100644 --- a/src/exchangedb/pg_get_global_fees.h +++ b/src/exchangedb/pg_get_global_fees.h @@ -35,6 +35,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_get_global_fees (void *cls, - TALER_EXCHANGEDB_GlobalFeeCallback cb, + TALER_EXCHANGEDB_GlobalFeeCallback cb, void *cb_cls); + #endif diff --git a/src/exchangedb/pg_get_known_coin.c b/src/exchangedb/pg_get_known_coin.c index fe5c683bc..bab48c119 100644 --- a/src/exchangedb/pg_get_known_coin.c +++ b/src/exchangedb/pg_get_known_coin.c @@ -27,8 +27,8 @@ enum GNUNET_DB_QueryStatus TEH_PG_get_known_coin (void *cls, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - struct TALER_CoinPublicInfo *coin_info) + const struct TALER_CoinSpendPublicKeyP *coin_pub, + struct TALER_CoinPublicInfo *coin_info) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -51,9 +51,9 @@ TEH_PG_get_known_coin (void *cls, "Getting known coin data for coin %s\n", TALER_B2S (coin_pub)); coin_info->coin_pub = *coin_pub; - /* Used in #postgres_get_known_coin() to fetch - the denomination public key and signature for - a coin known to the exchange. */ + /* Used in #postgres_get_known_coin() to fetch + the denomination public key and signature for + a coin known to the exchange. */ PREPARE (pg, "get_known_coin", "SELECT" diff --git a/src/exchangedb/pg_get_known_coin.h b/src/exchangedb/pg_get_known_coin.h index d7f55b33c..c34bd2a97 100644 --- a/src/exchangedb/pg_get_known_coin.h +++ b/src/exchangedb/pg_get_known_coin.h @@ -34,7 +34,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_get_known_coin (void *cls, - const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendPublicKeyP *coin_pub, struct TALER_CoinPublicInfo *coin_info); #endif diff --git a/src/exchangedb/pg_get_melt.c b/src/exchangedb/pg_get_melt.c index f239c605b..8e5685ec3 100644 --- a/src/exchangedb/pg_get_melt.c +++ b/src/exchangedb/pg_get_melt.c @@ -28,9 +28,9 @@ enum GNUNET_DB_QueryStatus TEH_PG_get_melt (void *cls, - const struct TALER_RefreshCommitmentP *rc, - struct TALER_EXCHANGEDB_Melt *melt, - uint64_t *melt_serial_id) + const struct TALER_RefreshCommitmentP *rc, + struct TALER_EXCHANGEDB_Melt *melt, + uint64_t *melt_serial_id) { struct PostgresClosure *pg = cls; bool h_age_commitment_is_null; @@ -66,8 +66,8 @@ TEH_PG_get_melt (void *cls, 0, sizeof (melt->session.coin.denom_sig)); - /* Used in #postgres_get_melt() to fetch - high-level information about a melt operation */ + /* Used in #postgres_get_melt() to fetch + high-level information about a melt operation */ PREPARE (pg, "get_melt", /* "SELECT" diff --git a/src/exchangedb/pg_get_melt.h b/src/exchangedb/pg_get_melt.h index 73d757a05..269960bad 100644 --- a/src/exchangedb/pg_get_melt.h +++ b/src/exchangedb/pg_get_melt.h @@ -37,8 +37,8 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_get_melt (void *cls, - const struct TALER_RefreshCommitmentP *rc, - struct TALER_EXCHANGEDB_Melt *melt, + const struct TALER_RefreshCommitmentP *rc, + struct TALER_EXCHANGEDB_Melt *melt, uint64_t *melt_serial_id); #endif diff --git a/src/exchangedb/pg_get_old_coin_by_h_blind.c b/src/exchangedb/pg_get_old_coin_by_h_blind.c index 385c3f1d1..dcce7b32f 100644 --- a/src/exchangedb/pg_get_old_coin_by_h_blind.c +++ b/src/exchangedb/pg_get_old_coin_by_h_blind.c @@ -26,7 +26,6 @@ #include "pg_helper.h" - enum GNUNET_DB_QueryStatus TEH_PG_get_old_coin_by_h_blind ( void *cls, @@ -47,7 +46,7 @@ TEH_PG_get_old_coin_by_h_blind ( GNUNET_PQ_result_spec_end }; - /* Used in #postgres_get_old_coin_by_h_blind() */ + /* Used in #postgres_get_old_coin_by_h_blind() */ PREPARE (pg, "old_coin_by_h_blind", "SELECT" diff --git a/src/exchangedb/pg_get_old_coin_by_h_blind.h b/src/exchangedb/pg_get_old_coin_by_h_blind.h index 1404990d9..93ed541b6 100644 --- a/src/exchangedb/pg_get_old_coin_by_h_blind.h +++ b/src/exchangedb/pg_get_old_coin_by_h_blind.h @@ -41,4 +41,5 @@ TEH_PG_get_old_coin_by_h_blind ( const struct TALER_BlindedCoinHashP *h_blind_ev, struct TALER_CoinSpendPublicKeyP *old_coin_pub, uint64_t *rrc_serial); + #endif diff --git a/src/exchangedb/pg_get_policy_details.c b/src/exchangedb/pg_get_policy_details.c index fafdca53c..6e1b5c5dc 100644 --- a/src/exchangedb/pg_get_policy_details.c +++ b/src/exchangedb/pg_get_policy_details.c @@ -57,7 +57,6 @@ TEH_PG_get_policy_details ( }; - return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "get_policy_details", params, diff --git a/src/exchangedb/pg_get_purse_deposit.c b/src/exchangedb/pg_get_purse_deposit.c index 539bd5ece..8a135818d 100644 --- a/src/exchangedb/pg_get_purse_deposit.c +++ b/src/exchangedb/pg_get_purse_deposit.c @@ -61,7 +61,7 @@ TEH_PG_get_purse_deposit ( *partner_url = NULL; - /* Used in #postgres_get_purse_deposit */ + /* Used in #postgres_get_purse_deposit */ PREPARE (pg, "select_purse_deposit_by_coin_pub", "SELECT " diff --git a/src/exchangedb/pg_get_purse_request.c b/src/exchangedb/pg_get_purse_request.c index ba8182857..c5f5aac76 100644 --- a/src/exchangedb/pg_get_purse_request.c +++ b/src/exchangedb/pg_get_purse_request.c @@ -59,7 +59,7 @@ TEH_PG_get_purse_request ( purse_sig), GNUNET_PQ_result_spec_end }; - + PREPARE (pg, "get_purse_request", "SELECT " @@ -80,4 +80,3 @@ TEH_PG_get_purse_request ( params, rs); } - diff --git a/src/exchangedb/pg_get_ready_deposit.h b/src/exchangedb/pg_get_ready_deposit.h index 19b6dafe4..b1dd7a968 100644 --- a/src/exchangedb/pg_get_ready_deposit.h +++ b/src/exchangedb/pg_get_ready_deposit.h @@ -38,9 +38,9 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_get_ready_deposit (void *cls, - uint64_t start_shard_row, - uint64_t end_shard_row, - struct TALER_MerchantPublicKeyP *merchant_pub, + uint64_t start_shard_row, + uint64_t end_shard_row, + struct TALER_MerchantPublicKeyP *merchant_pub, char **payto_uri); #endif diff --git a/src/exchangedb/pg_get_refresh_reveal.c b/src/exchangedb/pg_get_refresh_reveal.c index e2db082b7..07d632248 100644 --- a/src/exchangedb/pg_get_refresh_reveal.c +++ b/src/exchangedb/pg_get_refresh_reveal.c @@ -133,14 +133,11 @@ add_revealed_coins (void *cls, } - - - enum GNUNET_DB_QueryStatus TEH_PG_get_refresh_reveal (void *cls, - const struct TALER_RefreshCommitmentP *rc, - TALER_EXCHANGEDB_RefreshCallback cb, - void *cb_cls) + const struct TALER_RefreshCommitmentP *rc, + TALER_EXCHANGEDB_RefreshCallback cb, + void *cb_cls) { struct PostgresClosure *pg = cls; struct GetRevealContext grctx; @@ -154,8 +151,8 @@ TEH_PG_get_refresh_reveal (void *cls, 0, sizeof (grctx)); - /* Obtain information about the coins created in a refresh - operation, used in #postgres_get_refresh_reveal() */ + /* Obtain information about the coins created in a refresh + operation, used in #postgres_get_refresh_reveal() */ PREPARE (pg, "get_refresh_revealed_coins", "SELECT " diff --git a/src/exchangedb/pg_get_refresh_reveal.h b/src/exchangedb/pg_get_refresh_reveal.h index 0fcea26cd..15b57b343 100644 --- a/src/exchangedb/pg_get_refresh_reveal.h +++ b/src/exchangedb/pg_get_refresh_reveal.h @@ -37,8 +37,8 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_get_refresh_reveal (void *cls, - const struct TALER_RefreshCommitmentP *rc, - TALER_EXCHANGEDB_RefreshCallback cb, + const struct TALER_RefreshCommitmentP *rc, + TALER_EXCHANGEDB_RefreshCallback cb, void *cb_cls); #endif diff --git a/src/exchangedb/pg_get_reserve_balance.c b/src/exchangedb/pg_get_reserve_balance.c index e08261fc0..7d5eb58f8 100644 --- a/src/exchangedb/pg_get_reserve_balance.c +++ b/src/exchangedb/pg_get_reserve_balance.c @@ -27,8 +27,8 @@ enum GNUNET_DB_QueryStatus TEH_PG_get_reserve_balance (void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - struct TALER_Amount *balance) + const struct TALER_ReservePublicKeyP *reserve_pub, + struct TALER_Amount *balance) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { diff --git a/src/exchangedb/pg_get_reserve_balance.h b/src/exchangedb/pg_get_reserve_balance.h index fd15f0d80..6dc88d906 100644 --- a/src/exchangedb/pg_get_reserve_balance.h +++ b/src/exchangedb/pg_get_reserve_balance.h @@ -34,7 +34,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_get_reserve_balance (void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReservePublicKeyP *reserve_pub, struct TALER_Amount *balance); #endif diff --git a/src/exchangedb/pg_get_reserve_by_h_blind.c b/src/exchangedb/pg_get_reserve_by_h_blind.c index 2105b4766..f87fe6cd4 100644 --- a/src/exchangedb/pg_get_reserve_by_h_blind.c +++ b/src/exchangedb/pg_get_reserve_by_h_blind.c @@ -45,7 +45,7 @@ TEH_PG_get_reserve_by_h_blind ( reserve_out_serial_id), GNUNET_PQ_result_spec_end }; - /* Used in #postgres_get_reserve_by_h_blind() */ + /* Used in #postgres_get_reserve_by_h_blind() */ PREPARE (pg, "reserve_by_h_blind", "SELECT" diff --git a/src/exchangedb/pg_get_wire_accounts.c b/src/exchangedb/pg_get_wire_accounts.c index 6986eaef2..43590acf8 100644 --- a/src/exchangedb/pg_get_wire_accounts.c +++ b/src/exchangedb/pg_get_wire_accounts.c @@ -92,12 +92,10 @@ get_wire_accounts_cb (void *cls, } - - enum GNUNET_DB_QueryStatus TEH_PG_get_wire_accounts (void *cls, - TALER_EXCHANGEDB_WireAccountCallback cb, - void *cb_cls) + TALER_EXCHANGEDB_WireAccountCallback cb, + void *cb_cls) { struct PostgresClosure *pg = cls; struct GetWireAccountsContext ctx = { @@ -111,12 +109,12 @@ TEH_PG_get_wire_accounts (void *cls, enum GNUNET_DB_QueryStatus qs; PREPARE (pg, - "get_wire_accounts", - "SELECT" - " payto_uri" - ",master_sig" - " FROM wire_accounts" - " WHERE is_active"); + "get_wire_accounts", + "SELECT" + " payto_uri" + ",master_sig" + " FROM wire_accounts" + " WHERE is_active"); qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, "get_wire_accounts", params, diff --git a/src/exchangedb/pg_get_wire_accounts.h b/src/exchangedb/pg_get_wire_accounts.h index 4ddda0ed3..f4dc97ce0 100644 --- a/src/exchangedb/pg_get_wire_accounts.h +++ b/src/exchangedb/pg_get_wire_accounts.h @@ -36,7 +36,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_get_wire_accounts (void *cls, - TALER_EXCHANGEDB_WireAccountCallback cb, + TALER_EXCHANGEDB_WireAccountCallback cb, void *cb_cls); #endif diff --git a/src/exchangedb/pg_get_wire_fee.c b/src/exchangedb/pg_get_wire_fee.c index 4b4324766..4aab68b85 100644 --- a/src/exchangedb/pg_get_wire_fee.c +++ b/src/exchangedb/pg_get_wire_fee.c @@ -27,12 +27,12 @@ enum GNUNET_DB_QueryStatus TEH_PG_get_wire_fee (void *cls, - const char *type, - struct GNUNET_TIME_Timestamp date, - struct GNUNET_TIME_Timestamp *start_date, - struct GNUNET_TIME_Timestamp *end_date, - struct TALER_WireFeeSet *fees, - struct TALER_MasterSignatureP *master_sig) + const char *type, + struct GNUNET_TIME_Timestamp date, + struct GNUNET_TIME_Timestamp *start_date, + struct GNUNET_TIME_Timestamp *end_date, + struct TALER_WireFeeSet *fees, + struct TALER_MasterSignatureP *master_sig) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -55,22 +55,21 @@ TEH_PG_get_wire_fee (void *cls, }; - - /* Used in #postgres_get_wire_fee() */ - PREPARE(pg, - "get_wire_fee", - "SELECT " - " start_date" - ",end_date" - ",wire_fee_val" - ",wire_fee_frac" - ",closing_fee_val" - ",closing_fee_frac" - ",master_sig" - " FROM wire_fee" - " WHERE wire_method=$1" - " AND start_date <= $2" - " AND end_date > $2;"); + /* Used in #postgres_get_wire_fee() */ + PREPARE (pg, + "get_wire_fee", + "SELECT " + " start_date" + ",end_date" + ",wire_fee_val" + ",wire_fee_frac" + ",closing_fee_val" + ",closing_fee_frac" + ",master_sig" + " FROM wire_fee" + " WHERE wire_method=$1" + " AND start_date <= $2" + " AND end_date > $2;"); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "get_wire_fee", params, diff --git a/src/exchangedb/pg_get_wire_fee.h b/src/exchangedb/pg_get_wire_fee.h index 92107fe30..409a5c48b 100644 --- a/src/exchangedb/pg_get_wire_fee.h +++ b/src/exchangedb/pg_get_wire_fee.h @@ -39,11 +39,11 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_get_wire_fee (void *cls, - const char *type, - struct GNUNET_TIME_Timestamp date, - struct GNUNET_TIME_Timestamp *start_date, - struct GNUNET_TIME_Timestamp *end_date, - struct TALER_WireFeeSet *fees, + const char *type, + struct GNUNET_TIME_Timestamp date, + struct GNUNET_TIME_Timestamp *start_date, + struct GNUNET_TIME_Timestamp *end_date, + struct TALER_WireFeeSet *fees, struct TALER_MasterSignatureP *master_sig); #endif diff --git a/src/exchangedb/pg_get_wire_fees.c b/src/exchangedb/pg_get_wire_fees.c index a83db151d..e34d44a9a 100644 --- a/src/exchangedb/pg_get_wire_fees.c +++ b/src/exchangedb/pg_get_wire_fees.c @@ -109,9 +109,9 @@ get_wire_fees_cb (void *cls, enum GNUNET_DB_QueryStatus TEH_PG_get_wire_fees (void *cls, - const char *wire_method, - TALER_EXCHANGEDB_WireFeeCallback cb, - void *cb_cls) + const char *wire_method, + TALER_EXCHANGEDB_WireFeeCallback cb, + void *cb_cls) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { diff --git a/src/exchangedb/pg_get_wire_fees.h b/src/exchangedb/pg_get_wire_fees.h index 83bacd674..798a514db 100644 --- a/src/exchangedb/pg_get_wire_fees.h +++ b/src/exchangedb/pg_get_wire_fees.h @@ -37,8 +37,8 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_get_wire_fees (void *cls, - const char *wire_method, - TALER_EXCHANGEDB_WireFeeCallback cb, + const char *wire_method, + TALER_EXCHANGEDB_WireFeeCallback cb, void *cb_cls); #endif diff --git a/src/exchangedb/pg_get_withdraw_info.c b/src/exchangedb/pg_get_withdraw_info.c index ef3936269..d6a180b00 100644 --- a/src/exchangedb/pg_get_withdraw_info.c +++ b/src/exchangedb/pg_get_withdraw_info.c @@ -55,10 +55,10 @@ TEH_PG_get_withdraw_info ( GNUNET_PQ_result_spec_end }; - /* Used in #postgres_get_withdraw_info() to - locate the response for a /reserve/withdraw request - using the hash of the blinded message. Used to - make sure /reserve/withdraw requests are idempotent. */ + /* Used in #postgres_get_withdraw_info() to + locate the response for a /reserve/withdraw request + using the hash of the blinded message. Used to + make sure /reserve/withdraw requests are idempotent. */ PREPARE (pg, "get_withdraw_info", "SELECT" diff --git a/src/exchangedb/pg_have_deposit2.c b/src/exchangedb/pg_have_deposit2.c index 1616858c5..92c300605 100644 --- a/src/exchangedb/pg_have_deposit2.c +++ b/src/exchangedb/pg_have_deposit2.c @@ -71,29 +71,29 @@ TEH_PG_have_deposit2 ( "Getting deposits for coin %s\n", TALER_B2S (coin_pub)); - /* Fetch an existing deposit request, used to ensure idempotency - during /deposit processing. Used in #postgres_have_deposit(). */ + /* Fetch an existing deposit request, used to ensure idempotency + during /deposit processing. Used in #postgres_have_deposit(). */ PREPARE (pg, - "get_deposit", - "SELECT" - " dep.amount_with_fee_val" - ",dep.amount_with_fee_frac" - ",denominations.fee_deposit_val" - ",denominations.fee_deposit_frac" - ",dep.wallet_timestamp" - ",dep.exchange_timestamp" - ",dep.refund_deadline" - ",dep.wire_deadline" - ",dep.h_contract_terms" - ",dep.wire_salt" - ",wt.payto_uri AS receiver_wire_account" - " FROM deposits dep" - " JOIN known_coins kc ON (kc.coin_pub = dep.coin_pub)" - " JOIN denominations USING (denominations_serial)" - " JOIN wire_targets wt USING (wire_target_h_payto)" - " WHERE dep.coin_pub=$1" - " AND dep.merchant_pub=$3" - " AND dep.h_contract_terms=$2;"); + "get_deposit", + "SELECT" + " dep.amount_with_fee_val" + ",dep.amount_with_fee_frac" + ",denominations.fee_deposit_val" + ",denominations.fee_deposit_frac" + ",dep.wallet_timestamp" + ",dep.exchange_timestamp" + ",dep.refund_deadline" + ",dep.wire_deadline" + ",dep.h_contract_terms" + ",dep.wire_salt" + ",wt.payto_uri AS receiver_wire_account" + " FROM deposits dep" + " JOIN known_coins kc ON (kc.coin_pub = dep.coin_pub)" + " JOIN denominations USING (denominations_serial)" + " JOIN wire_targets wt USING (wire_target_h_payto)" + " WHERE dep.coin_pub=$1" + " AND dep.merchant_pub=$3" + " AND dep.h_contract_terms=$2;"); qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "get_deposit", diff --git a/src/exchangedb/pg_insert_aggregation_tracking.c b/src/exchangedb/pg_insert_aggregation_tracking.c index 01c5928ba..fe61b841d 100644 --- a/src/exchangedb/pg_insert_aggregation_tracking.c +++ b/src/exchangedb/pg_insert_aggregation_tracking.c @@ -51,4 +51,3 @@ TEH_PG_insert_aggregation_tracking ( "insert_aggregation_tracking", params); } - diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h b/src/exchangedb/pg_insert_aggregation_tracking.h index 4f0ac1aae..e67c0e8e7 100644 --- a/src/exchangedb/pg_insert_aggregation_tracking.h +++ b/src/exchangedb/pg_insert_aggregation_tracking.h @@ -40,4 +40,3 @@ TEH_PG_insert_aggregation_tracking ( unsigned long long deposit_serial_id); #endif - diff --git a/src/exchangedb/pg_insert_auditor.c b/src/exchangedb/pg_insert_auditor.c index 757dfa625..2f1de7ba7 100644 --- a/src/exchangedb/pg_insert_auditor.c +++ b/src/exchangedb/pg_insert_auditor.c @@ -27,10 +27,10 @@ enum GNUNET_DB_QueryStatus TEH_PG_insert_auditor (void *cls, - const struct TALER_AuditorPublicKeyP *auditor_pub, - const char *auditor_url, - const char *auditor_name, - struct GNUNET_TIME_Timestamp start_date) + const struct TALER_AuditorPublicKeyP *auditor_pub, + const char *auditor_url, + const char *auditor_name, + struct GNUNET_TIME_Timestamp start_date) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -41,7 +41,7 @@ TEH_PG_insert_auditor (void *cls, GNUNET_PQ_query_param_end }; - /* used in #postgres_insert_auditor() */ + /* used in #postgres_insert_auditor() */ PREPARE (pg, "insert_auditor", "INSERT INTO auditors " diff --git a/src/exchangedb/pg_insert_auditor.h b/src/exchangedb/pg_insert_auditor.h index 7523282e4..8de388f23 100644 --- a/src/exchangedb/pg_insert_auditor.h +++ b/src/exchangedb/pg_insert_auditor.h @@ -38,8 +38,8 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_insert_auditor (void *cls, - const struct TALER_AuditorPublicKeyP *auditor_pub, - const char *auditor_url, - const char *auditor_name, + const struct TALER_AuditorPublicKeyP *auditor_pub, + const char *auditor_url, + const char *auditor_name, struct GNUNET_TIME_Timestamp start_date); #endif diff --git a/src/exchangedb/pg_insert_contract.c b/src/exchangedb/pg_insert_contract.c index d3e6c23be..0274f8d93 100644 --- a/src/exchangedb/pg_insert_contract.c +++ b/src/exchangedb/pg_insert_contract.c @@ -45,20 +45,20 @@ TEH_PG_insert_contract ( }; *in_conflict = false; - /* Used in #postgres_insert_contract() */ + /* Used in #postgres_insert_contract() */ PREPARE (pg, - "insert_contract", - "INSERT INTO contracts" - " (purse_pub" - " ,pub_ckey" - " ,e_contract" - " ,contract_sig" - " ,purse_expiration" - " ) SELECT " - " $1, $2, $3, $4, purse_expiration" - " FROM purse_requests" - " WHERE purse_pub=$1" - " ON CONFLICT DO NOTHING;"); + "insert_contract", + "INSERT INTO contracts" + " (purse_pub" + " ,pub_ckey" + " ,e_contract" + " ,contract_sig" + " ,purse_expiration" + " ) SELECT " + " $1, $2, $3, $4, purse_expiration" + " FROM purse_requests" + " WHERE purse_pub=$1" + " ON CONFLICT DO NOTHING;"); qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, "insert_contract", params); @@ -68,8 +68,8 @@ TEH_PG_insert_contract ( struct TALER_EncryptedContract econtract2; qs = TEH_PG_select_contract_by_purse (pg, - purse_pub, - &econtract2); + purse_pub, + &econtract2); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { GNUNET_break (0); diff --git a/src/exchangedb/pg_insert_denomination_revocation.c b/src/exchangedb/pg_insert_denomination_revocation.c index 061d7adc0..49445f262 100644 --- a/src/exchangedb/pg_insert_denomination_revocation.c +++ b/src/exchangedb/pg_insert_denomination_revocation.c @@ -39,7 +39,7 @@ TEH_PG_insert_denomination_revocation ( GNUNET_PQ_query_param_end }; - /* Used in #postgres_insert_denomination_revocation() */ + /* Used in #postgres_insert_denomination_revocation() */ PREPARE (pg, "denomination_revocation_insert", "INSERT INTO denomination_revocations " diff --git a/src/exchangedb/pg_insert_deposit.h b/src/exchangedb/pg_insert_deposit.h index 15de39eff..82cbcd542 100644 --- a/src/exchangedb/pg_insert_deposit.h +++ b/src/exchangedb/pg_insert_deposit.h @@ -34,7 +34,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_insert_deposit (void *cls, - struct GNUNET_TIME_Timestamp exchange_timestamp, + struct GNUNET_TIME_Timestamp exchange_timestamp, const struct TALER_EXCHANGEDB_Deposit *deposit); #endif diff --git a/src/exchangedb/pg_insert_drain_profit.c b/src/exchangedb/pg_insert_drain_profit.c index 19340eafb..34ab0332c 100644 --- a/src/exchangedb/pg_insert_drain_profit.c +++ b/src/exchangedb/pg_insert_drain_profit.c @@ -45,7 +45,7 @@ TEH_PG_insert_drain_profit ( GNUNET_PQ_query_param_auto_from_type (master_sig), GNUNET_PQ_query_param_end }; - /* Used in #postgres_insert_drain_profit() */ + /* Used in #postgres_insert_drain_profit() */ PREPARE (pg, "drain_profit_insert", "INSERT INTO profit_drains " diff --git a/src/exchangedb/pg_insert_global_fee.c b/src/exchangedb/pg_insert_global_fee.c index c08fc23bb..1c34016a7 100644 --- a/src/exchangedb/pg_insert_global_fee.c +++ b/src/exchangedb/pg_insert_global_fee.c @@ -28,13 +28,13 @@ enum GNUNET_DB_QueryStatus TEH_PG_insert_global_fee (void *cls, - struct GNUNET_TIME_Timestamp start_date, - struct GNUNET_TIME_Timestamp end_date, - const struct TALER_GlobalFeeSet *fees, - struct GNUNET_TIME_Relative purse_timeout, - struct GNUNET_TIME_Relative history_expiration, - uint32_t purse_account_limit, - const struct TALER_MasterSignatureP *master_sig) + struct GNUNET_TIME_Timestamp start_date, + struct GNUNET_TIME_Timestamp end_date, + const struct TALER_GlobalFeeSet *fees, + struct GNUNET_TIME_Relative purse_timeout, + struct GNUNET_TIME_Relative history_expiration, + uint32_t purse_account_limit, + const struct TALER_MasterSignatureP *master_sig) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -59,14 +59,14 @@ TEH_PG_insert_global_fee (void *cls, uint32_t pal; qs = TEH_PG_get_global_fee (pg, - start_date, - &sd, - &ed, - &wx, - &pt, - &he, - &pal, - &sig); + start_date, + &sd, + &ed, + &wx, + &pt, + &he, + &pal, + &sig); if (qs < 0) return qs; if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) @@ -113,7 +113,7 @@ TEH_PG_insert_global_fee (void *cls, return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; } - /* Used in #postgres_insert_global_fee */ + /* Used in #postgres_insert_global_fee */ PREPARE (pg, "insert_global_fee", "INSERT INTO global_fee " diff --git a/src/exchangedb/pg_insert_global_fee.h b/src/exchangedb/pg_insert_global_fee.h index 9780d5322..411345dc4 100644 --- a/src/exchangedb/pg_insert_global_fee.h +++ b/src/exchangedb/pg_insert_global_fee.h @@ -40,11 +40,11 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_insert_global_fee (void *cls, - struct GNUNET_TIME_Timestamp start_date, - struct GNUNET_TIME_Timestamp end_date, - const struct TALER_GlobalFeeSet *fees, - struct GNUNET_TIME_Relative purse_timeout, - struct GNUNET_TIME_Relative history_expiration, - uint32_t purse_account_limit, + struct GNUNET_TIME_Timestamp start_date, + struct GNUNET_TIME_Timestamp end_date, + const struct TALER_GlobalFeeSet *fees, + struct GNUNET_TIME_Relative purse_timeout, + struct GNUNET_TIME_Relative history_expiration, + uint32_t purse_account_limit, const struct TALER_MasterSignatureP *master_sig); #endif diff --git a/src/exchangedb/pg_insert_history_request.c b/src/exchangedb/pg_insert_history_request.c index 00270b1a1..ab3f39133 100644 --- a/src/exchangedb/pg_insert_history_request.c +++ b/src/exchangedb/pg_insert_history_request.c @@ -51,7 +51,7 @@ TEH_PG_insert_history_request ( idempotent), GNUNET_PQ_result_spec_end }; - /* Used in #postgres_insert_history_request() */ + /* Used in #postgres_insert_history_request() */ PREPARE (pg, "call_history_request", "SELECT" diff --git a/src/exchangedb/pg_insert_kyc_requirement_for_account.c b/src/exchangedb/pg_insert_kyc_requirement_for_account.c index be5cbac87..2552aae40 100644 --- a/src/exchangedb/pg_insert_kyc_requirement_for_account.c +++ b/src/exchangedb/pg_insert_kyc_requirement_for_account.c @@ -43,7 +43,7 @@ TEH_PG_insert_kyc_requirement_for_account ( requirement_row), GNUNET_PQ_result_spec_end }; - /* Used in #postgres_insert_kyc_requirement_for_account() */ + /* Used in #postgres_insert_kyc_requirement_for_account() */ PREPARE (pg, "insert_legitimization_requirement", "INSERT INTO legitimization_requirements" diff --git a/src/exchangedb/pg_insert_kyc_requirement_for_account.h b/src/exchangedb/pg_insert_kyc_requirement_for_account.h index 5f9bf6a48..c2f03b02a 100644 --- a/src/exchangedb/pg_insert_kyc_requirement_for_account.h +++ b/src/exchangedb/pg_insert_kyc_requirement_for_account.h @@ -41,4 +41,5 @@ TEH_PG_insert_kyc_requirement_for_account ( const char *provider_section, const struct TALER_PaytoHashP *h_payto, uint64_t *requirement_row); + #endif diff --git a/src/exchangedb/pg_insert_kyc_requirement_process.c b/src/exchangedb/pg_insert_kyc_requirement_process.c index d520ac59c..f1ea5b490 100644 --- a/src/exchangedb/pg_insert_kyc_requirement_process.c +++ b/src/exchangedb/pg_insert_kyc_requirement_process.c @@ -52,7 +52,7 @@ TEH_PG_insert_kyc_requirement_process ( GNUNET_PQ_result_spec_end }; - /* Used in #postgres_insert_kyc_requirement_process() */ + /* Used in #postgres_insert_kyc_requirement_process() */ PREPARE (pg, "insert_legitimization_process", "INSERT INTO legitimization_processes" diff --git a/src/exchangedb/pg_insert_kyc_requirement_process.h b/src/exchangedb/pg_insert_kyc_requirement_process.h index 3f354472e..df21db8cd 100644 --- a/src/exchangedb/pg_insert_kyc_requirement_process.h +++ b/src/exchangedb/pg_insert_kyc_requirement_process.h @@ -45,4 +45,5 @@ TEH_PG_insert_kyc_requirement_process ( const char *provider_account_id, const char *provider_legitimization_id, uint64_t *process_row); + #endif diff --git a/src/exchangedb/pg_insert_partner.h b/src/exchangedb/pg_insert_partner.h index eed40a80e..3ebae786c 100644 --- a/src/exchangedb/pg_insert_partner.h +++ b/src/exchangedb/pg_insert_partner.h @@ -40,12 +40,12 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_insert_partner (void *cls, - const struct TALER_MasterPublicKeyP *master_pub, - struct GNUNET_TIME_Timestamp start_date, - struct GNUNET_TIME_Timestamp end_date, - struct GNUNET_TIME_Relative wad_frequency, - const struct TALER_Amount *wad_fee, - const char *partner_base_url, + const struct TALER_MasterPublicKeyP *master_pub, + struct GNUNET_TIME_Timestamp start_date, + struct GNUNET_TIME_Timestamp end_date, + struct GNUNET_TIME_Relative wad_frequency, + const struct TALER_Amount *wad_fee, + const char *partner_base_url, const struct TALER_MasterSignatureP *master_sig); #endif diff --git a/src/exchangedb/pg_insert_records_by_table.c b/src/exchangedb/pg_insert_records_by_table.c index d6630797a..3ec9c77cc 100644 --- a/src/exchangedb/pg_insert_records_by_table.c +++ b/src/exchangedb/pg_insert_records_by_table.c @@ -1,6 +1,6 @@ /* 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 under the terms of the GNU Affero General Public License as published @@ -19,8 +19,9 @@ */ /** * @file exchangedb/pg_insert_records_by_table.c - * @brief insert_records_by_table implementation + * @brief replicate_records_by_table implementation * @author Christian Grothoff + * @author Özgür Kesim */ #include "platform.h" #include "taler_error_codes.h" @@ -28,6 +29,7 @@ #include "taler_pq_lib.h" #include "pg_insert_records_by_table.h" #include "pg_helper.h" +#include /** @@ -1407,7 +1409,7 @@ irbt_cb_table_purse_decision (struct PostgresClosure *pg, GNUNET_PQ_query_param_timestamp ( &td->details.purse_decision.action_timestamp), GNUNET_PQ_query_param_bool ( - &td->details.purse_decision.refunded), + td->details.purse_decision.refunded), 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 TEH_PG_insert_records_by_table (void *cls, const struct TALER_EXCHANGEDB_TableData *td) { struct PostgresClosure *pg = cls; - InsertRecordCallback rh; + InsertRecordCallback rh = NULL; switch (td->table) { @@ -2007,7 +2301,27 @@ TEH_PG_insert_records_by_table (void *cls, case TALER_EXCHANGEDB_RT_PROFIT_DRAINS: rh = &irbt_cb_table_profit_drains; 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); 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 */ diff --git a/src/exchangedb/pg_insert_refund.c b/src/exchangedb/pg_insert_refund.c index 047df0334..8f9466575 100644 --- a/src/exchangedb/pg_insert_refund.c +++ b/src/exchangedb/pg_insert_refund.c @@ -28,7 +28,7 @@ enum GNUNET_DB_QueryStatus TEH_PG_insert_refund (void *cls, - const struct TALER_EXCHANGEDB_Refund *refund) + const struct TALER_EXCHANGEDB_Refund *refund) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -45,7 +45,7 @@ TEH_PG_insert_refund (void *cls, TALER_amount_cmp_currency (&refund->details.refund_amount, &refund->details.refund_fee)); - /* Used in #postgres_insert_refund() to store refund information */ + /* Used in #postgres_insert_refund() to store refund information */ PREPARE (pg, "insert_refund", "INSERT INTO refunds " diff --git a/src/exchangedb/pg_insert_reserve_closed.c b/src/exchangedb/pg_insert_reserve_closed.c index d17c37edc..963a38226 100644 --- a/src/exchangedb/pg_insert_reserve_closed.c +++ b/src/exchangedb/pg_insert_reserve_closed.c @@ -57,20 +57,20 @@ TEH_PG_insert_reserve_closed ( GNUNET_PQ_query_param_end }; - /* Used in #postgres_insert_reserve_closed() */ + /* Used in #postgres_insert_reserve_closed() */ PREPARE (pg, - "reserves_close_insert", - "INSERT INTO reserves_close " - "(reserve_pub" - ",execution_date" - ",wtid" - ",wire_target_h_payto" - ",amount_val" - ",amount_frac" - ",closing_fee_val" - ",closing_fee_frac" - ",close_request_row" - ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);"); + "reserves_close_insert", + "INSERT INTO reserves_close " + "(reserve_pub" + ",execution_date" + ",wtid" + ",wire_target_h_payto" + ",amount_val" + ",amount_frac" + ",closing_fee_val" + ",closing_fee_frac" + ",close_request_row" + ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);"); qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, "reserves_close_insert", @@ -83,7 +83,7 @@ TEH_PG_insert_reserve_closed ( reserve.pub = *reserve_pub; if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != (qs = TEH_PG_reserves_get (cls, - &reserve))) + &reserve))) { /* Existence should have been checked before we got here... */ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); @@ -110,5 +110,5 @@ TEH_PG_insert_reserve_closed ( GNUNET_break (TALER_AAR_RESULT_ZERO == ret); } return TEH_PG_reserves_update (cls, - &reserve); + &reserve); } diff --git a/src/exchangedb/pg_insert_wire.h b/src/exchangedb/pg_insert_wire.h index 15ce08674..670928d7c 100644 --- a/src/exchangedb/pg_insert_wire.h +++ b/src/exchangedb/pg_insert_wire.h @@ -37,8 +37,8 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_insert_wire (void *cls, - const char *payto_uri, - struct GNUNET_TIME_Timestamp start_date, + const char *payto_uri, + struct GNUNET_TIME_Timestamp start_date, const struct TALER_MasterSignatureP *master_sig); #endif diff --git a/src/exchangedb/pg_insert_wire_fee.c b/src/exchangedb/pg_insert_wire_fee.c index 278ec2bcb..ac14a8cbb 100644 --- a/src/exchangedb/pg_insert_wire_fee.c +++ b/src/exchangedb/pg_insert_wire_fee.c @@ -28,11 +28,11 @@ enum GNUNET_DB_QueryStatus TEH_PG_insert_wire_fee (void *cls, - const char *type, - struct GNUNET_TIME_Timestamp start_date, - struct GNUNET_TIME_Timestamp end_date, - const struct TALER_WireFeeSet *fees, - const struct TALER_MasterSignatureP *master_sig) + const char *type, + struct GNUNET_TIME_Timestamp start_date, + struct GNUNET_TIME_Timestamp end_date, + const struct TALER_WireFeeSet *fees, + const struct TALER_MasterSignatureP *master_sig) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -51,12 +51,12 @@ TEH_PG_insert_wire_fee (void *cls, enum GNUNET_DB_QueryStatus qs; qs = TEH_PG_get_wire_fee (pg, - type, - start_date, - &sd, - &ed, - &wx, - &sig); + type, + start_date, + &sd, + &ed, + &wx, + &sig); if (qs < 0) return qs; if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) @@ -88,7 +88,7 @@ TEH_PG_insert_wire_fee (void *cls, return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; } - /* Used in #postgres_insert_wire_fee */ + /* Used in #postgres_insert_wire_fee */ PREPARE (pg, "insert_wire_fee", "INSERT INTO wire_fee " diff --git a/src/exchangedb/pg_insert_wire_fee.h b/src/exchangedb/pg_insert_wire_fee.h index e53faf5a5..15c1a39f8 100644 --- a/src/exchangedb/pg_insert_wire_fee.h +++ b/src/exchangedb/pg_insert_wire_fee.h @@ -38,9 +38,9 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_insert_wire_fee (void *cls, - const char *type, - struct GNUNET_TIME_Timestamp start_date, - struct GNUNET_TIME_Timestamp end_date, - const struct TALER_WireFeeSet *fees, + const char *type, + struct GNUNET_TIME_Timestamp start_date, + struct GNUNET_TIME_Timestamp end_date, + const struct TALER_WireFeeSet *fees, const struct TALER_MasterSignatureP *master_sig); #endif diff --git a/src/exchangedb/pg_iterate_active_auditors.h b/src/exchangedb/pg_iterate_active_auditors.h index 1247d2d3d..f0e2808e9 100644 --- a/src/exchangedb/pg_iterate_active_auditors.h +++ b/src/exchangedb/pg_iterate_active_auditors.h @@ -36,6 +36,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_iterate_active_auditors (void *cls, - TALER_EXCHANGEDB_AuditorsCallback cb, + TALER_EXCHANGEDB_AuditorsCallback cb, void *cb_cls); + #endif diff --git a/src/exchangedb/pg_iterate_active_signkeys.h b/src/exchangedb/pg_iterate_active_signkeys.h index b99dfa8df..5ebba9f5a 100644 --- a/src/exchangedb/pg_iterate_active_signkeys.h +++ b/src/exchangedb/pg_iterate_active_signkeys.h @@ -37,7 +37,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_iterate_active_signkeys (void *cls, - TALER_EXCHANGEDB_ActiveSignkeysCallback cb, + TALER_EXCHANGEDB_ActiveSignkeysCallback cb, void *cb_cls); #endif diff --git a/src/exchangedb/pg_iterate_auditor_denominations.h b/src/exchangedb/pg_iterate_auditor_denominations.h index da1f36701..1278e8a9f 100644 --- a/src/exchangedb/pg_iterate_auditor_denominations.h +++ b/src/exchangedb/pg_iterate_auditor_denominations.h @@ -41,4 +41,5 @@ TEH_PG_iterate_auditor_denominations ( void *cls, TALER_EXCHANGEDB_AuditorDenominationsCallback cb, void *cb_cls); + #endif diff --git a/src/exchangedb/pg_iterate_denomination_info.h b/src/exchangedb/pg_iterate_denomination_info.h index 57847a515..27c08d0a9 100644 --- a/src/exchangedb/pg_iterate_denomination_info.h +++ b/src/exchangedb/pg_iterate_denomination_info.h @@ -35,7 +35,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_iterate_denomination_info (void *cls, - TALER_EXCHANGEDB_DenominationCallback cb, + TALER_EXCHANGEDB_DenominationCallback cb, void *cb_cls); #endif diff --git a/src/exchangedb/pg_iterate_denominations.h b/src/exchangedb/pg_iterate_denominations.h index a205fc6ba..9f59fc803 100644 --- a/src/exchangedb/pg_iterate_denominations.h +++ b/src/exchangedb/pg_iterate_denominations.h @@ -38,7 +38,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_iterate_denominations (void *cls, - TALER_EXCHANGEDB_DenominationsCallback cb, + TALER_EXCHANGEDB_DenominationsCallback cb, void *cb_cls); #endif diff --git a/src/exchangedb/pg_kyc_provider_account_lookup.c b/src/exchangedb/pg_kyc_provider_account_lookup.c index 32cd65f7d..f3bd84c1a 100644 --- a/src/exchangedb/pg_kyc_provider_account_lookup.c +++ b/src/exchangedb/pg_kyc_provider_account_lookup.c @@ -26,7 +26,6 @@ #include "pg_helper.h" - enum GNUNET_DB_QueryStatus TEH_PG_kyc_provider_account_lookup ( void *cls, @@ -48,7 +47,7 @@ TEH_PG_kyc_provider_account_lookup ( process_row), GNUNET_PQ_result_spec_end }; - /* Used in #postgres_kyc_provider_account_lookup() */ + /* Used in #postgres_kyc_provider_account_lookup() */ PREPARE (pg, "get_wire_target_by_legitimization_id", "SELECT " diff --git a/src/exchangedb/pg_kyc_provider_account_lookup.h b/src/exchangedb/pg_kyc_provider_account_lookup.h index 41bcb86ae..74f90d88d 100644 --- a/src/exchangedb/pg_kyc_provider_account_lookup.h +++ b/src/exchangedb/pg_kyc_provider_account_lookup.h @@ -44,4 +44,5 @@ TEH_PG_kyc_provider_account_lookup ( const char *provider_legitimization_id, struct TALER_PaytoHashP *h_payto, uint64_t *process_row); + #endif diff --git a/src/exchangedb/pg_lookup_auditor_status.c b/src/exchangedb/pg_lookup_auditor_status.c index 5e62bfa9e..91afe6eaa 100644 --- a/src/exchangedb/pg_lookup_auditor_status.c +++ b/src/exchangedb/pg_lookup_auditor_status.c @@ -46,7 +46,7 @@ TEH_PG_lookup_auditor_status ( GNUNET_PQ_result_spec_end }; - /* Used in #postgres_lookup_auditor_status() */ + /* Used in #postgres_lookup_auditor_status() */ PREPARE (pg, "lookup_auditor_status", "SELECT" diff --git a/src/exchangedb/pg_lookup_denomination_key.c b/src/exchangedb/pg_lookup_denomination_key.c index 36ada96e4..759af1b5c 100644 --- a/src/exchangedb/pg_lookup_denomination_key.c +++ b/src/exchangedb/pg_lookup_denomination_key.c @@ -60,7 +60,7 @@ TEH_PG_lookup_denomination_key ( GNUNET_PQ_result_spec_end }; - /* used in #postgres_lookup_denomination_key() */ + /* used in #postgres_lookup_denomination_key() */ PREPARE (pg, "lookup_denomination_key", "SELECT" diff --git a/src/exchangedb/pg_lookup_global_fee_by_time.h b/src/exchangedb/pg_lookup_global_fee_by_time.h index 9ac7d7dcd..c5ff95fc6 100644 --- a/src/exchangedb/pg_lookup_global_fee_by_time.h +++ b/src/exchangedb/pg_lookup_global_fee_by_time.h @@ -48,4 +48,5 @@ TEH_PG_lookup_global_fee_by_time ( struct GNUNET_TIME_Relative *purse_timeout, struct GNUNET_TIME_Relative *history_expiration, uint32_t *purse_account_limit); + #endif diff --git a/src/exchangedb/pg_lookup_kyc_process_by_account.h b/src/exchangedb/pg_lookup_kyc_process_by_account.h index 40af6a7f6..0300b498c 100644 --- a/src/exchangedb/pg_lookup_kyc_process_by_account.h +++ b/src/exchangedb/pg_lookup_kyc_process_by_account.h @@ -47,4 +47,5 @@ TEH_PG_lookup_kyc_process_by_account ( struct GNUNET_TIME_Absolute *expiration, char **provider_account_id, char **provider_legitimization_id); + #endif diff --git a/src/exchangedb/pg_lookup_kyc_requirement_by_row.c b/src/exchangedb/pg_lookup_kyc_requirement_by_row.c index 6542aa28f..6f9d76786 100644 --- a/src/exchangedb/pg_lookup_kyc_requirement_by_row.c +++ b/src/exchangedb/pg_lookup_kyc_requirement_by_row.c @@ -30,9 +30,11 @@ TEH_PG_lookup_kyc_requirement_by_row ( void *cls, uint64_t requirement_row, char **requirements, + enum TALER_AmlDecisionState *aml_status, struct TALER_PaytoHashP *h_payto) { struct PostgresClosure *pg = cls; + uint32_t status = TALER_AML_NORMAL; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_uint64 (&requirement_row), GNUNET_PQ_query_param_end @@ -42,19 +44,28 @@ TEH_PG_lookup_kyc_requirement_by_row ( requirements), GNUNET_PQ_result_spec_auto_from_type ("h_payto", h_payto), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_uint32 ("status", + &status), + NULL), GNUNET_PQ_result_spec_end }; -/* Used in #postgres_lookup_kyc_requirement_by_row() */ + enum GNUNET_DB_QueryStatus qs; + PREPARE (pg, "lookup_legitimization_requirement_by_row", "SELECT " - " required_checks" - ",h_payto" - " FROM legitimization_requirements" + " lr.required_checks" + ",lr.h_payto" + ",aml.status" + " FROM legitimization_requirements lr" + " LEFT JOIN aml_status aml USING (h_payto)" " WHERE legitimization_requirement_serial_id=$1;"); - return GNUNET_PQ_eval_prepared_singleton_select ( + qs = GNUNET_PQ_eval_prepared_singleton_select ( pg->conn, "lookup_legitimization_requirement_by_row", params, rs); + *aml_status = (enum TALER_AmlDecisionState) status; + return qs; } diff --git a/src/exchangedb/pg_lookup_kyc_requirement_by_row.h b/src/exchangedb/pg_lookup_kyc_requirement_by_row.h index 12d726187..3d223c985 100644 --- a/src/exchangedb/pg_lookup_kyc_requirement_by_row.h +++ b/src/exchangedb/pg_lookup_kyc_requirement_by_row.h @@ -32,6 +32,7 @@ * @param cls closure * @param requirement_row identifies requirement to look up * @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 * @return database transaction status */ @@ -40,5 +41,7 @@ TEH_PG_lookup_kyc_requirement_by_row ( void *cls, uint64_t requirement_row, char **requirements, + enum TALER_AmlDecisionState *aml_status, struct TALER_PaytoHashP *h_payto); + #endif diff --git a/src/exchangedb/pg_lookup_records_by_table.c b/src/exchangedb/pg_lookup_records_by_table.c index 806896e78..2e157360f 100644 --- a/src/exchangedb/pg_lookup_records_by_table.c +++ b/src/exchangedb/pg_lookup_records_by_table.c @@ -1,6 +1,6 @@ /* 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 under the terms of the GNU Affero General Public License as published @@ -21,6 +21,7 @@ * @file exchangedb/pg_lookup_records_by_table.c * @brief implementation of lookup_records_by_table * @author Christian Grothoff + * @author Özgür Kesim */ #include "platform.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; ierror = 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; ierror = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + /** * 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; ierror = 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; ierror = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + /** * 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; ierror = 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; ierror = 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; ierror = 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; ierror = 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; ierror = 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; ierror = true; + return; + } + ctx->cb (ctx->cb_cls, + &td); + GNUNET_PQ_cleanup_result (rs); + } +} + + /** * Assign statement to @a n and PREPARE * @a sql under name @a n. @@ -2321,8 +2915,8 @@ TEH_PG_lookup_records_by_table (void *cls, .cb = cb, .cb_cls = cb_cls }; - GNUNET_PQ_PostgresResultHandler rh; - const char *statement; + GNUNET_PQ_PostgresResultHandler rh = NULL; + const char *statement = NULL; enum GNUNET_DB_QueryStatus qs; switch (table) @@ -2375,6 +2969,31 @@ TEH_PG_lookup_records_by_table (void *cls, " ORDER BY wire_target_serial_id ASC;"); rh = &lrbt_cb_table_wire_targets; 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: XPREPARE ("select_above_serial_by_table_reserves", "SELECT" @@ -2420,6 +3039,37 @@ TEH_PG_lookup_records_by_table (void *cls, " ORDER BY close_uuid ASC;"); rh = &lrbt_cb_table_reserves_close; 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: XPREPARE ("select_above_serial_by_table_reserves_out", "SELECT" @@ -2885,7 +3535,103 @@ TEH_PG_lookup_records_by_table (void *cls, " ORDER BY profit_drain_serial_id ASC;"); rh = &lrbt_cb_table_profit_drains; 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); return GNUNET_DB_STATUS_HARD_ERROR; } diff --git a/src/exchangedb/pg_lookup_serial_by_table.c b/src/exchangedb/pg_lookup_serial_by_table.c index 7e150cd28..c98b4539e 100644 --- a/src/exchangedb/pg_lookup_serial_by_table.c +++ b/src/exchangedb/pg_lookup_serial_by_table.c @@ -390,6 +390,60 @@ TEH_PG_lookup_serial_by_table (void *cls, " LIMIT 1;"); statement = "select_serial_by_table_profit_drains"; 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) { diff --git a/src/exchangedb/pg_lookup_signing_key.c b/src/exchangedb/pg_lookup_signing_key.c index 3f31a6f49..3803d114f 100644 --- a/src/exchangedb/pg_lookup_signing_key.c +++ b/src/exchangedb/pg_lookup_signing_key.c @@ -62,4 +62,3 @@ TEH_PG_lookup_signing_key ( params, rs); } - diff --git a/src/exchangedb/pg_lookup_wire_timestamp.c b/src/exchangedb/pg_lookup_wire_timestamp.c index 19e915d48..17dffc706 100644 --- a/src/exchangedb/pg_lookup_wire_timestamp.c +++ b/src/exchangedb/pg_lookup_wire_timestamp.c @@ -28,8 +28,8 @@ enum GNUNET_DB_QueryStatus TEH_PG_lookup_wire_timestamp (void *cls, - const char *payto_uri, - struct GNUNET_TIME_Timestamp *last_date) + const char *payto_uri, + struct GNUNET_TIME_Timestamp *last_date) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { diff --git a/src/exchangedb/pg_lookup_wire_timestamp.h b/src/exchangedb/pg_lookup_wire_timestamp.h index 069dd940c..f2ee117de 100644 --- a/src/exchangedb/pg_lookup_wire_timestamp.h +++ b/src/exchangedb/pg_lookup_wire_timestamp.h @@ -34,7 +34,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_lookup_wire_timestamp (void *cls, - const char *payto_uri, + const char *payto_uri, struct GNUNET_TIME_Timestamp *last_date); #endif diff --git a/src/exchangedb/pg_profit_drains_get_pending.c b/src/exchangedb/pg_profit_drains_get_pending.c index a7044ebb8..f4a5d4517 100644 --- a/src/exchangedb/pg_profit_drains_get_pending.c +++ b/src/exchangedb/pg_profit_drains_get_pending.c @@ -57,7 +57,7 @@ TEH_PG_profit_drains_get_pending ( master_sig), GNUNET_PQ_result_spec_end }; - /* Used in #postgres_profit_drains_get_pending() */ + /* Used in #postgres_profit_drains_get_pending() */ PREPARE (pg, "get_ready_profit_drain", "SELECT" diff --git a/src/exchangedb/pg_profit_drains_set_finished.c b/src/exchangedb/pg_profit_drains_set_finished.c index b70af31fe..f0de27945 100644 --- a/src/exchangedb/pg_profit_drains_set_finished.c +++ b/src/exchangedb/pg_profit_drains_set_finished.c @@ -38,18 +38,12 @@ TEH_PG_profit_drains_set_finished ( }; PREPARE (pg, - "drain_profit_set_finished", - "UPDATE profit_drains" - " SET" - " executed=TRUE" - " WHERE profit_drain_serial_id=$1;"); + "drain_profit_set_finished", + "UPDATE profit_drains" + " SET" + " executed=TRUE" + " WHERE profit_drain_serial_id=$1;"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "drain_profit_set_finished", params); } - - - - - - diff --git a/src/exchangedb/pg_release_revolving_shard.c b/src/exchangedb/pg_release_revolving_shard.c index f176972b6..43e45c4bc 100644 --- a/src/exchangedb/pg_release_revolving_shard.c +++ b/src/exchangedb/pg_release_revolving_shard.c @@ -27,9 +27,9 @@ enum GNUNET_DB_QueryStatus TEH_PG_release_revolving_shard (void *cls, - const char *job_name, - uint32_t start_row, - uint32_t end_row) + const char *job_name, + uint32_t start_row, + uint32_t end_row) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { diff --git a/src/exchangedb/pg_release_revolving_shard.h b/src/exchangedb/pg_release_revolving_shard.h index f1712f538..ea65ab605 100644 --- a/src/exchangedb/pg_release_revolving_shard.h +++ b/src/exchangedb/pg_release_revolving_shard.h @@ -37,8 +37,8 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_release_revolving_shard (void *cls, - const char *job_name, - uint32_t start_row, + const char *job_name, + uint32_t start_row, uint32_t end_row); #endif diff --git a/src/exchangedb/pg_reserves_get.c b/src/exchangedb/pg_reserves_get.c index bea0022dd..d081ca00f 100644 --- a/src/exchangedb/pg_reserves_get.c +++ b/src/exchangedb/pg_reserves_get.c @@ -27,7 +27,7 @@ enum GNUNET_DB_QueryStatus TEH_PG_reserves_get (void *cls, - struct TALER_EXCHANGEDB_Reserve *reserve) + struct TALER_EXCHANGEDB_Reserve *reserve) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -43,7 +43,7 @@ TEH_PG_reserves_get (void *cls, &reserve->gc), GNUNET_PQ_result_spec_end }; - /* Used in #postgres_reserves_get() */ + /* Used in #postgres_reserves_get() */ PREPARE (pg, "reserves_get", "SELECT" diff --git a/src/exchangedb/pg_reserves_get_origin.c b/src/exchangedb/pg_reserves_get_origin.c index fd6c56586..55d3179d1 100644 --- a/src/exchangedb/pg_reserves_get_origin.c +++ b/src/exchangedb/pg_reserves_get_origin.c @@ -50,7 +50,7 @@ TEH_PG_reserves_get_origin ( " wire_source_h_payto" " FROM reserves_in" " WHERE reserve_pub=$1"); - return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "get_h_wire_source_of_reserve", params, rs); diff --git a/src/exchangedb/pg_reserves_in_insert.c b/src/exchangedb/pg_reserves_in_insert.c index 1c578478b..691c57d38 100644 --- a/src/exchangedb/pg_reserves_in_insert.c +++ b/src/exchangedb/pg_reserves_in_insert.c @@ -55,55 +55,106 @@ compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub) } +/** + * Record we keep per reserve to process. + */ +struct ReserveRecord +{ + /** + * Details about reserve to insert (input). + */ + const struct TALER_EXCHANGEDB_ReserveInInfo *reserve; + + /** + * Hash of the payto URI in @e reserve. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Notification to trigger on the reserve (input). + */ + char *notify_s; + + /** + * Set to UUID of the reserve (output); + */ + uint64_t reserve_uuid; + + /** + * Set to true if the transaction was an exact duplicate (output). + */ + bool transaction_duplicate; + + /** + * Set to true if the transaction conflicted with an existing reserve (output) + * and needs to be re-done with an UPDATE. + */ + bool conflicts; +}; + + +/** + * Generate the SQL parameters to insert the record @a rr at + * index @a index + */ +#define RR_QUERY_PARAM(rr,index) \ + GNUNET_PQ_query_param_auto_from_type (rr[index].reserve->reserve_pub), \ + GNUNET_PQ_query_param_uint64 (&rr[index].reserve->wire_reference), \ + TALER_PQ_query_param_amount (rr[index].reserve->balance), \ + GNUNET_PQ_query_param_string (rr[index].reserve->exchange_account_name), \ + GNUNET_PQ_query_param_timestamp (&rr[index].reserve->execution_time), \ + GNUNET_PQ_query_param_auto_from_type (&rr[index].h_payto), \ + GNUNET_PQ_query_param_string (rr[index].reserve->sender_account_details), \ + GNUNET_PQ_query_param_string (rr[index].notify_s) + + +/** + * Generate the SQL parameters to obtain results for record @a rr at + * index @a index + */ +#define RR_RESULT_PARAM(rr,index) \ + GNUNET_PQ_result_spec_bool ("transaction_duplicate" TALER_S (index), \ + &rr[index].transaction_duplicate), \ + GNUNET_PQ_result_spec_allow_null ( \ + GNUNET_PQ_result_spec_uint64 ("reserve_uuid" TALER_S (index), \ + &rr[index].reserve_uuid), \ + &rr[index].conflicts) + + +/** + * Insert 1 reserve record @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert1 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[1], - struct GNUNET_TIME_Timestamp expiry, struct GNUNET_TIME_Timestamp gc, - struct TALER_PaytoHashP h_payto, - char *const *notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid, - enum GNUNET_DB_QueryStatus results[1]) + struct ReserveRecord *rr) { enum GNUNET_DB_QueryStatus qs; - PREPARE (pg, - "batch1_reserve_create", - "SELECT " - " out_reserve_found AS conflicted" - ",transaction_duplicate" - ",ruuid AS reserve_uuid" - " FROM exchange_do_batch_reserves_in_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);"); - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_string (notify_s[0]), + RR_QUERY_PARAM (rr, 0), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), + RR_RESULT_PARAM (rr, 0), GNUNET_PQ_result_spec_end }; - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto); + PREPARE (pg, + "batch1_reserve_create", + "SELECT " + " transaction_duplicate0 AS transaction_duplicate0" + ",ruuid0 AS reserve_uuid0" + " FROM exchange_do_batch_reserves_in_insert" + " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);"); qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "batch1_reserve_create", params, @@ -113,537 +164,256 @@ insert1 (struct PostgresClosure *pg, GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to create reserves 1(%d)\n", qs); - results[0] = qs; return qs; } GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); - if ((! conflict[0]) && transaction_duplicate[0]) + if ((! rr[0].conflicts) && rr[0].transaction_duplicate) { GNUNET_break (0); TEH_PG_rollback (pg); - results[0] = GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR; } - results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; return qs; } +/** + * Insert 2 reserve records @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert2 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[2], - struct GNUNET_TIME_Timestamp expiry, struct GNUNET_TIME_Timestamp gc, - struct TALER_PaytoHashP h_payto, - char *const*notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid, - enum GNUNET_DB_QueryStatus results[1]) + struct ReserveRecord *rr) { - enum GNUNET_DB_QueryStatus qs1; - PREPARE (pg, - "batch2_reserve_create", - "SELECT " - "out_reserve_found AS conflicted" - ",out_reserve_found2 AS conflicted2" - ",transaction_duplicate" - ",transaction_duplicate2" - ",ruuid AS reserve_uuid" - ",ruuid2 AS reserve_uuid2" - " FROM exchange_do_batch2_reserves_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22);"); - + enum GNUNET_DB_QueryStatus qs; struct GNUNET_PQ_QueryParam params[] = { - - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), GNUNET_PQ_query_param_timestamp (&reserve_expiration), + RR_QUERY_PARAM (rr, 0), + RR_QUERY_PARAM (rr, 1), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), + RR_RESULT_PARAM (rr, 0), + RR_RESULT_PARAM (rr, 1), GNUNET_PQ_result_spec_end }; - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[1].sender_account_details, - &h_payto); - - - qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch2_reserve_create", - params, - rs); - if (qs1 < 0) + PREPARE (pg, + "batch2_reserve_create", + "SELECT" + " transaction_duplicate0" + ",transaction_duplicate1" + ",ruuid0 AS reserve_uuid0" + ",ruuid1 AS reserve_uuid1" + " FROM exchange_do_batch2_reserves_insert" + " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20);"); + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch2_reserve_create", + params, + rs); + if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to create reserves 2(%d)\n", - qs1); - results[0] = qs1; - return qs1; + qs); + return qs; } - - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); - /* results[i] = (transaction_duplicate) - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ - - if ( - ((! conflict[0]) && (transaction_duplicate[0])) - || ((! conflict[1]) && (transaction_duplicate[1])) - ) + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); + for (unsigned int i = 0; i<2; i++) { - GNUNET_break (0); - TEH_PG_rollback (pg); // ROLLBACK - results[0] = GNUNET_DB_STATUS_HARD_ERROR; - return GNUNET_DB_STATUS_HARD_ERROR; + if ((! rr[i].conflicts) && (rr[i].transaction_duplicate)) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + return GNUNET_DB_STATUS_HARD_ERROR; + } } - results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - return qs1; + return qs; } +/** + * Insert 4 reserve records @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert4 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[4], - struct GNUNET_TIME_Timestamp expiry, struct GNUNET_TIME_Timestamp gc, - struct TALER_PaytoHashP h_payto, - char *const*notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid, - enum GNUNET_DB_QueryStatus results[1]) + struct ReserveRecord *rr) { - enum GNUNET_DB_QueryStatus qs3; - PREPARE (pg, - "batch4_reserve_create", - "SELECT " - "out_reserve_found AS conflicted" - ",out_reserve_found2 AS conflicted2" - ",out_reserve_found3 AS conflicted3" - ",out_reserve_found4 AS conflicted4" - ",transaction_duplicate" - ",transaction_duplicate2" - ",transaction_duplicate3" - ",transaction_duplicate4" - ",ruuid AS reserve_uuid" - ",ruuid2 AS reserve_uuid2" - ",ruuid3 AS reserve_uuid3" - ",ruuid4 AS reserve_uuid4" - " FROM exchange_do_batch4_reserves_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42);"); - + enum GNUNET_DB_QueryStatus qs; struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - GNUNET_PQ_query_param_string (notify_s[2]), - GNUNET_PQ_query_param_string (notify_s[3]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), - TALER_PQ_query_param_amount (reserves[2].balance), - GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[2].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), - TALER_PQ_query_param_amount (reserves[3].balance), - GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[3].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - + RR_QUERY_PARAM (rr, 0), + RR_QUERY_PARAM (rr, 1), + RR_QUERY_PARAM (rr, 2), + RR_QUERY_PARAM (rr, 3), GNUNET_PQ_query_param_end }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("conflicted3", - &conflict[2]), - GNUNET_PQ_result_spec_bool ("conflicted4", - &conflict[3]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate3", - &transaction_duplicate[2]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate4", - &transaction_duplicate[3]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", - &reserve_uuid[2]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", - &reserve_uuid[3]), + RR_RESULT_PARAM (rr, 0), + RR_RESULT_PARAM (rr, 1), + RR_RESULT_PARAM (rr, 2), + RR_RESULT_PARAM (rr, 3), GNUNET_PQ_result_spec_end }; - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[1].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[2].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[3].sender_account_details, - &h_payto); - - qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch4_reserve_create", - params, - rs); - if (qs3 < 0) + PREPARE (pg, + "batch4_reserve_create", + "SELECT" + " transaction_duplicate0" + ",transaction_duplicate1" + ",transaction_duplicate2" + ",transaction_duplicate3" + ",ruuid0 AS reserve_uuid0" + ",ruuid1 AS reserve_uuid1" + ",ruuid2 AS reserve_uuid2" + ",ruuid3 AS reserve_uuid3" + " FROM exchange_do_batch4_reserves_insert" + " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38);"); + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch4_reserve_create", + params, + rs); + if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to create reserves4 (%d)\n", - qs3); - results[0] = qs3; - return qs3; + qs); + return qs; } - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); - - if ( - ((! conflict[0]) && (transaction_duplicate[0])) - || ((! conflict[1]) && (transaction_duplicate[1])) - || ((! conflict[2]) && (transaction_duplicate[2])) - || ((! conflict[3]) && (transaction_duplicate[3])) - ) + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); + for (unsigned int i = 0; i<4; i++) { - GNUNET_break (0); - TEH_PG_rollback (pg); - results[0] = GNUNET_DB_STATUS_HARD_ERROR; - return GNUNET_DB_STATUS_HARD_ERROR; + if ((! rr[i].conflicts) && (rr[i].transaction_duplicate)) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + return GNUNET_DB_STATUS_HARD_ERROR; + } } - results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - return qs3; + return qs; } +/** + * Insert 8 reserve records @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert8 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[8], - struct GNUNET_TIME_Timestamp expiry, struct GNUNET_TIME_Timestamp gc, - struct TALER_PaytoHashP h_payto, - char *const*notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid, - enum GNUNET_DB_QueryStatus results[1]) + struct ReserveRecord *rr) { - enum GNUNET_DB_QueryStatus qs3; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_timestamp (&gc), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + RR_QUERY_PARAM (rr, 0), + RR_QUERY_PARAM (rr, 1), + RR_QUERY_PARAM (rr, 2), + RR_QUERY_PARAM (rr, 3), + RR_QUERY_PARAM (rr, 4), + RR_QUERY_PARAM (rr, 5), + RR_QUERY_PARAM (rr, 6), + RR_QUERY_PARAM (rr, 7), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + RR_RESULT_PARAM (rr, 0), + RR_RESULT_PARAM (rr, 1), + RR_RESULT_PARAM (rr, 2), + RR_RESULT_PARAM (rr, 3), + RR_RESULT_PARAM (rr, 4), + RR_RESULT_PARAM (rr, 5), + RR_RESULT_PARAM (rr, 6), + RR_RESULT_PARAM (rr, 7), + GNUNET_PQ_result_spec_end + }; + PREPARE (pg, "batch8_reserve_create", - "SELECT " - "out_reserve_found AS conflicted" - ",out_reserve_found2 AS conflicted2" - ",out_reserve_found3 AS conflicted3" - ",out_reserve_found4 AS conflicted4" - ",out_reserve_found5 AS conflicted5" - ",out_reserve_found6 AS conflicted6" - ",out_reserve_found7 AS conflicted7" - ",out_reserve_found8 AS conflicted8" - ",transaction_duplicate" + "SELECT" + " transaction_duplicate0" + ",transaction_duplicate1" ",transaction_duplicate2" ",transaction_duplicate3" ",transaction_duplicate4" ",transaction_duplicate5" ",transaction_duplicate6" ",transaction_duplicate7" - ",transaction_duplicate8" - ",ruuid AS reserve_uuid" + ",ruuid0 AS reserve_uuid0" + ",ruuid1 AS reserve_uuid1" ",ruuid2 AS reserve_uuid2" ",ruuid3 AS reserve_uuid3" ",ruuid4 AS reserve_uuid4" ",ruuid5 AS reserve_uuid5" ",ruuid6 AS reserve_uuid6" ",ruuid7 AS reserve_uuid7" - ",ruuid8 AS reserve_uuid8" " FROM exchange_do_batch8_reserves_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$80,$81,$82);"); + " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$70,$71,$72,$73,$74);"); - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), - GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - GNUNET_PQ_query_param_string (notify_s[2]), - GNUNET_PQ_query_param_string (notify_s[3]), - GNUNET_PQ_query_param_string (notify_s[4]), - GNUNET_PQ_query_param_string (notify_s[5]), - GNUNET_PQ_query_param_string (notify_s[6]), - GNUNET_PQ_query_param_string (notify_s[7]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), - TALER_PQ_query_param_amount (reserves[2].balance), - GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[2].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), - TALER_PQ_query_param_amount (reserves[3].balance), - GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[3].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[4].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[4].wire_reference), - TALER_PQ_query_param_amount (reserves[4].balance), - GNUNET_PQ_query_param_string (reserves[4].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[4].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[4].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[5].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[5].wire_reference), - TALER_PQ_query_param_amount (reserves[5].balance), - GNUNET_PQ_query_param_string (reserves[5].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[5].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[5].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[6].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[6].wire_reference), - TALER_PQ_query_param_amount (reserves[6].balance), - GNUNET_PQ_query_param_string (reserves[6].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[6].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[6].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[7].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[7].wire_reference), - TALER_PQ_query_param_amount (reserves[7].balance), - GNUNET_PQ_query_param_string (reserves[7].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[7].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[7].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_end - }; - - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("conflicted3", - &conflict[2]), - GNUNET_PQ_result_spec_bool ("conflicted4", - &conflict[3]), - GNUNET_PQ_result_spec_bool ("conflicted5", - &conflict[4]), - GNUNET_PQ_result_spec_bool ("conflicted6", - &conflict[5]), - GNUNET_PQ_result_spec_bool ("conflicted7", - &conflict[6]), - GNUNET_PQ_result_spec_bool ("conflicted8", - &conflict[7]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate3", - &transaction_duplicate[2]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate4", - &transaction_duplicate[3]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate5", - &transaction_duplicate[4]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate6", - &transaction_duplicate[5]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate7", - &transaction_duplicate[6]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate8", - &transaction_duplicate[7]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", - &reserve_uuid[2]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", - &reserve_uuid[3]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid5", - &reserve_uuid[4]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid6", - &reserve_uuid[5]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid7", - &reserve_uuid[6]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid8", - &reserve_uuid[7]), - GNUNET_PQ_result_spec_end - }; - - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[1].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[2].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[3].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[4].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[5].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[6].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[7].sender_account_details, - &h_payto); - - qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch8_reserve_create", - params, - rs); - if (qs3 < 0) + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch8_reserve_create", + params, + rs); + if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to create reserves8 (%d)\n", - qs3); - results[0] = qs3; - return qs3; + qs); + return qs; } - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); - /* results[i] = (transaction_duplicate) - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ - - if ( - ((! conflict[0]) && (transaction_duplicate[0])) - || ((! conflict[1]) && (transaction_duplicate[1])) - || ((! conflict[2]) && (transaction_duplicate[2])) - || ((! conflict[3]) && (transaction_duplicate[3])) - || ((! conflict[4]) && (transaction_duplicate[4])) - || ((! conflict[5]) && (transaction_duplicate[5])) - || ((! conflict[6]) && (transaction_duplicate[6])) - || ((! conflict[7]) && (transaction_duplicate[7])) - ) + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); + for (unsigned int i = 0; i<8; i++) { - GNUNET_break (0); - TEH_PG_rollback (pg); - results[0] = GNUNET_DB_STATUS_HARD_ERROR; - return GNUNET_DB_STATUS_HARD_ERROR; + if ((! rr[i].conflicts) && (rr[i].transaction_duplicate)) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + return GNUNET_DB_STATUS_HARD_ERROR; + } } - results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - return qs3; + return qs; } -enum GNUNET_DB_QueryStatus -TEH_PG_reserves_in_insert (void *cls, - const struct - TALER_EXCHANGEDB_ReserveInInfo *reserves, - unsigned int reserves_length, - unsigned int batch_size, - enum GNUNET_DB_QueryStatus *results) +static enum GNUNET_DB_QueryStatus +transact ( + struct PostgresClosure *pg, + struct ReserveRecord *rr, + unsigned int reserves_length, + unsigned int batch_size, + enum GNUNET_DB_QueryStatus *results) { - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs1; - enum GNUNET_DB_QueryStatus qs2; - enum GNUNET_DB_QueryStatus qs4; - enum GNUNET_DB_QueryStatus qs5; - struct GNUNET_TIME_Timestamp expiry; - struct GNUNET_TIME_Timestamp gc; - struct TALER_PaytoHashP h_payto; - uint64_t reserve_uuid[reserves_length]; - bool transaction_duplicate[reserves_length]; - bool need_update = false; - bool t_duplicate = false; struct GNUNET_TIME_Timestamp reserve_expiration = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); - bool conflicts[reserves_length]; - char *notify_s[reserves_length]; + struct GNUNET_TIME_Timestamp gc + = GNUNET_TIME_relative_to_timestamp (pg->legal_reserve_expiration_time); + bool need_update = false; if (GNUNET_OK != TEH_PG_preflight (pg)) @@ -652,19 +422,6 @@ TEH_PG_reserves_in_insert (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; } - expiry = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (reserves->execution_time.abs_time, - pg->idle_reserve_expiration_time)); - gc = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), - pg->legal_reserve_expiration_time)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating reserve %s with expiration in %s\n", - TALER_B2S (&(reserves->reserve_pub)), - GNUNET_STRINGS_relative_time_to_string ( - pg->idle_reserve_expiration_time, - GNUNET_NO)); - if (GNUNET_OK != TEH_PG_start_read_committed (pg, "READ_COMMITED")) @@ -673,156 +430,74 @@ TEH_PG_reserves_in_insert (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; } - /* Optimistically assume this is a new reserve, create balance for the first - time; we do this before adding the actual transaction to "reserves_in", - as for a new reserve it can't be a duplicate 'add' operation, and as - the 'add' operation needs the reserve entry as a foreign key. */ - for (unsigned int i = 0; ireserve_pub); - } - - unsigned int i = 0; - - while (i < reserves_length) - { - unsigned int bs = GNUNET_MIN (batch_size, - reserves_length - i); - if (bs >= 8) + while (i < reserves_length) { - qs1 = insert8 (pg, - &reserves[i], - expiry, - gc, - h_payto, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i], - &results[i]); + enum GNUNET_DB_QueryStatus qs; + enum GNUNET_DB_QueryStatus + (*fun)(struct PostgresClosure *pg, + struct GNUNET_TIME_Timestamp gc, + struct GNUNET_TIME_Timestamp reserve_expiration, + struct ReserveRecord *rr); + unsigned int lim; + unsigned int bs; - if (qs1<0) + bs = GNUNET_MIN (batch_size, + reserves_length - i); + switch (bs) + { + case 7: + case 6: + case 5: + case 4: + fun = &insert4; + lim = 4; + break; + case 3: + case 2: + fun = &insert2; + lim = 2; + break; + case 1: + fun = &insert1; + lim = 1; + break; + case 0: + GNUNET_assert (0); + break; + default: + fun = insert8; + lim = 8; + break; + } + + qs = fun (pg, + gc, + reserve_expiration, + &rr[i]); + if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_8 (%d)\n", - qs1); - return qs1; + "Failed to create reserve batch_%u (%d)\n", + lim, + qs); + results[i] = qs; + return qs; } - need_update |= conflicts[i]; - need_update |= conflicts[i + 1]; - need_update |= conflicts[i + 2]; - need_update |= conflicts[i + 3]; - need_update |= conflicts[i + 4]; - need_update |= conflicts[i + 5]; - need_update |= conflicts[i + 6]; - need_update |= conflicts[i + 7]; - t_duplicate |= transaction_duplicate[i]; - t_duplicate |= transaction_duplicate[i + 1]; - t_duplicate |= transaction_duplicate[i + 2]; - t_duplicate |= transaction_duplicate[i + 3]; - t_duplicate |= transaction_duplicate[i + 4]; - t_duplicate |= transaction_duplicate[i + 5]; - t_duplicate |= transaction_duplicate[i + 6]; - t_duplicate |= transaction_duplicate[i + 7]; - i += 8; + for (unsigned int j = 0; jreserve_pub), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + GNUNET_PQ_query_param_uint64 (&rr[i].reserve->wire_reference), + TALER_PQ_query_param_amount (rr[i].reserve->balance), + GNUNET_PQ_query_param_string (rr[i].reserve->exchange_account_name), + GNUNET_PQ_query_param_auto_from_type (&rr[i].h_payto), + GNUNET_PQ_query_param_string (rr[i].notify_s), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { @@ -877,17 +548,19 @@ TEH_PG_reserves_in_insert (void *cls, &duplicate), GNUNET_PQ_result_spec_end }; - qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "reserves_update", - params, - rs); - if (qs3<0) + enum GNUNET_DB_QueryStatus qs; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "reserves_update", + params, + rs); + if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to update reserves (%d)\n", - qs3); - results[i] = qs3; - return qs3; + qs); + results[i] = qs; + return qs; } results[i] = duplicate ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS @@ -896,16 +569,49 @@ TEH_PG_reserves_in_insert (void *cls, } { - enum GNUNET_DB_QueryStatus cs; + enum GNUNET_DB_QueryStatus cs = TEH_PG_commit (pg); - cs = TEH_PG_commit (pg); - if (cs < 0) + if (0 > cs) return cs; } - -exit: - for (unsigned int i = 0; ireserve = reserve; + TALER_payto_hash (reserves->sender_account_details, + &rr->h_payto); + rr->notify_s = compute_notify_on_reserve (reserve->reserve_pub); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating reserve %s with expiration in %s\n", + TALER_B2S (&reserve->reserve_pub), + GNUNET_STRINGS_relative_time_to_string ( + pg->idle_reserve_expiration_time, + false)); + } + qs = transact (pg, + rrs, + reserves_length, + batch_size, + results); + for (unsigned int i = 0; iconn, "select_contract", params, diff --git a/src/exchangedb/pg_select_contract.h b/src/exchangedb/pg_select_contract.h index a503c8da9..747a82753 100644 --- a/src/exchangedb/pg_select_contract.h +++ b/src/exchangedb/pg_select_contract.h @@ -38,10 +38,10 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_select_contract (void *cls, - const struct TALER_ContractDiffiePublicP *pub_ckey, - struct TALER_PurseContractPublicKeyP *purse_pub, - struct TALER_PurseContractSignatureP *econtract_sig, - size_t *econtract_size, + const struct TALER_ContractDiffiePublicP *pub_ckey, + struct TALER_PurseContractPublicKeyP *purse_pub, + struct TALER_PurseContractSignatureP *econtract_sig, + size_t *econtract_size, void **econtract); #endif diff --git a/src/exchangedb/pg_select_contract_by_purse.c b/src/exchangedb/pg_select_contract_by_purse.c index aeeb56d48..8d29b3954 100644 --- a/src/exchangedb/pg_select_contract_by_purse.c +++ b/src/exchangedb/pg_select_contract_by_purse.c @@ -46,7 +46,7 @@ TEH_PG_select_contract_by_purse ( &econtract->econtract_size), GNUNET_PQ_result_spec_end }; - /* Used in #postgres_select_contract_by_purse */ + /* Used in #postgres_select_contract_by_purse */ PREPARE (pg, "select_contract_by_purse", "SELECT " diff --git a/src/exchangedb/pg_select_deposits_missing_wire.c b/src/exchangedb/pg_select_deposits_missing_wire.c index 2a260a369..e638c88e9 100644 --- a/src/exchangedb/pg_select_deposits_missing_wire.c +++ b/src/exchangedb/pg_select_deposits_missing_wire.c @@ -114,10 +114,10 @@ missing_wire_cb (void *cls, enum GNUNET_DB_QueryStatus TEH_PG_select_deposits_missing_wire (void *cls, - struct GNUNET_TIME_Timestamp start_date, - struct GNUNET_TIME_Timestamp end_date, - TALER_EXCHANGEDB_WireMissingCallback cb, - void *cb_cls) + struct GNUNET_TIME_Timestamp start_date, + struct GNUNET_TIME_Timestamp end_date, + TALER_EXCHANGEDB_WireMissingCallback cb, + void *cb_cls) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -133,11 +133,11 @@ TEH_PG_select_deposits_missing_wire (void *cls, }; enum GNUNET_DB_QueryStatus qs; - /* Used in #postgres_select_deposits_missing_wire */ - // FIXME: used by the auditor; can probably be done - // smarter by checking if 'done' or 'blocked' - // are set correctly when going over deposits, instead - // of JOINing with refunds. + /* Used in #postgres_select_deposits_missing_wire */ + // FIXME: used by the auditor; can probably be done + // smarter by checking if 'done' or 'blocked' + // are set correctly when going over deposits, instead + // of JOINing with refunds. PREPARE (pg, "deposits_get_overdue", "SELECT" @@ -164,7 +164,6 @@ TEH_PG_select_deposits_missing_wire (void *cls, " ORDER BY wire_deadline ASC"); - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, "deposits_get_overdue", params, diff --git a/src/exchangedb/pg_select_deposits_missing_wire.h b/src/exchangedb/pg_select_deposits_missing_wire.h index f702c2417..40c592cee 100644 --- a/src/exchangedb/pg_select_deposits_missing_wire.h +++ b/src/exchangedb/pg_select_deposits_missing_wire.h @@ -38,9 +38,9 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_select_deposits_missing_wire (void *cls, - struct GNUNET_TIME_Timestamp start_date, - struct GNUNET_TIME_Timestamp end_date, - TALER_EXCHANGEDB_WireMissingCallback cb, + struct GNUNET_TIME_Timestamp start_date, + struct GNUNET_TIME_Timestamp end_date, + TALER_EXCHANGEDB_WireMissingCallback cb, void *cb_cls); #endif diff --git a/src/exchangedb/pg_select_history_requests_above_serial_id.c b/src/exchangedb/pg_select_history_requests_above_serial_id.c index 81e038114..36902e0ab 100644 --- a/src/exchangedb/pg_select_history_requests_above_serial_id.c +++ b/src/exchangedb/pg_select_history_requests_above_serial_id.c @@ -113,8 +113,6 @@ history_request_serial_helper_cb (void *cls, } - - enum GNUNET_DB_QueryStatus TEH_PG_select_history_requests_above_serial_id ( void *cls, diff --git a/src/exchangedb/pg_select_merge_amounts_for_kyc_check.c b/src/exchangedb/pg_select_merge_amounts_for_kyc_check.c index 5cb665fa8..b1bdd1450 100644 --- a/src/exchangedb/pg_select_merge_amounts_for_kyc_check.c +++ b/src/exchangedb/pg_select_merge_amounts_for_kyc_check.c @@ -26,7 +26,6 @@ #include "pg_helper.h" - /** * Closure for #get_kyc_amounts_cb(). */ @@ -132,7 +131,7 @@ TEH_PG_select_merge_amounts_for_kyc_check ( }; enum GNUNET_DB_QueryStatus qs; - + PREPARE (pg, "select_kyc_relevant_merge_events", "SELECT" @@ -157,4 +156,3 @@ TEH_PG_select_merge_amounts_for_kyc_check ( return GNUNET_DB_STATUS_HARD_ERROR; return qs; } - diff --git a/src/exchangedb/pg_select_purse_decisions_above_serial_id.c b/src/exchangedb/pg_select_purse_decisions_above_serial_id.c index 2368f2d3e..02e67197b 100644 --- a/src/exchangedb/pg_select_purse_decisions_above_serial_id.c +++ b/src/exchangedb/pg_select_purse_decisions_above_serial_id.c @@ -112,7 +112,6 @@ purse_decision_serial_helper_cb (void *cls, } - enum GNUNET_DB_QueryStatus TEH_PG_select_purse_decisions_above_serial_id ( void *cls, diff --git a/src/exchangedb/pg_select_purse_decisions_above_serial_id.h b/src/exchangedb/pg_select_purse_decisions_above_serial_id.h index 53ab31c80..83168d546 100644 --- a/src/exchangedb/pg_select_purse_decisions_above_serial_id.h +++ b/src/exchangedb/pg_select_purse_decisions_above_serial_id.h @@ -43,4 +43,5 @@ TEH_PG_select_purse_decisions_above_serial_id ( bool refunded, TALER_EXCHANGEDB_PurseDecisionCallback cb, void *cb_cls); + #endif diff --git a/src/exchangedb/pg_select_purse_merge.c b/src/exchangedb/pg_select_purse_merge.c index d1f6a5396..ce9f03618 100644 --- a/src/exchangedb/pg_select_purse_merge.c +++ b/src/exchangedb/pg_select_purse_merge.c @@ -56,7 +56,7 @@ TEH_PG_select_purse_merge ( }; *partner_url = NULL; - /* Used in #postgres_select_purse_merge */ + /* Used in #postgres_select_purse_merge */ PREPARE (pg, "select_purse_merge", "SELECT " diff --git a/src/exchangedb/pg_select_recoup_above_serial_id.c b/src/exchangedb/pg_select_recoup_above_serial_id.c index 9047a86f8..b2933fae3 100644 --- a/src/exchangedb/pg_select_recoup_above_serial_id.c +++ b/src/exchangedb/pg_select_recoup_above_serial_id.c @@ -26,7 +26,6 @@ #include "pg_helper.h" - /** * Closure for #recoup_serial_helper_cb(). */ @@ -137,6 +136,7 @@ recoup_serial_helper_cb (void *cls, } } + enum GNUNET_DB_QueryStatus TEH_PG_select_recoup_above_serial_id ( void *cls, @@ -157,7 +157,7 @@ TEH_PG_select_recoup_above_serial_id ( }; enum GNUNET_DB_QueryStatus qs; - /* Used in #postgres_select_recoup_above_serial_id() to obtain recoup transactions */ + /* Used in #postgres_select_recoup_above_serial_id() to obtain recoup transactions */ PREPARE (pg, "recoup_get_incr", "SELECT" diff --git a/src/exchangedb/pg_select_recoup_refresh_above_serial_id.c b/src/exchangedb/pg_select_recoup_refresh_above_serial_id.c index a3f6bc93d..c6fb62cc7 100644 --- a/src/exchangedb/pg_select_recoup_refresh_above_serial_id.c +++ b/src/exchangedb/pg_select_recoup_refresh_above_serial_id.c @@ -141,7 +141,6 @@ recoup_refresh_serial_helper_cb (void *cls, } - enum GNUNET_DB_QueryStatus TEH_PG_select_recoup_refresh_above_serial_id ( void *cls, @@ -162,8 +161,8 @@ TEH_PG_select_recoup_refresh_above_serial_id ( }; enum GNUNET_DB_QueryStatus qs; - /* Used in #postgres_select_recoup_refresh_above_serial_id() to obtain - recoup-refresh transactions */ + /* Used in #postgres_select_recoup_refresh_above_serial_id() to obtain + recoup-refresh transactions */ PREPARE (pg, "recoup_refresh_get_incr", "SELECT" diff --git a/src/exchangedb/pg_select_refreshes_above_serial_id.c b/src/exchangedb/pg_select_refreshes_above_serial_id.c index d2b4a7fa6..401e6dcef 100644 --- a/src/exchangedb/pg_select_refreshes_above_serial_id.c +++ b/src/exchangedb/pg_select_refreshes_above_serial_id.c @@ -130,10 +130,6 @@ refreshs_serial_helper_cb (void *cls, } - - - - enum GNUNET_DB_QueryStatus TEH_PG_select_refreshes_above_serial_id ( void *cls, @@ -153,8 +149,8 @@ TEH_PG_select_refreshes_above_serial_id ( .status = GNUNET_OK }; enum GNUNET_DB_QueryStatus qs; - /* Used in #postgres_select_refreshes_above_serial_id() to fetch - refresh session with id '\geq' the given parameter */ + /* Used in #postgres_select_refreshes_above_serial_id() to fetch + refresh session with id '\geq' the given parameter */ PREPARE (pg, "audit_get_refresh_commitments_incr", "SELECT" diff --git a/src/exchangedb/pg_select_refunds_by_coin.h b/src/exchangedb/pg_select_refunds_by_coin.h index e1838b235..72df13fda 100644 --- a/src/exchangedb/pg_select_refunds_by_coin.h +++ b/src/exchangedb/pg_select_refunds_by_coin.h @@ -44,4 +44,5 @@ TEH_PG_select_refunds_by_coin ( const struct TALER_PrivateContractHashP *h_contract, TALER_EXCHANGEDB_RefundCoinCallback cb, void *cb_cls); + #endif diff --git a/src/exchangedb/pg_select_reserves_in_above_serial_id.c b/src/exchangedb/pg_select_reserves_in_above_serial_id.c index 1a6efc66b..8dd4a9aba 100644 --- a/src/exchangedb/pg_select_reserves_in_above_serial_id.c +++ b/src/exchangedb/pg_select_reserves_in_above_serial_id.c @@ -137,8 +137,8 @@ TEH_PG_select_reserves_in_above_serial_id ( }; enum GNUNET_DB_QueryStatus qs; - /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound - transactions for reserves with serial id '\geq' the given parameter */ + /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound + transactions for reserves with serial id '\geq' the given parameter */ PREPARE (pg, "audit_reserves_in_get_transactions_incr", "SELECT" diff --git a/src/exchangedb/pg_select_reserves_in_above_serial_id_by_account.c b/src/exchangedb/pg_select_reserves_in_above_serial_id_by_account.c index ba73994f0..809df191b 100644 --- a/src/exchangedb/pg_select_reserves_in_above_serial_id_by_account.c +++ b/src/exchangedb/pg_select_reserves_in_above_serial_id_by_account.c @@ -138,8 +138,8 @@ TEH_PG_select_reserves_in_above_serial_id_by_account ( }; enum GNUNET_DB_QueryStatus qs; - /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound - transactions for reserves with serial id '\geq' the given parameter */ + /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound + transactions for reserves with serial id '\geq' the given parameter */ PREPARE (pg, "audit_reserves_in_get_transactions_incr_by_account", "SELECT" diff --git a/src/exchangedb/pg_select_wire_out_above_serial_id.c b/src/exchangedb/pg_select_wire_out_above_serial_id.c index e219f5d4b..a9615ac8e 100644 --- a/src/exchangedb/pg_select_wire_out_above_serial_id.c +++ b/src/exchangedb/pg_select_wire_out_above_serial_id.c @@ -113,7 +113,6 @@ wire_out_serial_helper_cb (void *cls, } - enum GNUNET_DB_QueryStatus TEH_PG_select_wire_out_above_serial_id ( void *cls, @@ -133,7 +132,7 @@ TEH_PG_select_wire_out_above_serial_id ( .status = GNUNET_OK }; enum GNUNET_DB_QueryStatus qs; - /* Used in #postgres_select_wire_out_above_serial_id() */ + /* Used in #postgres_select_wire_out_above_serial_id() */ PREPARE (pg, "audit_get_wire_incr", "SELECT" diff --git a/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.c b/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.c index 08883c9a4..a6c3f0730 100644 --- a/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.c +++ b/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.c @@ -112,6 +112,7 @@ wire_out_serial_helper_cb (void *cls, } } + enum GNUNET_DB_QueryStatus TEH_PG_select_wire_out_above_serial_id_by_account ( void *cls, @@ -134,7 +135,7 @@ TEH_PG_select_wire_out_above_serial_id_by_account ( }; enum GNUNET_DB_QueryStatus qs; - /* Used in #postgres_select_wire_out_above_serial_id_by_account() */ + /* Used in #postgres_select_wire_out_above_serial_id_by_account() */ PREPARE (pg, "audit_get_wire_incr_by_account", "SELECT" diff --git a/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.h b/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.h index 98315cace..04c6a62b2 100644 --- a/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.h +++ b/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.h @@ -43,4 +43,5 @@ TEH_PG_select_wire_out_above_serial_id_by_account ( uint64_t serial_id, TALER_EXCHANGEDB_WireTransferOutCallback cb, void *cb_cls); + #endif diff --git a/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c index e200da8de..339fa3e23 100644 --- a/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c +++ b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c @@ -131,21 +131,21 @@ TEH_PG_select_withdraw_amounts_for_kyc_check ( .status = GNUNET_OK }; enum GNUNET_DB_QueryStatus qs; - /* Used in #postgres_select_withdraw_amounts_for_kyc_check ( -() */ + /* Used in #postgres_select_withdraw_amounts_for_kyc_check ( + () */ PREPARE (pg, - "select_kyc_relevant_withdraw_events", - "SELECT" - " ro.amount_with_fee_val AS amount_val" - ",ro.amount_with_fee_frac AS amount_frac" - ",ro.execution_date AS date" - " FROM reserves_out ro" - " JOIN reserves_out_by_reserve USING (h_blind_ev)" - " JOIN reserves res ON (ro.reserve_uuid = res.reserve_uuid)" - " JOIN reserves_in ri ON (res.reserve_pub = ri.reserve_pub)" - " WHERE wire_source_h_payto=$1" - " AND ro.execution_date >= $2" - " ORDER BY ro.execution_date DESC"); + "select_kyc_relevant_withdraw_events", + "SELECT" + " ro.amount_with_fee_val AS amount_val" + ",ro.amount_with_fee_frac AS amount_frac" + ",ro.execution_date AS date" + " FROM reserves_out ro" + " JOIN reserves_out_by_reserve USING (h_blind_ev)" + " JOIN reserves res ON (ro.reserve_uuid = res.reserve_uuid)" + " JOIN reserves_in ri ON (res.reserve_pub = ri.reserve_pub)" + " WHERE wire_source_h_payto=$1" + " AND ro.execution_date >= $2" + " ORDER BY ro.execution_date DESC"); qs = GNUNET_PQ_eval_prepared_multi_select ( pg->conn, "select_kyc_relevant_withdraw_events", diff --git a/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.h b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.h index 4c1283744..9a780adbe 100644 --- a/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.h +++ b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.h @@ -44,4 +44,5 @@ TEH_PG_select_withdraw_amounts_for_kyc_check ( struct GNUNET_TIME_Absolute time_limit, TALER_EXCHANGEDB_KycAmountCallback kac, void *kac_cls); + #endif diff --git a/src/exchangedb/pg_select_withdrawals_above_serial_id.c b/src/exchangedb/pg_select_withdrawals_above_serial_id.c index 4718a62ae..b842b11aa 100644 --- a/src/exchangedb/pg_select_withdrawals_above_serial_id.c +++ b/src/exchangedb/pg_select_withdrawals_above_serial_id.c @@ -121,7 +121,6 @@ reserves_out_serial_helper_cb (void *cls, } - enum GNUNET_DB_QueryStatus TEH_PG_select_withdrawals_above_serial_id ( void *cls, @@ -142,7 +141,7 @@ TEH_PG_select_withdrawals_above_serial_id ( }; enum GNUNET_DB_QueryStatus qs; - /* Fetch deposits with rowid '\geq' the given parameter */ + /* Fetch deposits with rowid '\geq' the given parameter */ PREPARE (pg, "audit_get_reserves_out_incr", diff --git a/src/exchangedb/pg_select_withdrawals_above_serial_id.h b/src/exchangedb/pg_select_withdrawals_above_serial_id.h index adc23fb30..2b741a3b4 100644 --- a/src/exchangedb/pg_select_withdrawals_above_serial_id.h +++ b/src/exchangedb/pg_select_withdrawals_above_serial_id.h @@ -41,4 +41,5 @@ TEH_PG_select_withdrawals_above_serial_id ( uint64_t serial_id, TALER_EXCHANGEDB_WithdrawCallback cb, void *cb_cls); + #endif diff --git a/src/exchangedb/pg_set_extension_manifest.c b/src/exchangedb/pg_set_extension_manifest.c index 86e9d3f08..c7db04312 100644 --- a/src/exchangedb/pg_set_extension_manifest.c +++ b/src/exchangedb/pg_set_extension_manifest.c @@ -28,8 +28,8 @@ enum GNUNET_DB_QueryStatus TEH_PG_set_extension_manifest (void *cls, - const char *extension_name, - const char *manifest) + const char *extension_name, + const char *manifest) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam pcfg = diff --git a/src/exchangedb/pg_set_extension_manifest.h b/src/exchangedb/pg_set_extension_manifest.h index ead3abd28..0befeedd8 100644 --- a/src/exchangedb/pg_set_extension_manifest.h +++ b/src/exchangedb/pg_set_extension_manifest.h @@ -37,7 +37,7 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_set_extension_manifest (void *cls, - const char *extension_name, + const char *extension_name, const char *manifest); #endif diff --git a/src/exchangedb/pg_set_purse_balance.c b/src/exchangedb/pg_set_purse_balance.c index a996104bc..e955cb1cb 100644 --- a/src/exchangedb/pg_set_purse_balance.c +++ b/src/exchangedb/pg_set_purse_balance.c @@ -50,6 +50,3 @@ TEH_PG_set_purse_balance ( "set_purse_balance", params); } - - - diff --git a/src/exchangedb/pg_setup_wire_target.c b/src/exchangedb/pg_setup_wire_target.c index a2d890c50..ed6fbe338 100644 --- a/src/exchangedb/pg_setup_wire_target.c +++ b/src/exchangedb/pg_setup_wire_target.c @@ -26,7 +26,7 @@ enum GNUNET_DB_QueryStatus -TEH_PG_setup_wire_target( +TEH_PG_setup_wire_target ( struct PostgresClosure *pg, const char *payto_uri, struct TALER_PaytoHashP *h_payto) diff --git a/src/exchangedb/pg_setup_wire_target.h b/src/exchangedb/pg_setup_wire_target.h index 12c0e59b0..77512a600 100644 --- a/src/exchangedb/pg_setup_wire_target.h +++ b/src/exchangedb/pg_setup_wire_target.h @@ -35,7 +35,7 @@ * @return transaction status */ enum GNUNET_DB_QueryStatus -TEH_PG_setup_wire_target( +TEH_PG_setup_wire_target ( struct PostgresClosure *pg, const char *payto_uri, struct TALER_PaytoHashP *h_payto); diff --git a/src/exchangedb/pg_store_wire_transfer_out.c b/src/exchangedb/pg_store_wire_transfer_out.c index 8bc0147dd..b8b0bb692 100644 --- a/src/exchangedb/pg_store_wire_transfer_out.c +++ b/src/exchangedb/pg_store_wire_transfer_out.c @@ -44,7 +44,7 @@ TEH_PG_store_wire_transfer_out ( GNUNET_PQ_query_param_end }; - /* Used in #postgres_store_wire_transfer_out */ + /* Used in #postgres_store_wire_transfer_out */ PREPARE (pg, "insert_wire_out", "INSERT INTO wire_out " diff --git a/src/exchangedb/pg_update_aggregation_transient.c b/src/exchangedb/pg_update_aggregation_transient.c index 1d91301c3..c44cd67ec 100644 --- a/src/exchangedb/pg_update_aggregation_transient.c +++ b/src/exchangedb/pg_update_aggregation_transient.c @@ -26,7 +26,6 @@ #include "pg_helper.h" - enum GNUNET_DB_QueryStatus TEH_PG_update_aggregation_transient ( void *cls, @@ -45,7 +44,7 @@ TEH_PG_update_aggregation_transient ( }; - /* Used in #postgres_update_aggregation_transient() */ + /* Used in #postgres_update_aggregation_transient() */ PREPARE (pg, "update_aggregation_transient", "UPDATE aggregation_transient" diff --git a/src/exchangedb/pg_update_auditor.c b/src/exchangedb/pg_update_auditor.c index 9d82f25db..167a270b9 100644 --- a/src/exchangedb/pg_update_auditor.c +++ b/src/exchangedb/pg_update_auditor.c @@ -28,11 +28,11 @@ enum GNUNET_DB_QueryStatus TEH_PG_update_auditor (void *cls, - const struct TALER_AuditorPublicKeyP *auditor_pub, - const char *auditor_url, - const char *auditor_name, - struct GNUNET_TIME_Timestamp change_date, - bool enabled) + const struct TALER_AuditorPublicKeyP *auditor_pub, + const char *auditor_url, + const char *auditor_name, + struct GNUNET_TIME_Timestamp change_date, + bool enabled) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -43,16 +43,16 @@ TEH_PG_update_auditor (void *cls, GNUNET_PQ_query_param_timestamp (&change_date), GNUNET_PQ_query_param_end }; - /* used in #postgres_update_auditor() */ - PREPARE(pg, - "update_auditor", - "UPDATE auditors" - " SET" - " auditor_url=$2" - " ,auditor_name=$3" - " ,is_active=$4" - " ,last_change=$5" - " WHERE auditor_pub=$1"); + /* used in #postgres_update_auditor() */ + PREPARE (pg, + "update_auditor", + "UPDATE auditors" + " SET" + " auditor_url=$2" + " ,auditor_name=$3" + " ,is_active=$4" + " ,last_change=$5" + " WHERE auditor_pub=$1"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "update_auditor", params); diff --git a/src/exchangedb/pg_update_auditor.h b/src/exchangedb/pg_update_auditor.h index af8d06062..ee869f8b7 100644 --- a/src/exchangedb/pg_update_auditor.h +++ b/src/exchangedb/pg_update_auditor.h @@ -38,10 +38,10 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_update_auditor (void *cls, - const struct TALER_AuditorPublicKeyP *auditor_pub, - const char *auditor_url, - const char *auditor_name, - struct GNUNET_TIME_Timestamp change_date, + const struct TALER_AuditorPublicKeyP *auditor_pub, + const char *auditor_url, + const char *auditor_name, + struct GNUNET_TIME_Timestamp change_date, bool enabled); #endif diff --git a/src/exchangedb/pg_update_wire.c b/src/exchangedb/pg_update_wire.c index f5f5672cb..4059348c9 100644 --- a/src/exchangedb/pg_update_wire.c +++ b/src/exchangedb/pg_update_wire.c @@ -28,9 +28,9 @@ enum GNUNET_DB_QueryStatus TEH_PG_update_wire (void *cls, - const char *payto_uri, - struct GNUNET_TIME_Timestamp change_date, - bool enabled) + const char *payto_uri, + struct GNUNET_TIME_Timestamp change_date, + bool enabled) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -40,7 +40,7 @@ TEH_PG_update_wire (void *cls, GNUNET_PQ_query_param_end }; - /* used in #postgres_update_wire() */ + /* used in #postgres_update_wire() */ PREPARE (pg, "update_wire", "UPDATE wire_accounts" diff --git a/src/exchangedb/pg_update_wire.h b/src/exchangedb/pg_update_wire.h index c01d68a46..67038b580 100644 --- a/src/exchangedb/pg_update_wire.h +++ b/src/exchangedb/pg_update_wire.h @@ -36,8 +36,8 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_update_wire (void *cls, - const char *payto_uri, - struct GNUNET_TIME_Timestamp change_date, + const char *payto_uri, + struct GNUNET_TIME_Timestamp change_date, bool enabled); #endif diff --git a/src/exchangedb/pg_wire_prepare_data_get.c b/src/exchangedb/pg_wire_prepare_data_get.c index d45413010..21d1b947a 100644 --- a/src/exchangedb/pg_wire_prepare_data_get.c +++ b/src/exchangedb/pg_wire_prepare_data_get.c @@ -99,10 +99,10 @@ prewire_cb (void *cls, enum GNUNET_DB_QueryStatus TEH_PG_wire_prepare_data_get (void *cls, - uint64_t start_row, - uint64_t limit, - TALER_EXCHANGEDB_WirePreparationIterator cb, - void *cb_cls) + uint64_t start_row, + uint64_t limit, + TALER_EXCHANGEDB_WirePreparationIterator cb, + void *cb_cls) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -118,7 +118,7 @@ TEH_PG_wire_prepare_data_get (void *cls, enum GNUNET_DB_QueryStatus qs; - /* Used in #postgres_wire_prepare_data_get() */ + /* Used in #postgres_wire_prepare_data_get() */ PREPARE (pg, "wire_prepare_data_get", "SELECT" diff --git a/src/exchangedb/pg_wire_prepare_data_get.h b/src/exchangedb/pg_wire_prepare_data_get.h index 91e21d27e..815c14bdf 100644 --- a/src/exchangedb/pg_wire_prepare_data_get.h +++ b/src/exchangedb/pg_wire_prepare_data_get.h @@ -38,8 +38,9 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_wire_prepare_data_get (void *cls, - uint64_t start_row, - uint64_t limit, - TALER_EXCHANGEDB_WirePreparationIterator cb, + uint64_t start_row, + uint64_t limit, + TALER_EXCHANGEDB_WirePreparationIterator cb, void *cb_cls); + #endif diff --git a/src/exchangedb/pg_wire_prepare_data_insert.c b/src/exchangedb/pg_wire_prepare_data_insert.c index 903f22a5b..919fccdaf 100644 --- a/src/exchangedb/pg_wire_prepare_data_insert.c +++ b/src/exchangedb/pg_wire_prepare_data_insert.c @@ -27,9 +27,9 @@ enum GNUNET_DB_QueryStatus TEH_PG_wire_prepare_data_insert (void *cls, - const char *type, - const char *buf, - size_t buf_size) + const char *type, + const char *buf, + size_t buf_size) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -39,15 +39,15 @@ TEH_PG_wire_prepare_data_insert (void *cls, }; - /* Used in #postgres_wire_prepare_data_insert() to store - wire transfer information before actually committing it with the bank */ + /* Used in #postgres_wire_prepare_data_insert() to store + wire transfer information before actually committing it with the bank */ PREPARE (pg, - "wire_prepare_data_insert", - "INSERT INTO prewire " - "(wire_method" - ",buf" - ") VALUES " - "($1, $2);"); + "wire_prepare_data_insert", + "INSERT INTO prewire " + "(wire_method" + ",buf" + ") VALUES " + "($1, $2);"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "wire_prepare_data_insert", params); diff --git a/src/exchangedb/pg_wire_prepare_data_insert.h b/src/exchangedb/pg_wire_prepare_data_insert.h index 2b6050d05..e73ee152d 100644 --- a/src/exchangedb/pg_wire_prepare_data_insert.h +++ b/src/exchangedb/pg_wire_prepare_data_insert.h @@ -36,7 +36,8 @@ */ enum GNUNET_DB_QueryStatus TEH_PG_wire_prepare_data_insert (void *cls, - const char *type, - const char *buf, + const char *type, + const char *buf, size_t buf_size); + #endif diff --git a/src/exchangedb/pg_wire_prepare_data_mark_failed.c b/src/exchangedb/pg_wire_prepare_data_mark_failed.c index fe2236b82..4e4d729a3 100644 --- a/src/exchangedb/pg_wire_prepare_data_mark_failed.c +++ b/src/exchangedb/pg_wire_prepare_data_mark_failed.c @@ -37,7 +37,7 @@ TEH_PG_wire_prepare_data_mark_failed ( GNUNET_PQ_query_param_end }; - /* Used in #postgres_wire_prepare_data_mark_failed() */ + /* Used in #postgres_wire_prepare_data_mark_failed() */ PREPARE (pg, "wire_prepare_data_mark_failed", diff --git a/src/exchangedb/pg_wire_prepare_data_mark_failed.h b/src/exchangedb/pg_wire_prepare_data_mark_failed.h index cae1523d1..98846b284 100644 --- a/src/exchangedb/pg_wire_prepare_data_mark_failed.h +++ b/src/exchangedb/pg_wire_prepare_data_mark_failed.h @@ -36,4 +36,5 @@ enum GNUNET_DB_QueryStatus TEH_PG_wire_prepare_data_mark_failed ( void *cls, uint64_t rowid); + #endif diff --git a/src/exchangedb/pg_wire_prepare_data_mark_finished.c b/src/exchangedb/pg_wire_prepare_data_mark_finished.c index de8738e40..af4a0fbbb 100644 --- a/src/exchangedb/pg_wire_prepare_data_mark_finished.c +++ b/src/exchangedb/pg_wire_prepare_data_mark_finished.c @@ -36,12 +36,12 @@ TEH_PG_wire_prepare_data_mark_finished ( GNUNET_PQ_query_param_end }; - /* Used in #postgres_wire_prepare_data_mark_finished() */ + /* Used in #postgres_wire_prepare_data_mark_finished() */ PREPARE (pg, - "wire_prepare_data_mark_done", - "UPDATE prewire" - " SET finished=TRUE" - " WHERE prewire_uuid=$1;"); + "wire_prepare_data_mark_done", + "UPDATE prewire" + " SET finished=TRUE" + " WHERE prewire_uuid=$1;"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "wire_prepare_data_mark_done", diff --git a/src/exchangedb/pg_wire_prepare_data_mark_finished.h b/src/exchangedb/pg_wire_prepare_data_mark_finished.h index 19db2ca99..ba2e384cd 100644 --- a/src/exchangedb/pg_wire_prepare_data_mark_finished.h +++ b/src/exchangedb/pg_wire_prepare_data_mark_finished.h @@ -36,4 +36,5 @@ enum GNUNET_DB_QueryStatus TEH_PG_wire_prepare_data_mark_finished ( void *cls, uint64_t rowid); + #endif diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 2ef250775..b3ebc7547 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -21,6 +21,7 @@ * @author Christian Grothoff * @author Sree Harsha Totakura * @author Marcello Stanisci + * @author Özgür Kesim */ #include "platform.h" #include @@ -216,7 +217,7 @@ #include "pg_select_aml_process.h" #include "pg_select_aml_history.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 @@ -773,6 +774,10 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &TEH_PG_select_aml_history; plugin->insert_aml_decision = &TEH_PG_insert_aml_decision; + + plugin->batch_ensure_coin_known + = &TEH_PG_batch_ensure_coin_known; + return plugin; } diff --git a/src/exchangedb/procedures.sql.in b/src/exchangedb/procedures.sql.in index a53396c36..12ec3656f 100644 --- a/src/exchangedb/procedures.sql.in +++ b/src/exchangedb/procedures.sql.in @@ -39,13 +39,11 @@ SET search_path TO exchange; #include "exchange_do_insert_or_update_policy_details.sql" #include "exchange_do_insert_aml_decision.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_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_get_ready_deposit.sql" #include "exchange_do_get_link_data.sql" +#include "exchange_do_batch_coin_known.sql" COMMIT; diff --git a/src/exchangedb/spi/Makefile b/src/exchangedb/spi/Makefile new file mode 100644 index 000000000..d654d91e9 --- /dev/null +++ b/src/exchangedb/spi/Makefile @@ -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) diff --git a/src/exchangedb/spi/README.md b/src/exchangedb/spi/README.md new file mode 100644 index 000000000..47eb37b94 --- /dev/null +++ b/src/exchangedb/spi/README.md @@ -0,0 +1,37 @@ + Server Programming Interface (SPI) + + +Overview +======== + +This folder contains results from an experiment by Joseph Xu +to use the Postgres SPI. They are not currently used at all +by the GNU Taler exchange. + + +Dependencies +============ + +These are the direct dependencies for compiling the code: + +# apt-get install libpq-dev postgresql-server-dev-13 +# apt-get install libkrb5-dev +# apt-get install libssl-dev + + +Compilation +=========== + +$ make + +Loading functions +================= + +# make install +$ psql "$DB_NAME" < own_test.sql + + +Calling functions +================== + +$ psql -c "SELECT $FUNCTION_NAME($ARGS);" "$DB_NAME" diff --git a/src/exchangedb/spi/own_test.c b/src/exchangedb/spi/own_test.c new file mode 100644 index 000000000..ac72fad7b --- /dev/null +++ b/src/exchangedb/spi/own_test.c @@ -0,0 +1,873 @@ +#include "postgres.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef PG_MODULE_MAGIC +PG_MODULE_MAGIC; +#endif + +typedef struct +{ + Datum col1; + Datum col2; +} valuest; + +void _PG_init (void); + +void _PG_fini (void); + +void +_PG_init (void) +{ +} + + +PG_FUNCTION_INFO_V1 (pg_spi_insert_int); +PG_FUNCTION_INFO_V1 (pg_spi_select_from_x); +PG_FUNCTION_INFO_V1 (pg_spi_select_pair_from_y); +// PG_FUNCTION_INFO_V1(pg_spi_select_with_cond); +PG_FUNCTION_INFO_V1 (pg_spi_update_y); +PG_FUNCTION_INFO_V1 (pg_spi_prepare_example); +PG_FUNCTION_INFO_V1 (pg_spi_prepare_example_without_saveplan); +PG_FUNCTION_INFO_V1 (pg_spi_prepare_insert); +PG_FUNCTION_INFO_V1 (pg_spi_prepare_insert_without_saveplan); +// PG_FUNCTION_INFO_V1(pg_spi_prepare_select_with_cond); +PG_FUNCTION_INFO_V1 (pg_spi_prepare_select_with_cond_without_saveplan); +PG_FUNCTION_INFO_V1 (pg_spi_prepare_update); +PG_FUNCTION_INFO_V1 (pg_spi_get_dep_ref_fees); +// SIMPLE SELECT +Datum +pg_spi_prepare_example (PG_FUNCTION_ARGS) +{ + static SPIPlanPtr prepared_plan; + int ret; + int64 result; + char *value; + SPIPlanPtr new_plan; + + ret = SPI_connect (); + if (ret != SPI_OK_CONNECT) + { + elog (ERROR, "DB connection failed ! \n"); + } + { + if (prepared_plan == NULL) + { + new_plan = SPI_prepare ("SELECT 1 FROM X", 0, NULL); + prepared_plan = SPI_saveplan (new_plan); + + if (prepared_plan == NULL) + { + elog (ERROR, "FAIL TO SAVE !\n"); + } + } + + ret = SPI_execute_plan (prepared_plan, NULL, 0,false, 0); + if (ret != SPI_OK_SELECT) + { + elog (ERROR, "SELECT FAILED %d !\n", ret); + } + + if (SPI_tuptable != NULL && SPI_tuptable->vals != NULL && + SPI_tuptable->tupdesc != NULL) + { + value = SPI_getvalue (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1); + result = atoi (value); + } + else + { + elog (ERROR, "EMPTY TABLE !\n"); + } + } + SPI_finish (); + PG_RETURN_INT64 (result); +} + + +Datum +pg_spi_prepare_example_without_saveplan (PG_FUNCTION_ARGS) +{ + int ret; + int64 result; + char *value; + SPIPlanPtr new_plan; + + ret = SPI_connect (); + if (ret != SPI_OK_CONNECT) + { + elog (ERROR, "DB connection failed ! \n"); + } + + { + new_plan = SPI_prepare ("SELECT 1 FROM X", 0, NULL); + ret = SPI_execute_plan (new_plan, NULL, 0,false, 0); + if (ret != SPI_OK_SELECT) + { + elog (ERROR, "SELECT FAILED %d !\n", ret); + } + + if (SPI_tuptable != NULL + && SPI_tuptable->vals != NULL + && SPI_tuptable->tupdesc != NULL) + { + value = SPI_getvalue (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1); + result = atoi (value); + } + else + { + elog (ERROR, "EMPTY TABLE !\n"); + } + } + SPI_finish (); + PG_RETURN_INT64 (result);// PG_RETURN_INT64(result); +} + + +// SELECT 1 FROM X +// V1 +Datum +pg_spi_select_from_x (PG_FUNCTION_ARGS) +{ + int ret; + char *query = "SELECT 1 FROM X"; + uint64 proc; + ret = SPI_connect (); + + if (ret != SPI_OK_CONNECT) + { + elog (ERROR, "SPI_connect failed"); + } + + ret = SPI_exec (query, 10); + proc = SPI_processed; + if (ret != SPI_OK_SELECT) + { + elog (ERROR, "SPI_exec failed"); + } + + SPI_finish (); + + PG_RETURN_INT64 (proc); +} + + +// INSERT INTO X VALUES (1) +Datum +pg_spi_insert_int (PG_FUNCTION_ARGS) +{ + int ret; + int nargs; + Oid argtypes[1]; + Datum values[1]; + char *query = "INSERT INTO X (a) VALUES ($1)"; + + ret = SPI_connect (); + if (ret != SPI_OK_CONNECT) + { + elog (ERROR, "SPI_connect failed"); + } + + nargs = 1; + argtypes[0] = INT4OID; + values[0] = Int32GetDatum (3); + + ret = SPI_execute_with_args (query, nargs, argtypes, values, NULL, false, 0); + if (ret != SPI_OK_INSERT) + { + elog (ERROR, "SPI_execute_with_args failed"); + } + + SPI_finish (); + + PG_RETURN_VOID (); +} + + +Datum +pg_spi_prepare_insert (PG_FUNCTION_ARGS) +{ + static SPIPlanPtr prepared_plan = NULL; + int ret; + int nargs; + Oid argtypes[1]; + Datum values[1]; + const char *query = "INSERT INTO X (a) VALUES ($1)"; + SPIPlanPtr new_plan; + ret = SPI_connect (); + if (ret != SPI_OK_CONNECT) + { + elog (ERROR, "SPI_connect failed ! \n"); + } + if (prepared_plan == NULL) + { + + argtypes[0] = INT4OID; + nargs = 1; + values[0] = Int32GetDatum (3); + new_plan = SPI_prepare (query, nargs, argtypes); + if (new_plan== NULL) + { + elog (ERROR, "SPI_prepare failed ! \n"); + } + prepared_plan = SPI_saveplan (new_plan); + if (prepared_plan == NULL) + { + elog (ERROR, "SPI_saveplan failed ! \n"); + } + } + + ret = SPI_execute_plan (prepared_plan, values, NULL, false, 0); + if (ret != SPI_OK_INSERT) + { + elog (ERROR, "SPI_execute_plan failed ! \n"); + } + + SPI_finish (); + + PG_RETURN_VOID (); +} + + +/* +Datum +pg_spi_prepare_insert_bytea(PG_FUNCTION_ARGS) +{ + static SPIPlanPtr prepared_plan = NULL; + int ret; + int nargs; + Oid argtypes[1]; + Datum values[1]; + Oid argtypes2[1]; + Datum val[1]; + char *query = "INSERT INTO X (a) VALUES ($1)"; + SPIPlanPtr new_plan; + ret = SPI_connect(); + if (ret != SPI_OK_CONNECT) + { + elog(ERROR, "SPI_connect failed ! \n"); + } + if (prepared_plan == NULL) { + argtypes2[0] = BOOLOID; + val[0] = BoolGetDatum(); + argtypes[0] = BYTEAOID; + nargs = 1; + values[0] = Int32GetDatum(3); + new_plan = SPI_prepare(query, nargs, argtypes); + if (new_plan== NULL) + { + elog(ERROR, "SPI_prepare failed ! \n"); + } + prepared_plan = SPI_saveplan(new_plan); + if (prepared_plan == NULL) + { + elog(ERROR, "SPI_saveplan failed ! \n"); + } + } + + ret = SPI_execute_plan(prepared_plan, values, NULL, false, 0); + if (ret != SPI_OK_INSERT) + { + elog(ERROR, "SPI_execute_plan failed ! \n"); + } + + SPI_finish(); + + PG_RETURN_VOID(); +} +*/ + +Datum +pg_spi_prepare_insert_without_saveplan (PG_FUNCTION_ARGS) +{ + int ret; + int nargs; + Oid argtypes[1]; + Datum values[1]; + const char *query = "INSERT INTO X (a) VALUES ($1)"; + SPIPlanPtr new_plan; + ret = SPI_connect (); + if (ret != SPI_OK_CONNECT) + { + elog (ERROR, "SPI_connect failed"); + } + { + argtypes[0] = INT4OID; + nargs = 1; + values[0] = Int32GetDatum (3); + new_plan = SPI_prepare (query, nargs, argtypes); + if (new_plan== NULL) + { + elog (ERROR, "SPI_prepare failed"); + } + } + + ret = SPI_execute_plan (new_plan, values, NULL, false, 0); + if (ret != SPI_OK_INSERT) + { + elog (ERROR, "SPI_execute_plan failed"); + } + + SPI_finish (); + + PG_RETURN_VOID (); +} + + +/* +Datum +pg_spi_select_pair_from_y(PG_FUNCTION_ARGS) +{ + int ret; + valuest result; + bool isnull; + char *query = "SELECT 1,1 FROM Y"; + result.col1 = 0; + result.col2 = 0; + + if ((ret = SPI_connect()) < 0) { + fprintf(stderr, "SPI_connect returned %d\n", ret); + exit(1); + } + ret = SPI_exec(query, 0); + if (ret == SPI_OK_SELECT && SPI_processed > 0) { + int i; + SPITupleTable *tuptable = SPI_tuptable; + TupleDesc tupdesc = tuptable->tupdesc; + for (i = 0; i < SPI_processed; i++) { + HeapTuple tuple = tuptable->vals[i]; + result.col1 = SPI_getbinval(tuple, tupdesc, 1, &isnull); + result.col2 = SPI_getbinval(tuple, tupdesc, 2, &isnull); + } + } + SPI_finish(); + PG_RETURN_TEXT_P(result); +} +*/ + +// SELECT X FROM Y WHERE Z=$1 +/* +Datum +pg_spi_select_with_cond(PG_FUNCTION_ARGS) +{ + int ret; + char *query; + int nargs; + Oid argtypes[1]; + Datum values[1]; + uint64 proc; + query = "SELECT col1 FROM Y WHERE col2 = $1"; + + ret = SPI_connect(); + if (ret != SPI_OK_CONNECT) { + elog(ERROR, "SPI_connect failed: %d", ret); + } + nargs = 1; + argtypes[0] = INT4OID; + values[0] = Int32GetDatum(2); + + ret = SPI_execute_with_args(query, nargs, argtypes, values, NULL, false, 0); + proc = SPI_processed; + if (ret != SPI_OK_SELECT) + { + elog(ERROR, "SPI_execute_with_args failed"); + } + + SPI_finish(); + + + PG_RETURN_INT64(proc); + }*/ + +////////SELECT WITH COND +/* +Datum pg_spi_prepare_select_with_cond(PG_FUNCTION_ARGS) { + static SPIPlanPtr prepared_plan = NULL; + SPIPlanPtr new_plan; + int ret; + Datum values[1]; + uint64 proc; + int nargs; + Oid argtypes[1]; + char *query = "SELECT col1 FROM Y WHERE col1 = $1"; + int result = 0; + + ret = SPI_connect(); + if (ret != SPI_OK_CONNECT) + elog(ERROR, "SPI_connect failed ! \n"); + + if (prepared_plan == NULL) { + + argtypes[0] = INT4OID; + nargs = 1; + values[0] = DatumGetByteaP(SPI_getbinval(tuptable->vals[0], tupdesc, 1, &isnull)); //Value col2 + + new_plan = SPI_prepare(query, nargs, argtypes); + if (new_plan == NULL) + elog(ERROR, "SPI_prepare failed ! \n"); + + prepared_plan = SPI_saveplan(new_plan); + if (prepared_plan == NULL) + elog(ERROR, "SPI_saveplan failed ! \n"); + } + + + ret = SPI_execute_plan(prepared_plan, values, NULL, false, 0); + + if (ret != SPI_OK_SELECT) { + elog(ERROR, "SPI_execute_plan failed: %d \n", ret); + } + + proc = SPI_processed; + + if (proc > 0) { + SPITupleTable *tuptable = SPI_tuptable; + TupleDesc tupdesc = tuptable->tupdesc; + HeapTuple tuple; + int i; + + for (i = 0; i < proc; i++) { + tuple = tuptable->vals[i]; + for (int j = 1; j <= tupdesc->natts; j++) { + char * value = SPI_getvalue(tuple, tupdesc, j); + result += atoi(value); + } + } + } + SPI_finish(); + PG_RETURN_INT64(result); +} +*/ + +Datum +pg_spi_prepare_select_with_cond_without_saveplan (PG_FUNCTION_ARGS) +{ + + SPIPlanPtr new_plan; + int ret; + Datum values[1]; + uint64 proc; + int nargs; + Oid argtypes[1]; + char *query = "SELECT col1 FROM Y WHERE col2 = $1"; + int result = 0; + + ret = SPI_connect (); + if (ret != SPI_OK_CONNECT) + elog (ERROR, "SPI_connect failed ! \n"); + + { + + argtypes[0] = INT4OID; + nargs = 1; + values[0] = Int32GetDatum (2); // Value col2 + + new_plan = SPI_prepare (query, nargs, argtypes); + if (new_plan == NULL) + elog (ERROR, "SPI_prepare failed ! \n"); + + } + + + ret = SPI_execute_plan (new_plan, values, NULL, false, 0); + + if (ret != SPI_OK_SELECT) + { + elog (ERROR, "SPI_execute_plan failed: %d \n", ret); + } + + proc = SPI_processed; + + if (proc > 0) + { + SPITupleTable *tuptable = SPI_tuptable; + TupleDesc tupdesc = tuptable->tupdesc; + HeapTuple tuple; + int i; + + for (i = 0; i < proc; i++) + { + tuple = tuptable->vals[i]; + for (int j = 1; j <= tupdesc->natts; j++) + { + char *value = SPI_getvalue (tuple, tupdesc, j); + result += atoi (value); + } + } + } + SPI_finish (); + PG_RETURN_INT64 (result); +} + + +Datum +pg_spi_update_y (PG_FUNCTION_ARGS) +{ + int ret; + int nargs; + Oid argtypes[1]; + Datum values[1]; + const char *query = "UPDATE Y SET col1 = 4 WHERE (col2 = $1)"; + + ret = SPI_connect (); + if (ret != SPI_OK_CONNECT) + { + elog (ERROR, "SPI_connect failed ! \n"); + } + + nargs = 1; + argtypes[0] = INT4OID; + values[0] = Int32GetDatum (0); + + ret = SPI_execute_with_args (query, nargs, argtypes, values, NULL, false, 0); + if (ret != SPI_OK_UPDATE) + { + elog (ERROR, "SPI_execute_with_args failed ! \n"); + } + + SPI_finish (); + + PG_RETURN_VOID (); +} + + +Datum +pg_spi_prepare_update (PG_FUNCTION_ARGS) +{ + static SPIPlanPtr prepared_plan = NULL; + SPIPlanPtr new_plan; + int ret; + int nargs; + Oid argtypes[1]; + Datum values[1]; + const char *query = "UPDATE Y SET col1 = 4 WHERE (col2 = $1)"; + + ret = SPI_connect (); + if (ret != SPI_OK_CONNECT) + { + elog (ERROR, "SPI_connect failed ! \n"); + } + + if (prepared_plan == NULL) + { + argtypes[0] = INT4OID; + nargs = 1; + values[0] = Int32GetDatum (3); + // PREPARE + new_plan = SPI_prepare (query, nargs, argtypes); + if (new_plan == NULL) + elog (ERROR, "SPI_prepare failed ! \n"); + // SAVEPLAN + prepared_plan = SPI_saveplan (new_plan); + if (prepared_plan == NULL) + elog (ERROR, "SPI_saveplan failed ! \n"); + } + ret = SPI_execute_plan (prepared_plan, values, NULL, false, 0); + if (ret != SPI_OK_UPDATE) + elog (ERROR, "SPI_execute_plan failed ! \n"); + + SPI_finish (); + PG_RETURN_VOID (); +} + + +/* +Datum +pg_spi_prepare_update_without_saveplan(PG_FUNCTION_ARGS) +{}*/ +void +_PG_fini (void) +{ +} + + +/* + +*/ + + +Datum +pg_spi_get_dep_ref_fees (PG_FUNCTION_ARGS) +{ + /* Define plan to save */ + static SPIPlanPtr deposit_plan; + static SPIPlanPtr ref_plan; + static SPIPlanPtr fees_plan; + static SPIPlanPtr dummy_plan; + /* Define variables to update */ + Timestamp refund_deadline = PG_GETARG_TIMESTAMP (0); + bytea *merchant_pub = PG_GETARG_BYTEA_P (1); + bytea *wire_target_h_payto = PG_GETARG_BYTEA_P (2); + bytea *wtid_raw = PG_GETARG_BYTEA_P (3); + bool is_null; + /* Define variables to store the results of each SPI query */ + uint64_t sum_deposit_val = 0; + uint32_t sum_deposit_frac = 0; + uint64_t s_refund_val = 0; + uint32_t s_refund_frac = 0; + uint64_t sum_dep_fee_val = 0; + uint32_t sum_dep_fee_frac = 0; + uint64_t norm_refund_val = 0; + uint32_t norm_refund_frac = 0; + uint64_t sum_refund_val = 0; + uint32_t sum_refund_frac = 0; + /* Define variables to store the Tuptable */ + SPITupleTable *dep_res; + SPITupleTable *ref_res; + SPITupleTable *ref_by_coin_res; + SPITupleTable *norm_ref_by_coin_res; + SPITupleTable *fully_refunded_coins_res; + SPITupleTable *fees_res; + SPITupleTable *dummys_res; + /* Define variable to update */ + Datum values_refund[2]; + Datum values_deposit[3]; + Datum values_fees[2]; + Datum values_dummys[2]; + TupleDesc tupdesc; + /* Define variables to replace some tables */ + bytea *ref_by_coin_coin_pub; + int64 ref_by_coin_deposit_serial_id = 0; + bytea *norm_ref_by_coin_coin_pub; + int64_t norm_ref_by_coin_deposit_serial_id = 0; + bytea *new_dep_coin_pub = NULL; + int res = SPI_connect (); + + /* Connect to SPI */ + if (res < 0) + { + elog (ERROR, "Could not connect to SPI manager"); + } + if (deposit_plan == NULL) + { + const char *dep_sql; + SPIPlanPtr new_plan; + + // Execute first query and store results in variables + dep_sql = + "UPDATE deposits SET done=TRUE " + "WHERE NOT (done OR policy_blocked) " + "AND refund_deadline=$1 " + "AND merchant_pub=$2 " + "AND wire_target_h_payto=$3 " + "RETURNING " + "deposit_serial_id," + "coin_pub," + "amount_with_fee_val," + "amount_with_fee_frac;"; + fprintf (stderr, "dep sql %d\n", 1); + new_plan = + SPI_prepare (dep_sql, 4,(Oid[]){INT8OID, BYTEAOID, BYTEAOID}); + fprintf (stderr, "dep sql %d\n", 2); + if (new_plan == NULL) + elog (ERROR, "SPI_prepare failed for dep \n"); + deposit_plan = SPI_saveplan (new_plan); + if (deposit_plan == NULL) + elog (ERROR, "SPI_saveplan failed for dep \n"); + } + fprintf (stdout, "dep sql %d\n", 3); + + values_deposit[0] = Int64GetDatum (refund_deadline); + values_deposit[1] = PointerGetDatum (merchant_pub); + values_deposit[2] = PointerGetDatum (wire_target_h_payto); + + res = SPI_execute_plan (deposit_plan, + values_deposit, + NULL, + true, + 0); + fprintf (stdout, "dep sql %d\n", 4); + if (res != SPI_OK_UPDATE) + { + elog (ERROR, "Failed to execute subquery 1 \n"); + } + // STORE TUPTABLE deposit + dep_res = SPI_tuptable; + + for (unsigned int i = 0; i < SPI_processed; i++) + { + int64 dep_deposit_serial_ids = DatumGetInt64 (SPI_getbinval ( + SPI_tuptable->vals[i], + SPI_tuptable->tupdesc, 1, + &is_null)); + bytea *dep_coin_pub = DatumGetByteaP (SPI_getbinval (SPI_tuptable->vals[i], + SPI_tuptable->tupdesc, + 2, &is_null)); + int64 dep_amount_val = DatumGetInt64 (SPI_getbinval (SPI_tuptable->vals[i], + SPI_tuptable->tupdesc, + 3, &is_null)); + int32 dep_amount_frac = DatumGetInt32 (SPI_getbinval (SPI_tuptable->vals[i], + SPI_tuptable->tupdesc, + 4, &is_null)); + + if (is_null) + elog (ERROR, "Failed to retrieve data from deposit \n"); + if (ref_plan == NULL) + { + // Execute second query with parameters from first query and store results in variables + const char *ref_sql = + "SELECT amount_with_fee_val, amount_with_fee_frac, coin_pub, deposit_serial_id " + "FROM refunds " + "WHERE coin_pub=$1 " + "AND deposit_serial_id=$2;"; + SPIPlanPtr new_plan = SPI_prepare (ref_sql, 3, (Oid[]){BYTEAOID, + INT8OID}); + if (new_plan == NULL) + elog (ERROR, "SPI_prepare failed for refund\n"); + ref_plan = SPI_saveplan (new_plan); + if (ref_plan == NULL) + elog (ERROR, "SPI_saveplan failed for refund\n"); + } + values_refund[0] = PointerGetDatum (dep_coin_pub); + values_refund[1] = Int64GetDatum (dep_deposit_serial_ids); + res = SPI_execute_plan (ref_plan, + values_refund, + NULL, + false, + 0); + if (res != SPI_OK_SELECT) + elog (ERROR, "Failed to execute subquery 2\n"); + // STORE TUPTABLE refund + ref_res = SPI_tuptable; + for (unsigned int j = 0; j < SPI_processed; j++) + { + int64 ref_refund_val = DatumGetInt64 (SPI_getbinval ( + SPI_tuptable->vals[j], + SPI_tuptable->tupdesc, 1, + &is_null)); + int32 ref_refund_frac = DatumGetInt32 (SPI_getbinval ( + SPI_tuptable->vals[j], + SPI_tuptable->tupdesc, 2, + &is_null)); + bytea *ref_coin_pub = DatumGetByteaP (SPI_getbinval ( + SPI_tuptable->vals[j], + SPI_tuptable->tupdesc, 3, + &is_null)); + int64 ref_deposit_serial_id = DatumGetInt64 (SPI_getbinval ( + SPI_tuptable->vals[j], + SPI_tuptable->tupdesc, 4, + &is_null)); + // Execute third query with parameters from second query and store results in variables + ref_by_coin_coin_pub = ref_coin_pub; + ref_by_coin_deposit_serial_id = ref_deposit_serial_id; + // LOOP TO GET THE SUM FROM REFUND BY COIN + for (unsigned int i = 0; ivals[i], + SPI_tuptable->tupdesc, 1, + &is_null))) + && + (ref_by_coin_deposit_serial_id == + DatumGetUInt64 (SPI_getbinval (SPI_tuptable->vals[i], + SPI_tuptable->tupdesc, 2, + &is_null))) + ) + { + sum_refund_val += ref_refund_val; + sum_refund_frac += ref_refund_frac; + norm_ref_by_coin_coin_pub = ref_by_coin_coin_pub; + norm_ref_by_coin_deposit_serial_id = ref_by_coin_deposit_serial_id; + } + }// END SUM CALCULATION + // NORMALIZE REFUND VAL FRAC + norm_refund_val = + (sum_refund_val + sum_refund_frac) / 100000000; + norm_refund_frac = + sum_refund_frac % 100000000; + // Get refund values + s_refund_val += sum_refund_val; + s_refund_frac = sum_refund_frac; + }// END REFUND + if (norm_ref_by_coin_coin_pub == dep_coin_pub + && ref_by_coin_deposit_serial_id == dep_deposit_serial_ids + && norm_refund_val == dep_amount_val + && norm_refund_frac == dep_amount_frac) + { + new_dep_coin_pub = dep_coin_pub; + } + // Ensure we get the fee for each coin and not only once per denomination + if (fees_plan == NULL) + { + const char *fees_sql = + "SELECT " + " denom.fee_deposit_val AS fee_val, " + " denom.fee_deposit_frac AS fee_frac, " + "FROM known_coins kc" + "JOIN denominations denom USING (denominations_serial) " + "WHERE kc.coin_pub = $1 AND kc.coin_pub != $2;"; + SPIPlanPtr new_plan = SPI_prepare (fees_sql, 3, (Oid[]){BYTEAOID, + BYTEAOID}); + if (new_plan == NULL) + { + elog (ERROR, "SPI_prepare for fees failed ! \n"); + } + fees_plan = SPI_saveplan (new_plan); + if (fees_plan == NULL) + { + elog (ERROR, "SPI_saveplan for fees failed ! \n"); + } + } + values_fees[0] = PointerGetDatum (dep_coin_pub); + values_fees[1] = PointerGetDatum (new_dep_coin_pub); + res = SPI_execute_plan (fees_plan, values_fees, NULL, false, 0); + if (res != SPI_OK_SELECT) + elog (ERROR, "SPI_execute_plan failed for fees \n"); + fees_res = SPI_tuptable; + tupdesc = fees_res->tupdesc; + for (unsigned int i = 0; ivals[i]; + bool is_null; + uint64_t fee_val = DatumGetUInt64 (SPI_getbinval (tuple, tupdesc, 1, + &is_null)); + uint32_t fee_frac = DatumGetUInt32 (SPI_getbinval (tuple, tupdesc, 2, + &is_null)); + uint64_t fees_deposit_serial_id = DatumGetUInt64 (SPI_getbinval (tuple, + tupdesc, + 3, + &is_null)); + if (dummy_plan == NULL) + { + const char *insert_dummy_sql = + "INSERT INTO " + "aggregation_tracking(deposit_serial_id, wtid_raw)" + " VALUES ($1, $2)"; + + SPIPlanPtr new_plan = SPI_prepare (insert_dummy_sql, 2, (Oid[]){INT8OID, + BYTEAOID}); + if (new_plan == NULL) + elog (ERROR, "FAILED to prepare aggregation tracking \n"); + dummy_plan = SPI_saveplan (new_plan); + if (dummy_plan == NULL) + elog (ERROR, "FAILED to saveplan aggregation tracking\n"); + } + values_dummys[0] = Int64GetDatum (dep_deposit_serial_ids); + values_dummys[1] = PointerGetDatum (wtid_raw); + res = SPI_execute_plan (dummy_plan, values_dummys, NULL, false, 0); + if (res != SPI_OK_INSERT) + elog (ERROR, "Failed to insert dummy\n"); + dummys_res = SPI_tuptable; + // Calculation of deposit fees for not fully refunded deposits + sum_dep_fee_val += fee_val; + sum_dep_fee_frac += fee_frac; + } + // Get deposit values + sum_deposit_val += dep_amount_val; + sum_deposit_frac += dep_amount_frac; + }// END DEPOSIT + SPI_finish (); + PG_RETURN_VOID (); +} diff --git a/src/exchangedb/spi/own_test.control b/src/exchangedb/spi/own_test.control new file mode 100644 index 000000000..4e73e207f --- /dev/null +++ b/src/exchangedb/spi/own_test.control @@ -0,0 +1,4 @@ +comment = 'Example extension for testing purposes' +default_version = '1.0' +module_pathname = '$libdir/own_test' +relocatable = true diff --git a/src/exchangedb/spi/own_test.sql b/src/exchangedb/spi/own_test.sql new file mode 100644 index 000000000..12729d068 --- /dev/null +++ b/src/exchangedb/spi/own_test.sql @@ -0,0 +1,201 @@ +DROP TABLE IF EXISTS X; +CREATE TABLE X ( + a integer +); + +INSERT INTO X (a) + VALUES (1), (2), (3), (4), (5), (6), (7); + +DROP TABLE IF EXISTS Y; +CREATE TABLE Y (col1 INT, col2 INT); +INSERT INTO Y (col1,col2) + VALUES (1,2), (2,0), (0,4), (4,0), (0,6), (6,7), (7,8); + +DROP TABLE IF EXISTS Z; +CREATE TABLE Z (col1 BYTEA); + +DROP TABLE IF EXISTS deposits; +CREATE TABLE deposits( + deposit_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY + ,shard INT8 NOT NULL + ,coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32) + ,known_coin_id INT8 NOT NULL + ,amount_with_fee_val INT8 NOT NULL + ,amount_with_fee_frac INT4 NOT NULL + ,wallet_timestamp INT8 NOT NULL + ,exchange_timestamp INT8 NOT NULL + ,refund_deadline INT8 NOT NULL + ,wire_deadline INT8 NOT NULL + ,merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32) + ,h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64) + ,coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64) + ,wire_salt BYTEA NOT NULL CHECK (LENGTH(wire_salt)=16) + ,wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32) + ,done BOOLEAN NOT NULL DEFAULT FALSE + ,policy_blocked BOOLEAN NOT NULL DEFAULT FALSE + ,policy_details_serial_id INT8); + + +DROP FUNCTION IF EXISTS pg_spi_insert_int; +CREATE FUNCTION pg_spi_insert_int() + RETURNS VOID + LANGUAGE c VOLATILE COST 100 +AS '$libdir/own_test', 'pg_spi_insert_int'; + +DROP FUNCTION IF EXISTS pg_spi_select_from_x; +CREATE FUNCTION pg_spi_select_from_x() + RETURNS INT8 + LANGUAGE c COST 100 +AS '$libdir/own_test', 'pg_spi_select_from_x'; + +/* +CREATE FUNCTION pg_spi_select_pair_from_y() + RETURNS valuest + LANGUAGE c COST 100 +AS '$libdir/own_test', 'pg_spi_select_pair_from_y'; +*/ +/*CREATE FUNCTION pg_spi_select_with_cond() + RETURNS INT8 + LANGUAGE c COST 100 +AS '$libdir/own_test', 'pg_spi_select_with_cond'; +*/ + +DROP FUNCTION IF EXISTS pg_spi_update_y; +CREATE FUNCTION pg_spi_update_y() + RETURNS VOID + LANGUAGE c VOLATILE COST 100 +AS '$libdir/own_test', 'pg_spi_update_y'; + +DROP FUNCTION IF EXISTS pg_spi_prepare_example; +CREATE FUNCTION pg_spi_prepare_example() + RETURNS INT8 + LANGUAGE c COST 100 +AS '$libdir/own_test', 'pg_spi_prepare_example'; + +DROP FUNCTION IF EXISTS pg_spi_prepare_example_without_saveplan; +CREATE FUNCTION pg_spi_prepare_example_without_saveplan() + RETURNS INT8 + LANGUAGE c COST 100 +AS '$libdir/own_test', 'pg_spi_prepare_example_without_saveplan'; + +DROP FUNCTION IF EXISTS pg_spi_prepare_insert; +CREATE FUNCTION pg_spi_prepare_insert() + RETURNS VOID + LANGUAGE c VOLATILE COST 100 +AS '$libdir/own_test', 'pg_spi_prepare_insert'; + +DROP FUNCTION IF EXISTS pg_spi_prepare_insert_without_saveplan; +CREATE FUNCTION pg_spi_prepare_insert_without_saveplan() + RETURNS VOID + LANGUAGE c VOLATILE COST 100 +AS '$libdir/own_test', 'pg_spi_prepare_insert_without_saveplan'; + +/* +CREATE FUNCTION pg_spi_prepare_select_with_cond() + RETURNS INT8 + LANGUAGE c COST 100 +AS '$libdir/own_test', 'pg_spi_prepare_select_with_cond'; +*/ + +DROP FUNCTION IF EXISTS pg_spi_prepare_select_with_cond_without_saveplan; +CREATE FUNCTION pg_spi_prepare_select_with_cond_without_saveplan() + RETURNS INT8 + LANGUAGE c COST 100 +AS '$libdir/own_test', 'pg_spi_prepare_select_with_cond_without_saveplan'; + +DROP FUNCTION IF EXISTS pg_spi_prepare_update; +CREATE FUNCTION pg_spi_prepare_update() + RETURNS VOID + LANGUAGE c VOLATILE COST 100 +AS '$libdir/own_test', 'pg_spi_prepare_update'; + +DROP FUNCTION IF EXISTS pg_spi_get_dep_ref_fees; +CREATE FUNCTION pg_spi_get_dep_ref_fees( + IN in_timestamp INT8 + ,IN merchant_pub BYTEA + ,IN wire_target_h_payto BYTEA + ,IN wtid BYTEA +) + RETURNS VOID + LANGUAGE c VOLATILE COST 100 +AS '$libdir/own_test', 'pg_spi_get_dep_ref_fees'; + +DROP FUNCTION IF EXISTS update_pg_spi_get_dep_ref_fees; +CREATE FUNCTION update_pg_spi_get_dep_ref_fees( + IN in_refund_deadline INT8, + IN in_merchant_pub BYTEA, + IN in_wire_target_h_payto BYTEA +) +RETURNS SETOF record +LANGUAGE plpgsql VOLATILE +AS $$ +DECLARE + +BEGIN +RETURN QUERY + UPDATE deposits + SET done = TRUE + WHERE NOT (done OR policy_blocked) + AND refund_deadline < in_refund_deadline + AND merchant_pub = in_merchant_pub + AND wire_target_h_payto = in_wire_target_h_payto + RETURNING + deposit_serial_id, + coin_pub, + amount_with_fee_val, + amount_with_fee_frac; +END $$; + +DROP FUNCTION IF EXISTS stored_procedure_update; +CREATE FUNCTION stored_procedure_update( +IN in_number INT8 +) +RETURNS VOID +LANGUAGE plpgsql +AS $$ +BEGIN + UPDATE Y + SET col1 = 4 + WHERE col2 = in_number; +END $$; + +DROP FUNCTION IF EXISTS stored_procedure_select; +CREATE FUNCTION stored_procedure_select(OUT out_value INT8) +RETURNS INT8 +LANGUAGE plpgsql +AS $$ +BEGIN + SELECT 1 + INTO out_value + FROM X; + RETURN; +END $$; + + +DROP FUNCTION IF EXISTS stored_procedure_insert; +CREATE FUNCTION stored_procedure_insert( +IN in_number INT8, +OUT out_number INT8) +RETURNS INT8 +LANGUAGE plpgsql +AS $$ +BEGIN + INSERT INTO X (a) + VALUES (in_number) + RETURNING a INTO out_number; +END $$; + +DROP FUNCTION IF EXISTS stored_procedure_select_with_cond; +CREATE FUNCTION stored_procedure_select_with_cond( +IN in_number INT8, +OUT out_number INT8 +) +RETURNS INT8 +LANGUAGE plpgsql +AS $$ +BEGIN + SELECT col1 INTO out_number + FROM Y + WHERE col2 = in_number; + RETURN; +END $$; diff --git a/src/exchangedb/spi/perf_own_test.c b/src/exchangedb/spi/perf_own_test.c new file mode 100644 index 000000000..92be2235e --- /dev/null +++ b/src/exchangedb/spi/perf_own_test.c @@ -0,0 +1,25 @@ +/* + 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 +*/ +/** + * @file exchangedb/spi/perf_own_test.c + * @brief benchmark for 'own_test' + * @author Joseph Xu + */ +#include "exchangedb/platform.h" +#include "exchangedb/taler_exchangedb_lib.h" +#include "exchangedb/taler_json_lib.h" +#include "exchangedb/taler_exchangedb_plugin.h" +#include "own_test.sql" diff --git a/src/exchangedb/spi/pg_aggregate.c b/src/exchangedb/spi/pg_aggregate.c new file mode 100644 index 000000000..721f247c7 --- /dev/null +++ b/src/exchangedb/spi/pg_aggregate.c @@ -0,0 +1,411 @@ +#include "postgres.h" +#include "fmgr.h" +#include "utils/numeric.h" +#include "utils/builtins.h" +#include "executor/spi.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1 (get_deposit_summary); + +Datum +get_deposit_summary (PG_FUNCTION_ARGS) +{ + + static SPIPlanPtr deposit_plan; + static SPIPlanPtr refund_plan; + static SPIPlanPtr refund_by_coin_plan; + static SPIPlanPtr norm_refund_by_coin_plan; + static SPIPlanPtr fully_refunded_by_coins_plan; + static SPIPlanPtr fees_plan; + + int shard = PG_GETARG_INT32 (0); + char *sql; + char *merchant_pub = text_to_cstring (PG_GETARG_TEXT_P (1)); + char *wire_target_h_payto = text_to_cstring (PG_GETARG_TEXT_P (2)); + char *wtid_raw = text_to_cstring (PG_GETARG_TEXT_P (3)); + int refund_deadline = PG_GETARG_INT32 (4); + int conn = SPI_connect (); + if (conn != SPI_OK_CONNECT) + { + elog (ERROR, "DB connection failed ! \n"); + } + + if (deposit_plan == NULL + || refund_plan == NULL + || refund_by_coin_plan == NULL + || norm_refund_by_coin_plan = NULL + || fully_refunded_coins_plan = NULL + || fees_plan + == NULL) + { + if (deposit_plan == NULL) + { + int nargs = 3; + Oid argtypes[3]; + argtypes[0] = INT8OID; + argtypes[1] = BYTEAOID; + argtypes[2] = BYTEAOID; + const char *dep_sql = + " UPDATE deposits" + " SET done=TRUE" + " WHERE NOT (done OR policy_blocked)" + " AND refund_deadline < $1" + " AND merchant_pub = $2" + " AND wire_target_h_payto = $3" + " RETURNING" + " deposit_serial_id" + " ,coin_pub" + " ,amount_with_fee_val AS amount_val" + " ,amount_with_fee_frac AS amount_frac"; + SPIPlanPtr new_plan = + SPI_prepare (dep_sql, 4, argtypes); + if (new_plan == NULL) + { + elog (ERROR, "SPI_prepare for deposit failed ! \n"); + } + deposit_plan = SPI_saveplan (new_plan); + if (deposit_plan == NULL) + { + elog (ERROR, "SPI_saveplan for deposit failed ! \n"); + } + } + + Datum values[4]; + values[0] = Int64GetDatum (refund_deadline); + values[1] = CStringGetDatum (merchant_pub); + values[2] = CStringGetDatum (wire_target_h_payto); + int ret = SPI_execute_plan (deposit_plan, + values, + NULL, + true, + 0); + if (ret != SPI_OK_UPDATE) + { + elog (ERROR, "Failed to execute subquery 1\n"); + } + uint64_t *dep_deposit_serial_ids = palloc (sizeof(uint64_t) + * SPI_processed); + BYTEA **dep_coin_pubs = palloc (sizeof(BYTEA *) * SPI_processed); + uint64_t *dep_amount_vals = palloc (sizeof(uint64_t) * SPI_processed); + uint32_t *dep_amount_fracs = palloc (sizeof(uint32_t) * SPI_processed); + for (unsigned int i = 0; i < SPI_processed; i++) + { + HeapTuple tuple = SPI_tuptable->vals[i]; + dep_deposit_serial_ids[i] = + DatumGetInt64 (SPI_getbinval (tuple, SPI_tuptable->tupdesc, 1, &ret)); + dep_coin_pubs[i] = + DatumGetByteaP (SPI_getbinval (tuple, SPI_tuptable->tupdesc, 2, &ret)); + dep_amount_vals[i] = + DatumGetInt64 (SPI_getbinval (tuple, SPI_tuptable->tupdesc, 3, &ret)); + dep_amount_fracs[i] = + DatumGetInt32 (SPI_getbinval (tuple, SPI_tuptable->tupdesc, 4, &ret)); + } + + + if (refund_plan == NULL) + { + const char *ref_sql = + "ref AS (" + " SELECT" + " amount_with_fee_val AS refund_val" + " ,amount_with_fee_frac AS refund_frac" + " ,coin_pub" + " ,deposit_serial_id" + " FROM refunds" + " WHERE coin_pub IN (SELECT coin_pub FROM dep)" + " AND deposit_serial_id IN (SELECT deposit_serial_id FROM dep)) "; + SPIPlanPtr new_plan = SPI_prepare (ref_sql, 0, NULL); + if (new_plan == NULL) + elog (ERROR, "SPI_prepare for refund failed ! \n"); + refund_plan = SPI_saveplan (new_plan); + if (refund_plan == NULL) + { + elog (ERROR, "SPI_saveplan for refund failed ! \n"); + } + } + + int64t_t *ref_deposit_serial_ids = palloc (sizeof(int64_t) * SPI_processed); + + int res = SPI_execute_plan (refund_plan, NULL, NULL, false, 0); + if (res != SPI_OK_SELECT) + { + elog (ERROR, "Failed to execute subquery 2\n"); + } + SPITupleTable *tuptable = SPI_tuptable; + TupleDesc tupdesc = tuptable->tupdesc; + for (unsigned int i = 0; i < SPI_processed; i++) + { + HeapTuple tuple = tuptable->vals[i]; + Datum refund_val = SPI_getbinval (tuple, tupdesc, 1, &refund_val_isnull); + Datum refund_frac = SPI_getbinval (tuple, tupdesc, 2, + &refund_frac_isnull); + Datum coin_pub = SPI_getbinval (tuple, tupdesc, 3, &coin_pub_isnull); + Datum deposit_serial_id = SPI_getbinval (tuple, tupdesc, 4, + &deposit_serial_id_isnull); + if (refund_val_isnull + || refund_frac_isnull + || coin_pub_isnull + || deposit_serial_id_isnull) + { + elog (ERROR, "Failed to retrieve data from subquery 2"); + } + uint64_t refund_val_int = DatumGetUInt64 (refund_val); + uint32_t refund_frac_int = DatumGetUInt32 (refund_frac); + BYTEA coin_pub = DatumGetByteaP (coin_pub); + ref_deposit_serial_ids = DatumGetInt64 (deposit_serial_id); + + refund *new_refund = (refund*) palloc (sizeof(refund)); + new_refund->coin_pub = coin_pub_str; + new_refund->deposit_serial_id = deposit_serial_id_int; + new_refund->amount_with_fee_val = refund_val_int; + new_refund->amount_with_fee_frac = refund_frac_int; + } + + + if (refund_by_coin_plan == NULL) + { + const char *ref_by_coin_sql = + "ref_by_coin AS (" + " SELECT" + " SUM(refund_val) AS sum_refund_val" + " ,SUM(refund_frac) AS sum_refund_frac" + " ,coin_pub" + " ,deposit_serial_id" + " FROM ref" + " GROUP BY coin_pub, deposit_serial_id) "; + SPIPlanPtr new_plan = SPI_prepare (ref_by_coin_sql, 0, NULL); + if (new_plan == NULL) + elog (ERROR, "SPI_prepare for refund by coin failed ! \n"); + refund_by_coin_plan = SPI_saveplan (new_plan); + if (refund_by_coin_plan == NULL) + elog (ERROR, "SPI_saveplan for refund failed"); + } + + + int res = SPI_execute_plan (refund_by_coin_plan, NULL, NULL, false, 0); + if (res != SPI_OK_SELECT) + { + elog (ERROR, "Failed to execute subquery 2\n"); + } + + SPITupleTable *tuptable = SPI_tuptable; + TupleDesc tupdesc = tuptable->tupdesc; + for (unsigned int i = 0; i < SPI_processed; i++) + { + HeapTuple tuple = tuptable->vals[i]; + Datum sum_refund_val = SPI_getbinval (tuple, tupdesc, 1, + &refund_val_isnull); + Datum sum_refund_frac = SPI_getbinval (tuple, tupdesc, 2, + &refund_frac_isnull); + Datum coin_pub = SPI_getbinval (tuple, tupdesc, 3, &coin_pub_isnull); + Datum deposit_serial_id_int = SPI_getbinval (tuple, tupdesc, 4, + &deposit_serial_id_isnull); + if (refund_val_isnull + || refund_frac_isnull + || coin_pub_isnull + || deposit_serial_id_isnull) + { + elog (ERROR, "Failed to retrieve data from subquery 2"); + } + uint64_t s_refund_val_int = DatumGetUInt64 (sum_refund_val); + uint32_t s_refund_frac_int = DatumGetUInt32 (sum_refund_frac); + BYTEA coin_pub = DatumGetByteaP (coin_pub); + uint64_t deposit_serial_id_int = DatumGetInt64 (deposit_serial_id_int); + refund *new_refund_by_coin = (refund*) palloc (sizeof(refund)); + new_refund_by_coin->coin_pub = coin_pub; + new_refund_by_coin->deposit_serial_id = deposit_serial_id_int; + new_refund_by_coin->refund_amount_with_fee_val = s_refund_val_int; + new_refund_by_coin->refund_amount_with_fee_frac = s_refund_frac_int; + } + + + if (norm_refund_by_coin_plan == NULL) + { + const char *norm_ref_by_coin_sql = + "norm_ref_by_coin AS (" + " SELECT" + " coin_pub" + " ,deposit_serial_id" + " FROM ref_by_coin) "; + SPIPlanPtr new_plan = SPI_prepare (norm_ref_by_coin_sql, 0, NULL); + if (new_plan == NULL) + elog (ERROR, "SPI_prepare for norm refund by coin failed ! \n"); + norm_refund_by_coin_plan = SPI_saveplan (new_plan); + if (norm_refund_by_coin_plan == NULL) + elog (ERROR, "SPI_saveplan for norm refund by coin failed ! \n"); + } + + double norm_refund_val = + ((double) new_refund_by_coin->refund_amount_with_fee_val + + (double) new_refund_by_coin->refund_amount_with_fee_frac) / 100000000; + double norm_refund_frac = + (double) new_refund_by_coin->refund_amount_with_fee_frac % 100000000; + + if (fully_refunded_coins_plan == NULL) + { + const char *fully_refunded_coins_sql = + "fully_refunded_coins AS (" + " SELECT" + " dep.coin_pub" + " FROM norm_ref_by_coin norm" + " JOIN dep" + " ON (norm.coin_pub = dep.coin_pub" + " AND norm.deposit_serial_id = dep.deposit_serial_id" + " AND norm.norm_refund_val = dep.amount_val" + " AND norm.norm_refund_frac = dep.amount_frac)) "; + SPIPlanPtr new_plan = + SPI_prepare (fully_refunded_coins_sql, 0, NULL); + if (new_plan == NULL) + elog (ERROR, "SPI_prepare for fully refunded coins failed ! \n"); + fully_refunded_coins_plan = SPI_saveplan (new_plan); + if (fully_refunded_coins_plan == NULL) + elog (ERROR, "SPI_saveplan for fully refunded coins failed ! \n"); + } + + int res = SPI_execute_plan (fully_refunded_coins_sql); + if (res != SPI_OK_SELECT) + elog (ERROR, "Failed to execute subquery 4\n"); + SPITupleTable *tuptable = SPI_tuptable; + TupleDesc tupdesc = tuptable->tupdesc; + + BYTEA coin_pub = SPI_getbinval (tuple, tupdesc, 1, &coin_pub_isnull); + if (fees_plan == NULL) + { + const char *fees_sql = + "SELECT " + " denom.fee_deposit_val AS fee_val, " + " denom.fee_deposit_frac AS fee_frac, " + " cs.deposit_serial_id " + "FROM dep cs " + "JOIN known_coins kc USING (coin_pub) " + "JOIN denominations denom USING (denominations_serial) " + "WHERE coin_pub NOT IN (SELECT coin_pub FROM fully_refunded_coins)"; + SPIPlanPtr new_plan = + SPI_prepare (fees_sql, 0, NULL); + if (new_plan == NULL) + { + elog (ERROR, "SPI_prepare for fees failed ! \n"); + } + fees_plan = SPI_saveplan (new_plan); + if (fees_plan == NULL) + { + elog (ERROR, "SPI_saveplan for fees failed ! \n"); + } + } + } + int fees_ntuples; + SPI_execute (fees_sql, true, 0); + if (SPI_result_code () != SPI_OK_SELECT) + { + ereport ( + ERROR, + (errcode (ERRCODE_INTERNAL_ERROR), + errmsg ("deposit fee query failed: error code %d \n", + SPI_result_code ()))); + } + fees_ntuples = SPI_processed; + + if (fees_ntuples > 0) + { + for (i = 0; i < fees_ntuples; i++) + { + Datum fee_val_datum = + SPI_getbinval (SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, + &fee_null); + Datum fee_frac_datum = + SPI_getbinval (SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, + &fee_null); + Datum deposit_id_datum = + SPI_getbinval (SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 3, + &deposit_null); + if (! fee_null && ! deposit_null) + { + int64 fee_val = DatumGetInt64 (fee_val_datum); + int32 fee_frac = DatumGetInt32 (fee_frac_datum); + int64 deposit_id = DatumGetInt64 (deposit_id_datum); + sum_fee_value += fee_val; + sum_fee_fraction += fee_frac; + char *insert_agg_sql = + psprintf ( + "INSERT INTO " + "aggregation_tracking(deposit_serial_id, wtid_raw)" + " VALUES (%lld, '%s')", + deposit_id, wtid_raw); + SPI_execute (insert_agg_sql, false, 0); + } + } + } + + TupleDesc tupdesc; + SPITupleTable *tuptable = SPI_tuptable; + HeapTuple tuple; + Datum result; + + if (tuptable == NULL || SPI_processed != 1) + { + ereport ( + ERROR, + (errcode (ERRCODE_INTERNAL_ERROR), + errmsg ("Unexpected result \n"))); + } + tupdesc = SPI_tuptable->tupdesc; + tuple = SPI_tuptable->vals[0]; + result = HeapTupleGetDatum (tuple); + + TupleDesc result_desc = CreateTemplateTupleDesc (6, false); + TupleDescInitEntry (result_desc, (AttrNumber) 1, "sum_deposit_value", INT8OID, + -1, 0); + TupleDescInitEntry (result_desc, (AttrNumber) 2, "sum_deposit_fraction", + INT4OID, -1, 0); + TupleDescInitEntry (result_desc, (AttrNumber) 3, "sum_refund_value", INT8OID, + -1, 0); + TupleDescInitEntry (result_desc, (AttrNumber) 4, "sum_refund_fraction", + INT4OID, -1, 0); + TupleDescInitEntry (result_desc, (AttrNumber) 5, "sum_fee_value", INT8OID, -1, + 0); + TupleDescInitEntry (result_desc, (AttrNumber) 6, "sum_fee_fraction", INT4OID, + -1, 0); + + int ret = SPI_prepare (sql, 4, argtypes); + if (ret != SPI_OK_PREPARE) + { + elog (ERROR, "Failed to prepare statement: %s \n", sql); + } + + ret = SPI_execute_plan (plan, args, nulls, true, 0); + if (ret != SPI_OK_SELECT) + { + elog (ERROR, "Failed to execute statement: %s \n", sql); + } + + if (SPI_processed > 0) + { + HeapTuple tuple; + Datum values[6]; + bool nulls[6] = {false}; + values[0] = + SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, + &nulls[0]); + values[1] = + SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, + &nulls[1]); + values[2] = + SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, + &nulls[2]); + values[3] = + SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 4, + &nulls[3]); + values[4] = + SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 5, + &nulls[4]); + values[5] = + SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 6, + &nulls[5]); + tuple = heap_form_tuple (result_desc, values, nulls); + PG_RETURN_DATUM (HeapTupleGetDatum (tuple)); + } + SPI_finish (); + + PG_RETURN_NULL (); +} diff --git a/src/exchangedb/test_exchangedb_by_j.c b/src/exchangedb/test_exchangedb_by_j.c index 9769d964b..24b24d5b0 100644 --- a/src/exchangedb/test_exchangedb_by_j.c +++ b/src/exchangedb/test_exchangedb_by_j.c @@ -74,8 +74,8 @@ static void run (void *cls) { static const unsigned int batches[] = {1, 2, 3, 4, 8, 16 }; - struct GNUNET_TIME_Relative times[sizeof (batches)/sizeof(*batches)]; - unsigned long long sqrs[sizeof (batches)/sizeof(*batches)]; + struct GNUNET_TIME_Relative times[sizeof (batches) / sizeof(*batches)]; + unsigned long long sqrs[sizeof (batches) / sizeof(*batches)]; struct GNUNET_CONFIGURATION_Handle *cfg = cls; const uint32_t num_partitions = 10; @@ -101,74 +101,75 @@ run (void *cls) memset (times, 0, sizeof (times)); memset (sqrs, 0, sizeof (sqrs)); for (unsigned int r = 0; r < ROUNDS; r++) - { + { for (unsigned int i = 0; i< 6; i++) + { + const char *sndr = "payto://x-taler-bank/localhost:8080/1"; + struct TALER_Amount value; + unsigned int batch_size = batches[i]; + unsigned int iterations = 16; // 1024*10; + struct TALER_ReservePublicKeyP reserve_pubs[iterations]; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Timestamp ts; + struct GNUNET_TIME_Relative duration; + struct TALER_EXCHANGEDB_ReserveInInfo reserves[iterations]; + enum GNUNET_DB_QueryStatus results[iterations]; + unsigned long long duration_sq; + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1.000010", + &value)); + now = GNUNET_TIME_absolute_get (); + ts = GNUNET_TIME_timestamp_get (); + for (unsigned int r = 0; rbatch2_reserves_in_insert (plugin->cls, - reserves, - iterations, - batch_size, - results)); - duration = GNUNET_TIME_absolute_get_duration (now); - times[i] = GNUNET_TIME_relative_add (times[i], - duration); - duration_sq = duration.rel_value_us * duration.rel_value_us; - GNUNET_assert (duration_sq / duration.rel_value_us == duration.rel_value_us); - GNUNET_assert (sqrs[i] + duration_sq >= sqrs[i]); - sqrs[i] += duration_sq; - fprintf (stdout, - "for a batchsize equal to %d it took %s\n", - batch_size, - GNUNET_STRINGS_relative_time_to_string (duration, - GNUNET_NO) ); - - system ("./test.sh"); //DELETE AFTER TIMER + RND_BLK (&reserve_pubs[r]); + reserves[r].reserve_pub = &reserve_pubs[r]; + reserves[r].balance = &value; + reserves[r].execution_time = ts; + reserves[r].sender_account_details = sndr; + reserves[r].exchange_account_name = "name"; + reserves[r].wire_reference = r; } - } - for (unsigned int i = 0; i< 6; i++) - { - struct GNUNET_TIME_Relative avg; - double avg_dbl; - double variance; + FAILIF (iterations != + plugin->batch2_reserves_in_insert (plugin->cls, + reserves, + iterations, + batch_size, + results)); + duration = GNUNET_TIME_absolute_get_duration (now); + times[i] = GNUNET_TIME_relative_add (times[i], + duration); + duration_sq = duration.rel_value_us * duration.rel_value_us; + GNUNET_assert (duration_sq / duration.rel_value_us == + duration.rel_value_us); + GNUNET_assert (sqrs[i] + duration_sq >= sqrs[i]); + sqrs[i] += duration_sq; + fprintf (stdout, + "for a batchsize equal to %d it took %s\n", + batch_size, + GNUNET_STRINGS_relative_time_to_string (duration, + GNUNET_NO) ); - avg = GNUNET_TIME_relative_divide (times[i], - ROUNDS); - avg_dbl = avg.rel_value_us; - variance = sqrs[i] - (avg_dbl * avg_dbl * ROUNDS); - fprintf(stdout, - "Batch[%2u]: %8llu ± %6.0f\n", - batches[i], - (unsigned long long) avg.rel_value_us, - sqrt (variance / (ROUNDS-1))); + system ("./test.sh"); // DELETE AFTER TIMER } + } + for (unsigned int i = 0; i< 6; i++) + { + struct GNUNET_TIME_Relative avg; + double avg_dbl; + double variance; + + avg = GNUNET_TIME_relative_divide (times[i], + ROUNDS); + avg_dbl = avg.rel_value_us; + variance = sqrs[i] - (avg_dbl * avg_dbl * ROUNDS); + fprintf (stdout, + "Batch[%2u]: %8llu ± %6.0f\n", + batches[i], + (unsigned long long) avg.rel_value_us, + sqrt (variance / (ROUNDS - 1))); + } result = 0; drop: diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 4f52d78fa..61d92483f 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -1947,6 +1947,7 @@ void TALER_payto_hash (const char *payto, struct TALER_PaytoHashP *h_payto); + /** * Details about a planchet that the customer wants to obtain * a withdrawal authorization. This is the information that diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 2bf71a17e..4099d6bb0 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -3490,8 +3490,16 @@ struct TALER_EXCHANGE_KycStatus */ struct TALER_ExchangeSignatureP exchange_sig; + /** + * AML status for the account. + */ + enum TALER_AmlDecisionState aml_status; + } success; + /** + * KYC is required. + */ struct { @@ -3502,8 +3510,26 @@ struct TALER_EXCHANGE_KycStatus */ const char *kyc_url; + /** + * AML status for the account. + */ + enum TALER_AmlDecisionState aml_status; + } accepted; + /** + * KYC is OK, but account needs positive AML decision. + */ + struct + { + + /** + * AML status for the account. + */ + enum TALER_AmlDecisionState aml_status; + + } unavailable_for_legal_reasons; + } details; }; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index cf7659b3b..c3f670579 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -1,6 +1,6 @@ /* 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 terms of the GNU General Public License as published by the Free Software @@ -18,6 +18,7 @@ * @brief Low-level (statement-level) database access for the exchange * @author Florian Dold * @author Christian Grothoff + * @author Özgür Kesim */ #ifndef TALER_EXCHANGEDB_PLUGIN_H #define TALER_EXCHANGEDB_PLUGIN_H @@ -29,6 +30,47 @@ #include "taler_extensions_policy.h" +/** + * Per-coin information returned when doing a batch insert. + */ +struct TALER_EXCHANGEDB_CoinInfo +{ + /** + * Row of the coin in the known_coins table. + */ + uint64_t known_coin_id; + + /** + * Hash of the denomination, relevant on @e denom_conflict. + */ + struct TALER_DenominationHashP denom_hash; + + /** + * Hash of the age commitment, relevant on @e age_conflict. + */ + struct TALER_AgeCommitmentHash h_age_commitment; + + /** + * True if the coin was known previously. + */ + bool existed; + + /** + * True if the known coin has a different denomination; + * application will find denomination of the already + * known coin in @e denom_hash. + */ + bool denom_conflict; + + /** + * True if the known coin has a different age restriction; + * application will find age commitment of the already + * known coin in @e h_age_commitment. + */ + bool age_conflict; +}; + + /** * Information about a denomination key. */ @@ -193,6 +235,7 @@ struct TALER_EXCHANGEDB_SignkeyMetaData */ enum TALER_EXCHANGEDB_ReplicatedTable { + /* From exchange-0002.sql: */ TALER_EXCHANGEDB_RT_DENOMINATIONS, TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS, TALER_EXCHANGEDB_RT_WIRE_TARGETS, @@ -235,6 +278,13 @@ enum TALER_EXCHANGEDB_ReplicatedTable TALER_EXCHANGEDB_RT_WADS_IN, TALER_EXCHANGEDB_RT_WADS_IN_ENTRIES, TALER_EXCHANGEDB_RT_PROFIT_DRAINS, + /* From exchange-0003.sql: */ + TALER_EXCHANGEDB_RT_AML_STAFF, + TALER_EXCHANGEDB_RT_AML_HISTORY, + TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES, + TALER_EXCHANGEDB_RT_PURSE_DELETION, + TALER_EXCHANGEDB_RT_WITHDRAW_AGE_COMMITMENTS, + TALER_EXCHANGEDB_RT_WITHDRAW_AGE_REVEALED_COINS, }; @@ -660,6 +710,70 @@ struct TALER_EXCHANGEDB_TableData struct TALER_MasterSignatureP master_sig; } profit_drains; + struct + { + struct TALER_AmlOfficerPublicKeyP decider_pub; + struct TALER_MasterSignatureP master_sig; + char *decider_name; + bool is_active; + bool read_only; + struct GNUNET_TIME_Timestamp last_change; + } aml_staff; + + struct + { + struct TALER_PaytoHashP h_payto; + struct TALER_Amount new_threshold; + enum TALER_AmlDecisionState new_status; + struct GNUNET_TIME_Timestamp decision_time; + char *justification; + char *kyc_requirements; /* NULL allowed! */ + uint64_t kyc_req_row; + struct TALER_AmlOfficerPublicKeyP decider_pub; + struct TALER_AmlOfficerSignatureP decider_sig; + } aml_history; + + struct + { + struct TALER_PaytoHashP h_payto; + struct GNUNET_ShortHashCode kyc_prox; + char *provider; + char *birthdate; /* NULL allowed! */ + struct GNUNET_TIME_Timestamp collection_time; + struct GNUNET_TIME_Timestamp expiration_time; + void *encrypted_attributes; + size_t encrypted_attributes_size; + } kyc_attributes; + + struct + { + struct TALER_PurseContractPublicKeyP purse_pub; + struct TALER_PurseContractSignatureP purse_sig; + } purse_deletion; + + struct + { + struct TALER_AgeWithdrawCommitmentHashP h_commitment; + struct TALER_Amount amount_with_fee; + uint16_t max_age; + struct TALER_ReservePublicKeyP reserve_pub; + struct TALER_ReserveSignatureP reserve_sig; + uint32_t noreveal_index; + struct GNUNET_TIME_Absolute timestamp; + } withdraw_age_commitments; + + struct + { + struct TALER_AgeWithdrawCommitmentHashP h_commitment; + uint32_t freshcoin_index; + uint64_t denominations_serial; + void *coin_ev; + size_t coin_ev_size; + struct TALER_ExchangeWithdrawValues ewv; + // h_coin_ev omitted, to be recomputed! + struct TALER_BlindedDenominationSignature ev_sig; + } withdraw_age_revealed_coins; + } details; }; @@ -1066,7 +1180,7 @@ struct TALER_EXCHANGEDB_AgeWithdrawCommitment /** * Maximum age that the coins are restricted to. */ - uint32_t max_age; + uint16_t max_age; /** * The hash of the commitment of all n*kappa coins @@ -1095,11 +1209,6 @@ struct TALER_EXCHANGEDB_AgeWithdrawCommitment * The exchange's signature of the response. */ struct TALER_ExchangeSignatureP sig; - - /** - * Timestamp of the request being made - */ - struct GNUNET_TIME_Timestamp timestamp; }; @@ -3683,7 +3792,6 @@ struct TALER_EXCHANGEDB_Plugin * * @param cls the `struct PostgresClosure` with the plugin-specific state * @param commitment corresponding commitment for the age-withdraw - * @param now current time (rounded) * @param[out] found set to true if the reserve was found * @param[out] balance_ok set to true if the balance was sufficient * @param[out] ruuid set to the reserve's UUID (reserves table row) @@ -3693,7 +3801,6 @@ struct TALER_EXCHANGEDB_Plugin (*do_age_withdraw)( void *cls, const struct TALER_EXCHANGEDB_AgeWithdrawCommitment *commitment, - struct GNUNET_TIME_Timestamp now, bool *found, bool *balance_ok, uint64_t *ruuid); @@ -4059,6 +4166,25 @@ struct TALER_EXCHANGEDB_Plugin struct TALER_AgeCommitmentHash *age_hash); + /** + * 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 + (*batch_ensure_coin_known)( + void *cls, + const struct TALER_CoinPublicInfo *coin, + struct TALER_EXCHANGEDB_CoinInfo *result, + unsigned int coin_length, + unsigned int batch_size); + + /** * Retrieve information about the given @a coin from the database. * @@ -5688,6 +5814,7 @@ struct TALER_EXCHANGEDB_Plugin * Insert record set into @a table. Used in exchange-auditor database * replication. * + memset (&awc, 0, sizeof (awc)); * @param cls closure * @param tb table data to insert * @return transaction status code, #GNUNET_DB_STATUS_HARD_ERROR if @@ -6428,6 +6555,7 @@ struct TALER_EXCHANGEDB_Plugin * @param cls closure * @param legi_row identifies requirement to look up * @param[out] requirements space-separated list of requirements + * @param[out] aml_status set to the AML status of the account * @param[out] h_payto account that must be KYC'ed * @return database transaction status */ @@ -6436,6 +6564,7 @@ struct TALER_EXCHANGEDB_Plugin void *cls, uint64_t requirement_row, char **requirements, + enum TALER_AmlDecisionState *aml_status, struct TALER_PaytoHashP *h_payto); diff --git a/src/kyclogic/plugin_kyclogic_oauth2.c b/src/kyclogic/plugin_kyclogic_oauth2.c index d4aaf4494..228525e28 100644 --- a/src/kyclogic/plugin_kyclogic_oauth2.c +++ b/src/kyclogic/plugin_kyclogic_oauth2.c @@ -514,6 +514,11 @@ initiate_task (void *cls) pd->client_id, redirect_uri_encoded); GNUNET_free (redirect_uri_encoded); + /* FIXME-API: why do we *redirect* the client here, + instead of making the HTTP request *ourselves* + and forwarding the response? This prevents us + from using authentication on initiation, + (which is desirable for challenger!) */ ih->cb (ih->cb_cls, TALER_EC_NONE, url, diff --git a/src/lib/auditor_api_deposit_confirmation.c b/src/lib/auditor_api_deposit_confirmation.c index afbeda75a..55a05d962 100644 --- a/src/lib/auditor_api_deposit_confirmation.c +++ b/src/lib/auditor_api_deposit_confirmation.c @@ -362,10 +362,16 @@ TALER_AUDITOR_deposit_confirmation ( dh->ctx.headers, &handle_deposit_confirmation_finished, dh); - /* Disable 100 continue processing */ - GNUNET_CURL_extend_headers (dh->job, - curl_slist_append (NULL, - "Expect:")); + { + /* Disable 100 continue processing */ + struct curl_slist *x_headers; + + x_headers = curl_slist_append (NULL, + "Expect:"); + GNUNET_CURL_extend_headers (dh->job, + x_headers); + curl_slist_free_all (x_headers); + } return dh; } diff --git a/src/lib/exchange_api_kyc_check.c b/src/lib/exchange_api_kyc_check.c index 68a40a962..2f03730a8 100644 --- a/src/lib/exchange_api_kyc_check.c +++ b/src/lib/exchange_api_kyc_check.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2021 Taler Systems SA + Copyright (C) 2021-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 @@ -97,6 +97,7 @@ handle_kyc_check_finished (void *cls, case MHD_HTTP_OK: { json_t *kyc_details; + uint32_t status; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("exchange_sig", &ks.details.success.exchange_sig), @@ -106,6 +107,8 @@ handle_kyc_check_finished (void *cls, &ks.details.success.timestamp), GNUNET_JSON_spec_json ("kyc_details", &kyc_details), + GNUNET_JSON_spec_uint32 ("aml_status", + &status), GNUNET_JSON_spec_end () }; const struct TALER_EXCHANGE_Keys *key_state; @@ -121,6 +124,8 @@ handle_kyc_check_finished (void *cls, break; } ks.details.success.kyc_details = kyc_details; + ks.details.success.aml_status + = (enum TALER_AmlDecisionState) status; key_state = TALER_EXCHANGE_get_keys (kch->exchange); if (GNUNET_OK != TALER_EXCHANGE_test_signing_key (key_state, @@ -155,9 +160,12 @@ handle_kyc_check_finished (void *cls, } case MHD_HTTP_ACCEPTED: { + uint32_t status; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_string ("kyc_url", &ks.details.accepted.kyc_url), + GNUNET_JSON_spec_uint32 ("aml_status", + &status), GNUNET_JSON_spec_end () }; @@ -171,6 +179,8 @@ handle_kyc_check_finished (void *cls, ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; } + ks.details.accepted.aml_status + = (enum TALER_AmlDecisionState) status; kch->cb (kch->cb_cls, &ks); GNUNET_JSON_parse_free (spec); @@ -190,6 +200,33 @@ handle_kyc_check_finished (void *cls, case MHD_HTTP_NOT_FOUND: ks.ec = TALER_JSON_get_error_code (j); break; + case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + { + uint32_t status; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint32 ("aml_status", + &status), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (j, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + ks.http_status = 0; + ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + } + ks.details.unavailable_for_legal_reasons.aml_status + = (enum TALER_AmlDecisionState) status; + kch->cb (kch->cb_cls, + &ks); + GNUNET_JSON_parse_free (spec); + TALER_EXCHANGE_kyc_check_cancel (kch); + return; + } case MHD_HTTP_INTERNAL_SERVER_ERROR: ks.ec = TALER_JSON_get_error_code (j); /* Server had an internal issue; we should retry, but this API diff --git a/src/lib/exchange_api_wire.c b/src/lib/exchange_api_wire.c index 995a0933c..c23ea62d8 100644 --- a/src/lib/exchange_api_wire.c +++ b/src/lib/exchange_api_wire.c @@ -111,11 +111,13 @@ free_fees (struct FeeMap *fm) /** * Parse wire @a fees and return map. * + * @param master_pub master public key to use to check signatures * @param fees json AggregateTransferFee to parse * @return NULL on error */ static struct FeeMap * -parse_fees (json_t *fees) +parse_fees (const struct TALER_MasterPublicKeyP *master_pub, + json_t *fees) { struct FeeMap *fm = NULL; const char *key; @@ -164,6 +166,19 @@ parse_fees (json_t *fees) free_fees (fm); return NULL; } + if (GNUNET_OK != + TALER_exchange_offline_wire_fee_verify ( + key, + wa->start_date, + wa->end_date, + &wa->fees, + master_pub, + &wa->master_sig)) + { + GNUNET_break_op (0); + free_fees (fm); + return NULL; + } if (idx + 1 < len) wa->next = &fe->fee_list[idx + 1]; else @@ -227,8 +242,10 @@ handle_wire_finished (void *cls, json_t *fees; unsigned int num_accounts; struct FeeMap *fm; - const struct TALER_EXCHANGE_Keys *key_state; + struct TALER_MasterPublicKeyP master_pub; struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("master_public_key", + &master_pub), GNUNET_JSON_spec_json ("accounts", &accounts), GNUNET_JSON_spec_json ("fees", @@ -249,6 +266,21 @@ handle_wire_finished (void *cls, hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } + { + const struct TALER_EXCHANGE_Keys *key_state; + + key_state = TALER_EXCHANGE_get_keys (wh->exchange); + if (0 != GNUNET_memcmp (&key_state->master_pub, + &master_pub)) + { + /* bogus reply: master public key in /wire differs from that in /keys */ + GNUNET_break_op (0); + hr.http_status = 0; + hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } + } + if (0 == (num_accounts = json_array_size (accounts))) { /* bogus reply */ @@ -258,7 +290,8 @@ handle_wire_finished (void *cls, hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - if (NULL == (fm = parse_fees (fees))) + if (NULL == (fm = parse_fees (&master_pub, + fees))) { /* bogus reply */ GNUNET_break_op (0); @@ -268,7 +301,6 @@ handle_wire_finished (void *cls, break; } - key_state = TALER_EXCHANGE_get_keys (wh->exchange); /* parse accounts */ { struct TALER_EXCHANGE_WireAccount was[num_accounts]; @@ -290,7 +322,7 @@ handle_wire_finished (void *cls, i); if (GNUNET_OK != TALER_JSON_exchange_wire_signature_check (account, - &key_state->master_pub)) + &master_pub)) { /* bogus reply */ GNUNET_break_op (0); diff --git a/src/mhd/mhd_legal.c b/src/mhd/mhd_legal.c index 25435210e..2c4127117 100644 --- a/src/mhd/mhd_legal.c +++ b/src/mhd/mhd_legal.c @@ -232,7 +232,7 @@ TALER_MHD_reply_legal (struct MHD_Connection *conn, MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT); if (NULL == mime) - mime = "text/html"; + mime = "text/plain"; lang = MHD_lookup_connection_value (conn, MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT_LANGUAGE); @@ -257,7 +257,7 @@ TALER_MHD_reply_legal (struct MHD_Connection *conn, char *tmp = langs; GNUNET_asprintf (&langs, - "%s %s", + "%s,%s", tmp, p->language); GNUNET_free (tmp); @@ -327,7 +327,7 @@ TALER_MHD_reply_legal (struct MHD_Connection *conn, { GNUNET_break (MHD_YES == MHD_add_response_header (resp, - "Acceptable-Languages", + "Avail-Languages", langs)); GNUNET_free (langs); } @@ -385,9 +385,9 @@ load_terms (struct TALER_MHD_Legal *legal, const char *mime; unsigned int priority; } mm[] = { + { .ext = ".txt", .mime = "text/plain", .priority = 150 }, { .ext = ".html", .mime = "text/html", .priority = 100 }, { .ext = ".htm", .mime = "text/html", .priority = 99 }, - { .ext = ".txt", .mime = "text/plain", .priority = 50 }, { .ext = ".md", .mime = "text/markdown", .priority = 50 }, { .ext = ".pdf", .mime = "application/pdf", .priority = 25 }, { .ext = ".jpg", .mime = "image/jpeg" }, diff --git a/src/testing/testing_api_cmd_exec_wirewatch.c b/src/testing/testing_api_cmd_exec_wirewatch.c index 2517bf74d..32d23a170 100644 --- a/src/testing/testing_api_cmd_exec_wirewatch.c +++ b/src/testing/testing_api_cmd_exec_wirewatch.c @@ -34,7 +34,6 @@ */ struct WirewatchState { - /** * Process for the wirewatcher. */ diff --git a/src/testing/testing_api_cmd_take_aml_decision.c b/src/testing/testing_api_cmd_take_aml_decision.c index 871cdb712..21ba9af6f 100644 --- a/src/testing/testing_api_cmd_take_aml_decision.c +++ b/src/testing/testing_api_cmd_take_aml_decision.c @@ -151,9 +151,14 @@ take_aml_decision_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_h_payto (ref, - &h_payto)); + if (GNUNET_OK != + TALER_TESTING_get_trait_h_payto (ref, + &h_payto)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } ref = TALER_TESTING_interpreter_lookup_command (is, ds->officer_ref_cmd); if (NULL == ref) @@ -162,9 +167,14 @@ take_aml_decision_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_officer_priv (ref, - &officer_priv)); + if (GNUNET_OK != + TALER_TESTING_get_trait_officer_priv (ref, + &officer_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } ds->h_payto = *h_payto; if (NULL != ds->kyc_requirement) { diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c index 986358ed3..1865a1129 100644 --- a/src/testing/testing_api_loop.c +++ b/src/testing/testing_api_loop.c @@ -353,7 +353,7 @@ maint_child_death (void *cls) while (TALER_TESTING_cmd_is_batch (cmd)) cmd = TALER_TESTING_cmd_batch_get_current (cmd); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got SIGCHLD for `%s'.\n", cmd->label); is->child_death_task = NULL; diff --git a/src/util/crypto_confirmation.c b/src/util/crypto_confirmation.c index c5a674501..e52562e3e 100644 --- a/src/util/crypto_confirmation.c +++ b/src/util/crypto_confirmation.c @@ -189,7 +189,7 @@ executive_totp (void *h_key, if (NULL == ret) { GNUNET_asprintf (&ret, - "%llu", + "%08llu", (unsigned long long) code); } else @@ -197,7 +197,7 @@ executive_totp (void *h_key, char *tmp; GNUNET_asprintf (&tmp, - "%s\n%llu", + "%s\n%08llu", ret, (unsigned long long) code); GNUNET_free (ret);