From 4a36ed7fbfcaa220d1b2605851b38fc1a386e7d3 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 2 Oct 2022 22:47:28 +0200 Subject: complete taler-exchange-httpd_reserves_open.c logic (first pass, still without DB logic or tests) --- src/include/taler_exchangedb_plugin.h | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'src/include/taler_exchangedb_plugin.h') diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 261ffb18..e6c38ad9 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4043,6 +4043,55 @@ struct TALER_EXCHANGEDB_Plugin void *rec_cls); + /** + * Insert reserve open coin deposit data into database. + * Subtracts the @a coin_total from the coin's balance. + * + * @param cls closure + * @param cpi public information about the coin + * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT + * @param known_coin_id ID of the coin in the known_coins table + * @param coin_total amount to be spent of the coin (including deposit fee) + * @param reserve_sig signature by the reserve affirming the open operation + * @param[out] insufficient_funds set to true if the coin's balance is insufficient, otherwise to false + * @return transaction status code, 0 if operation is already in the DB + */ + enum GNUNET_DB_QueryStatus + (*insert_reserve_open_deposit)( + void *cls, + const struct TALER_CoinPublicInfo *cpi, + const struct TALER_CoinSpendSignatureP *coin_sig, + uint64_t known_coin_id, + const struct TALER_Amount *coin_total, + const struct TALER_ReserveSignatureP *reserve_sig, + bool *insufficient_funds); + + + /** + * Insert reserve close operation into database. + * + * @param cls closure + * @param reserve_pub which reserve is this about? + * @param execution_date when did we perform the transfer? + * @param receiver_account to which account do we transfer, in payto://-format + * @param wtid identifier for the wire transfer + * @param amount_with_fee amount we charged to the reserve + * @param closing_fee how high is the closing fee + * @return transaction status code + */ + enum GNUNET_DB_QueryStatus + (*do_reserve_open)(void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *total_paid, + uint32_t min_purse_limit, + const struct TALER_ReserveSignatureP *reserve_sig, + struct GNUNET_TIME_Timestamp desired_expiration, + struct GNUNET_TIME_Timestamp now, + const struct TALER_Amount *open_fee, + struct TALER_Amount *open_cost, + const struct GNUNET_TIME_Timestamp *final_expiration); + + /** * Insert reserve close operation into database. * -- cgit v1.2.3 From 1ce70b1dabb390d04b3b886816e49237288b9b31 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 2 Oct 2022 23:19:48 +0200 Subject: complete taler-exchange-httpd_reserves_close.c logic (first pass, still without DB logic or tests) --- src/exchange/taler-exchange-httpd_reserves_close.c | 218 ++++++++++++++------- src/include/taler_exchangedb_plugin.h | 45 +++++ src/include/taler_kyclogic_lib.h | 7 +- src/kyclogic/kyclogic_api.c | 3 + 4 files changed, 203 insertions(+), 70 deletions(-) (limited to 'src/include/taler_exchangedb_plugin.h') diff --git a/src/exchange/taler-exchange-httpd_reserves_close.c b/src/exchange/taler-exchange-httpd_reserves_close.c index 40fba25f..6d998bb9 100644 --- a/src/exchange/taler-exchange-httpd_reserves_close.c +++ b/src/exchange/taler-exchange-httpd_reserves_close.c @@ -23,6 +23,7 @@ #include "platform.h" #include #include +#include "taler_kyclogic_lib.h" #include "taler_mhd_lib.h" #include "taler_json_lib.h" #include "taler_dbevents.h" @@ -60,14 +61,14 @@ struct ReserveCloseContext struct TALER_ReserveSignatureP reserve_sig; /** - * Wire fees applying to the request. + * Amount that will be wired (after closing fees). */ - const struct TALER_WireFeeSet *wf; + struct TALER_Amount wire_amount; /** - * Amount that will be wired (after closing fees). + * Current balance of the reserve. */ - struct TALER_Amount wire_amount; + struct TALER_Amount balance; /** * Where to wire the funds, may be NULL. @@ -75,10 +76,24 @@ struct ReserveCloseContext const char *payto_uri; /** - * Hash of the @e payto_uri. + * Hash of the @e payto_uri, if given (otherwise zero). */ struct TALER_PaytoHashP h_payto; + /** + * KYC status for the request. + */ + struct TALER_EXCHANGEDB_KycStatus kyc; + + /** + * Hash of the payto-URI that was used for the KYC decision. + */ + struct TALER_PaytoHashP kyc_payto; + + /** + * Query status from the amount_it() helper function. + */ + enum GNUNET_DB_QueryStatus qs; }; @@ -101,6 +116,46 @@ reply_reserve_close_success (struct MHD_Connection *connection, } +/** + * Function called to iterate over KYC-relevant + * transaction amounts for a particular time range. + * Called within a database transaction, so must + * not start a new one. + * + * @param cls closure, identifies the event type and + * account to iterate over events for + * @param limit maximum time-range for which events + * should be fetched (timestamp in the past) + * @param cb function to call on each event found, + * events must be returned in reverse chronological + * order + * @param cb_cls closure for @a cb + */ +static void +amount_it (void *cls, + struct GNUNET_TIME_Absolute limit, + TALER_EXCHANGEDB_KycAmountCallback cb, + void *cb_cls) +{ + struct ReserveCloseContext *rcc = cls; + enum GNUNET_GenericReturnValue ret; + + ret = cb (cb_cls, + &rcc->balance, + GNUNET_TIME_absolute_get ()); + GNUNET_break (GNUNET_SYSERR != ret); + if (GNUNET_OK != ret) + return; + rcc->qs + = TEH_plugin->iterate_reserve_close_info ( + TEH_plugin->cls, + &rcc->kyc_payto, + limit, + cb, + cb_cls); +} + + /** * Function implementing /reserves/$RID/close transaction. Given the public * key of a reserve, return the associated transaction close. Runs the @@ -124,17 +179,14 @@ reserve_close_transaction (void *cls, struct ReserveCloseContext *rcc = cls; enum GNUNET_DB_QueryStatus qs; struct TALER_Amount balance; - char *payto_uri; - -#if FIXME - qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls, - rcc->reserve_pub, - &balance, - &payto_uri); -#else - qs = GNUNET_DB_STATUS_HARD_ERROR; - payto_uri = NULL; -#endif + char *payto_uri = NULL; + const struct TALER_WireFeeSet *wf; + + qs = TEH_plugin->select_reserve_close_info ( + TEH_plugin->cls, + rcc->reserve_pub, + &balance, + &payto_uri); switch (qs) { case GNUNET_DB_STATUS_HARD_ERROR: @@ -143,7 +195,7 @@ reserve_close_transaction (void *cls, = TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_reserve_balance"); + "select_reserve_close_info"); return qs; case GNUNET_DB_STATUS_SOFT_ERROR: return qs; @@ -174,27 +226,66 @@ reserve_close_transaction (void *cls, (0 != strcmp (payto_uri, rcc->payto_uri)) ) ) { - struct TALER_EXCHANGEDB_KycStatus kyc; - struct TALER_PaytoHashP kyc_payto; - - /* FIXME: also fetch KYC status from reserve - in query above, and if payto_uri specified - and KYC not yet done (check KYC triggers!), - fail with 451 kyc required! */ - *mhd_ret - = TEH_RESPONSE_reply_kyc_required (connection, - &kyc_payto, - &kyc); - return GNUNET_DB_STATUS_HARD_ERROR; + const char *kyc_needed; + + TALER_payto_hash (rcc->payto_uri, + &rcc->kyc_payto); + rcc->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; + kyc_needed + = TALER_KYCLOGIC_kyc_test_required ( + TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE, + &rcc->kyc_payto, + TEH_plugin->select_satisfied_kyc_processes, + TEH_plugin->cls, + &amount_it, + rcc); + if (rcc->qs < 0) + { + if (GNUNET_DB_STATUS_SOFT_ERROR == rcc->qs) + return rcc->qs; + GNUNET_break (0); + *mhd_ret + = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "iterate_reserve_close_info"); + return qs; + } + rcc->kyc.ok = false; + return TEH_plugin->insert_kyc_requirement_for_account ( + TEH_plugin->cls, + kyc_needed, + &rcc->kyc_payto, + &rcc->kyc.requirement_row); } + rcc->kyc.ok = true; if (NULL == rcc->payto_uri) rcc->payto_uri = payto_uri; + { + char *method; + + method = TALER_payto_get_method (rcc->payto_uri); + wf = TEH_wire_fees_by_time (rcc->timestamp, + method); + if (NULL == wf) + { + GNUNET_break (0); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_WIRE_FEES_NOT_CONFIGURED, + method); + GNUNET_free (method); + return GNUNET_DB_STATUS_HARD_ERROR; + } + GNUNET_free (method); + } + if (0 > TALER_amount_subtract (&rcc->wire_amount, &balance, - &rcc->wf->closing)) + &wf->closing)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client attempted to close reserve with insufficient balance.\n"); @@ -206,34 +297,29 @@ reserve_close_transaction (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; } + + qs = TEH_plugin->insert_close_request (TEH_plugin->cls, + rcc->reserve_pub, + payto_uri, + &rcc->reserve_sig, + rcc->timestamp, + &wf->closing, + &rcc->wire_amount); + GNUNET_free (payto_uri); + if (GNUNET_DB_STATUS_HARD_ERROR == qs) { -#if FIXME - qs = TEH_plugin->insert_close_request (TEH_plugin->cls, - rcc->reserve_pub, - payto_uri, - &rcc->reserve_sig, - rcc->timestamp, - &rcc->wf->closing, - &rcc->wire_amount); -#else - qs = GNUNET_DB_STATUS_HARD_ERROR; -#endif - GNUNET_free (payto_uri); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - GNUNET_break (0); - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "insert_close_request"); - return qs; - } - if (qs <= 0) - { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - return qs; - } + GNUNET_break (0); + *mhd_ret + = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "insert_close_request"); + return qs; + } + if (qs <= 0) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + return qs; } return qs; } @@ -295,18 +381,6 @@ TEH_handler_reserves_close (struct TEH_RequestContext *rc, } } - // FIXME: can only do this later, as we may get the payto://-URI - // with the method from the database! - rcc.wf = TEH_wire_fees_by_time (rcc.timestamp, - "FIXME-method"); - if (NULL == rcc.wf) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_EXCHANGE_WIRE_FEES_NOT_CONFIGURED, - "FIXME-method"); - } if (NULL != rcc.payto_uri) TALER_payto_hash (rcc.payto_uri, &rcc.h_payto); @@ -322,6 +396,7 @@ TEH_handler_reserves_close (struct TEH_RequestContext *rc, TALER_EC_EXCHANGE_RESERVES_CLOSE_BAD_SIGNATURE, NULL); } + if (GNUNET_OK != TEH_DB_run_transaction (rc->connection, "reserve close", @@ -332,6 +407,11 @@ TEH_handler_reserves_close (struct TEH_RequestContext *rc, { return mhd_ret; } + if (! rcc.kyc.ok) + return TEH_RESPONSE_reply_kyc_required (rc->connection, + &rcc.kyc_payto, + &rcc.kyc); + return reply_reserve_close_success (rc->connection, &rcc); } diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index e6c38ad9..609265f1 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4092,6 +4092,47 @@ struct TALER_EXCHANGEDB_Plugin const struct GNUNET_TIME_Timestamp *final_expiration); + /** + * Select information needed to see if we can close + * a reserve. + * + * @param cls closure + * @param reserve_pub which reserve is this about? + * @param[out] balance current reserve balance + * @param[out] payto_uri set to URL of account that + * originally funded the reserve; + * could be set to NULL if not known + * @return transaction status code, 0 if reserve unknown + */ + enum GNUNET_DB_QueryStatus + (*select_reserve_close_info)( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + struct TALER_Amount *balance, + char **payto_uri); + + + /** + * Select information needed for KYC checks on reserve close: historic + * reserve closures going to the same account. + * + * @param cls closure + * @param h_payto which target account is this about? + * @param h_payto account identifier + * @param time_limit oldest transaction that could be relevant + * @param kac function to call for each applicable amount, in reverse chronological order (or until @a kac aborts by returning anything except #GNUNET_OK). + * @param kac_cls closure for @a kac + * @return transaction status code, @a kac aborting with #GNUNET_NO is not an error + */ + enum GNUNET_DB_QueryStatus + (*iterate_reserve_close_info)( + void *cls, + const struct TALER_PaytoHashP *h_payto, + struct GNUNET_TIME_Absolute time_limit, + TALER_EXCHANGEDB_KycAmountCallback kac, + void *kac_cls); + + /** * Insert reserve close operation into database. * @@ -5537,16 +5578,20 @@ struct TALER_EXCHANGEDB_Plugin * * @param cls the @e cls of this struct with the plugin-specific state * @param reserve_pub public key of the account to close + * @param payto_uri where to wire the funds * @param reserve_sig signature affiming that the account is to be closed * @param request_timestamp timestamp of the close request + * @param closing_fee closing fee to charge * @param[out] final_balance set to the final balance in the account that will be wired back to the origin account * @return transaction status code */ enum GNUNET_DB_QueryStatus (*insert_close_request)(void *cls, const struct TALER_ReservePublicKeyP *reserve_pub, + const char *payto_uri, const struct TALER_ReserveSignatureP *reserve_sig, struct GNUNET_TIME_Timestamp request_timestamp, + const struct TALER_Amount *closing_fee, struct TALER_Amount *final_balance); diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h index 494f7787..2ff652f9 100644 --- a/src/include/taler_kyclogic_lib.h +++ b/src/include/taler_kyclogic_lib.h @@ -68,7 +68,12 @@ enum TALER_KYCLOGIC_KycTriggerEvent /** * Wallet balance exceeds threshold. */ - TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE = 3 + TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE = 3, + + /** + * Reserve is being closed by force. + */ + TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE = 4 }; diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c index 96bf16aa..b04c2419 100644 --- a/src/kyclogic/kyclogic_api.c +++ b/src/kyclogic/kyclogic_api.c @@ -183,6 +183,7 @@ TALER_KYCLOGIC_kyc_trigger_from_string (const char *trigger_s, { "deposit", TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT }, { "merge", TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE }, { "balance", TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE }, + { "close", TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE }, { NULL, 0 } }; @@ -213,6 +214,8 @@ TALER_KYCLOGIC_kyc_trigger2s (enum TALER_KYCLOGIC_KycTriggerEvent trigger) return "merge"; case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE: return "balance"; + case TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE: + return "close"; } GNUNET_break (0); return NULL; -- cgit v1.2.3 From 3bca75d6cfb4c28e9800198d606ae030930e126b Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 2 Oct 2022 23:57:09 +0200 Subject: complete taler-exchange-httpd_reserves_get_attest.c logic (first pass, still without DB logic or tests) --- .../taler-exchange-httpd_reserves_get_attest.c | 119 ++++++++++++++++++--- src/include/taler_exchangedb_plugin.h | 37 +++++++ src/include/taler_kyclogic_lib.h | 21 ++++ src/kyclogic/kyclogic_api.c | 14 +++ 4 files changed, 178 insertions(+), 13 deletions(-) (limited to 'src/include/taler_exchangedb_plugin.h') diff --git a/src/exchange/taler-exchange-httpd_reserves_get_attest.c b/src/exchange/taler-exchange-httpd_reserves_get_attest.c index 8fd346c2..bd574acd 100644 --- a/src/exchange/taler-exchange-httpd_reserves_get_attest.c +++ b/src/exchange/taler-exchange-httpd_reserves_get_attest.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA + Copyright (C) 2022 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 @@ -21,6 +21,7 @@ #include "platform.h" #include #include +#include "taler_kyclogic_lib.h" #include "taler_mhd_lib.h" #include "taler_json_lib.h" #include "taler_dbevents.h" @@ -39,11 +40,21 @@ struct ReserveAttestContext */ struct TALER_ReservePublicKeyP reserve_pub; + /** + * Hash of the payto URI of this reserve. + */ + struct TALER_PaytoHashP h_payto; + /** * Available attributes. */ json_t *attributes; + /** + * Error code encountered in interaction with KYC provider. + */ + enum TALER_ErrorCode ec; + /** * Set to true if we did not find the reserve. */ @@ -51,6 +62,62 @@ struct ReserveAttestContext }; +/** + * Function called with information about all applicable + * legitimization processes for the given user. + * + * @param cls our `struct ReserveAttestContext *` + * @param provider_section KYC provider configuration section + * @param provider_user_id UID at a provider (can be NULL) + * @param legi_id legitimization process ID (can be NULL) + */ +static void +kyc_process_cb (void *cls, + const char *provider_section, + const char *provider_user_id, + const char *legi_id) +{ + struct ReserveAttestContext *rsc = cls; + struct GNUNET_TIME_Timestamp etime; + json_t *attrs; + + rsc->ec = TALER_KYCLOGIC_user_to_attributes (provider_section, + provider_user_id, + legi_id, + &etime, + &attrs); + if (TALER_EC_NONE != rsc->ec) + return; + + { + json_t *val; + const char *name; + + json_object_foreach (attrs, name, val) + { + bool duplicate = false; + size_t idx; + json_t *str; + + json_array_foreach (rsc->attributes, idx, str) + { + if (0 == strcmp (json_string_value (str), + name)) + { + duplicate = true; + break; + } + } + if (duplicate) + continue; + GNUNET_assert (0 == + json_array_append (rsc->attributes, + json_string (name))); + } + } +} + + /** * Function implementing GET /reserves/$RID/attest transaction. * Execute a /reserves/ get attest. Given the public key of a reserve, @@ -75,26 +142,32 @@ reserve_attest_transaction (void *cls, struct ReserveAttestContext *rsc = cls; enum GNUNET_DB_QueryStatus qs; -#if FIXME - qs = TEH_plugin->get_reserve_attributes (TEH_plugin->cls, - &rsc->reserve_pub, - &rsc->attributes); -#else - qs = GNUNET_DB_STATUS_HARD_ERROR; -#endif - if (GNUNET_DB_STATUS_HARD_ERROR == qs) + rsc->attributes = json_array (); + GNUNET_assert (NULL != rsc->attributes); + qs = TEH_plugin->iterate_kyc_reference (TEH_plugin->cls, + &rsc->h_payto, + &kyc_process_cb, + rsc); + switch (qs) { + case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_break (0); *mhd_ret = TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_FETCH_FAILED, "get_reserve_attributes"); - } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + return qs; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return qs; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: rsc->not_found = true; - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) + return qs; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: rsc->not_found = false; + break; + } return qs; } @@ -103,7 +176,9 @@ MHD_RESULT TEH_handler_reserves_get_attest (struct TEH_RequestContext *rc, const char *const args[1]) { - struct ReserveAttestContext rsc; + struct ReserveAttestContext rsc = { + .attributes = NULL + }; if (GNUNET_OK != GNUNET_STRINGS_string_to_data (args[0], @@ -117,6 +192,15 @@ TEH_handler_reserves_get_attest (struct TEH_RequestContext *rc, TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, args[0]); } + { + char *payto_uri; + + payto_uri = TALER_reserve_make_payto (TEH_base_url, + &rsc.reserve_pub); + TALER_payto_hash (payto_uri, + &rsc.h_payto); + GNUNET_free (payto_uri); + } { MHD_RESULT mhd_ret; @@ -128,17 +212,26 @@ TEH_handler_reserves_get_attest (struct TEH_RequestContext *rc, &reserve_attest_transaction, &rsc)) { + json_decref (rsc.attributes); return mhd_ret; } } /* generate proper response */ if (rsc.not_found) { + json_decref (rsc.attributes); return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_NOT_FOUND, TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN, args[0]); } + if (TALER_EC_NONE != rsc.ec) + { + json_decref (rsc.attributes); + return TALER_MHD_reply_with_ec (rc->connection, + rsc.ec, + NULL); + } return TALER_MHD_REPLY_JSON_PACK ( rc->connection, MHD_HTTP_OK, diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 609265f1..e5cc8dfa 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -877,6 +877,25 @@ typedef void const char *kyc_provider_section_name); +/** + * Function called on all legitimization operations + * we have performed for the given account so far + * (and that have not yet expired). + * + * @param cls closure + * @param kyc_provider_section_name configuration section + * of the respective KYC process + * @param provider_user_id UID at a provider (can be NULL) + * @param legi_id legitimization process ID (can be NULL) + */ +typedef void +(*TALER_EXCHANGEDB_LegitimizationProcessCallback)( + void *cls, + const char *kyc_provider_section_name, + const char *provider_user_id, + const char *legi_id); + + /** * Function called with information about the exchange's auditors. * @@ -5819,6 +5838,24 @@ struct TALER_EXCHANGEDB_Plugin void *spc_cls); + /** + * Call us on KYC legitimization processes satisfied and not expired for the + * given account. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param h_payto account identifier + * @param lpc function to call for each satisfied KYC legitimization process + * @param lpc_cls closure for @a lpc + * @return transaction status code + */ + enum GNUNET_DB_QueryStatus + (*iterate_kyc_reference)( + void *cls, + const struct TALER_PaytoHashP *h_payto, + TALER_EXCHANGEDB_LegitimizationProcessCallback lpc, + void *lpc_cls); + + /** * Call @a kac on withdrawn amounts after @a time_limit which are relevant * for a KYC trigger for a the (debited) account identified by @a h_payto. diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h index 2ff652f9..7f4bf5b5 100644 --- a/src/include/taler_kyclogic_lib.h +++ b/src/include/taler_kyclogic_lib.h @@ -306,6 +306,27 @@ TALER_KYCLOGIC_requirements_to_logic (const char *requirements, const char **configuration_section); +/** + * Obtain attributes we collected about a user from a + * provider. + * + * @param provider_section configuration section of a + * provider that triggered KYC process for a user + * @param provider_user user ID of the user at the provider + * @param legitimization_id legitimizatin ID of a process + * of that user at the provider + * @param[out] attr_expiration set to when the @a attrs expire + * @param[out] attrs attributes we have about the user + * @return error code, #TALER_EC_NONE on success + */ +enum TALER_ErrorCode +TALER_KYCLOGIC_user_to_attributes (const char *provider_section, + const char *provider_user_id, + const char *legitimization_id, + struct GNUNET_TIME_Timestamp *attr_expiration, + json_t **attrs); + + /** * Obtain the provider logic for a given @a name. * diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c index b04c2419..0c4a5112 100644 --- a/src/kyclogic/kyclogic_api.c +++ b/src/kyclogic/kyclogic_api.c @@ -1311,4 +1311,18 @@ TALER_KYCLOGIC_kyc_iterate_thresholds ( } +enum TALER_ErrorCode +TALER_KYCLOGIC_user_to_attributes (const char *provider_section, + const char *provider_user_id, + const char *legitimization_id, + struct GNUNET_TIME_Timestamp *attr_expiration, + json_t **attrs) +{ + GNUNET_break (0); // FIXME: not yet implemented!!! + *attrs = json_object (); + *attr_expiration = GNUNET_TIME_UNIT_ZERO_TS; + return TALER_EC_NONE; +} + + /* end of taler-exchange-httpd_kyc.c */ -- cgit v1.2.3 From 4a487b179c013886721c4aa06af9c75e9aad508c Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 3 Oct 2022 19:34:11 +0200 Subject: -implement sketch for pg_do_reserve_open.c --- contrib/gana | 2 +- src/exchangedb/Makefile.am | 3 ++- src/exchangedb/pg_do_reserve_open.c | 31 ++++++++++++++++----------- src/exchangedb/pg_do_reserve_open.h | 2 +- src/exchangedb/pg_select_reserve_close_info.c | 2 +- src/include/taler_exchangedb_plugin.h | 2 +- 6 files changed, 24 insertions(+), 18 deletions(-) (limited to 'src/include/taler_exchangedb_plugin.h') diff --git a/contrib/gana b/contrib/gana index d402af78..57d96e8e 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit d402af78f6d360841db53baa46dddae13590ec33 +Subproject commit 57d96e8e123df90c804a821874fc6cb88671ab75 diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index e446682b..1fc89d1b 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -69,11 +69,12 @@ endif libtaler_plugin_exchangedb_postgres_la_SOURCES = \ plugin_exchangedb_postgres.c pg_helper.h \ + pg_do_reserve_open.c pg_do_reserve_open.h \ pg_insert_close_request.c pg_insert_close_request.h \ pg_insert_reserve_open_deposit.c pg_insert_reserve_open_deposit.h \ pg_iterate_kyc_reference.c pg_iterate_kyc_reference.h \ pg_iterate_reserve_close_info.c pg_iterate_reserve_close_info.h \ - pg_select_reserve_close_info.c pg_select_reserve_close_info.h + pg_select_reserve_close_info.c pg_select_reserve_close_info.h libtaler_plugin_exchangedb_postgres_la_LIBADD = \ $(LTLIBINTL) libtaler_plugin_exchangedb_postgres_la_LDFLAGS = \ diff --git a/src/exchangedb/pg_do_reserve_open.c b/src/exchangedb/pg_do_reserve_open.c index e4f72845..bd4f7240 100644 --- a/src/exchangedb/pg_do_reserve_open.c +++ b/src/exchangedb/pg_do_reserve_open.c @@ -37,32 +37,37 @@ TEH_PG_do_reserve_open ( struct GNUNET_TIME_Timestamp now, const struct TALER_Amount *open_fee, struct TALER_Amount *open_cost, - const struct GNUNET_TIME_Timestamp *final_expiration) + struct GNUNET_TIME_Timestamp *final_expiration) { struct PostgresClosure *pg = cls; - // FIXME: everything from here is cut&paste struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&cpi->coin_pub), - GNUNET_PQ_query_param_uint64 (&known_coin_id), - GNUNET_PQ_query_param_auto_from_type (coin_sig), + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + TALER_PQ_query_param_amount (total_paid), + GNUNET_PQ_query_param_uint32 (&min_purse_limit), GNUNET_PQ_query_param_auto_from_type (reserve_sig), - TALER_PQ_query_param_amount (coin_total), + GNUNET_PQ_query_param_timestamp (&desired_expiration), + GNUNET_PQ_query_param_timestamp (&now), + TALER_PQ_query_param_amount (open_fee), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("insufficient_funds", - insufficient_funds), + TALER_PQ_RESULT_SPEC_AMOUNT ("open_cost", + open_cost), + GNUNET_PQ_result_spec_timestamp ("final_expiration", + final_expiration), GNUNET_PQ_result_spec_end }; PREPARE (pg, - "insert_reserve_open_deposit", + "do_reserve_open", "SELECT " - " insufficient_funds" - " FROM exchange_do_reserve_open_deposit" - " ($1,$2,$3,$4,$5,$6);"); + " open_cost_val" + ",open_cost_frac" + ",final_expiration" + " FROM exchange_do_reserve_open" + " ($1,$2,$3,$4,$5,$6,$7,$8,$9);"); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "insert_reserve_open_deposit", + "do_reserve_open", params, rs); } diff --git a/src/exchangedb/pg_do_reserve_open.h b/src/exchangedb/pg_do_reserve_open.h index 6e4c91fc..aeef59eb 100644 --- a/src/exchangedb/pg_do_reserve_open.h +++ b/src/exchangedb/pg_do_reserve_open.h @@ -49,7 +49,7 @@ TEH_PG_do_reserve_open ( struct GNUNET_TIME_Timestamp now, const struct TALER_Amount *open_fee, struct TALER_Amount *open_cost, - const struct GNUNET_TIME_Timestamp *final_expiration); + struct GNUNET_TIME_Timestamp *final_expiration); #endif diff --git a/src/exchangedb/pg_select_reserve_close_info.c b/src/exchangedb/pg_select_reserve_close_info.c index a573f100..53ea4568 100644 --- a/src/exchangedb/pg_select_reserve_close_info.c +++ b/src/exchangedb/pg_select_reserve_close_info.c @@ -22,7 +22,7 @@ #include "taler_error_codes.h" #include "taler_dbevents.h" #include "taler_pq_lib.h" -#include "pg_insert_reserve_open_deposit.h" +#include "pg_select_reserve_close_info.h" #include "pg_helper.h" diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index e5cc8dfa..bde3c813 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4108,7 +4108,7 @@ struct TALER_EXCHANGEDB_Plugin struct GNUNET_TIME_Timestamp now, const struct TALER_Amount *open_fee, struct TALER_Amount *open_cost, - const struct GNUNET_TIME_Timestamp *final_expiration); + struct GNUNET_TIME_Timestamp *final_expiration); /** -- cgit v1.2.3 From 856b8e26c2b83ebce31eb35c9fc9f23641187be9 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 3 Oct 2022 23:54:12 +0200 Subject: -more work on new DB logic --- src/exchange/taler-exchange-httpd_reserves_close.c | 5 +- src/exchange/taler-exchange-httpd_reserves_open.c | 1 + src/exchangedb/common-0001.sql | 8 +- src/exchangedb/pg_insert_close_request.c | 39 +++---- src/exchangedb/pg_insert_close_request.h | 6 +- src/exchangedb/pg_insert_reserve_open_deposit.c | 8 +- src/exchangedb/pg_insert_reserve_open_deposit.h | 2 + src/exchangedb/pg_iterate_kyc_reference.c | 10 +- src/exchangedb/pg_iterate_reserve_close_info.c | 23 ++-- src/exchangedb/pg_select_reserve_close_info.c | 8 +- src/exchangedb/plugin_exchangedb_postgres.c | 15 ++- src/exchangedb/procedures.sql | 117 ++++++++++++--------- src/include/taler_exchangedb_plugin.h | 8 +- 13 files changed, 147 insertions(+), 103 deletions(-) (limited to 'src/include/taler_exchangedb_plugin.h') diff --git a/src/exchange/taler-exchange-httpd_reserves_close.c b/src/exchange/taler-exchange-httpd_reserves_close.c index 6d998bb9..be36f1e7 100644 --- a/src/exchange/taler-exchange-httpd_reserves_close.c +++ b/src/exchange/taler-exchange-httpd_reserves_close.c @@ -297,14 +297,13 @@ reserve_close_transaction (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; } - qs = TEH_plugin->insert_close_request (TEH_plugin->cls, rcc->reserve_pub, payto_uri, &rcc->reserve_sig, rcc->timestamp, - &wf->closing, - &rcc->wire_amount); + &balance, + &wf->closing); GNUNET_free (payto_uri); if (GNUNET_DB_STATUS_HARD_ERROR == qs) { diff --git a/src/exchange/taler-exchange-httpd_reserves_open.c b/src/exchange/taler-exchange-httpd_reserves_open.c index c9f5e401..d446d9b4 100644 --- a/src/exchange/taler-exchange-httpd_reserves_open.c +++ b/src/exchange/taler-exchange-httpd_reserves_open.c @@ -191,6 +191,7 @@ reserve_open_transaction (void *cls, coin->known_coin_id, &coin->amount, &rsc->reserve_sig, + rsc->reserve_pub, &insufficient_funds); /* 0 == qs is fine, then the coin was already spent for this very operation as identified diff --git a/src/exchangedb/common-0001.sql b/src/exchangedb/common-0001.sql index 4a0aac38..564bf3b3 100644 --- a/src/exchangedb/common-0001.sql +++ b/src/exchangedb/common-0001.sql @@ -459,7 +459,8 @@ BEGIN PERFORM create_partitioned_table( 'CREATE TABLE IF NOT EXISTS %I' '(reserve_open_deposit_uuid BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE / PRIMARY KEY' - ',reserve_pub BYTEA NOT NULL' -- REFERENCES reserves (reserve_pub) ON DELETE CASCADE' + ',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)' + ',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=32)' ',request_timestamp INT8 NOT NULL' ',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)' ',coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)' @@ -496,7 +497,7 @@ BEGIN EXECUTE FORMAT ( 'ALTER TABLE reserves_open_deposits_' || partition_suffix || ' ' 'ADD CONSTRAINT reserves_open_deposits_' || partition_suffix || '_coin_unique ' - 'PRIMARY KEY (coin_pub,reserve_pub)' + 'PRIMARY KEY (coin_pub,coin_sig)' ); END $$; @@ -1749,6 +1750,9 @@ BEGIN ',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)' ',close_val INT8 NOT NULL' ',close_frac INT4 NOT NULL' + ',close_fee_val INT8 NOT NULL' + ',close_fee_frac INT4 NOT NULL' + ',payto_uri VARCHAR NOT NULL' ',PRIMARY KEY (reserve_pub,close_timestamp)' ') %s ;' ,table_name diff --git a/src/exchangedb/pg_insert_close_request.c b/src/exchangedb/pg_insert_close_request.c index 3622149a..43ca944f 100644 --- a/src/exchangedb/pg_insert_close_request.c +++ b/src/exchangedb/pg_insert_close_request.c @@ -33,32 +33,35 @@ TEH_PG_insert_close_request ( const char *payto_uri, const struct TALER_ReserveSignatureP *reserve_sig, struct GNUNET_TIME_Timestamp request_timestamp, - const struct TALER_Amount *closing_fee, - struct TALER_Amount *final_balance) + const struct TALER_Amount *balance, + const struct TALER_Amount *closing_fee) { struct PostgresClosure *pg = cls; - // FIXME: deal with payto_uri and closing_fee!! struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (reserve_pub), GNUNET_PQ_query_param_timestamp (&request_timestamp), GNUNET_PQ_query_param_auto_from_type (reserve_sig), + TALER_PQ_query_param_amount (balance), + TALER_PQ_query_param_amount (closing_fee), + GNUNET_PQ_query_param_string (payto_uri), GNUNET_PQ_query_param_end }; - struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_RESULT_SPEC_AMOUNT ("out_final_balance", - final_balance), - GNUNET_PQ_result_spec_end - }; PREPARE (pg, - "call_account_close", - "SELECT " - " out_final_balance_val" - ",out_final_balance_frac" - " FROM exchange_do_close_request" - " ($1, $2, $3)"); - return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "call_account_close", - params, - rs); + "insert_account_close", + "INSERT INTO close_requests" + "(reserve_pub" + ",close_timestamp" + ",reserve_sig" + ",close_val" + ",close_frac," + ",close_fee_val" + ",close_fee_frac" + ",payto_uri" + ")" + "VALUES ($1, $2, $3, $4, $5, $6, $7)" + " ON CONFLICT DO NOTHING;"); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "insert_account_close", + params); } diff --git a/src/exchangedb/pg_insert_close_request.h b/src/exchangedb/pg_insert_close_request.h index 09404094..c014a10b 100644 --- a/src/exchangedb/pg_insert_close_request.h +++ b/src/exchangedb/pg_insert_close_request.h @@ -34,8 +34,8 @@ * @param payto_uri where to wire the funds * @param reserve_sig signature affiming that the account is to be closed * @param request_timestamp time of the close request (client-side?) + * @param balance final balance in the reserve * @param closing_fee closing fee to charge - * @param[out] final_balance set to the final balance in the account that will be wired back to the origin account * @return transaction status code */ enum GNUNET_DB_QueryStatus @@ -45,8 +45,8 @@ TEH_PG_insert_close_request ( const char *payto_uri, const struct TALER_ReserveSignatureP *reserve_sig, struct GNUNET_TIME_Timestamp request_timestamp, - const struct TALER_Amount *closing_fee, - struct TALER_Amount *final_balance); + const struct TALER_Amount *balance, + const struct TALER_Amount *closing_fee); #endif diff --git a/src/exchangedb/pg_insert_reserve_open_deposit.c b/src/exchangedb/pg_insert_reserve_open_deposit.c index c767bfee..8bf70e7b 100644 --- a/src/exchangedb/pg_insert_reserve_open_deposit.c +++ b/src/exchangedb/pg_insert_reserve_open_deposit.c @@ -34,6 +34,7 @@ TEH_PG_insert_reserve_open_deposit ( uint64_t known_coin_id, const struct TALER_Amount *coin_total, const struct TALER_ReserveSignatureP *reserve_sig, + const struct TALER_ReservePublicKeyP *reserve_pub, bool *insufficient_funds) { struct PostgresClosure *pg = cls; @@ -42,11 +43,12 @@ TEH_PG_insert_reserve_open_deposit ( GNUNET_PQ_query_param_uint64 (&known_coin_id), GNUNET_PQ_query_param_auto_from_type (coin_sig), GNUNET_PQ_query_param_auto_from_type (reserve_sig), + GNUNET_PQ_query_param_auto_from_type (reserve_pub), TALER_PQ_query_param_amount (coin_total), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("insufficient_funds", + GNUNET_PQ_result_spec_bool ("out_insufficient_funds", insufficient_funds), GNUNET_PQ_result_spec_end }; @@ -54,9 +56,9 @@ TEH_PG_insert_reserve_open_deposit ( PREPARE (pg, "insert_reserve_open_deposit", "SELECT " - " insufficient_funds" + " out_insufficient_funds" " FROM exchange_do_reserve_open_deposit" - " ($1,$2,$3,$4,$5,$6);"); + " ($1,$2,$3,$4,$5,$6,$7);"); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "insert_reserve_open_deposit", params, diff --git a/src/exchangedb/pg_insert_reserve_open_deposit.h b/src/exchangedb/pg_insert_reserve_open_deposit.h index 335fda52..7eb2fe09 100644 --- a/src/exchangedb/pg_insert_reserve_open_deposit.h +++ b/src/exchangedb/pg_insert_reserve_open_deposit.h @@ -36,6 +36,7 @@ * @param known_coin_id ID of the coin in the known_coins table * @param coin_total amount to be spent of the coin (including deposit fee) * @param reserve_sig signature by the reserve affirming the open operation + * @param reserve_pub public key of the reserve being opened * @param[out] insufficient_funds set to true if the coin's balance is insufficient, otherwise to false * @return transaction status code, 0 if operation is already in the DB */ @@ -47,6 +48,7 @@ TEH_PG_insert_reserve_open_deposit ( uint64_t known_coin_id, const struct TALER_Amount *coin_total, const struct TALER_ReserveSignatureP *reserve_sig, + const struct TALER_ReservePublicKeyP *reserve_pub, bool *insufficient_funds); #endif diff --git a/src/exchangedb/pg_iterate_kyc_reference.c b/src/exchangedb/pg_iterate_kyc_reference.c index 4a94722c..772c51e2 100644 --- a/src/exchangedb/pg_iterate_kyc_reference.c +++ b/src/exchangedb/pg_iterate_kyc_reference.c @@ -69,11 +69,11 @@ iterate_kyc_reference_cb (void *cls, char *provider_user_id; char *legitimization_id; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_string ("section_name", + GNUNET_PQ_result_spec_string ("provider_section", &kyc_provider_section_name), GNUNET_PQ_result_spec_string ("provider_user_id", &provider_user_id), - GNUNET_PQ_result_spec_string ("legi_id", + GNUNET_PQ_result_spec_string ("provider_legitimization_id", &legitimization_id), GNUNET_PQ_result_spec_end }; @@ -116,10 +116,10 @@ TEH_PG_iterate_kyc_reference ( PREPARE (pg, "iterate_kyc_reference", "SELECT " - " section_name" + " provider_section" ",provider_user_id" - ",legi_id" - " FROM FIXME" + ",provider_legitimization_id" + " FROM legitimization_processes" " WHERE h_payto=$1;"); return GNUNET_PQ_eval_prepared_multi_select (pg->conn, "iterate_kyc_reference", diff --git a/src/exchangedb/pg_iterate_reserve_close_info.c b/src/exchangedb/pg_iterate_reserve_close_info.c index c5ff6132..f1b2d452 100644 --- a/src/exchangedb/pg_iterate_reserve_close_info.c +++ b/src/exchangedb/pg_iterate_reserve_close_info.c @@ -68,7 +68,7 @@ iterate_reserve_close_info_cb (void *cls, struct TALER_Amount amount; struct GNUNET_TIME_Absolute ts; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_absolute_time ("timestamp", + GNUNET_PQ_result_spec_absolute_time ("execution_date", &ts), TALER_PQ_RESULT_SPEC_AMOUNT ("amount", &amount), @@ -115,14 +115,15 @@ TEH_PG_iterate_reserve_close_info ( "SELECT" " amount_val" ",amount_frac" - ",timestamp" - " FROM FIXME" - " WHERE h_payto=$1" - " AND timestamp >= $2" - " ORDER BY timestamp DESC"); - return GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "iterate_reserve_close_info", - params, - &iterate_reserve_close_info_cb, - &ic); + ",execution_date" + " FROM reserves_close" + " WHERE wire_target_h_payto=$1" + " AND execution_date >= $2" + " ORDER BY execution_date DESC"); + return GNUNET_PQ_eval_prepared_multi_select ( + pg->conn, + "iterate_reserve_close_info", + params, + &iterate_reserve_close_info_cb, + &ic); } diff --git a/src/exchangedb/pg_select_reserve_close_info.c b/src/exchangedb/pg_select_reserve_close_info.c index 53ea4568..0b373b7b 100644 --- a/src/exchangedb/pg_select_reserve_close_info.c +++ b/src/exchangedb/pg_select_reserve_close_info.c @@ -39,7 +39,7 @@ TEH_PG_select_reserve_close_info ( GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_RESULT_SPEC_AMOUNT ("balance", + TALER_PQ_RESULT_SPEC_AMOUNT ("close", balance), GNUNET_PQ_result_spec_string ("payto_uri", payto_uri), @@ -49,10 +49,10 @@ TEH_PG_select_reserve_close_info ( PREPARE (pg, "select_reserve_close_info", "SELECT " - " balance_frac" - ",balance_val" + " close_frac" + ",close_val" ",payto_uri" - " FROM FIXME" + " FROM close_requests" " WHERE reserve_pub=$1;"); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "select_reserve_close_info", diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 341364f9..d2e2eb5d 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -32,6 +32,9 @@ #include "pg_helper.h" #include "pg_insert_close_request.h" #include "pg_insert_reserve_open_deposit.h" +#include "pg_iterate_kyc_reference.h" +#include "pg_iterate_reserve_close_info.h" +#include "pg_select_reserve_close_info.h" #include #include #include @@ -17264,8 +17267,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &postgres_select_purse_merge; plugin->insert_history_request = &postgres_insert_history_request; - plugin->insert_close_request - = &TEH_PG_insert_close_request; plugin->insert_drain_profit = &postgres_insert_drain_profit; plugin->profit_drains_get_pending @@ -17294,6 +17295,16 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &postgres_select_aggregation_amounts_for_kyc_check; plugin->select_merge_amounts_for_kyc_check = &postgres_select_merge_amounts_for_kyc_check; + /* NEW style, sort alphabetically! */ + plugin->insert_close_request + = &TEH_PG_insert_close_request; + plugin->iterate_reserve_close_info + = &TEH_PG_iterate_reserve_close_info; + plugin->iterate_kyc_reference + = &TEH_PG_iterate_kyc_reference; + plugin->select_reserve_close_info + = &TEH_PG_select_reserve_close_info; + return plugin; } diff --git a/src/exchangedb/procedures.sql b/src/exchangedb/procedures.sql index 1940fa7b..8407f20c 100644 --- a/src/exchangedb/procedures.sql +++ b/src/exchangedb/procedures.sql @@ -1778,7 +1778,7 @@ ELSE my_amount_val = my_amount_val + my_amount_frac / 100000000; my_amount_frac = my_amount_frac % 100000000; - UPDATE reserves + UPDATE exchange.reserves SET current_balance_frac=current_balance_frac+my_amount_frac - CASE @@ -1795,7 +1795,7 @@ ELSE WHERE reserve_pub=in_reserve_pub; -- ... and mark purse as finished. - UPDATE purse_requests + UPDATE exchange.purse_requests SET finished=true WHERE purse_pub=in_purse_pub; END IF; @@ -1881,7 +1881,7 @@ THEN out_no_funds=TRUE; RETURN; END IF; - UPDATE reserves + UPDATE exchange.reserves SET purses_active=purses_active+1 WHERE reserve_pub=in_reserve_pub AND purses_active < purses_allowed; @@ -1901,7 +1901,7 @@ ELSE RETURN; END IF; ELSE - UPDATE reserves + UPDATE exchange.reserves SET current_balance_frac=current_balance_frac-in_purse_fee_frac + CASE @@ -1993,7 +1993,7 @@ THEN RETURN; END IF; -UPDATE purse_requests +UPDATE exchange.purse_requests SET refunded=TRUE, finished=TRUE WHERE purse_pub=my_purse_pub; @@ -2011,7 +2011,7 @@ FOR my_deposit IN FROM exchange.purse_deposits WHERE purse_pub = my_purse_pub LOOP - UPDATE known_coins SET + UPDATE exchange.known_coins SET remaining_frac=remaining_frac+my_deposit.amount_with_fee_frac - CASE WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000 @@ -2071,7 +2071,7 @@ BEGIN out_idempotent=FALSE; -- Update reserve balance. - UPDATE reserves + UPDATE exchange.reserves SET current_balance_frac=current_balance_frac-in_history_fee_frac + CASE @@ -2103,57 +2103,76 @@ BEGIN END $$; -CREATE OR REPLACE FUNCTION exchange_do_close_request( - IN in_reserve_pub BYTEA, - IN in_close_timestamp INT8, +CREATE OR REPLACE FUNCTION exchange_do_reserve_open_deposit( + IN in_coin_pub BYTEA, + IN in_known_coin_id INT8, + IN in_coin_sig BYTEA, IN in_reserve_sig BYTEA, - OUT out_final_balance_val INT8, - OUT out_final_balance_frac INT4, - OUT out_balance_ok BOOLEAN, - OUT out_conflict BOOLEAN) + IN in_reserve_pub BYTEA, + IN in_coin_total_val INT8, + IN in_coin_total_frac INT4, + OUT out_insufficient_funds BOOLEAN) LANGUAGE plpgsql AS $$ BEGIN - SELECT - current_balance_val - ,current_balance_frac - INTO - out_final_balance_val - ,out_final_balance_frac - FROM exchange.reserves - WHERE reserve_pub=in_reserve_pub; +INSERT INTO exchange.reserves_open_deposits + (reserve_sig + ,reserve_pub + ,request_timestamp + ,coin_pub + ,coin_sig + ,contribution_val + ,contribution_frac + ) + VALUES + (in_reserve_sig + ,in_reserve_pub + ,in_request_timestamp + ,in_coin_pub + ,in_coin_sig + ,in_coin_total_val + ,in_coin_total_frac) + ON CONFLICT DO NOTHING; - IF NOT FOUND - THEN - out_final_balance_val=0; - out_final_balance_frac=0; - out_balance_ok = FALSE; - out_conflict = FALSE; - END IF; +IF NOT FOUND +THEN + -- Idempotent request known, return success. + out_insufficient_funds=FALSE; + RETURN; +END IF; - INSERT INTO exchange.close_requests - (reserve_pub - ,close_timestamp - ,reserve_sig - ,close_val - ,close_frac) - VALUES - (in_reserve_pub - ,in_close_timestamp - ,in_reserve_sig - ,out_final_balance_val - ,out_final_balance_frac) - ON CONFLICT DO NOTHING; - out_conflict = NOT FOUND; - UPDATE reserves SET - current_balance_val=0 - ,current_balance_frac=0 - WHERE reserve_pub=in_reserve_pub; - out_balance_ok = TRUE; +-- Check and update balance of the coin. +UPDATE exchange.known_coins + SET + remaining_frac=remaining_frac-in_coin_total_frac + + CASE + WHEN remaining_frac < in_coin_total_frac + THEN 100000000 + ELSE 0 + END, + remaining_val=remaining_val-in_coin_total_val + - CASE + WHEN remaining_frac < in_coin_total_frac + THEN 1 + ELSE 0 + END + WHERE coin_pub=in_coin_pub + AND ( (remaining_val > in_coin_total_val) OR + ( (remaining_frac >= in_coin_total_frac) AND + (remaining_val >= in_coin_total_val) ) ); -END $$; +IF NOT FOUND +THEN + -- Insufficient balance. + out_insufficient_funds=TRUE; + RETURN; +END IF; +-- Everything fine, return success! +out_insufficient_funds=FALSE; + +END $$; COMMIT; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index bde3c813..0ce8ff47 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4072,6 +4072,7 @@ struct TALER_EXCHANGEDB_Plugin * @param known_coin_id ID of the coin in the known_coins table * @param coin_total amount to be spent of the coin (including deposit fee) * @param reserve_sig signature by the reserve affirming the open operation + * @param reserve_pub public key of the reserve being opened * @param[out] insufficient_funds set to true if the coin's balance is insufficient, otherwise to false * @return transaction status code, 0 if operation is already in the DB */ @@ -4083,6 +4084,7 @@ struct TALER_EXCHANGEDB_Plugin uint64_t known_coin_id, const struct TALER_Amount *coin_total, const struct TALER_ReserveSignatureP *reserve_sig, + const struct TALER_ReservePublicKeyP *reserve_pub, bool *insufficient_funds); @@ -5600,8 +5602,8 @@ struct TALER_EXCHANGEDB_Plugin * @param payto_uri where to wire the funds * @param reserve_sig signature affiming that the account is to be closed * @param request_timestamp timestamp of the close request + * @param balance balance at the time of closing * @param closing_fee closing fee to charge - * @param[out] final_balance set to the final balance in the account that will be wired back to the origin account * @return transaction status code */ enum GNUNET_DB_QueryStatus @@ -5610,8 +5612,8 @@ struct TALER_EXCHANGEDB_Plugin const char *payto_uri, const struct TALER_ReserveSignatureP *reserve_sig, struct GNUNET_TIME_Timestamp request_timestamp, - const struct TALER_Amount *closing_fee, - struct TALER_Amount *final_balance); + const struct TALER_Amount *balance, + const struct TALER_Amount *closing_fee); /** -- cgit v1.2.3