address FIXMEs in bank service API

This commit is contained in:
Christian Grothoff 2023-06-04 14:29:15 +02:00
parent 0ad3de938e
commit 9e7d3f9065
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
7 changed files with 194 additions and 161 deletions

View File

@ -74,25 +74,25 @@ handle_admin_add_incoming_finished (void *cls,
const void *response)
{
struct TALER_BANK_AdminAddIncomingHandle *aai = cls;
uint64_t row_id = UINT64_MAX;
struct GNUNET_TIME_Timestamp timestamp;
enum TALER_ErrorCode ec;
const json_t *j = response;
struct TALER_BANK_AdminAddIncomingResponse ir = {
.http_status = response_code,
.response = response
};
aai->job = NULL;
timestamp = GNUNET_TIME_UNIT_FOREVER_TS;
switch (response_code)
{
case 0:
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("row_id",
&row_id),
&ir.details.ok.serial_id),
GNUNET_JSON_spec_timestamp ("timestamp",
&timestamp),
&ir.details.ok.timestamp),
GNUNET_JSON_spec_end ()
};
@ -102,42 +102,41 @@ handle_admin_add_incoming_finished (void *cls,
NULL, NULL))
{
GNUNET_break_op (0);
response_code = 0;
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
ir.http_status = 0;
ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
ec = TALER_EC_NONE;
}
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the bank is buggy
(or API version conflict); just pass JSON reply to the application */
GNUNET_break_op (0);
ec = TALER_JSON_get_error_code (j);
ir.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_FORBIDDEN:
/* Access denied */
ec = TALER_JSON_get_error_code (j);
ir.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_UNAUTHORIZED:
/* Nothing really to verify, bank says the password is invalid; we should
pass the JSON reply to the application */
ec = TALER_JSON_get_error_code (j);
ir.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, maybe account really does not exist.
We should pass the JSON reply to the application */
ec = TALER_JSON_get_error_code (j);
ir.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_CONFLICT:
/* Nothing to verify, we used the same wire subject
twice? */
ec = TALER_JSON_get_error_code (j);
ir.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
ec = TALER_JSON_get_error_code (j);
ir.ec = TALER_JSON_get_error_code (j);
break;
default:
/* unexpected response code */
@ -145,15 +144,11 @@ handle_admin_add_incoming_finished (void *cls,
"Unexpected response code %u\n",
(unsigned int) response_code);
GNUNET_break (0);
ec = TALER_JSON_get_error_code (j);
ir.ec = TALER_JSON_get_error_code (j);
break;
}
aai->cb (aai->cb_cls,
response_code,
ec,
row_id,
timestamp,
j);
&ir);
TALER_BANK_admin_add_incoming_cancel (aai);
}

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2015--2020 Taler Systems SA
Copyright (C) 2015--2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -158,23 +158,24 @@ handle_transfer_finished (void *cls,
{
struct TALER_BANK_TransferHandle *th = cls;
const json_t *j = response;
uint64_t row_id = UINT64_MAX;
struct GNUNET_TIME_Timestamp timestamp = GNUNET_TIME_UNIT_FOREVER_TS;
enum TALER_ErrorCode ec;
struct TALER_BANK_TransferResponse tr = {
.http_status = response_code,
.response = j
};
th->job = NULL;
switch (response_code)
{
case 0:
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
tr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("row_id",
&row_id),
&tr.details.ok.row_id),
GNUNET_JSON_spec_timestamp ("timestamp",
&timestamp),
&tr.details.ok.timestamp),
GNUNET_JSON_spec_end ()
};
@ -184,39 +185,38 @@ handle_transfer_finished (void *cls,
NULL, NULL))
{
GNUNET_break_op (0);
response_code = 0;
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
tr.http_status = 0;
tr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
ec = TALER_EC_NONE;
}
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the bank is buggy
(or API version conflict); just pass JSON reply to the application */
GNUNET_break_op (0);
ec = TALER_JSON_get_error_code (j);
tr.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_UNAUTHORIZED:
/* Nothing really to verify, bank says our credentials are
invalid. We should pass the JSON reply to the application. */
ec = TALER_JSON_get_error_code (j);
tr.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, endpoint wrong -- could be user unknown */
ec = TALER_JSON_get_error_code (j);
tr.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_CONFLICT:
/* Nothing really to verify. Server says we used the same transfer request
UID before, but with different details. Should not happen if the user
properly used #TALER_BANK_prepare_transfer() and our PRNG is not
broken... */
ec = TALER_JSON_get_error_code (j);
tr.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
ec = TALER_JSON_get_error_code (j);
tr.ec = TALER_JSON_get_error_code (j);
break;
default:
/* unexpected response code */
@ -224,14 +224,11 @@ handle_transfer_finished (void *cls,
"Unexpected response code %u\n",
(unsigned int) response_code);
GNUNET_break (0);
ec = TALER_JSON_get_error_code (j);
tr.ec = TALER_JSON_get_error_code (j);
break;
}
th->cb (th->cb_cls,
response_code,
ec,
row_id,
timestamp);
&tr);
TALER_BANK_transfer_cancel (th);
}

View File

@ -357,34 +357,28 @@ execute_debit_history (void)
* execution.
*
* @param cls closure
* @param response_code HTTP status code
* @param ec taler error code
* @param row_id unique ID of the wire transfer in the bank's records
* @param timestamp when did the transaction go into effect
* @param tr response details
*/
static void
confirmation_cb (void *cls,
unsigned int response_code,
enum TALER_ErrorCode ec,
uint64_t row_id,
struct GNUNET_TIME_Timestamp timestamp)
const struct TALER_BANK_TransferResponse *tr)
{
(void) cls;
eh = NULL;
if (MHD_HTTP_OK != response_code)
if (MHD_HTTP_OK != tr->http_status)
{
fprintf (stderr,
"The wire transfer didn't execute correctly (%u/%d).\n",
response_code,
ec);
tr->http_status,
tr->ec);
GNUNET_SCHEDULER_shutdown ();
return;
}
fprintf (stdout,
"Wire transfer #%llu executed successfully at %s.\n",
(unsigned long long) row_id,
GNUNET_TIME_timestamp2s (timestamp));
(unsigned long long) tr->details.ok.row_id,
GNUNET_TIME_timestamp2s (tr->details.ok.timestamp));
global_ret = 0;
GNUNET_SCHEDULER_shutdown ();
}
@ -464,39 +458,29 @@ execute_wire_transfer (void)
* Function called with the result of the operation.
*
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the bank's reply is bogus (fails to follow the protocol)
* @param ec detailed error code
* @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
* @param timestamp timestamp when the transaction got settled at the bank.
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON
* @param air response details
*/
static void
res_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
uint64_t serial_id,
struct GNUNET_TIME_Timestamp timestamp,
const json_t *json)
const struct TALER_BANK_AdminAddIncomingResponse *air)
{
(void) cls;
(void) timestamp;
op = NULL;
switch (ec)
switch (air->http_status)
{
case TALER_EC_NONE:
case MHD_HTTP_OK:
global_ret = 0;
fprintf (stdout,
"%llu\n",
(unsigned long long) serial_id);
(unsigned long long) air->details.ok.serial_id);
break;
default:
fprintf (stderr,
"Operation failed with status code %u/%u\n",
(unsigned int) ec,
http_status);
if (NULL != json)
json_dumpf (json,
(unsigned int) air->ec,
air->http_status);
if (NULL != air->response)
json_dumpf (air->response,
stderr,
JSON_INDENT (2));
break;

View File

@ -406,25 +406,17 @@ batch_done (void)
* except for irrecoverable errors.
*
* @param cls `struct WirePrepareData` we are working on
* @param http_status_code #MHD_HTTP_OK on success
* @param ec taler error code
* @param row_id unique ID of the wire transfer in the bank's records
* @param wire_timestamp when did the transfer happen
* @param tr transfer response
*/
static void
wire_confirm_cb (void *cls,
unsigned int http_status_code,
enum TALER_ErrorCode ec,
uint64_t row_id,
struct GNUNET_TIME_Timestamp wire_timestamp)
const struct TALER_BANK_TransferResponse *tr)
{
struct WirePrepareData *wpd = cls;
enum GNUNET_DB_QueryStatus qs;
(void) row_id;
(void) wire_timestamp;
wpd->eh = NULL;
switch (http_status_code)
switch (tr->http_status)
{
case MHD_HTTP_OK:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@ -438,8 +430,8 @@ wire_confirm_cb (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire transaction %llu failed: %u/%d\n",
(unsigned long long) wpd->row_id,
http_status_code,
ec);
tr->http_status,
tr->ec);
qs = db_plugin->wire_prepare_data_mark_failed (db_plugin->cls,
wpd->row_id);
/* continued below */
@ -456,7 +448,7 @@ wire_confirm_cb (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Wire transfer %llu failed (%u), trying again\n",
(unsigned long long) wpd->row_id,
http_status_code);
tr->http_status);
wpd->eh = TALER_BANK_transfer (ctx,
wpd->wa->auth,
&wpd[1],
@ -468,8 +460,8 @@ wire_confirm_cb (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire transaction %llu failed: %u/%d\n",
(unsigned long long) wpd->row_id,
http_status_code,
ec);
tr->http_status,
tr->ec);
cleanup_wpd ();
db_plugin->rollback (db_plugin->cls);
global_ret = EXIT_FAILURE;
@ -479,8 +471,8 @@ wire_confirm_cb (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire transfer %llu failed: %u/%d\n",
(unsigned long long) wpd->row_id,
http_status_code,
ec);
tr->http_status,
tr->ec);
db_plugin->rollback (db_plugin->cls);
cleanup_wpd ();
global_ret = EXIT_FAILURE;

View File

@ -99,27 +99,65 @@ struct TALER_BANK_AuthenticationData
struct TALER_BANK_AdminAddIncomingHandle;
/**
* Response details for a history request.
*/
struct TALER_BANK_AdminAddIncomingResponse
{
/**
* HTTP status.
*/
unsigned int http_status;
/**
* Taler error code, #TALER_EC_NONE on success.
*/
enum TALER_ErrorCode ec;
/**
* Full response, NULL if body was not in JSON format.
*/
const json_t *response;
/**
* Details returned depending on the @e http_status.
*/
union
{
/**
* Details if status was #MHD_HTTP_OK
*/
struct
{
/**
* unique ID of the wire transfer in the bank's records
*/
uint64_t serial_id;
/**
* time when the transaction was made.
*/
struct GNUNET_TIME_Timestamp timestamp;
} ok;
} details;
};
/**
* Callbacks of this type are used to return the result of submitting
* a request to transfer funds to the exchange.
*
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the bank's reply is bogus (fails to follow the protocol)
* @param ec detailed error code
* @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
* @param timestamp time when the transaction was made.
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON
* @param air response details
*/
// FIXME: bad API
typedef void
(*TALER_BANK_AdminAddIncomingCallback) (
void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
uint64_t serial_id,
struct GNUNET_TIME_Timestamp timestamp,
const json_t *json);
const struct TALER_BANK_AdminAddIncomingResponse *air);
/**
@ -191,23 +229,65 @@ TALER_BANK_prepare_transfer (
struct TALER_BANK_TransferHandle;
/**
* Response details for a history request.
*/
struct TALER_BANK_TransferResponse
{
/**
* HTTP status.
*/
unsigned int http_status;
/**
* Taler error code, #TALER_EC_NONE on success.
*/
enum TALER_ErrorCode ec;
/**
* Full response, NULL if body was not in JSON format.
*/
const json_t *response;
/**
* Details returned depending on the @e http_status.
*/
union
{
/**
* Details if status was #MHD_HTTP_OK
*/
struct
{
/**
* unique ID of the wire transfer in the bank's records
*/
uint64_t row_id;
/**
* when did the transaction go into effect
*/
struct GNUNET_TIME_Timestamp timestamp;
} ok;
} details;
};
/**
* Function called with the result from the execute step.
*
* @param cls closure
* @param response_code HTTP status code
* @param ec taler error code
* @param row_id unique ID of the wire transfer in the bank's records
* @param timestamp when did the transaction go into effect
* @param tr response details
*/
// FIXME: bad API
typedef void
(*TALER_BANK_TransferCallback)(
void *cls,
unsigned int response_code,
enum TALER_ErrorCode ec,
uint64_t row_id,
struct GNUNET_TIME_Timestamp timestamp);
const struct TALER_BANK_TransferResponse *tr);
/**

View File

@ -194,28 +194,15 @@ do_retry (void *cls)
* acceptable.
*
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for
* successful status request; 0 if the exchange's reply is
* bogus (fails to follow the protocol)
* @param ec taler-specific error code, #TALER_EC_NONE on success
* @param serial_id unique ID of the wire transfer
* @param timestamp time stamp of the transaction made.
* @param json raw response
* @param air response details
*/
static void
confirmation_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
uint64_t serial_id,
struct GNUNET_TIME_Timestamp timestamp,
const json_t *json)
const struct TALER_BANK_AdminAddIncomingResponse *air)
{
struct AdminAddIncomingState *fts = cls;
struct TALER_TESTING_Interpreter *is = fts->is;
(void) json;
fts->reserve_history.details.in_details.timestamp = timestamp;
fts->reserve_history.details.in_details.wire_reference = serial_id;
fts->aih = NULL;
/**
* Test case not caring about the HTTP status code.
@ -237,17 +224,23 @@ confirmation_cb (void *cls,
TALER_TESTING_interpreter_next (is);
return;
}
if (http_status != fts->expected_http_status)
if (air->http_status != fts->expected_http_status)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
switch (http_status)
switch (air->http_status)
{
case MHD_HTTP_OK:
fts->serial_id = serial_id;
fts->timestamp = timestamp;
fts->reserve_history.details.in_details.timestamp
= air->details.ok.timestamp;
fts->reserve_history.details.in_details.wire_reference
= air->details.ok.serial_id;
fts->serial_id
= air->details.ok.serial_id;
fts->timestamp
= air->details.ok.timestamp;
TALER_TESTING_interpreter_next (is);
return;
case MHD_HTTP_UNAUTHORIZED:
@ -271,17 +264,17 @@ confirmation_cb (void *cls,
if (0 != fts->do_retry)
{
fts->do_retry--;
if ( (0 == http_status) ||
(TALER_EC_GENERIC_DB_SOFT_FAILURE == ec) ||
(MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
if ( (0 == air->http_status) ||
(TALER_EC_GENERIC_DB_SOFT_FAILURE == air->ec) ||
(MHD_HTTP_INTERNAL_SERVER_ERROR == air->http_status) )
{
GNUNET_log (
GNUNET_ERROR_TYPE_INFO,
"Retrying fakebank transfer failed with %u/%d\n",
http_status,
(int) ec);
air->http_status,
(int) air->ec);
/* on DB conflicts, do not use backoff */
if (TALER_EC_GENERIC_DB_SOFT_FAILURE == ec)
if (TALER_EC_GENERIC_DB_SOFT_FAILURE == air->ec)
fts->backoff = GNUNET_TIME_UNIT_ZERO;
else
fts->backoff = GNUNET_TIME_randomized_backoff (fts->backoff,
@ -299,8 +292,8 @@ confirmation_cb (void *cls,
GNUNET_break (0);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Fakebank returned HTTP status %u/%d\n",
http_status,
(int) ec);
air->http_status,
(int) air->ec);
TALER_TESTING_interpreter_fail (is);
}

View File

@ -163,39 +163,31 @@ do_retry (void *cls)
* acceptable.
*
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for
* successful status request; 0 if the exchange's reply is
* bogus (fails to follow the protocol)
* @param ec taler-specific error code, #TALER_EC_NONE on success
* @param serial_id unique ID of the wire transfer
* @param timestamp time stamp of the transaction made.
* @param tr response details
*/
static void
confirmation_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
uint64_t serial_id,
struct GNUNET_TIME_Timestamp timestamp)
const struct TALER_BANK_TransferResponse *tr)
{
struct TransferState *fts = cls;
struct TALER_TESTING_Interpreter *is = fts->is;
fts->weh = NULL;
if (MHD_HTTP_OK != http_status)
if (MHD_HTTP_OK != tr->http_status)
{
if (0 != fts->do_retry)
{
fts->do_retry--;
if ( (0 == http_status) ||
(TALER_EC_GENERIC_DB_SOFT_FAILURE == ec) ||
(MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
if ( (0 == tr->http_status) ||
(TALER_EC_GENERIC_DB_SOFT_FAILURE == tr->ec) ||
(MHD_HTTP_INTERNAL_SERVER_ERROR == tr->http_status) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Retrying transfer failed with %u/%d\n",
http_status,
(int) ec);
tr->http_status,
(int) tr->ec);
/* on DB conflicts, do not use backoff */
if (TALER_EC_GENERIC_DB_SOFT_FAILURE == ec)
if (TALER_EC_GENERIC_DB_SOFT_FAILURE == tr->ec)
fts->backoff = GNUNET_TIME_UNIT_ZERO;
else
fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff);
@ -210,14 +202,14 @@ confirmation_cb (void *cls,
GNUNET_break (0);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Bank returned HTTP status %u/%d\n",
http_status,
(int) ec);
tr->http_status,
(int) tr->ec);
TALER_TESTING_interpreter_fail (is);
return;
}
fts->serial_id = serial_id;
fts->timestamp = timestamp;
fts->serial_id = tr->details.ok.row_id;
fts->timestamp = tr->details.ok.timestamp;
TALER_TESTING_interpreter_next (is);
}