finish new withdraw command implementation

This commit is contained in:
Christian Grothoff 2018-01-21 16:27:58 +01:00
parent 6ba7747ac3
commit bba0ec72fa
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
5 changed files with 247 additions and 34 deletions

View File

@ -40,6 +40,8 @@ libtalertesting_la_LDFLAGS = \
-no-undefined -no-undefined
libtalertesting_la_SOURCES = \ libtalertesting_la_SOURCES = \
testing_api_cmd_fakebank_transfer.c \ testing_api_cmd_fakebank_transfer.c \
testing_api_cmd_withdraw.c \
testing_api_helpers.c \
testing_api_loop.c \ testing_api_loop.c \
testing_api_traits.c \ testing_api_traits.c \
testing_api_trait_blinding_key.c \ testing_api_trait_blinding_key.c \

View File

@ -1497,13 +1497,12 @@ static const struct TALER_EXCHANGE_DenomPublicKey *
find_pk (const struct TALER_EXCHANGE_Keys *keys, find_pk (const struct TALER_EXCHANGE_Keys *keys,
const struct TALER_Amount *amount) const struct TALER_Amount *amount)
{ {
unsigned int i;
struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_Absolute now;
struct TALER_EXCHANGE_DenomPublicKey *pk; struct TALER_EXCHANGE_DenomPublicKey *pk;
char *str; char *str;
now = GNUNET_TIME_absolute_get (); now = GNUNET_TIME_absolute_get ();
for (i=0;i<keys->num_denom_keys;i++) for (unsigned int i=0;i<keys->num_denom_keys;i++)
{ {
pk = &keys->denom_keys[i]; pk = &keys->denom_keys[i];
if ( (0 == TALER_amount_cmp (amount, if ( (0 == TALER_amount_cmp (amount,
@ -1514,7 +1513,7 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys,
} }
/* do 2nd pass to check if expiration times are to blame for failure */ /* do 2nd pass to check if expiration times are to blame for failure */
str = TALER_amount_to_string (amount); str = TALER_amount_to_string (amount);
for (i=0;i<keys->num_denom_keys;i++) for (unsigned int i=0;i<keys->num_denom_keys;i++)
{ {
pk = &keys->denom_keys[i]; pk = &keys->denom_keys[i];
if ( (0 == TALER_amount_cmp (amount, if ( (0 == TALER_amount_cmp (amount,

View File

@ -25,6 +25,7 @@
#include <gnunet/gnunet_curl_lib.h> #include <gnunet/gnunet_curl_lib.h>
#include "exchange_api_handle.h" #include "exchange_api_handle.h"
#include "taler_signatures.h" #include "taler_signatures.h"
#include "taler_testing_lib.h"
struct WithdrawState struct WithdrawState
@ -49,6 +50,16 @@ struct WithdrawState
*/ */
const struct TALER_EXCHANGE_DenomPublicKey *pk; const struct TALER_EXCHANGE_DenomPublicKey *pk;
/**
* Exchange we should use for the withdrawal.
*/
struct TALER_EXCHANGE_Handle *exchange;
/**
* Interpreter state (during command).
*/
struct TALER_TESTING_Interpreter *is;
/** /**
* Set (by the interpreter) to the exchange's signature over the * Set (by the interpreter) to the exchange's signature over the
* coin's public key. * coin's public key.
@ -65,34 +76,101 @@ struct WithdrawState
*/ */
struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh; struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
/**
* Expected HTTP response code to the request.
*/
unsigned int expected_response_code;
}; };
/** /**
* Runs the command. Note that upon return, the interpreter * Function called upon completion of our /reserve/withdraw request.
* will not automatically run the next command, as the command *
* may continue asynchronously in other scheduler tasks. Thus, * @param cls closure with the withdraw state
* the command must ensure to eventually call * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* #TALER_TESTING_interpreter_next() or * 0 if the exchange's reply is bogus (fails to follow the protocol)
* #TALER_TESTING_interpreter_fail(). * @param ec taler-specific error code, #TALER_EC_NONE on success
* * @param sig signature over the coin, NULL on error
* @param i interpreter state * @param full_response full response from the exchange (for logging, in case of errors)
*/ */
static void static void
withdraw_run (void *cls, reserve_withdraw_cb (void *cls,
struct TALER_TESTING_Interpreter *i) unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_DenominationSignature *sig,
const json_t *full_response)
{ {
struct WithdrawState *ws = cls; struct WithdrawState *ws = cls;
struct TALER_ReservePrivateKeyP rp; struct TALER_TESTING_Interpreter *is = ws->is;
struct TALER_TESTING_Command *create_reserve;
ws->wsh = NULL;
if (ws->expected_response_code != http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s\n",
http_status,
TALER_TESTING_interpreter_get_current_label (is));
json_dumpf (full_response,
stderr,
0);
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
switch (http_status)
{
case MHD_HTTP_OK:
if (NULL == sig)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
ws->sig.rsa_signature
= GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
break;
case MHD_HTTP_FORBIDDEN:
/* nothing to check */
break;
case MHD_HTTP_NOT_FOUND:
/* nothing to check */
break;
default:
/* Unsupported status code (by test harness) */
GNUNET_break (0);
break;
}
TALER_TESTING_interpreter_next (is);
}
/**
* Runs the command. Note that upon return, the interpreter
* will not automatically run the next command, as the command
* may continue asynchronously in other scheduler tasks. Thus,
* the command must ensure to eventually call
* #TALER_TESTING_interpreter_next() or
* #TALER_TESTING_interpreter_fail().
*
* @param is interpreter state
*/
static void
withdraw_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct WithdrawState *ws = cls;
struct TALER_ReservePrivateKeyP *rp;
const struct TALER_TESTING_Command *create_reserve;
create_reserve create_reserve
= TALER_TESTING_interpreter_lookup_command (i, = TALER_TESTING_interpreter_lookup_command (is,
ws->reserve_reference); ws->reserve_reference);
if (NULL == create_reserve) if (NULL == create_reserve)
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (i); TALER_TESTING_interpreter_fail (is);
return; return;
} }
if (GNUNET_OK != if (GNUNET_OK !=
@ -101,11 +179,24 @@ withdraw_run (void *cls,
&rp)) &rp))
{ {
GNUNET_break (0); GNUNET_break (0);
TALER_TESTING_interpreter_fail (i); TALER_TESTING_interpreter_fail (is);
return;
}
TALER_planchet_setup_random (&ws->ps);
ws->is = is;
ws->wsh
= TALER_EXCHANGE_reserve_withdraw (ws->exchange,
ws->pk,
rp,
&ws->ps,
&reserve_withdraw_cb,
ws);
if (NULL == ws->wsh)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return; return;
} }
// ... trigger withdraw
// ... eventually: TALER_TESTING_interpreter_next (i);
} }
@ -116,10 +207,25 @@ withdraw_run (void *cls,
* @param cls closure * @param cls closure
*/ */
static void static void
withdraw_cleanup (void *cls) withdraw_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{ {
struct WithdrawState *ws = cls; struct WithdrawState *ws = cls;
if (NULL != ws->wsh)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Command %s did not complete\n",
cmd->label);
TALER_EXCHANGE_reserve_withdraw_cancel (ws->wsh);
ws->wsh = NULL;
}
if (NULL != ws->sig.rsa_signature)
{
GNUNET_CRYPTO_rsa_signature_free (ws->sig.rsa_signature);
ws->sig.rsa_signature = NULL;
}
GNUNET_free (ws);
} }
@ -142,17 +248,15 @@ withdraw_traits (void *cls,
const char *selector) const char *selector)
{ {
struct WithdrawState *ws = cls; struct WithdrawState *ws = cls;
struct TALER_INTERPRETER_Trait traits[] = { struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_coin_priv (NULL /* only one coin */, TALER_TESTING_make_trait_coin_priv (NULL /* only one coin */,
&ws->ps.coin_priv), &ws->ps.coin_priv),
#if 0 TALER_TESTING_make_trait_blinding_key (NULL /* only one coin */,
TALER_TESTING_make_trait_coin_blinding_key (NULL /* only one coin */, &ws->ps.blinding_key),
&ws->ps.blinding_key), TALER_TESTING_make_trait_denom_pub (NULL /* only one coin */,
TALER_TESTING_make_trait_coin_denomination_key (NULL /* only one coin */, ws->pk),
ws->pk), TALER_TESTING_make_trait_denom_sig (NULL /* only one coin */,
TALER_TESTING_make_trait_coin_denomination_sig (NULL /* only one coin */, &ws->sig),
&ws->sig),
#endif
TALER_TESTING_trait_end () TALER_TESTING_trait_end ()
}; };
@ -169,15 +273,73 @@ withdraw_traits (void *cls,
*/ */
struct TALER_TESTING_Command struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_amount (const char *label, TALER_TESTING_cmd_withdraw_amount (const char *label,
struct TALER_EXCHANGE_Handle *exchange,
const char *reserve_reference, const char *reserve_reference,
const char *amount) const char *amount,
unsigned int expected_response_code)
{ {
struct TALER_TESTING_Command cmd; struct TALER_TESTING_Command cmd;
struct WithdrawState *ws; struct WithdrawState *ws;
ws = GNUNET_new (struct WithdrawState); ws = GNUNET_new (struct WithdrawState);
ws->reserve_reference = reserve_reference; ws->reserve_reference = reserve_reference;
// convert amount -> ws->amount;
if (GNUNET_OK !=
TALER_string_to_amount (amount,
&ws->amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse amount `%s' at %s\n",
amount,
label);
GNUNET_assert (0);
}
ws->pk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (exchange),
&ws->amount);
if (NULL == ws->pk)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to determine denomination key at %s\n",
label);
GNUNET_assert (0);
}
ws->expected_response_code = expected_response_code;
ws->exchange = exchange;
cmd.cls = ws;
cmd.label = label;
cmd.run = &withdraw_run;
cmd.cleanup = &withdraw_cleanup;
cmd.traits = &withdraw_traits;
return cmd;
}
/**
* Create withdraw command.
*
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_denomination (const char *label,
struct TALER_EXCHANGE_Handle *exchange,
const char *reserve_reference,
const struct TALER_EXCHANGE_DenomPublicKey *dk,
unsigned int expected_response_code)
{
struct TALER_TESTING_Command cmd;
struct WithdrawState *ws;
if (NULL == dk)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Denomination key not specified at %s\n",
label);
GNUNET_assert (0);
}
ws = GNUNET_new (struct WithdrawState);
ws->reserve_reference = reserve_reference;
ws->pk = dk;
ws->expected_response_code = expected_response_code;
ws->exchange = exchange;
cmd.cls = ws; cmd.cls = ws;
cmd.label = label; cmd.label = label;
cmd.run = &withdraw_run; cmd.run = &withdraw_run;

View File

@ -166,6 +166,18 @@ TALER_TESTING_cmd_end (void)
} }
/**
* Obtain current label.
*/
const char *
TALER_TESTING_interpreter_get_current_label (struct TALER_TESTING_Interpreter *is)
{
struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
return cmd->label;
}
/** /**
* Run the main interpreter loop that performs exchange operations. * Run the main interpreter loop that performs exchange operations.
* *

View File

@ -28,6 +28,21 @@
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include <microhttpd.h> #include <microhttpd.h>
/* ********************* Helper functions *********************** */
/**
* Find denomination key matching the given amount.
*
* @param keys array of keys to search
* @param amount coin value to look for
* @return NULL if no matching key was found
*/
const struct TALER_EXCHANGE_DenomPublicKey *
TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys,
const struct TALER_Amount *amount);
/* ******************* Generic interpreter logic ****************** */ /* ******************* Generic interpreter logic ****************** */
/** /**
@ -115,6 +130,18 @@ TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *i,
struct GNUNET_CURL_Context * struct GNUNET_CURL_Context *
TALER_TESTING_interpreter_get_context (struct TALER_TESTING_Interpreter *is); TALER_TESTING_interpreter_get_context (struct TALER_TESTING_Interpreter *is);
/**
* Obtain current label.
*/
const char *
TALER_TESTING_interpreter_get_current_label (struct TALER_TESTING_Interpreter *is);
/**
* Obtain main execution context for the main loop.
*/
struct GNUNET_CURL_Context *
TALER_TESTING_interpreter_get_context (struct TALER_TESTING_Interpreter *is);
/** /**
* Current command is done, run the next one. * Current command is done, run the next one.
@ -185,6 +212,17 @@ TALER_TESTING_cmd_withdraw_amount (const char *label,
/**
* Create withdraw command.
*
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_denomination (const char *label,
struct TALER_EXCHANGE_Handle *exchange,
const char *reserve_reference,
const struct TALER_EXCHANGE_DenomPublicKey *dk,
unsigned int expected_response_code);
/* ********************** Generic trait logic for implementing traits ******************* */ /* ********************** Generic trait logic for implementing traits ******************* */