-more work on extended fakebank API

This commit is contained in:
Christian Grothoff 2022-08-15 20:23:02 +02:00
parent 82e11b4d93
commit f76f645732
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
2 changed files with 372 additions and 37 deletions

@ -1 +1 @@
Subproject commit 1a8af54b491e8300287eb7afb08ba22b91107f9a
Subproject commit e340b038e3a5ae3fbb87a68b534bd2646df5e6f0

View File

@ -118,6 +118,60 @@ struct LongPoller
*/
struct Transaction;
/**
* Information we keep per withdraw operation.
*/
struct WithdrawalOperation
{
/**
* Unique (random) operation ID.
*/
struct GNUNET_ShortHashCode wopid;
/**
* Debited account.
*/
struct Account *debit_account;
/**
* Target exchange account, or NULL if unknown.
*/
char *exchange_account;
/**
* Resulting transaction, if any. Otherwise NULL.
*/
struct Transaction *transaction;
/**
* Amount transferred.
*/
struct TALER_Amount amount;
/**
* Public key of the reserve, wire transfer subject.
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* Was the withdrawal aborted?
*/
bool aborted;
/**
* Did the bank confirm the withdrawal?
*/
bool confirmation_done;
/**
* Is @e reserve_pub initialized?
*/
bool selection_done;
};
/**
* Per account information.
*/
@ -365,6 +419,13 @@ struct TALER_FAKEBANK_Handle
*/
struct GNUNET_CONTAINER_MultiPeerMap *rpubs;
/**
* Hashmap of short hashes (wopids) to
* `struct WithdrawalOperation`.
* Used to lookup withdrawal operations.
*/
struct GNUNET_CONTAINER_MultiShortmap *wops;
/**
* Lock for accessing @a rpubs map.
*/
@ -481,6 +542,35 @@ static void
run_mhd (void *cls);
/**
* Find withdrawal operation @a wopid in @a h.
*
* @param h fakebank handle
* @param wopid withdrawal operation ID as a string
* @return NULL if operation was not found
*/
static struct WithdrawalOperation *
lookup_withdrawal_operation (struct TALER_FAKEBANK_Handle *h,
const char *wopid)
{
struct GNUNET_ShortHashCode sh;
if (NULL == h->wops)
return NULL;
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (wopid,
strlen (wopid),
&sh,
sizeof (sh)))
{
GNUNET_break_op (0);
return NULL;
}
return GNUNET_CONTAINER_multishortmap_get (h->wops,
&sh);
}
/**
* Trigger the @a lp. Frees associated resources,
* except the entry of @a lp in the timeout heap.
@ -1268,7 +1358,14 @@ TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h)
}
static int
/**
* Helper function to free memory when finished.
*
* @param cls NULL
* @param key key of the account to free (ignored)
* @param val a `struct Account` to free.
*/
static enum GNUNET_GenericReturnValue
free_account (void *cls,
const struct GNUNET_HashCode *key,
void *val)
@ -1285,6 +1382,28 @@ free_account (void *cls,
}
/**
* Helper function to free memory when finished.
*
* @param cls NULL
* @param key key of the operation to free (ignored)
* @param val a `struct WithdrawalOperation *` to free.
*/
static enum GNUNET_GenericReturnValue
free_withdraw_op (void *cls,
const struct GNUNET_ShortHashCode *key,
void *val)
{
struct WithdrawalOperation *wo = val;
(void) cls;
(void) key;
GNUNET_free (wo->exchange_account);
GNUNET_free (wo);
return GNUNET_OK;
}
void
TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h)
{
@ -1365,6 +1484,13 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h)
NULL);
GNUNET_CONTAINER_multihashmap_destroy (h->accounts);
}
if (NULL != h->wops)
{
GNUNET_CONTAINER_multishortmap_iterate (h->wops,
&free_withdraw_op,
NULL);
GNUNET_CONTAINER_multishortmap_destroy (h->wops);
}
GNUNET_CONTAINER_multihashmap_destroy (h->uuid_map);
GNUNET_CONTAINER_multipeermap_destroy (h->rpubs);
GNUNET_CONTAINER_heap_destroy (h->lp_heap);
@ -2530,27 +2656,42 @@ get_withdrawal_operation (struct TALER_FAKEBANK_Handle *h,
struct GNUNET_TIME_Relative lp,
void **con_cls)
{
// FIXME: check if ready, if so, return reply.
struct WithdrawalOperation *wo;
if ( (NULL != *con_cls) ||
(GNUNET_TIME_relative_is_zero (lp)) )
wo = lookup_withdrawal_operation (h,
wopid);
if (NULL == wo)
{
// FIXME: timeout, return with negative status
struct TALER_Amount amount;
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_TRANSACTION_NOT_FOUND,
wopid);
}
if ( (NULL != *con_cls) ||
(GNUNET_TIME_relative_is_zero (lp)) ||
wo->confirmation_done ||
wo->aborted)
{
json_t *wt;
wt = json_array ();
GNUNET_assert (NULL != wt);
GNUNET_assert (0 ==
json_array_append_new (wt,
json_string ("x-taler-bank")));
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_bool ("aborted",
false),
wo->aborted),
GNUNET_JSON_pack_bool ("selection_done",
false),
wo->selection_done),
GNUNET_JSON_pack_bool ("transfer_done",
false),
wo->confirmation_done),
TALER_JSON_pack_amount ("amount",
&amount),
&wo->amount),
GNUNET_JSON_pack_array_steal ("wire_types",
json_array ()));
wt));
}
// FIXME: needs variant of 'start_lp()'
@ -2576,18 +2717,49 @@ do_post_withdrawal (struct TALER_FAKEBANK_Handle *h,
struct MHD_Connection *connection,
const char *wopid,
const struct TALER_ReservePublicKeyP *reserve_pub,
const void *exchange_url)
const char *exchange_url)
{
GNUNET_break (0); // FIXME: not implemented!
struct WithdrawalOperation *wo;
wo = lookup_withdrawal_operation (h,
wopid);
if (NULL == wo)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_TRANSACTION_NOT_FOUND,
wopid);
}
if ( (wo->selection_done) &&
(0 != GNUNET_memcmp (&wo->reserve_pub,
reserve_pub)) )
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_CONFLICT,
TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT,
NULL);
}
// FIXME: check if reserve_pub is known. If so:
if (0)
{
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_bool ("transfer_done",
true));
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_CONFLICT,
TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT,
NULL);
}
return MHD_NO;
wo->reserve_pub = *reserve_pub;
GNUNET_free (wo->exchange_account); // FIXME: or conflict if changed?
wo->exchange_account = GNUNET_strdup ("FIXME"); // we have 'exchange_url', how is this useful?
wo->selection_done = true;
GNUNET_break (0); // FIXME: not implemented!
// FIXME: do we auto-confirm? Or do we want to allow aborts?
wo->confirmation_done = true;
// FIXME: trigger transfer? but we need the exchange account for that!
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_bool ("transfer_done",
wo->confirmation_done));
}
@ -2790,7 +2962,19 @@ get_account_access (struct TALER_FAKEBANK_Handle *h,
const char *account_name,
void **con_cls)
{
struct TALER_Amount amount; // FIXME: balance...
struct Account *acc;
acc = lookup_account (h,
account_name,
NULL);
if (NULL == acc)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_UNKNOWN_ACCOUNT,
account_name);
}
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_OK,
@ -2800,9 +2984,11 @@ get_account_access (struct TALER_FAKEBANK_Handle *h,
"balance",
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("credit_debit_indicator",
"credit"),
acc->is_negative
? "debit"
: "credit"),
TALER_JSON_pack_amount ("amount",
&amount))));
&acc->balance))));
}
@ -2824,19 +3010,55 @@ get_account_withdrawals_access (struct TALER_FAKEBANK_Handle *h,
const char *withdrawal_id,
void **con_cls)
{
struct TALER_Amount amount; // FIXME: balance...
struct WithdrawalOperation *wo;
struct Account *acc;
wo = lookup_withdrawal_operation (h,
withdrawal_id);
if (NULL == wo)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_TRANSACTION_NOT_FOUND,
withdrawal_id);
}
acc = lookup_account (h,
account_name,
NULL);
if (NULL == acc)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_UNKNOWN_ACCOUNT,
account_name);
}
if (wo->debit_account != acc)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_TRANSACTION_NOT_FOUND,
account_name);
}
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_string ("paytoUri",
"payto://FIXME"),
GNUNET_JSON_pack_object_steal (
"balance",
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("credit_debit_indicator",
"credit"),
TALER_JSON_pack_amount ("amount",
&amount))));
GNUNET_JSON_pack_bool ("aborted",
wo->aborted),
GNUNET_JSON_pack_bool ("selection_done",
wo->selection_done),
GNUNET_JSON_pack_bool ("transfer_done",
wo->confirmation_done),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("selected_exchange_account",
wo->exchange_account)),
GNUNET_JSON_pack_allow_null (
wo->selection_done
? GNUNET_JSON_pack_data_auto ("selected_reserve_pub",
&wo->reserve_pub)
: GNUNET_JSON_pack_string ("selected_reserve_pub",
NULL)),
TALER_JSON_pack_amount ("amount",
&wo->amount));
}
@ -2855,9 +3077,47 @@ do_post_account_withdrawals_access (struct TALER_FAKEBANK_Handle *h,
const char *account_name,
const struct TALER_Amount *amount)
{
GNUNET_break (0); // FIXME!
struct Account *acc;
struct WithdrawalOperation *wo;
return MHD_NO;
acc = lookup_account (h,
account_name,
NULL);
if (NULL == acc)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_UNKNOWN_ACCOUNT,
account_name);
}
wo = GNUNET_new (struct WithdrawalOperation);
wo->debit_account = acc;
wo->amount = *amount;
if (NULL == h->wops)
{
h->wops = GNUNET_CONTAINER_multishortmap_create (32,
GNUNET_YES);
}
while (1)
{
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
&wo->wopid,
sizeof (wo->wopid));
if (GNUNET_OK ==
GNUNET_CONTAINER_multishortmap_put (h->wops,
&wo->wopid,
wo,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
break;
}
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_OK,
GNUNET_JSON_pack_string ("taler_withdraw_uri",
"taler://withdraw/FIXME"),
GNUNET_JSON_pack_data_auto ("withdrawal_id",
&wo->wopid));
}
@ -2957,7 +3217,44 @@ access_withdrawals_abort (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size,
void **con_cls)
{
// fIXME: actual abort logic here...
struct WithdrawalOperation *wo;
struct Account *acc;
wo = lookup_withdrawal_operation (h,
withdrawal_id);
if (NULL == wo)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_TRANSACTION_NOT_FOUND,
withdrawal_id);
}
acc = lookup_account (h,
account_name,
NULL);
if (NULL == acc)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_UNKNOWN_ACCOUNT,
account_name);
}
if (wo->debit_account != acc)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_TRANSACTION_NOT_FOUND,
account_name);
}
if (wo->confirmation_done)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_CONFLICT,
TALER_EC_BANK_ABORT_CONFIRM_CONFLICT,
account_name);
}
wo->aborted = true;
// FIXME: resume long-pollers here...
return TALER_MHD_reply_json (connection,
json_object (),
MHD_HTTP_OK);
@ -2985,7 +3282,45 @@ access_withdrawals_confirm (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size,
void **con_cls)
{
// FIXME: actual confirm logic here...
struct WithdrawalOperation *wo;
struct Account *acc;
wo = lookup_withdrawal_operation (h,
withdrawal_id);
if (NULL == wo)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_TRANSACTION_NOT_FOUND,
withdrawal_id);
}
acc = lookup_account (h,
account_name,
NULL);
if (NULL == acc)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_UNKNOWN_ACCOUNT,
account_name);
}
if (wo->debit_account != acc)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_TRANSACTION_NOT_FOUND,
account_name);
}
if (wo->aborted)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_CONFLICT,
TALER_EC_BANK_CONFIRM_ABORT_CONFLICT,
account_name);
}
wo->confirmation_done = true;
// FIXME: resume long-pollers here...
// FIXME: trigger transaction here?
return TALER_MHD_reply_json (connection,
json_object (),
MHD_HTTP_OK);