From 1009084e94b8e8cf19e3b5568c3cccaba2bd2209 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 11 Aug 2022 23:35:33 +0200 Subject: major rework of the KYC logic, making it more configurable, not complete, but tests pass again --- src/exchangedb/common-0001.sql | 4 +- src/exchangedb/exchange-0001-part.sql | 16 ++ src/exchangedb/plugin_exchangedb_postgres.c | 376 ++++++++++++++++++++++++---- src/exchangedb/procedures.sql | 82 +----- src/exchangedb/test_exchangedb.c | 9 +- 5 files changed, 349 insertions(+), 138 deletions(-) (limited to 'src/exchangedb') diff --git a/src/exchangedb/common-0001.sql b/src/exchangedb/common-0001.sql index 76185572c..7829b0b34 100644 --- a/src/exchangedb/common-0001.sql +++ b/src/exchangedb/common-0001.sql @@ -99,11 +99,12 @@ BEGIN PERFORM create_partitioned_table( 'CREATE TABLE IF NOT EXISTS %I' '(legitimization_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE' - ',h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=64)' + ',h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=32)' ',expiration_time INT8 NOT NULL DEFAULT (0)' ',provider_section VARCHAR NOT NULL' ',provider_user_id VARCHAR DEFAULT NULL' ',provider_legitimization_id VARCHAR DEFAULT NULL' + ',UNIQUE (h_payto, provider_section)' ') %s ;' ,'legitimizations' ,'PARTITION BY HASH (h_payto)' @@ -898,6 +899,7 @@ BEGIN '(amount_val INT8 NOT NULL' ',amount_frac INT4 NOT NULL' ',wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)' + ',merchant_pub BYTEA CHECK (LENGTH(merchant_pub)=32)' ',exchange_account_section TEXT NOT NULL' ',wtid_raw BYTEA NOT NULL CHECK (LENGTH(wtid_raw)=32)' ') %s ;' diff --git a/src/exchangedb/exchange-0001-part.sql b/src/exchangedb/exchange-0001-part.sql index 54b7112f9..792af685e 100644 --- a/src/exchangedb/exchange-0001-part.sql +++ b/src/exchangedb/exchange-0001-part.sql @@ -63,6 +63,22 @@ COMMENT ON TABLE denomination_revocations IS 'remembering which denomination keys have been revoked'; + +-- -------------------------- kyc_alerts ---------------------------------------- + +CREATE TABLE IF NOT EXISTS kyc_alerts + (h_payto BYTEA PRIMARY KEY CHECK (LENGTH(h_payto)=32) + ,trigger_type INT4 NOT NULL + ,UNIQUE(trigger_type,h_payto) + ); +COMMENT ON TABLE kyc_alerts + IS 'alerts about completed KYC events reliably notifying other components (even if they are not running)'; +COMMENT ON COLUMN kyc_alerts.h_payto + IS 'hash of the payto://-URI for which the KYC status changed'; +COMMENT ON COLUMN kyc_alerts.trigger_type + IS 'identifies the receiver of the alert, as the same h_payto may require multiple components to be notified'; + + -- ------------------------------ profit drains ---------------------------------------- CREATE TABLE IF NOT EXISTS profit_drains diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index e501dc2d6..cbb8164e9 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -589,6 +589,14 @@ prepare_statements (struct PostgresClosure *pg) " WHERE reserve_pub=$1" " LIMIT 1;", 1), + /* Used in #postgres_reserves_get_origin() */ + GNUNET_PQ_make_prepare ( + "get_h_wire_source_of_reserve", + "SELECT" + " wire_source_h_payto" + " FROM reserves_in" + " WHERE reserve_pub=$1", + 1), /* Used in #postgres_set_kyc_ok() */ GNUNET_PQ_make_prepare ( "set_kyc_ok", @@ -638,6 +646,18 @@ prepare_statements (struct PostgresClosure *pg) " FROM wire_targets" " WHERE wire_target_h_payto=$1;", 1), + /* Used in #postgres_drain_kyc_alert() */ + GNUNET_PQ_make_prepare ( + "drain_kyc_alert", + "DELETE FROM kyc_alerts" + " WHERE trigger_type=$1" + " AND h_payto = " + " (SELECT h_payto " + " FROM kyc_alerts" + " WHERE trigger_type=$1" + " LIMIT 1)" + " RETURNING h_payto;", + 1), /* Used in #reserves_get() */ GNUNET_PQ_make_prepare ( "reserves_get", @@ -876,8 +896,6 @@ prepare_statements (struct PostgresClosure *pg) " reserve_found" ",balance_ok" ",nonce_ok" - ",kycok AS kyc_ok" - ",account_uuid AS payment_target_uuid" ",ruuid" " FROM exchange_do_withdraw" " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);", @@ -889,8 +907,6 @@ prepare_statements (struct PostgresClosure *pg) "SELECT " " reserve_found" ",balance_ok" - ",kycok AS kyc_ok" - ",account_uuid AS payment_target_uuid" ",ruuid" " FROM exchange_do_batch_withdraw" " ($1,$2,$3,$4,$5);", @@ -1719,8 +1735,8 @@ prepare_statements (struct PostgresClosure *pg) GNUNET_PQ_make_prepare ( "get_deposit_without_wtid", "SELECT" - " wt.kyc_ok" - ",wt.wire_target_serial_id AS payment_target_uuid" + " legi.expiration_time" + ",legi.legitimization_serial_id" ",dep.wire_salt" ",wt.payto_uri" ",dep.amount_with_fee_val" @@ -1732,9 +1748,12 @@ prepare_statements (struct PostgresClosure *pg) " JOIN wire_targets wt USING (wire_target_h_payto)" " JOIN known_coins kc ON (kc.coin_pub = dep.coin_pub)" " JOIN denominations denom USING (denominations_serial)" + " LEFT JOIN legitimizations legi ON (wt.wire_target_h_payto = legi.h_payto)" " WHERE dep.coin_pub=$1" " AND dep.merchant_pub=$3" - " AND dep.h_contract_terms=$2;", + " AND dep.h_contract_terms=$2" + " ORDER BY legi.expiration_time ASC" + " LIMIT 1;", 3), /* Used in #postgres_get_ready_deposit() */ GNUNET_PQ_make_prepare ( @@ -1744,18 +1763,18 @@ prepare_statements (struct PostgresClosure *pg) ",merchant_pub" " FROM deposits_by_ready dbr" " JOIN deposits dep" - " ON (dbr.coin_pub = dep.coin_pub AND dbr.deposit_serial_id = dep.deposit_serial_id)" + " ON (dbr.coin_pub = dep.coin_pub AND" + " dbr.deposit_serial_id = dep.deposit_serial_id)" " JOIN wire_targets wt" " USING (wire_target_h_payto)" " WHERE dbr.wire_deadline<=$1" " AND dbr.shard >= $2" " AND dbr.shard <= $3" - " AND (wt.kyc_ok OR $4)" " ORDER BY " " dbr.wire_deadline ASC" " ,dbr.shard ASC" " LIMIT 1;", - 4), + 3), /* Used in #postgres_aggregate() */ GNUNET_PQ_make_prepare ( "aggregate", @@ -1850,11 +1869,12 @@ prepare_statements (struct PostgresClosure *pg) "INSERT INTO aggregation_transient" " (amount_val" " ,amount_frac" + " ,merchant_pub" " ,wire_target_h_payto" " ,exchange_account_section" " ,wtid_raw)" - " VALUES ($1, $2, $3, $4, $5);", - 5), + " VALUES ($1, $2, $3, $4, $5, $6);", + 6), /* Used in #postgres_select_aggregation_transient() */ GNUNET_PQ_make_prepare ( "select_aggregation_transient", @@ -1864,8 +1884,22 @@ prepare_statements (struct PostgresClosure *pg) " ,wtid_raw" " FROM aggregation_transient" " WHERE wire_target_h_payto=$1" - " AND exchange_account_section=$2;", - 2), + " AND merchant_pub=$2" + " AND exchange_account_section=$3;", + 3), + /* Used in #postgres_find_aggregation_transient() */ + GNUNET_PQ_make_prepare ( + "find_transient_aggregations", + "SELECT" + " amount_val" + " ,amount_frac" + " ,wtid_raw" + " ,merchant_pub" + " ,payto_uri" + " FROM aggregation_transient atr" + " JOIN wire_targets wt USING (wire_target_h_payto)" + " WHERE atr.wire_target_h_payto=$1;", + 1), /* Used in #postgres_update_aggregation_transient() */ GNUNET_PQ_make_prepare ( "update_aggregation_transient", @@ -4525,6 +4559,8 @@ prepare_statements (struct PostgresClosure *pg) " ,provider_section" " ) VALUES " " ($1, $2)" + " ON CONFLICT (h_payto,provider_section) " + " DO UPDATE SET h_payto=$1" /* syntax requirement: dummy op */ " RETURNING legitimization_serial_id", 2), /* Used in #postgres_update_kyc_requirement_by_row() */ @@ -4533,12 +4569,20 @@ prepare_statements (struct PostgresClosure *pg) "UPDATE legitimizations" " SET provider_user_id=$4" " ,provider_legitimization_id=$5" - " ,expiration_time=$6" + " ,expiration_time=GREATEST(expiration_time,$6)" " WHERE" " h_payto=$3" " AND legitimization_serial_id=$1" " AND provider_section=$2;", 6), + GNUNET_PQ_make_prepare ( + "alert_kyc_status_change", + "INSERT INTO kyc_alerts" + " (h_payto" + " ,trigger_type)" + " VALUES" + " ($1,$2);", + 2), /* Used in #postgres_lookup_kyc_requirement_by_row() */ GNUNET_PQ_make_prepare ( "lookup_legitimization_by_row", @@ -4598,7 +4642,6 @@ prepare_statements (struct PostgresClosure *pg) " AND ro.execution_date >= $2" " ORDER BY ro.execution_date DESC", 2), - /* Used in #postgres_select_aggregation_amounts_for_kyc_check ( () */ GNUNET_PQ_make_prepare ( @@ -5705,7 +5748,6 @@ postgres_reserves_get (void *cls, GNUNET_PQ_result_spec_end }; - kyc->type = TALER_EXCHANGEDB_KYC_WITHDRAW; return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "reserves_get_with_kyc", params, @@ -5713,6 +5755,38 @@ postgres_reserves_get (void *cls, } +/** + * Get the origin of funds of a reserve. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param reserve_pub public key of the reserve + * @param[out] h_payto set to hash of the wire source payto://-URI + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +postgres_reserves_get_origin ( + void *cls, + const struct TALER_ReservePublicKeyP *reserve_pub, + struct TALER_PaytoHashP *h_payto) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("wire_source_h_payto", + h_payto), + GNUNET_PQ_result_spec_end + }; + + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "get_h_wire_source_of_reserve", + params, + rs); +} + + /** * Set the KYC status to "OK" for a bank account. * @@ -5766,6 +5840,37 @@ postgres_set_kyc_ok (void *cls, } +/** + * Extract next KYC alert. Deletes the alert. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param trigger_type which type of alert to drain + * @param[out] h_payto set to hash of payto-URI where KYC status changed + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +postgres_drain_kyc_alert (void *cls, + uint32_t trigger_type, + struct TALER_PaytoHashP *h_payto) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint32 (&trigger_type), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("h_payto", + h_payto), + GNUNET_PQ_result_spec_end + }; + + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "drain_kyc_alert", + params, + rs); +} + + /** * Get the @a kyc status and @a h_payto by UUID. * @@ -5792,7 +5897,6 @@ postgres_select_kyc_status (void *cls, GNUNET_PQ_result_spec_end }; - kyc->type = TALER_EXCHANGEDB_KYC_UNKNOWN; return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "select_kyc_status_by_payto", params, @@ -5863,7 +5967,6 @@ inselect_account_kyc_status ( kyc->ok = false; } } - kyc->type = TALER_EXCHANGEDB_KYC_BALANCE; return qs; } @@ -5888,7 +5991,7 @@ postgres_inselect_wallet_kyc_status ( enum GNUNET_DB_QueryStatus qs; struct TALER_PaytoHashP h_payto; - payto_uri = TALER_payto_from_reserve (pg->exchange_url, + payto_uri = TALER_reserve_make_payto (pg->exchange_url, reserve_pub); qs = inselect_account_kyc_status (pg, payto_uri, @@ -6284,7 +6387,6 @@ postgres_get_withdraw_info ( * @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] nonce_ok set to false if the nonce was reused - * @param[out] kyc set to true if the kyc status of the reserve is satisfied * @param[out] ruuid set to the reserve's UUID (reserves table row) * @return query execution status */ @@ -6297,7 +6399,6 @@ postgres_do_withdraw ( bool *found, bool *balance_ok, bool *nonce_ok, - struct TALER_EXCHANGEDB_KycStatus *kyc, uint64_t *ruuid) { struct PostgresClosure *pg = cls; @@ -6321,12 +6422,8 @@ postgres_do_withdraw ( found), GNUNET_PQ_result_spec_bool ("balance_ok", balance_ok), - GNUNET_PQ_result_spec_bool ("kyc_ok", - &kyc->ok), GNUNET_PQ_result_spec_bool ("nonce_ok", nonce_ok), - GNUNET_PQ_result_spec_uint64 ("payment_target_uuid", - &kyc->payment_target_uuid), GNUNET_PQ_result_spec_uint64 ("ruuid", ruuid), GNUNET_PQ_result_spec_end @@ -6335,7 +6432,6 @@ postgres_do_withdraw ( gc = GNUNET_TIME_absolute_to_timestamp ( GNUNET_TIME_absolute_add (now.abs_time, pg->legal_reserve_expiration_time)); - kyc->type = TALER_EXCHANGEDB_KYC_WITHDRAW; return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "call_withdraw", params, @@ -6354,7 +6450,6 @@ postgres_do_withdraw ( * @param amount total amount to withdraw * @param[out] found set to true if the reserve was found * @param[out] balance_ok set to true if the balance was sufficient - * @param[out] kyc set to the KYC status of the reserve * @param[out] ruuid set to the reserve's UUID (reserves table row) * @return query execution status */ @@ -6366,7 +6461,6 @@ postgres_do_batch_withdraw ( const struct TALER_Amount *amount, bool *found, bool *balance_ok, - struct TALER_EXCHANGEDB_KycStatus *kyc, uint64_t *ruuid) { struct PostgresClosure *pg = cls; @@ -6383,10 +6477,6 @@ postgres_do_batch_withdraw ( found), GNUNET_PQ_result_spec_bool ("balance_ok", balance_ok), - GNUNET_PQ_result_spec_bool ("kyc_ok", - &kyc->ok), - GNUNET_PQ_result_spec_uint64 ("payment_target_uuid", - &kyc->payment_target_uuid), GNUNET_PQ_result_spec_uint64 ("ruuid", ruuid), GNUNET_PQ_result_spec_end @@ -6395,7 +6485,6 @@ postgres_do_batch_withdraw ( gc = GNUNET_TIME_absolute_to_timestamp ( GNUNET_TIME_absolute_add (now.abs_time, pg->legal_reserve_expiration_time)); - kyc->type = TALER_EXCHANGEDB_KYC_WITHDRAW; return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "call_batch_withdraw", params, @@ -7743,12 +7832,14 @@ postgres_create_aggregation_transient ( void *cls, const struct TALER_PaytoHashP *h_payto, const char *exchange_account_section, + const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_WireTransferIdentifierRawP *wtid, const struct TALER_Amount *total) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { TALER_PQ_query_param_amount (total), + GNUNET_PQ_query_param_auto_from_type (merchant_pub), GNUNET_PQ_query_param_auto_from_type (h_payto), GNUNET_PQ_query_param_string (exchange_account_section), GNUNET_PQ_query_param_auto_from_type (wtid), @@ -7775,6 +7866,7 @@ static enum GNUNET_DB_QueryStatus postgres_select_aggregation_transient ( void *cls, const struct TALER_PaytoHashP *h_payto, + const struct TALER_MerchantPublicKeyP *merchant_pub, const char *exchange_account_section, struct TALER_WireTransferIdentifierRawP *wtid, struct TALER_Amount *total) @@ -7782,6 +7874,7 @@ postgres_select_aggregation_transient ( struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (h_payto), + GNUNET_PQ_query_param_auto_from_type (merchant_pub), GNUNET_PQ_query_param_string (exchange_account_section), GNUNET_PQ_query_param_end }; @@ -7800,6 +7893,129 @@ postgres_select_aggregation_transient ( } +/** + * Closure for #get_refunds_cb(). + */ +struct FindAggregationTransientContext +{ + /** + * Function to call on each result. + */ + TALER_EXCHANGEDB_TransientAggregationCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Plugin context. + */ + struct PostgresClosure *pg; + + /** + * Set to #GNUNET_SYSERR on error. + */ + enum GNUNET_GenericReturnValue status; +}; + + +/** + * Function to be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls closure of type `struct SelectRefundContext *` + * @param result the postgres result + * @param num_results the number of results in @a result + */ +static void +get_transients_cb (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct FindAggregationTransientContext *srctx = cls; + struct PostgresClosure *pg = srctx->pg; + + for (unsigned int i = 0; istatus = GNUNET_SYSERR; + return; + } + cont = srctx->cb (srctx->cb_cls, + payto_uri, + &wtid, + &merchant_pub, + &amount); + GNUNET_free (payto_uri); + if (! cont) + break; + } +} + + +/** + * Find existing entry in the transient aggregation table. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param h_payto destination of the wire transfer + * @param cb function to call on each matching entry + * @param cb_cls closure for @a cb + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +postgres_find_aggregation_transient ( + void *cls, + const struct TALER_PaytoHashP *h_payto, + TALER_EXCHANGEDB_TransientAggregationCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (h_payto), + GNUNET_PQ_query_param_end + }; + struct FindAggregationTransientContext srctx = { + .cb = cb, + .cb_cls = cb_cls, + .pg = pg, + .status = GNUNET_OK + }; + + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, + "find_transient_aggregations", + params, + &get_transients_cb, + &srctx); + if (GNUNET_SYSERR == srctx.status) + return GNUNET_DB_STATUS_HARD_ERROR; + return qs; +} + + /** * Update existing entry in the transient aggregation table. * @a h_payto is only needed for query performance. @@ -7867,8 +8083,6 @@ postgres_delete_aggregation_transient ( * @param cls the @e cls of this struct with the plugin-specific state * @param start_shard_row minimum shard row to select * @param end_shard_row maximum shard row to select (inclusive) - * @param kyc_off true if we should not check the KYC status because - * this exchange does not need/support KYC checks. * @param[out] merchant_pub set to the public key of a merchant with a ready deposit * @param[out] payto_uri set to the account of the merchant, to be freed by caller * @return transaction status code @@ -7877,7 +8091,6 @@ static enum GNUNET_DB_QueryStatus postgres_get_ready_deposit (void *cls, uint64_t start_shard_row, uint64_t end_shard_row, - bool kyc_off, struct TALER_MerchantPublicKeyP *merchant_pub, char **payto_uri) { @@ -7887,7 +8100,6 @@ postgres_get_ready_deposit (void *cls, GNUNET_PQ_query_param_absolute_time (&now), GNUNET_PQ_query_param_uint64 (&start_shard_row), GNUNET_PQ_query_param_uint64 (&end_shard_row), - GNUNET_PQ_query_param_bool (kyc_off), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { @@ -9644,7 +9856,11 @@ postgres_lookup_transfer_by_deposit ( deposit_fee), GNUNET_PQ_result_spec_end }; + struct GNUNET_TIME_Absolute expiration; + memset (kyc, + 0, + sizeof (*kyc)); /* check if the aggregation record exists and get it */ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "lookup_deposit_wtid", @@ -9663,10 +9879,6 @@ postgres_lookup_transfer_by_deposit ( h_wire)) { *pending = false; - memset (kyc, - 0, - sizeof (*kyc)); - kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT; kyc->ok = true; return qs; } @@ -9685,15 +9897,21 @@ postgres_lookup_transfer_by_deposit ( /* Check if transaction exists in deposits, so that we just do not have a WTID yet. In that case, return without wtid (by setting 'pending' true). */ + bool no_kyc = false; struct GNUNET_PQ_ResultSpec rs2[] = { GNUNET_PQ_result_spec_auto_from_type ("wire_salt", &wire_salt), GNUNET_PQ_result_spec_string ("payto_uri", &payto_uri), - GNUNET_PQ_result_spec_uint64 ("payment_target_uuid", - &kyc->payment_target_uuid), - GNUNET_PQ_result_spec_auto_from_type ("kyc_ok", - &kyc->ok), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_uint64 ("legitimization_serial_id", + + &kyc->payment_target_uuid), + &no_kyc), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_absolute_time ("expiration_time", + &expiration), + &no_kyc), TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", amount_with_fee), TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit", @@ -9711,6 +9929,10 @@ postgres_lookup_transfer_by_deposit ( { struct TALER_MerchantWireHashP wh; + if (no_kyc) + kyc->payment_target_uuid = 0; + else + kyc->ok = GNUNET_TIME_absolute_is_future (expiration); TALER_merchant_wire_signature_hash (payto_uri, &wire_salt, &wh); @@ -9720,7 +9942,6 @@ postgres_lookup_transfer_by_deposit ( h_wire)) return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; } - kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT; return qs; } } @@ -16149,7 +16370,7 @@ postgres_do_purse_merge ( { char *payto_uri; - payto_uri = TALER_payto_from_reserve (pg->exchange_url, + payto_uri = TALER_reserve_make_payto (pg->exchange_url, reserve_pub); TALER_payto_hash (payto_uri, &h_payto); @@ -16228,7 +16449,7 @@ postgres_do_reserve_purse ( { char *payto_uri; - payto_uri = TALER_payto_from_reserve (pg->exchange_url, + payto_uri = TALER_reserve_make_payto (pg->exchange_url, reserve_pub); TALER_payto_hash (payto_uri, &h_payto); @@ -16612,16 +16833,57 @@ postgres_update_kyc_requirement_by_row ( GNUNET_PQ_query_param_uint64 (&legi_row), GNUNET_PQ_query_param_string (provider_section), GNUNET_PQ_query_param_auto_from_type (h_payto), - GNUNET_PQ_query_param_string (provider_account_id), - GNUNET_PQ_query_param_string (provider_legitimization_id), + (NULL != provider_account_id) + ? GNUNET_PQ_query_param_string (provider_account_id) + : GNUNET_PQ_query_param_null (), + (NULL != provider_legitimization_id) + ? GNUNET_PQ_query_param_string (provider_legitimization_id) + : GNUNET_PQ_query_param_null (), GNUNET_PQ_query_param_absolute_time (&expiration), GNUNET_PQ_query_param_end }; + enum GNUNET_DB_QueryStatus qs; - return GNUNET_PQ_eval_prepared_non_select ( + qs = GNUNET_PQ_eval_prepared_non_select ( pg->conn, "update_legitimization_requirement", params); + if (qs <= 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to update legitimization: %d\n", + qs); + return qs; + } + if (GNUNET_TIME_absolute_is_future (expiration)) + { + enum GNUNET_DB_QueryStatus qs2; + struct TALER_KycCompletedEventP rep = { + .header.size = htons (sizeof (rep)), + .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED), + .h_payto = *h_payto + }; + uint32_t trigger_type = 1; + struct GNUNET_PQ_QueryParam params2[] = { + GNUNET_PQ_query_param_auto_from_type (h_payto), + GNUNET_PQ_query_param_uint32 (&trigger_type), + GNUNET_PQ_query_param_end + }; + + postgres_event_notify (pg, + &rep.header, + NULL, + 0); + qs2 = GNUNET_PQ_eval_prepared_non_select ( + pg->conn, + "alert_kyc_status_change", + params2); + if (qs2 < 0) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to store KYC alert: %d\n", + qs2); + } + return qs; } @@ -16831,6 +17093,9 @@ get_legitimizations_cb (void *cls, ctx->status = GNUNET_SYSERR; return; } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Found satisfied LEGI: %s\n", + provider_section); ctx->cb (ctx->cb_cls, provider_section); GNUNET_PQ_cleanup_result (rs); @@ -16877,6 +17142,9 @@ postgres_select_satisfied_kyc_processes ( params, &get_legitimizations_cb, &ctx); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Satisfied LEGI check returned %d\n", + qs); if (GNUNET_OK != ctx.status) return GNUNET_DB_STATUS_HARD_ERROR; return qs; @@ -17220,7 +17488,9 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) &postgres_iterate_auditor_denominations; plugin->select_kyc_status = &postgres_select_kyc_status; plugin->reserves_get = &postgres_reserves_get; + plugin->reserves_get_origin = &postgres_reserves_get_origin; plugin->set_kyc_ok = &postgres_set_kyc_ok; + plugin->drain_kyc_alert = &postgres_drain_kyc_alert; plugin->inselect_wallet_kyc_status = &postgres_inselect_wallet_kyc_status; plugin->reserves_in_insert = &postgres_reserves_in_insert; plugin->get_withdraw_info = &postgres_get_withdraw_info; @@ -17247,6 +17517,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &postgres_create_aggregation_transient; plugin->select_aggregation_transient = &postgres_select_aggregation_transient; + plugin->find_aggregation_transient + = &postgres_find_aggregation_transient; plugin->update_aggregation_transient = &postgres_update_aggregation_transient; plugin->delete_aggregation_transient diff --git a/src/exchangedb/procedures.sql b/src/exchangedb/procedures.sql index 8366bc811..f05f4d2ad 100644 --- a/src/exchangedb/procedures.sql +++ b/src/exchangedb/procedures.sql @@ -37,8 +37,6 @@ CREATE OR REPLACE FUNCTION exchange_do_withdraw( OUT reserve_found BOOLEAN, OUT balance_ok BOOLEAN, OUT nonce_ok BOOLEAN, - OUT kycok BOOLEAN, - OUT account_uuid INT8, OUT ruuid INT8) LANGUAGE plpgsql AS $$ @@ -67,8 +65,6 @@ THEN -- denomination unknown, should be impossible! reserve_found=FALSE; balance_ok=FALSE; - kycok=FALSE; - account_uuid=0; ruuid=0; ASSERT false, 'denomination unknown'; RETURN; @@ -94,8 +90,6 @@ THEN reserve_found=FALSE; balance_ok=FALSE; nonce_ok=TRUE; - kycok=FALSE; - account_uuid=0; ruuid=2; RETURN; END IF; @@ -128,8 +122,6 @@ THEN reserve_found=TRUE; balance_ok=TRUE; nonce_ok=TRUE; - kycok=TRUE; - account_uuid=0; RETURN; END IF; @@ -153,8 +145,6 @@ ELSE reserve_found=TRUE; nonce_ok=TRUE; -- we do not really know balance_ok=FALSE; - kycok=FALSE; -- we do not really know or care - account_uuid=0; RETURN; END IF; END IF; @@ -201,8 +191,6 @@ THEN THEN reserve_found=FALSE; balance_ok=FALSE; - kycok=FALSE; - account_uuid=0; nonce_ok=FALSE; RETURN; END IF; @@ -211,40 +199,9 @@ ELSE nonce_ok=TRUE; -- no nonce, hence OK! END IF; - - --- Obtain KYC status based on the last wire transfer into --- this reserve. FIXME: likely not adequate for reserves that got P2P transfers! --- SELECT --- kyc_ok --- ,wire_target_serial_id --- INTO --- kycok --- ,account_uuid --- FROM exchange.reserves_in --- JOIN wire_targets ON (wire_source_h_payto = wire_target_h_payto) --- WHERE reserve_pub=rpub --- LIMIT 1; -- limit 1 should not be required (without p2p transfers) - -WITH my_reserves_in AS materialized ( - SELECT wire_source_h_payto - FROM exchange.reserves_in - WHERE reserve_pub=rpub -) -SELECT - kyc_ok - ,wire_target_serial_id -INTO - kycok - ,account_uuid -FROM exchange.wire_targets - WHERE wire_target_h_payto = ( - SELECT wire_source_h_payto - FROM my_reserves_in - ); - END $$; + COMMENT ON FUNCTION exchange_do_withdraw(BYTEA, INT8, INT4, BYTEA, BYTEA, BYTEA, BYTEA, BYTEA, INT8, INT8) IS 'Checks whether the reserve has sufficient balance for a withdraw operation (or the request is repeated and was previously approved) and if so updates the database with the result'; @@ -259,8 +216,6 @@ CREATE OR REPLACE FUNCTION exchange_do_batch_withdraw( IN min_reserve_gc INT8, OUT reserve_found BOOLEAN, OUT balance_ok BOOLEAN, - OUT kycok BOOLEAN, - OUT account_uuid INT8, OUT ruuid INT8) LANGUAGE plpgsql AS $$ @@ -295,8 +250,6 @@ THEN -- reserve unknown reserve_found=FALSE; balance_ok=FALSE; - kycok=FALSE; - account_uuid=0; ruuid=2; RETURN; END IF; @@ -320,8 +273,6 @@ ELSE ELSE reserve_found=TRUE; balance_ok=FALSE; - kycok=FALSE; -- we do not really know or care - account_uuid=0; RETURN; END IF; END IF; @@ -340,37 +291,6 @@ WHERE reserve_found=TRUE; balance_ok=TRUE; - --- Obtain KYC status based on the last wire transfer into --- this reserve. FIXME: likely not adequate for reserves that got P2P transfers! --- SELECT --- kyc_ok --- ,wire_target_serial_id --- INTO --- kycok --- ,account_uuid --- FROM exchange.reserves_in --- JOIN wire_targets ON (wire_source_h_payto = wire_target_h_payto) --- WHERE reserve_pub=rpub --- LIMIT 1; -- limit 1 should not be required (without p2p transfers) - -WITH my_reserves_in AS materialized ( - SELECT wire_source_h_payto - FROM exchange.reserves_in - WHERE reserve_pub=rpub -) -SELECT - kyc_ok - ,wire_target_serial_id -INTO - kycok - ,account_uuid -FROM exchange.wire_targets - WHERE wire_target_h_payto = ( - SELECT wire_source_h_payto - FROM my_reserves_in - ); - END $$; COMMENT ON FUNCTION exchange_do_batch_withdraw(INT8, INT4, BYTEA, INT8, INT8) diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index db46aeae8..1cd081652 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -1399,7 +1399,6 @@ run (void *cls) bool found; bool nonce_ok; bool balance_ok; - struct TALER_EXCHANGEDB_KycStatus kyc; uint64_t ruuid; FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != @@ -1410,12 +1409,10 @@ run (void *cls) &found, &balance_ok, &nonce_ok, - &kyc, &ruuid)); GNUNET_assert (found); GNUNET_assert (nonce_ok); GNUNET_assert (balance_ok); - GNUNET_assert (! kyc.ok); } FAILIF (GNUNET_OK != check_reserve (&reserve_pub, @@ -2159,7 +2156,6 @@ run (void *cls) plugin->get_ready_deposit (plugin->cls, 0, INT32_MAX, - true, &merchant_pub2, &payto_uri2)); FAILIF (0 != GNUNET_memcmp (&merchant_pub2, @@ -2205,6 +2201,7 @@ run (void *cls) FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->select_aggregation_transient (plugin->cls, &wire_target_h_payto, + &deposit.merchant_pub, "x-bank", &wtid2, &total2)); @@ -2212,11 +2209,13 @@ run (void *cls) plugin->create_aggregation_transient (plugin->cls, &wire_target_h_payto, "x-bank", + &deposit.merchant_pub, &wtid, &total)); FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->select_aggregation_transient (plugin->cls, &wire_target_h_payto, + &deposit.merchant_pub, "x-bank", &wtid2, &total2)); @@ -2237,6 +2236,7 @@ run (void *cls) FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->select_aggregation_transient (plugin->cls, &wire_target_h_payto, + &deposit.merchant_pub, "x-bank", &wtid2, &total2)); @@ -2253,6 +2253,7 @@ run (void *cls) FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->select_aggregation_transient (plugin->cls, &wire_target_h_payto, + &deposit.merchant_pub, "x-bank", &wtid2, &total2)); -- cgit v1.2.3