From 5a18e955ebd663a6e1318378002a6368a7c07566 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 4 Feb 2023 21:54:47 +0100 Subject: [PATCH] -fix AML decision update logic and history fetch logic --- .../taler-exchange-httpd_aml-decision.c | 5 ++- .../taler-exchange-httpd_aml-decisions-get.c | 15 ++++---- src/exchangedb/0003-aml_history.sql | 2 +- src/exchangedb/pg_select_aml_process.c | 8 ++-- src/include/taler_exchange_service.h | 9 ++++- src/include/taler_testing_lib.h | 18 +++++++++ src/lib/exchange_api_lookup_aml_decisions.c | 31 +++++++++++++--- src/testing/Makefile.am | 1 + src/testing/test_kyc_api.c | 37 +++++++++++++++++++ 9 files changed, 105 insertions(+), 21 deletions(-) diff --git a/src/exchange/taler-exchange-httpd_aml-decision.c b/src/exchange/taler-exchange-httpd_aml-decision.c index 16dc0d965..56935df55 100644 --- a/src/exchange/taler-exchange-httpd_aml-decision.c +++ b/src/exchange/taler-exchange-httpd_aml-decision.c @@ -119,7 +119,7 @@ TEH_handler_post_aml_decision ( if (0 == --retries_left) break; } while (GNUNET_DB_STATUS_SOFT_ERROR == qs); - if (qs < 0) + if (qs <= 0) { GNUNET_break (0); return TALER_MHD_reply_with_error (connection, @@ -129,6 +129,7 @@ TEH_handler_post_aml_decision ( } if (invalid_officer) { + GNUNET_break_op (0); return TALER_MHD_reply_with_error ( connection, MHD_HTTP_FORBIDDEN, @@ -136,7 +137,7 @@ TEH_handler_post_aml_decision ( NULL); } if (GNUNET_TIME_timestamp_cmp (last_date, - >, + >=, decision_time)) { GNUNET_break_op (0); diff --git a/src/exchange/taler-exchange-httpd_aml-decisions-get.c b/src/exchange/taler-exchange-httpd_aml-decisions-get.c index ad160b821..0183ac3b8 100644 --- a/src/exchange/taler-exchange-httpd_aml-decisions-get.c +++ b/src/exchange/taler-exchange-httpd_aml-decisions-get.c @@ -63,10 +63,10 @@ record_cb ( GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_auto ("h_payto", h_payto), - TALER_JSON_pack_amount ("threshold", - threshold), GNUNET_JSON_pack_int64 ("current_state", status), + TALER_JSON_pack_amount ("threshold", + threshold), GNUNET_JSON_pack_int64 ("rowid", row_id) ))); @@ -98,8 +98,8 @@ TEH_handler_aml_decisions_get ( else if (0 == strcmp (state_str, "frozen")) decision = TALER_AML_FROZEN; - if (0 == strcmp (state_str, - "normal")) + else if (0 == strcmp (state_str, + "normal")) decision = TALER_AML_NORMAL; else { @@ -172,10 +172,11 @@ TEH_handler_aml_decisions_get ( qs = TEH_plugin->select_aml_process (TEH_plugin->cls, decision, start, - delta > 0, GNUNET_MIN (MAX_RECORDS, - delta > 0 ? delta : - -delta), + delta > 0 + ? delta + : -delta), + delta > 0, &record_cb, records); switch (qs) diff --git a/src/exchangedb/0003-aml_history.sql b/src/exchangedb/0003-aml_history.sql index 1c737265b..36c0b3865 100644 --- a/src/exchangedb/0003-aml_history.sql +++ b/src/exchangedb/0003-aml_history.sql @@ -26,7 +26,7 @@ BEGIN PERFORM create_partitioned_table( 'CREATE TABLE IF NOT EXISTS %I' '(aml_history_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY' - ',h_payto BYTEA PRIMARY KEY CHECK (LENGTH(h_payto)=32)' + ',h_payto BYTEA CHECK (LENGTH(h_payto)=32)' ',new_threshold_val INT8 NOT NULL DEFAULT(0)' ',new_threshold_frac INT4 NOT NULL DEFAULT(0)' ',new_status INT4 NOT NULL DEFAULT(0)' diff --git a/src/exchangedb/pg_select_aml_process.c b/src/exchangedb/pg_select_aml_process.c index 6ee0dbeb9..5df5fe657 100644 --- a/src/exchangedb/pg_select_aml_process.c +++ b/src/exchangedb/pg_select_aml_process.c @@ -140,25 +140,25 @@ TEH_PG_select_aml_process ( "SELECT" " aml_status_serial_id" ",h_payto" - ",threshold_var" + ",threshold_val" ",threshold_frac" ",status" " FROM aml_status" " WHERE aml_status_serial_id > $2" " AND status = $1" - " ORDER BY aml_status_serial_id INC" + " ORDER BY aml_status_serial_id ASC" " LIMIT $3"); PREPARE (pg, "select_aml_process_dec", "SELECT" " aml_status_serial_id" ",h_payto" - ",threshold_var" + ",threshold_val" ",threshold_frac" ",status" " FROM aml_status" " WHERE aml_status_serial_id < $2" - " AND $1 = status & $1" + " AND status = $1" " ORDER BY aml_status_serial_id DESC" " LIMIT $3"); qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 2d57b6530..bfdc062b5 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -4305,15 +4305,20 @@ TALER_EXCHANGE_management_update_aml_officer_cancel ( struct TALER_EXCHANGE_AmlDecisionSummary { /** - * When was the last decision made. + * What is the current monthly threshold. */ - struct GNUNET_TIME_Timestamp last_decision_time; + struct TALER_Amount threshold; /** * Account the decision was made for. */ struct TALER_PaytoHashP h_payto; + /** + * RowID of this decision. + */ + uint64_t rowid; + /** * Current decision state. */ diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 940233232..cf4279514 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -2774,6 +2774,24 @@ TALER_TESTING_cmd_check_aml_decision ( unsigned int expected_http_status); +/** + * Fetch AML decisions. + * + * @param label command label + * @param ref_officer command that previously created an + * officer + * @param filter AML state to filter by + * @param expected_http_status expected HTTP response status + * @return the command + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_aml_decisions ( + const char *label, + const char *ref_officer, + enum TALER_AmlDecisionState filter, + unsigned int expected_http_status); + + /* *** Generic trait logic for implementing traits ********* */ diff --git a/src/lib/exchange_api_lookup_aml_decisions.c b/src/lib/exchange_api_lookup_aml_decisions.c index 3b1db4556..f8a1d7fa3 100644 --- a/src/lib/exchange_api_lookup_aml_decisions.c +++ b/src/lib/exchange_api_lookup_aml_decisions.c @@ -82,12 +82,14 @@ parse_aml_decisions (const json_t *decisions, struct TALER_EXCHANGE_AmlDecisionSummary *decision = &decision_ar[idx]; uint32_t state32; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_timestamp ("last_decision_time", - &decision->last_decision_time), GNUNET_JSON_spec_fixed_auto ("h_payto", &decision->h_payto), GNUNET_JSON_spec_uint32 ("current_state", &state32), + TALER_JSON_spec_amount_any ("threshold", + &decision->threshold), + GNUNET_JSON_spec_uint64 ("rowid", + &decision->rowid), GNUNET_JSON_spec_end () }; @@ -196,6 +198,8 @@ handle_lookup_finished (void *cls, GNUNET_assert (NULL == lh->decisions_cb); TALER_EXCHANGE_lookup_aml_decisions_cancel (lh); return; + case MHD_HTTP_NO_CONTENT: + break; case MHD_HTTP_BAD_REQUEST: lr.hr.ec = TALER_JSON_get_error_code (j); lr.hr.hint = TALER_JSON_get_error_hint (j); @@ -292,9 +296,26 @@ TALER_EXCHANGE_lookup_aml_decisions ( lh = GNUNET_new (struct TALER_EXCHANGE_LookupAmlDecisions); lh->decisions_cb = cb; lh->decisions_cb_cls = cb_cls; - lh->url = TALER_url_join (exchange_url, - arg_str, - NULL); + { + char delta_s[24]; + char start_s[24]; + + GNUNET_snprintf (delta_s, + sizeof (delta_s), + "%d", + delta); + GNUNET_snprintf (start_s, + sizeof (start_s), + "%llu", + (unsigned long long) start); + lh->url = TALER_url_join (exchange_url, + arg_str, + "delta", + delta_s, + "start", + start_s, + NULL); + } if (NULL == lh->url) { GNUNET_free (lh); diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am index 242eda1e5..38a3d549f 100644 --- a/src/testing/Makefile.am +++ b/src/testing/Makefile.am @@ -56,6 +56,7 @@ libtalertesting_la_SOURCES = \ testing_api_cmd_batch_withdraw.c \ testing_api_cmd_change_auth.c \ testing_api_cmd_check_aml_decision.c \ + testing_api_cmd_check_aml_decisions.c \ testing_api_cmd_check_keys.c \ testing_api_cmd_common.c \ testing_api_cmd_contract_get.c \ diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c index 517138530..feeed3c78 100644 --- a/src/testing/test_kyc_api.c +++ b/src/testing/test_kyc_api.c @@ -421,6 +421,18 @@ run (void *cls, "Peter Falk", true, false), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-none-normal", + "create-aml-officer-1", + TALER_AML_NORMAL, + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-none-pending", + "create-aml-officer-1", + TALER_AML_PENDING, + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-none-frozen", + "create-aml-officer-1", + TALER_AML_FROZEN, + MHD_HTTP_NO_CONTENT), TALER_TESTING_cmd_sleep ("sleep-1a", 1), TALER_TESTING_cmd_set_officer ("create-aml-officer-1-disable", @@ -457,12 +469,37 @@ run (void *cls, "party time", TALER_AML_NORMAL, MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-normal", + "create-aml-officer-1", + TALER_AML_NORMAL, + MHD_HTTP_OK), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-zero-frozen", + "create-aml-officer-1", + TALER_AML_FROZEN, + MHD_HTTP_NO_CONTENT), TALER_TESTING_cmd_check_aml_decision ("check-aml-decision", "create-aml-officer-1", "aml-decide", MHD_HTTP_OK), TALER_TESTING_cmd_sleep ("sleep-1c", 1), + TALER_TESTING_cmd_take_aml_decision ("aml-decide-freeze", + "create-aml-officer-1", + "wallet-trigger-kyc-for-aml", + "EUR:1000", + "party over", + TALER_AML_FROZEN, + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-frozen", + "create-aml-officer-1", + TALER_AML_FROZEN, + MHD_HTTP_OK), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-zero-normal", + "create-aml-officer-1", + TALER_AML_NORMAL, + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_sleep ("sleep-1d", + 1), TALER_TESTING_cmd_set_officer ("create-aml-officer-1-disable", "create-aml-officer-1", "Peter Falk",