work on AML notification logic

This commit is contained in:
Christian Grothoff 2023-02-13 16:00:37 +01:00
parent 3760d43097
commit dc40f6c679
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
8 changed files with 74 additions and 14 deletions

View File

@ -90,6 +90,11 @@ struct DepositWtidContext
*/ */
struct TALER_EXCHANGEDB_KycStatus kyc; 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 * Set to #GNUNET_YES by #handle_wtid if the wire transfer is still pending
* (and the above were not set). * (and the above were not set).
@ -128,6 +133,7 @@ reply_deposit_details (
&pub, &pub,
&sig))) &sig)))
{ {
GNUNET_break (0);
return TALER_MHD_reply_with_ec (connection, return TALER_MHD_reply_with_ec (connection,
ec, ec,
NULL); NULL);
@ -184,7 +190,8 @@ deposits_get_transaction (void *cls,
&ctx->execution_time, &ctx->execution_time,
&ctx->coin_contribution, &ctx->coin_contribution,
&fee, &fee,
&ctx->kyc); &ctx->kyc,
&ctx->aml_decision);
if (0 > qs) if (0 > qs)
{ {
if (GNUNET_DB_STATUS_HARD_ERROR == qs) if (GNUNET_DB_STATUS_HARD_ERROR == qs)
@ -257,6 +264,8 @@ handle_track_transaction_request (
NULL) NULL)
: GNUNET_JSON_pack_uint64 ("requirement_row", : GNUNET_JSON_pack_uint64 ("requirement_row",
ctx->kyc.requirement_row)), ctx->kyc.requirement_row)),
GNUNET_JSON_pack_uint64 ("aml_decision",
(uint32_t) ctx->aml_decision),
GNUNET_JSON_pack_bool ("kyc_ok", GNUNET_JSON_pack_bool ("kyc_ok",
ctx->kyc.ok), ctx->kyc.ok),
GNUNET_JSON_pack_timestamp ("execution_time", GNUNET_JSON_pack_timestamp ("execution_time",

View File

@ -23,6 +23,7 @@ CREATE OR REPLACE FUNCTION exchange_do_insert_aml_decision(
IN in_justification VARCHAR, IN in_justification VARCHAR,
IN in_decider_pub BYTEA, IN in_decider_pub BYTEA,
IN in_decider_sig BYTEA, IN in_decider_sig BYTEA,
IN in_notify_s VARCHAR,
OUT out_invalid_officer BOOLEAN, OUT out_invalid_officer BOOLEAN,
OUT out_last_date INT8) OUT out_last_date INT8)
LANGUAGE plpgsql LANGUAGE plpgsql
@ -95,8 +96,25 @@ INSERT INTO exchange.aml_history
,in_decider_pub ,in_decider_pub
,in_decider_sig); ,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 $$; 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'; IS 'Checks whether the AML officer is eligible to make AML decisions and if so inserts the decision into the table';

View File

@ -24,6 +24,7 @@
#include "taler_pq_lib.h" #include "taler_pq_lib.h"
#include "pg_insert_aml_decision.h" #include "pg_insert_aml_decision.h"
#include "pg_helper.h" #include "pg_helper.h"
#include <gnunet/gnunet_pq_lib.h>
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -41,6 +42,12 @@ TEH_PG_insert_aml_decision (
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
uint32_t ns = (uint32_t) new_status; 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[] = { struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_payto), GNUNET_PQ_query_param_auto_from_type (h_payto),
TALER_PQ_query_param_amount (new_threshold), 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_string (justification),
GNUNET_PQ_query_param_auto_from_type (decider_pub), GNUNET_PQ_query_param_auto_from_type (decider_pub),
GNUNET_PQ_query_param_auto_from_type (decider_sig), GNUNET_PQ_query_param_auto_from_type (decider_sig),
GNUNET_PQ_query_param_string (notify_s),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
struct GNUNET_PQ_ResultSpec rs[] = { struct GNUNET_PQ_ResultSpec rs[] = {
@ -58,6 +66,7 @@ TEH_PG_insert_aml_decision (
last_date), last_date),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
enum GNUNET_DB_QueryStatus qs;
PREPARE (pg, PREPARE (pg,
"do_insert_aml_decision", "do_insert_aml_decision",
@ -66,8 +75,10 @@ TEH_PG_insert_aml_decision (
",out_last_date" ",out_last_date"
" FROM exchange_do_insert_aml_decision" " FROM exchange_do_insert_aml_decision"
"($1, $2, $3, $4, $5, $6, $7, $8);"); "($1, $2, $3, $4, $5, $6, $7, $8);");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"do_insert_aml_decision", "do_insert_aml_decision",
params, params,
rs); rs);
GNUNET_free (notify_s);
return qs;
} }

View File

@ -26,7 +26,6 @@
#include "pg_helper.h" #include "pg_helper.h"
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
TEH_PG_lookup_transfer_by_deposit ( TEH_PG_lookup_transfer_by_deposit (
void *cls, void *cls,
@ -39,7 +38,8 @@ TEH_PG_lookup_transfer_by_deposit (
struct GNUNET_TIME_Timestamp *exec_time, struct GNUNET_TIME_Timestamp *exec_time,
struct TALER_Amount *amount_with_fee, struct TALER_Amount *amount_with_fee,
struct TALER_Amount *deposit_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; struct PostgresClosure *pg = cls;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
@ -71,8 +71,6 @@ TEH_PG_lookup_transfer_by_deposit (
0, 0,
sizeof (*kyc)); sizeof (*kyc));
/* check if the aggregation record exists and get it */ /* check if the aggregation record exists and get it */
/* Used in #postgres_lookup_transfer_by_deposit */
PREPARE (pg, PREPARE (pg,
"lookup_deposit_wtid", "lookup_deposit_wtid",
"SELECT" "SELECT"
@ -117,6 +115,7 @@ TEH_PG_lookup_transfer_by_deposit (
{ {
*pending = false; *pending = false;
kyc->ok = true; kyc->ok = true;
*aml_decision = TALER_AML_NORMAL;
return qs; return qs;
} }
qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; 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 /* Check if transaction exists in deposits, so that we just
do not have a WTID yet. In that case, return without wtid do not have a WTID yet. In that case, return without wtid
(by setting 'pending' true). */ (by setting 'pending' true). */
uint32_t status32 = TALER_AML_NORMAL;
struct GNUNET_PQ_ResultSpec rs2[] = { struct GNUNET_PQ_ResultSpec rs2[] = {
GNUNET_PQ_result_spec_auto_from_type ("wire_salt", GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
&wire_salt), &wire_salt),
@ -149,11 +149,13 @@ TEH_PG_lookup_transfer_by_deposit (
deposit_fee), deposit_fee),
GNUNET_PQ_result_spec_timestamp ("wire_deadline", GNUNET_PQ_result_spec_timestamp ("wire_deadline",
exec_time), exec_time),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_uint32 ("status",
&status32),
NULL),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
/* Fetch an existing deposit request.
Used in #postgres_lookup_transfer_by_deposit(). */
PREPARE (pg, PREPARE (pg,
"get_deposit_without_wtid", "get_deposit_without_wtid",
"SELECT" "SELECT"
@ -165,6 +167,7 @@ TEH_PG_lookup_transfer_by_deposit (
",denom.fee_deposit_val" ",denom.fee_deposit_val"
",denom.fee_deposit_frac" ",denom.fee_deposit_frac"
",dep.wire_deadline" ",dep.wire_deadline"
",aml.status"
" FROM deposits dep" " FROM deposits dep"
" JOIN wire_targets wt" " JOIN wire_targets wt"
" USING (wire_target_h_payto)" " USING (wire_target_h_payto)"
@ -175,6 +178,8 @@ TEH_PG_lookup_transfer_by_deposit (
" LEFT JOIN aggregation_transient agt " " LEFT JOIN aggregation_transient agt "
" ON ( (dep.wire_target_h_payto = agt.wire_target_h_payto) AND" " ON ( (dep.wire_target_h_payto = agt.wire_target_h_payto) AND"
" (dep.merchant_pub = agt.merchant_pub) )" " (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" " WHERE dep.coin_pub=$1"
" AND dep.merchant_pub=$3" " AND dep.merchant_pub=$3"
" AND dep.h_contract_terms=$2" " AND dep.h_contract_terms=$2"
@ -187,6 +192,7 @@ TEH_PG_lookup_transfer_by_deposit (
{ {
struct TALER_MerchantWireHashP wh; struct TALER_MerchantWireHashP wh;
*aml_decision = (enum TALER_AmlDecisionState) status32;
if (0 == kyc->requirement_row) if (0 == kyc->requirement_row)
kyc->ok = true; /* technically: unknown */ kyc->ok = true; /* technically: unknown */
TALER_merchant_wire_signature_hash (payto_uri, TALER_merchant_wire_signature_hash (payto_uri,
@ -198,6 +204,7 @@ TEH_PG_lookup_transfer_by_deposit (
h_wire)) h_wire))
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
} }
*aml_decision = TALER_AML_NORMAL;
return qs; return qs;
} }
} }

View File

@ -42,6 +42,7 @@
* @param[out] amount_with_fee set to the total deposited amount * @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] 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] 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 * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -56,6 +57,7 @@ TEH_PG_lookup_transfer_by_deposit (
struct GNUNET_TIME_Timestamp *exec_time, struct GNUNET_TIME_Timestamp *exec_time,
struct TALER_Amount *amount_with_fee, struct TALER_Amount *amount_with_fee,
struct TALER_Amount *deposit_fee, struct TALER_Amount *deposit_fee,
struct TALER_EXCHANGEDB_KycStatus *kyc); struct TALER_EXCHANGEDB_KycStatus *kyc,
enum TALER_AmlDecisionState *aml_decision);
#endif #endif

View File

@ -3182,6 +3182,12 @@ struct TALER_EXCHANGE_GetDepositResponse
*/ */
uint64_t requirement_row; 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 * Set to 'true' if the KYC check is already finished and
* the exchange is merely waiting for the @e execution_time. * the exchange is merely waiting for the @e execution_time.

View File

@ -4319,6 +4319,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param[out] execution_time when was the transaction done, or * @param[out] execution_time when was the transaction done, or
* when we expect it to be done (if @a pending is false) * 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] 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 * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -4333,7 +4334,8 @@ struct TALER_EXCHANGEDB_Plugin
struct GNUNET_TIME_Timestamp *exec_time, struct GNUNET_TIME_Timestamp *exec_time,
struct TALER_Amount *amount_with_fee, struct TALER_Amount *amount_with_fee,
struct TALER_Amount *deposit_fee, struct TALER_Amount *deposit_fee,
struct TALER_EXCHANGEDB_KycStatus *kyc); struct TALER_EXCHANGEDB_KycStatus *kyc,
enum TALER_AmlDecisionState *aml_decision);
/** /**

View File

@ -177,6 +177,7 @@ handle_deposit_wtid_finished (void *cls,
{ {
/* Transaction known, but not executed yet */ /* Transaction known, but not executed yet */
bool no_legi = false; bool no_legi = false;
uint32_t state32;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_timestamp ("execution_time", GNUNET_JSON_spec_timestamp ("execution_time",
&dr.details.accepted.execution_time), &dr.details.accepted.execution_time),
@ -184,6 +185,8 @@ handle_deposit_wtid_finished (void *cls,
GNUNET_JSON_spec_uint64 ("requirement_row", GNUNET_JSON_spec_uint64 ("requirement_row",
&dr.details.accepted.requirement_row), &dr.details.accepted.requirement_row),
&no_legi), &no_legi),
GNUNET_JSON_spec_uint32 ("aml_decision",
&state32),
GNUNET_JSON_spec_bool ("kyc_ok", GNUNET_JSON_spec_bool ("kyc_ok",
&dr.details.accepted.kyc_ok), &dr.details.accepted.kyc_ok),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
@ -199,6 +202,8 @@ handle_deposit_wtid_finished (void *cls,
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break; break;
} }
dr.details.accepted.aml_decision
= (enum TALER_AmlDecisionState) state32;
if (no_legi) if (no_legi)
dr.details.accepted.requirement_row = 0; dr.details.accepted.requirement_row = 0;
dwh->cb (dwh->cb_cls, dwh->cb (dwh->cb_cls,