diff --git a/src/exchange/taler-exchange-httpd_deposits_get.c b/src/exchange/taler-exchange-httpd_deposits_get.c index 86af9fff1..ebbb13e08 100644 --- a/src/exchange/taler-exchange-httpd_deposits_get.c +++ b/src/exchange/taler-exchange-httpd_deposits_get.c @@ -90,6 +90,11 @@ struct DepositWtidContext */ struct TALER_EXCHANGEDB_KycStatus kyc; + /** + * AML status information for the receiving account. + */ + enum TALER_AmlDecisionState aml_decision; + /** * Set to #GNUNET_YES by #handle_wtid if the wire transfer is still pending * (and the above were not set). @@ -128,6 +133,7 @@ reply_deposit_details ( &pub, &sig))) { + GNUNET_break (0); return TALER_MHD_reply_with_ec (connection, ec, NULL); @@ -184,7 +190,8 @@ deposits_get_transaction (void *cls, &ctx->execution_time, &ctx->coin_contribution, &fee, - &ctx->kyc); + &ctx->kyc, + &ctx->aml_decision); if (0 > qs) { if (GNUNET_DB_STATUS_HARD_ERROR == qs) @@ -257,6 +264,8 @@ handle_track_transaction_request ( NULL) : GNUNET_JSON_pack_uint64 ("requirement_row", ctx->kyc.requirement_row)), + GNUNET_JSON_pack_uint64 ("aml_decision", + (uint32_t) ctx->aml_decision), GNUNET_JSON_pack_bool ("kyc_ok", ctx->kyc.ok), GNUNET_JSON_pack_timestamp ("execution_time", diff --git a/src/exchangedb/exchange_do_insert_aml_decision.sql b/src/exchangedb/exchange_do_insert_aml_decision.sql index ef3e60048..0009ecb40 100644 --- a/src/exchangedb/exchange_do_insert_aml_decision.sql +++ b/src/exchangedb/exchange_do_insert_aml_decision.sql @@ -23,6 +23,7 @@ CREATE OR REPLACE FUNCTION exchange_do_insert_aml_decision( IN in_justification VARCHAR, IN in_decider_pub BYTEA, IN in_decider_sig BYTEA, + IN in_notify_s VARCHAR, OUT out_invalid_officer BOOLEAN, OUT out_last_date INT8) LANGUAGE plpgsql @@ -95,8 +96,25 @@ INSERT INTO exchange.aml_history ,in_decider_pub ,in_decider_sig); + +-- wake up taler-exchange-aggregator +IF 0 = in_new_status +THEN + INSERT INTO kyc_alerts + (h_payto + ,trigger_type) + VALUES + (in_h_payto,1); + + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in_notify_s); + +END IF; + + END $$; -COMMENT ON FUNCTION exchange_do_insert_aml_decision(BYTEA, INT8, INT4, INT4, INT8, VARCHAR, BYTEA, BYTEA) +COMMENT ON FUNCTION exchange_do_insert_aml_decision(BYTEA, INT8, INT4, INT4, INT8, VARCHAR, BYTEA, BYTEA, VARCHAR) IS 'Checks whether the AML officer is eligible to make AML decisions and if so inserts the decision into the table'; diff --git a/src/exchangedb/pg_insert_aml_decision.c b/src/exchangedb/pg_insert_aml_decision.c index 85570ed85..e54197e52 100644 --- a/src/exchangedb/pg_insert_aml_decision.c +++ b/src/exchangedb/pg_insert_aml_decision.c @@ -24,6 +24,7 @@ #include "taler_pq_lib.h" #include "pg_insert_aml_decision.h" #include "pg_helper.h" +#include enum GNUNET_DB_QueryStatus @@ -41,6 +42,12 @@ TEH_PG_insert_aml_decision ( { struct PostgresClosure *pg = cls; uint32_t ns = (uint32_t) new_status; + struct TALER_KycCompletedEventP rep = { + .header.size = htons (sizeof (rep)), + .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED), + .h_payto = *h_payto + }; + char *notify_s = GNUNET_PG_get_event_notify_channel (&rep.header); struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (h_payto), TALER_PQ_query_param_amount (new_threshold), @@ -49,6 +56,7 @@ TEH_PG_insert_aml_decision ( GNUNET_PQ_query_param_string (justification), GNUNET_PQ_query_param_auto_from_type (decider_pub), GNUNET_PQ_query_param_auto_from_type (decider_sig), + GNUNET_PQ_query_param_string (notify_s), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { @@ -58,6 +66,7 @@ TEH_PG_insert_aml_decision ( last_date), GNUNET_PQ_result_spec_end }; + enum GNUNET_DB_QueryStatus qs; PREPARE (pg, "do_insert_aml_decision", @@ -66,8 +75,10 @@ TEH_PG_insert_aml_decision ( ",out_last_date" " FROM exchange_do_insert_aml_decision" "($1, $2, $3, $4, $5, $6, $7, $8);"); - return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "do_insert_aml_decision", - params, - rs); + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "do_insert_aml_decision", + params, + rs); + GNUNET_free (notify_s); + return qs; } diff --git a/src/exchangedb/pg_lookup_transfer_by_deposit.c b/src/exchangedb/pg_lookup_transfer_by_deposit.c index 686b67cc4..63b132f0a 100644 --- a/src/exchangedb/pg_lookup_transfer_by_deposit.c +++ b/src/exchangedb/pg_lookup_transfer_by_deposit.c @@ -26,7 +26,6 @@ #include "pg_helper.h" - enum GNUNET_DB_QueryStatus TEH_PG_lookup_transfer_by_deposit ( void *cls, @@ -39,7 +38,8 @@ TEH_PG_lookup_transfer_by_deposit ( struct GNUNET_TIME_Timestamp *exec_time, struct TALER_Amount *amount_with_fee, struct TALER_Amount *deposit_fee, - struct TALER_EXCHANGEDB_KycStatus *kyc) + struct TALER_EXCHANGEDB_KycStatus *kyc, + enum TALER_AmlDecisionState *aml_decision) { struct PostgresClosure *pg = cls; enum GNUNET_DB_QueryStatus qs; @@ -71,8 +71,6 @@ TEH_PG_lookup_transfer_by_deposit ( 0, sizeof (*kyc)); /* check if the aggregation record exists and get it */ - - /* Used in #postgres_lookup_transfer_by_deposit */ PREPARE (pg, "lookup_deposit_wtid", "SELECT" @@ -117,6 +115,7 @@ TEH_PG_lookup_transfer_by_deposit ( { *pending = false; kyc->ok = true; + *aml_decision = TALER_AML_NORMAL; return qs; } qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; @@ -134,6 +133,7 @@ TEH_PG_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). */ + uint32_t status32 = TALER_AML_NORMAL; struct GNUNET_PQ_ResultSpec rs2[] = { GNUNET_PQ_result_spec_auto_from_type ("wire_salt", &wire_salt), @@ -149,11 +149,13 @@ TEH_PG_lookup_transfer_by_deposit ( deposit_fee), GNUNET_PQ_result_spec_timestamp ("wire_deadline", exec_time), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_uint32 ("status", + &status32), + NULL), GNUNET_PQ_result_spec_end }; - /* Fetch an existing deposit request. - Used in #postgres_lookup_transfer_by_deposit(). */ PREPARE (pg, "get_deposit_without_wtid", "SELECT" @@ -165,6 +167,7 @@ TEH_PG_lookup_transfer_by_deposit ( ",denom.fee_deposit_val" ",denom.fee_deposit_frac" ",dep.wire_deadline" + ",aml.status" " FROM deposits dep" " JOIN wire_targets wt" " USING (wire_target_h_payto)" @@ -175,6 +178,8 @@ TEH_PG_lookup_transfer_by_deposit ( " LEFT JOIN aggregation_transient agt " " ON ( (dep.wire_target_h_payto = agt.wire_target_h_payto) AND" " (dep.merchant_pub = agt.merchant_pub) )" + " LEFT JOIN aml_status aml" + " ON (wt.wire_target_h_payto = aml.h_payto)" " WHERE dep.coin_pub=$1" " AND dep.merchant_pub=$3" " AND dep.h_contract_terms=$2" @@ -187,6 +192,7 @@ TEH_PG_lookup_transfer_by_deposit ( { struct TALER_MerchantWireHashP wh; + *aml_decision = (enum TALER_AmlDecisionState) status32; if (0 == kyc->requirement_row) kyc->ok = true; /* technically: unknown */ TALER_merchant_wire_signature_hash (payto_uri, @@ -198,6 +204,7 @@ TEH_PG_lookup_transfer_by_deposit ( h_wire)) return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; } + *aml_decision = TALER_AML_NORMAL; return qs; } } diff --git a/src/exchangedb/pg_lookup_transfer_by_deposit.h b/src/exchangedb/pg_lookup_transfer_by_deposit.h index ff5554dcc..155ba6d53 100644 --- a/src/exchangedb/pg_lookup_transfer_by_deposit.h +++ b/src/exchangedb/pg_lookup_transfer_by_deposit.h @@ -42,6 +42,7 @@ * @param[out] amount_with_fee set to the total deposited amount * @param[out] deposit_fee set to how much the exchange did charge for the deposit * @param[out] kyc set to the kyc status of the receiver (if @a pending) + * @param[out[ aml_decision set to the AML status of the receiver * @return transaction status code */ enum GNUNET_DB_QueryStatus @@ -56,6 +57,7 @@ TEH_PG_lookup_transfer_by_deposit ( struct GNUNET_TIME_Timestamp *exec_time, struct TALER_Amount *amount_with_fee, struct TALER_Amount *deposit_fee, - struct TALER_EXCHANGEDB_KycStatus *kyc); + struct TALER_EXCHANGEDB_KycStatus *kyc, + enum TALER_AmlDecisionState *aml_decision); #endif diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index bfdc062b5..15329ad1c 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -3182,6 +3182,12 @@ struct TALER_EXCHANGE_GetDepositResponse */ uint64_t requirement_row; + /** + * Current AML state for the account. May explain why transfers are + * not happening. + */ + enum TALER_AmlDecisionState aml_decision; + /** * Set to 'true' if the KYC check is already finished and * the exchange is merely waiting for the @e execution_time. diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 125254612..0a389bd6e 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4319,6 +4319,7 @@ struct TALER_EXCHANGEDB_Plugin * @param[out] execution_time when was the transaction done, or * when we expect it to be done (if @a pending is false) * @param[out] kyc set to the kyc status of the receiver (if @a pending) + * @param[out] aml_decision set to the current AML status for the target account * @return transaction status code */ enum GNUNET_DB_QueryStatus @@ -4333,7 +4334,8 @@ struct TALER_EXCHANGEDB_Plugin struct GNUNET_TIME_Timestamp *exec_time, struct TALER_Amount *amount_with_fee, struct TALER_Amount *deposit_fee, - struct TALER_EXCHANGEDB_KycStatus *kyc); + struct TALER_EXCHANGEDB_KycStatus *kyc, + enum TALER_AmlDecisionState *aml_decision); /** diff --git a/src/lib/exchange_api_deposits_get.c b/src/lib/exchange_api_deposits_get.c index 7f83fad17..2e8a5e5e8 100644 --- a/src/lib/exchange_api_deposits_get.c +++ b/src/lib/exchange_api_deposits_get.c @@ -177,6 +177,7 @@ handle_deposit_wtid_finished (void *cls, { /* Transaction known, but not executed yet */ bool no_legi = false; + uint32_t state32; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_timestamp ("execution_time", &dr.details.accepted.execution_time), @@ -184,6 +185,8 @@ handle_deposit_wtid_finished (void *cls, GNUNET_JSON_spec_uint64 ("requirement_row", &dr.details.accepted.requirement_row), &no_legi), + GNUNET_JSON_spec_uint32 ("aml_decision", + &state32), GNUNET_JSON_spec_bool ("kyc_ok", &dr.details.accepted.kyc_ok), GNUNET_JSON_spec_end () @@ -199,6 +202,8 @@ handle_deposit_wtid_finished (void *cls, dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } + dr.details.accepted.aml_decision + = (enum TALER_AmlDecisionState) state32; if (no_legi) dr.details.accepted.requirement_row = 0; dwh->cb (dwh->cb_cls,