This commit is contained in:
Christian Grothoff 2021-11-17 13:03:47 +01:00
parent 0f5fc95ecf
commit 6e86a3c43c
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
7 changed files with 1339 additions and 2162 deletions

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2021 Taler Systems SA Copyright (C) 2014-2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as it under the terms of the GNU General Public License as
@ -113,15 +113,22 @@ batch_cleanup (void *cls,
* @param index index number of the object to offer. * @param index index number of the object to offer.
* @return #GNUNET_OK on success. * @return #GNUNET_OK on success.
*/ */
static enum GNUNET_GenericReturnValue static int
batch_traits (void *cls, batch_traits (void *cls,
const void **ret, const void **ret,
const char *trait, const char *trait,
unsigned int index) unsigned int index)
{ {
#define CURRENT_CMD_INDEX 0
#define BATCH_INDEX 1
struct BatchState *bs = cls; struct BatchState *bs = cls;
struct TALER_TESTING_Trait traits[] = { struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_batch_cmds (&bs->batch), TALER_TESTING_make_trait_cmd
(CURRENT_CMD_INDEX, &bs->batch[bs->batch_ip]),
TALER_TESTING_make_trait_cmd
(BATCH_INDEX, bs->batch),
TALER_TESTING_trait_end () TALER_TESTING_trait_end ()
}; };
@ -133,6 +140,18 @@ batch_traits (void *cls,
} }
/**
* Create a "batch" command. Such command takes a
* end_CMD-terminated array of CMDs and executed them.
* Once it hits the end CMD, it passes the control
* to the next top-level CMD, regardless of it being
* another batch or ordinary CMD.
*
* @param label the command label.
* @param batch array of CMDs to execute.
*
* @return the command.
*/
struct TALER_TESTING_Command struct TALER_TESTING_Command
TALER_TESTING_cmd_batch (const char *label, TALER_TESTING_cmd_batch (const char *label,
struct TALER_TESTING_Command *batch) struct TALER_TESTING_Command *batch)
@ -166,29 +185,68 @@ TALER_TESTING_cmd_batch (const char *label,
} }
/**
* Advance internal pointer to next command.
*
* @param is interpreter state.
* @param cmd batch to advance
*/
void void
TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is) TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is,
struct TALER_TESTING_Command *par,
struct TALER_TESTING_Command *cmd)
{ {
struct BatchState *bs = is->commands[is->ip].cls; struct BatchState *bs = cmd->cls;
struct TALER_TESTING_Command *chld;
if (NULL == bs->batch[bs->batch_ip].label) if (NULL == bs->batch[bs->batch_ip].label)
{ {
is->commands[is->ip].finish_time = GNUNET_TIME_absolute_get (); if (NULL == par)
is->ip++; {
is->commands[is->ip].finish_time = GNUNET_TIME_absolute_get ();
is->ip++;
}
else
{
struct BatchState *ps = par->cls;
cmd->finish_time = GNUNET_TIME_absolute_get ();
ps->batch_ip++;
}
return; return;
} }
bs->batch[bs->batch_ip].finish_time = GNUNET_TIME_absolute_get (); chld = &bs->batch[bs->batch_ip];
bs->batch_ip++; if (TALER_TESTING_cmd_is_batch (chld))
{
TALER_TESTING_cmd_batch_next (is,
cmd,
chld);
}
else
{
bs->batch[bs->batch_ip].finish_time = GNUNET_TIME_absolute_get ();
bs->batch_ip++;
}
} }
bool /**
* Test if this command is a batch command.
*
* @return false if not, true if it is a batch command
*/
int
TALER_TESTING_cmd_is_batch (const struct TALER_TESTING_Command *cmd) TALER_TESTING_cmd_is_batch (const struct TALER_TESTING_Command *cmd)
{ {
return cmd->run == &batch_run; return cmd->run == &batch_run;
} }
/**
* Obtain what command the batch is at.
*
* @return cmd current batch command
*/
struct TALER_TESTING_Command * struct TALER_TESTING_Command *
TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd) TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd)
{ {
@ -199,6 +257,12 @@ TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd)
} }
/**
* Set what command the batch should be at.
*
* @param cmd current batch command
* @param new_ip where to move the IP
*/
void void
TALER_TESTING_cmd_batch_set_current (const struct TALER_TESTING_Command *cmd, TALER_TESTING_cmd_batch_set_current (const struct TALER_TESTING_Command *cmd,
unsigned int new_ip) unsigned int new_ip)

View File

@ -36,6 +36,49 @@
*/ */
static struct GNUNET_DISK_PipeHandle *sigpipe; static struct GNUNET_DISK_PipeHandle *sigpipe;
const struct TALER_TESTING_Command *
lookup_helper (const struct TALER_TESTING_Command *cmd,
const char *label)
{
#define BATCH_INDEX 1
struct TALER_TESTING_Command *batch;
struct TALER_TESTING_Command *current;
struct TALER_TESTING_Command *icmd;
const struct TALER_TESTING_Command *match;
current = TALER_TESTING_cmd_batch_get_current (cmd);
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_cmd (cmd,
BATCH_INDEX,
&batch));
/* We must do the loop forward, but we can find the last match */
match = NULL;
for (unsigned int j = 0;
NULL != (icmd = &batch[j])->label;
j++)
{
if (TALER_TESTING_cmd_is_batch (icmd))
{
const struct TALER_TESTING_Command *imatch;
imatch = lookup_helper (icmd,
label);
if (NULL != imatch)
match = imatch;
}
if ( (current != icmd) &&
(NULL != icmd->label) &&
(0 == strcmp (icmd->label,
label)) )
match = icmd;
if (current == icmd)
break;
}
return match;
}
/** /**
* Lookup command by label. * Lookup command by label.
* *
@ -66,30 +109,12 @@ TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
if (TALER_TESTING_cmd_is_batch (cmd)) if (TALER_TESTING_cmd_is_batch (cmd))
{ {
struct TALER_TESTING_Command **batch; const struct TALER_TESTING_Command *ret;
struct TALER_TESTING_Command *current;
struct TALER_TESTING_Command *icmd;
const struct TALER_TESTING_Command *match;
current = TALER_TESTING_cmd_batch_get_current (cmd); ret = lookup_helper (cmd,
GNUNET_assert (GNUNET_OK == label);
TALER_TESTING_get_trait_batch_cmds (cmd, if (NULL != ret)
&batch)); return ret;
/* We must do the loop forward, but we can find the last match */
match = NULL;
for (unsigned int j = 0;
NULL != (icmd = &(*batch)[j])->label;
j++)
{
if (current == icmd)
break; /* do not go past current command */
if ( (NULL != icmd->label) &&
(0 == strcmp (icmd->label,
label)) )
match = icmd;
}
if (NULL != match)
return match;
} }
} }
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -118,6 +143,15 @@ TALER_TESTING_interpreter_get_fakebank (struct TALER_TESTING_Interpreter *is)
} }
/**
* Run tests starting the "fakebank" first. The "fakebank"
* is a C minimalist version of the human-oriented Python bank,
* which is also part of the Taler project.
*
* @param is pointer to the interpreter state
* @param commands the list of commands to execute
* @param bank_url the url the fakebank is supposed to run on
*/
void void
TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is, TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is,
struct TALER_TESTING_Command *commands, struct TALER_TESTING_Command *commands,
@ -155,6 +189,9 @@ static void
interpreter_run (void *cls); interpreter_run (void *cls);
/**
* Current command is done, run the next one.
*/
void void
TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is) TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is)
{ {
@ -166,7 +203,9 @@ TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is)
return; /* ignore, we already failed! */ return; /* ignore, we already failed! */
if (TALER_TESTING_cmd_is_batch (cmd)) if (TALER_TESTING_cmd_is_batch (cmd))
{ {
TALER_TESTING_cmd_batch_next (is); TALER_TESTING_cmd_batch_next (is,
NULL,
cmd);
} }
else else
{ {
@ -189,6 +228,11 @@ TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is)
} }
/**
* Current command failed, clean up and fail the test case.
*
* @param is interpreter of the test
*/
void void
TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is) TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is)
{ {
@ -209,6 +253,11 @@ TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is)
} }
/**
* Create command array terminator.
*
* @return a end-command.
*/
struct TALER_TESTING_Command struct TALER_TESTING_Command
TALER_TESTING_cmd_end (void) TALER_TESTING_cmd_end (void)
{ {
@ -219,6 +268,9 @@ TALER_TESTING_cmd_end (void)
} }
/**
* Obtain current label.
*/
const char * const char *
TALER_TESTING_interpreter_get_current_label (struct TALER_TESTING_interpreter_get_current_label (struct
TALER_TESTING_Interpreter *is) TALER_TESTING_Interpreter *is)
@ -289,9 +341,8 @@ do_shutdown (void *cls)
for (unsigned int j = 0; for (unsigned int j = 0;
NULL != (cmd = &is->commands[j])->label; NULL != (cmd = &is->commands[j])->label;
j++) j++)
if (NULL != cmd->cleanup) cmd->cleanup (cmd->cls,
cmd->cleanup (cmd->cls, cmd);
cmd);
if (NULL != is->exchange) if (NULL != is->exchange)
{ {
@ -367,8 +418,17 @@ maint_child_death (void *cls)
enum GNUNET_OS_ProcessStatusType type; enum GNUNET_OS_ProcessStatusType type;
unsigned long code; unsigned long code;
while (TALER_TESTING_cmd_is_batch (cmd)) if (TALER_TESTING_cmd_is_batch (cmd))
cmd = TALER_TESTING_cmd_batch_get_current (cmd); {
struct TALER_TESTING_Command *batch_cmd;
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_cmd (cmd,
0,
&batch_cmd));
cmd = batch_cmd;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Got SIGCHLD for `%s'.\n", "Got SIGCHLD for `%s'.\n",
cmd->label); cmd->label);
@ -381,6 +441,7 @@ maint_child_death (void *cls)
sizeof (c))); sizeof (c)));
if (GNUNET_OK != if (GNUNET_OK !=
TALER_TESTING_get_trait_process (cmd, TALER_TESTING_get_trait_process (cmd,
0,
&processp)) &processp))
{ {
GNUNET_break (0); GNUNET_break (0);
@ -433,6 +494,12 @@ maint_child_death (void *cls)
} }
/**
* Wait until we receive SIGCHLD signal.
* Then obtain the process trait of the current
* command, wait on the the zombie and continue
* with the next command.
*/
void void
TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is) TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is)
{ {
@ -449,6 +516,16 @@ TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is)
} }
/**
* Run the testsuite. Note, CMDs are copied into
* the interpreter state because they are _usually_
* defined into the "run" method that returns after
* having scheduled the test interpreter.
*
* @param is the interpreter state
* @param commands the list of command to execute
* @param timeout how long to wait
*/
void void
TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is, TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
struct TALER_TESTING_Command *commands, struct TALER_TESTING_Command *commands,
@ -478,6 +555,15 @@ TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
} }
/**
* Run the testsuite. Note, CMDs are copied into
* the interpreter state because they are _usually_
* defined into the "run" method that returns after
* having scheduled the test interpreter.
*
* @param is the interpreter state
* @param commands the list of command to execute
*/
void void
TALER_TESTING_run (struct TALER_TESTING_Interpreter *is, TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
struct TALER_TESTING_Command *commands) struct TALER_TESTING_Command *commands)
@ -536,6 +622,16 @@ sighandler_child_death (void)
} }
/**
* "Canonical" cert_cb used when we are connecting to the
* Exchange.
*
* @param cls closure, typically, the "run" method containing
* all the commands to be run, and a closure for it.
* @param hr HTTP response details
* @param keys the exchange's keys.
* @param compat protocol compatibility information.
*/
void void
TALER_TESTING_cert_cb (void *cls, TALER_TESTING_cert_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr, const struct TALER_EXCHANGE_HttpResponse *hr,
@ -804,6 +900,25 @@ load_urls (struct TALER_TESTING_Interpreter *is)
} }
/**
* Install signal handlers plus schedules the main wrapper
* around the "run" method.
*
* @param main_cb the "run" method which contains all the
* commands.
* @param main_cb_cls a closure for "run", typically NULL.
* @param cfg configuration to use
* @param exchanged exchange process handle: will be put in the
* state as some commands - e.g. revoke - need to send
* signal to it, for example to let it know to reload the
* key state.. if NULL, the interpreter will run without
* trying to connect to the exchange first.
* @param exchange_connect #GNUNET_YES if the test should connect
* to the exchange, #GNUNET_NO otherwise
* @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
* non-GNUNET_OK codes are #GNUNET_SYSERR most of the
* times.
*/
int int
TALER_TESTING_setup (TALER_TESTING_Main main_cb, TALER_TESTING_setup (TALER_TESTING_Main main_cb,
void *main_cb_cls, void *main_cb_cls,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -102,7 +102,7 @@ struct TALER_CRYPTO_RsaKeyPurgeNotification
/** /**
* Hash of the public key of the purged RSA key. * Hash of the public key of the purged RSA key.
*/ */
struct TALER_DenominationHash h_denom_pub; struct GNUNET_HashCode h_denom_pub;
}; };
@ -125,7 +125,7 @@ struct TALER_CRYPTO_SignRequest
/** /**
* Hash of the public key of the RSA key to use for the signature. * Hash of the public key of the RSA key to use for the signature.
*/ */
struct TALER_DenominationHash h_denom_pub; struct GNUNET_HashCode h_denom_pub;
/* followed by message to sign */ /* followed by message to sign */
}; };
@ -149,7 +149,7 @@ struct TALER_CRYPTO_RevokeRequest
/** /**
* Hash of the public key of the revoked RSA key. * Hash of the public key of the revoked RSA key.
*/ */
struct TALER_DenominationHash h_denom_pub; struct GNUNET_HashCode h_denom_pub;
}; };

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
(C) 2020 Taler Systems SA (C) 2020, 2021 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -36,7 +36,7 @@
/** /**
* How many iterations of the successful signing test should we run * How many iterations of the successful signing test should we run
* during the benchmark phase? * during the test phase?
*/ */
#define NUM_SIGN_TESTS 3 #define NUM_SIGN_TESTS 3
@ -46,6 +46,11 @@
*/ */
#define NUM_SIGN_PERFS 100 #define NUM_SIGN_PERFS 100
/**
* How many parallel clients should we use for the parallel
* benchmark? (> 500 may cause problems with the max open FD number limit).
*/
#define NUM_CORES 8
/** /**
* Number of keys currently in #keys. * Number of keys currently in #keys.
@ -270,7 +275,8 @@ test_signing (struct TALER_CRYPTO_ExchangeSignHelper *esh)
* @return 0 on success * @return 0 on success
*/ */
static int static int
perf_signing (struct TALER_CRYPTO_ExchangeSignHelper *esh) perf_signing (struct TALER_CRYPTO_ExchangeSignHelper *esh,
const char *type)
{ {
struct GNUNET_CRYPTO_EccSignaturePurpose purpose = { struct GNUNET_CRYPTO_EccSignaturePurpose purpose = {
.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST), .purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST),
@ -303,8 +309,69 @@ perf_signing (struct TALER_CRYPTO_ExchangeSignHelper *esh)
delay); delay);
} /* for j */ } /* for j */
fprintf (stderr, fprintf (stderr,
"%u (sequential) signature operations took %s\n", "%u (%s) signature operations took %s\n",
(unsigned int) NUM_SIGN_TESTS, (unsigned int) NUM_SIGN_PERFS,
type,
GNUNET_STRINGS_relative_time_to_string (duration,
GNUNET_YES));
return 0;
}
/**
* Parallel signing logic.
*
* @param esh handle to the helper
* @return 0 on success
*/
static int
par_signing (struct GNUNET_CONFIGURATION_Handle *cfg)
{
struct GNUNET_TIME_Absolute start;
struct GNUNET_TIME_Relative duration;
pid_t pids[NUM_CORES];
struct TALER_CRYPTO_ExchangeSignHelper *esh;
memset (keys,
0,
sizeof (keys));
num_keys = 0;
start = GNUNET_TIME_absolute_get ();
for (unsigned int i = 0; i<NUM_CORES; i++)
{
pids[i] = fork ();
GNUNET_assert (-1 != pids[i]);
if (0 == pids[i])
{
int ret;
esh = TALER_CRYPTO_helper_esign_connect (cfg,
&key_cb,
NULL);
if (NULL == esh)
{
GNUNET_break (0);
exit (EXIT_FAILURE);
}
ret = perf_signing (esh,
"parallel");
TALER_CRYPTO_helper_esign_disconnect (esh);
exit (ret);
}
}
for (unsigned int i = 0; i<NUM_CORES; i++)
{
int wstatus;
GNUNET_assert (pids[i] ==
waitpid (pids[i],
&wstatus,
0));
}
duration = GNUNET_TIME_absolute_get_duration (start);
fprintf (stderr,
"%u (parallel) signature operations took %s (total real time)\n",
(unsigned int) NUM_SIGN_PERFS * NUM_CORES,
GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_STRINGS_relative_time_to_string (duration,
GNUNET_YES)); GNUNET_YES));
return 0; return 0;
@ -319,10 +386,10 @@ run_test (void)
{ {
struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CONFIGURATION_Handle *cfg;
struct TALER_CRYPTO_ExchangeSignHelper *esh; struct TALER_CRYPTO_ExchangeSignHelper *esh;
int ret;
struct timespec req = { struct timespec req = {
.tv_nsec = 250000000 .tv_nsec = 250000000
}; };
int ret;
cfg = GNUNET_CONFIGURATION_create (); cfg = GNUNET_CONFIGURATION_create ();
if (GNUNET_OK != if (GNUNET_OK !=
@ -334,54 +401,47 @@ run_test (void)
} }
/* wait for helper to start and give us keys */ /* wait for helper to start and give us keys */
fprintf (stderr, "Waiting for helper client directory to become available "); fprintf (stderr, "Waiting for helper to start ... ");
for (unsigned int i = 0; i<1000; i++) for (unsigned int i = 0; i<100; i++)
{ {
nanosleep (&req,
NULL);
esh = TALER_CRYPTO_helper_esign_connect (cfg, esh = TALER_CRYPTO_helper_esign_connect (cfg,
&key_cb, &key_cb,
NULL); NULL);
if (NULL != esh) if (NULL != esh)
break; break;
nanosleep (&req, NULL);
fprintf (stderr, "."); fprintf (stderr, ".");
} }
GNUNET_CONFIGURATION_destroy (cfg);
if (NULL == esh) if (NULL == esh)
{ {
GNUNET_break (0); fprintf (stderr,
"\nFAILED: timeout trying to connect to helper\n");
GNUNET_CONFIGURATION_destroy (cfg);
return 1; return 1;
} }
fprintf (stderr, " done.\n");
/* wait for helper to start and give us keys */
fprintf (stderr, "Waiting for helper to start ");
for (unsigned int i = 0; i<1000; i++)
{
TALER_CRYPTO_helper_esign_poll (esh);
if (0 != num_keys)
break;
nanosleep (&req, NULL);
fprintf (stderr, ".");
}
if (0 == num_keys) if (0 == num_keys)
{ {
fprintf (stderr, fprintf (stderr,
"\nFAILED: timeout trying to connect to helper\n"); "\nFAILED: no keys returend by helper\n");
TALER_CRYPTO_helper_esign_disconnect (esh); TALER_CRYPTO_helper_esign_disconnect (esh);
GNUNET_CONFIGURATION_destroy (cfg);
return 1; return 1;
} }
fprintf (stderr, fprintf (stderr,
"\nOK: Helper ready (%u keys)\n", " Done (%u keys)\n",
num_keys); num_keys);
ret = 0; ret = 0;
if (0 == ret) if (0 == ret)
ret = test_revocation (esh); ret = test_revocation (esh);
if (0 == ret) if (0 == ret)
ret = test_signing (esh); ret = test_signing (esh);
if (0 == ret) if (0 == ret)
ret = perf_signing (esh); ret = perf_signing (esh,
"sequential");
TALER_CRYPTO_helper_esign_disconnect (esh); TALER_CRYPTO_helper_esign_disconnect (esh);
if (0 == ret)
ret = par_signing (cfg);
/* clean up our state */ /* clean up our state */
for (unsigned int i = 0; i<MAX_KEYS; i++) for (unsigned int i = 0; i<MAX_KEYS; i++)
if (keys[i].valid) if (keys[i].valid)
@ -390,6 +450,7 @@ run_test (void)
GNUNET_assert (num_keys > 0); GNUNET_assert (num_keys > 0);
num_keys--; num_keys--;
} }
GNUNET_CONFIGURATION_destroy (cfg);
return ret; return ret;
} }
@ -408,7 +469,7 @@ main (int argc,
(void) argc; (void) argc;
(void) argv; (void) argv;
GNUNET_log_setup ("test-helper-eddsa", GNUNET_log_setup ("test-helper-eddsa",
"INFO", "WARNING",
NULL); NULL);
GNUNET_OS_init (TALER_project_data_default ()); GNUNET_OS_init (TALER_project_data_default ());
libexec_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); libexec_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
@ -424,7 +485,7 @@ main (int argc,
"-c", "-c",
"test_helper_eddsa.conf", "test_helper_eddsa.conf",
"-L", "-L",
"INFO", "WARNING",
NULL); NULL);
if (NULL == helper) if (NULL == helper)
{ {

View File

@ -22,11 +22,12 @@
#include "taler_util.h" #include "taler_util.h"
/** /**
* Configuration has 1 minute duration and 5 minutes lookahead, so * Configuration has 1 minute duration and 5 minutes lookahead, but
* we should never have more than 6 active keys, plus for during * we do not get 'revocations' for expired keys. So this must be
* key expiration / revocation. * large enough to deal with key rotation during the runtime of
* the benchmark.
*/ */
#define MAX_KEYS 7 #define MAX_KEYS 1024
/** /**
* How many random key revocations should we test? * How many random key revocations should we test?
@ -38,6 +39,17 @@
*/ */
#define NUM_SIGN_TESTS 5 #define NUM_SIGN_TESTS 5
/**
* How many iterations of the successful signing test should we run
* during the benchmark phase?
*/
#define NUM_SIGN_PERFS 100
/**
* How many parallel clients should we use for the parallel
* benchmark? (> 500 may cause problems with the max open FD number limit).
*/
#define NUM_CORES 8
/** /**
* Number of keys currently in #keys. * Number of keys currently in #keys.
@ -62,7 +74,7 @@ struct KeyData
/** /**
* Hash of the public key. * Hash of the public key.
*/ */
struct TALER_DenominationHash h_denom_pub; struct GNUNET_HashCode h_denom_pub;
/** /**
* Full public key. * Full public key.
@ -110,7 +122,7 @@ key_cb (void *cls,
const char *section_name, const char *section_name,
struct GNUNET_TIME_Absolute start_time, struct GNUNET_TIME_Absolute start_time,
struct GNUNET_TIME_Relative validity_duration, struct GNUNET_TIME_Relative validity_duration,
const struct TALER_DenominationHash *h_denom_pub, const struct GNUNET_HashCode *h_denom_pub,
const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_DenominationPublicKey *denom_pub,
const struct TALER_SecurityModulePublicKeyP *sm_pub, const struct TALER_SecurityModulePublicKeyP *sm_pub,
const struct TALER_SecurityModuleSignatureP *sm_sig) const struct TALER_SecurityModuleSignatureP *sm_sig)
@ -119,7 +131,7 @@ key_cb (void *cls,
(void) sm_sig; (void) sm_sig;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Key notification about key %s in `%s'\n", "Key notification about key %s in `%s'\n",
GNUNET_h2s (&h_denom_pub->hash), GNUNET_h2s (h_denom_pub),
section_name); section_name);
if (0 == validity_duration.rel_value_us) if (0 == validity_duration.rel_value_us)
{ {
@ -133,7 +145,8 @@ key_cb (void *cls,
{ {
keys[i].valid = false; keys[i].valid = false;
keys[i].revoked = false; keys[i].revoked = false;
TALER_denom_pub_free (&keys[i].denom_pub); GNUNET_CRYPTO_rsa_public_key_free (keys[i].denom_pub.rsa_public_key);
keys[i].denom_pub.rsa_public_key = NULL;
GNUNET_assert (num_keys > 0); GNUNET_assert (num_keys > 0);
num_keys--; num_keys--;
found = true; found = true;
@ -154,9 +167,8 @@ key_cb (void *cls,
keys[i].h_denom_pub = *h_denom_pub; keys[i].h_denom_pub = *h_denom_pub;
keys[i].start_time = start_time; keys[i].start_time = start_time;
keys[i].validity_duration = validity_duration; keys[i].validity_duration = validity_duration;
keys[i].denom_pub = *denom_pub; keys[i].denom_pub.rsa_public_key
TALER_denom_pub_deep_copy (&keys[i].denom_pub, = GNUNET_CRYPTO_rsa_public_key_dup (denom_pub->rsa_public_key);
denom_pub);
num_keys++; num_keys++;
return; return;
} }
@ -199,7 +211,7 @@ test_revocation (struct TALER_CRYPTO_DenominationHelper *dh)
keys[j].revoked = true; keys[j].revoked = true;
fprintf (stderr, fprintf (stderr,
"Revoking key %s ...", "Revoking key %s ...",
GNUNET_h2s (&keys[j].h_denom_pub.hash)); GNUNET_h2s (&keys[j].h_denom_pub));
TALER_CRYPTO_helper_denom_revoke (dh, TALER_CRYPTO_helper_denom_revoke (dh,
&keys[j].h_denom_pub); &keys[j].h_denom_pub);
for (unsigned int k = 0; k<1000; k++) for (unsigned int k = 0; k<1000; k++)
@ -235,35 +247,42 @@ test_revocation (struct TALER_CRYPTO_DenominationHelper *dh)
static int static int
test_signing (struct TALER_CRYPTO_DenominationHelper *dh) test_signing (struct TALER_CRYPTO_DenominationHelper *dh)
{ {
struct TALER_BlindedDenominationSignature ds; struct TALER_DenominationSignature ds;
enum TALER_ErrorCode ec; enum TALER_ErrorCode ec;
bool success = false; bool success = false;
struct TALER_PlanchetSecretsP ps; struct GNUNET_HashCode m_hash;
struct TALER_CoinPubHash c_hash; struct GNUNET_CRYPTO_RsaBlindingKeySecret bks;
TALER_planchet_setup_random (&ps); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&bks,
sizeof (bks));
GNUNET_CRYPTO_hash ("Hello",
strlen ("Hello"),
&m_hash);
for (unsigned int i = 0; i<MAX_KEYS; i++) for (unsigned int i = 0; i<MAX_KEYS; i++)
{ {
if (! keys[i].valid) if (! keys[i].valid)
continue; continue;
{ {
struct TALER_PlanchetDetail pd; void *buf;
size_t buf_size;
GNUNET_assert (GNUNET_YES == GNUNET_assert (GNUNET_YES ==
TALER_planchet_prepare (&keys[i].denom_pub, TALER_rsa_blind (&m_hash,
&ps, &bks,
&c_hash, keys[i].denom_pub.rsa_public_key,
&pd)); &buf,
&buf_size));
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Requesting signature over %u bytes with key %s\n", "Requesting signature over %u bytes with key %s\n",
(unsigned int) pd.coin_ev_size, (unsigned int) buf_size,
GNUNET_h2s (&keys[i].h_denom_pub.hash)); GNUNET_h2s (&keys[i].h_denom_pub));
ds = TALER_CRYPTO_helper_denom_sign (dh, ds = TALER_CRYPTO_helper_denom_sign (dh,
&keys[i].h_denom_pub, &keys[i].h_denom_pub,
pd.coin_ev, buf,
pd.coin_ev_size, buf_size,
&ec); &ec);
GNUNET_free (pd.coin_ev); GNUNET_free (buf);
} }
switch (ec) switch (ec)
{ {
@ -283,33 +302,32 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh)
return 5; return 5;
} }
{ {
struct TALER_DenominationSignature rs; struct GNUNET_CRYPTO_RsaSignature *rs;
if (GNUNET_OK != rs = TALER_rsa_unblind (ds.rsa_signature,
TALER_denom_sig_unblind (&rs, &bks,
&ds, keys[i].denom_pub.rsa_public_key);
&ps.blinding_key, if (NULL == rs)
&keys[i].denom_pub))
{ {
GNUNET_break (0); GNUNET_break (0);
return 6; return 6;
} }
TALER_blinded_denom_sig_free (&ds); GNUNET_CRYPTO_rsa_signature_free (ds.rsa_signature);
if (GNUNET_OK != if (GNUNET_OK !=
TALER_denom_pub_verify (&keys[i].denom_pub, GNUNET_CRYPTO_rsa_verify (&m_hash,
&rs, rs,
&c_hash)) keys[i].denom_pub.rsa_public_key))
{ {
/* signature invalid */ /* signature invalid */
GNUNET_break (0); GNUNET_break (0);
TALER_denom_sig_free (&rs); GNUNET_CRYPTO_rsa_signature_free (rs);
return 7; return 7;
} }
TALER_denom_sig_free (&rs); GNUNET_CRYPTO_rsa_signature_free (rs);
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received valid signature for key %s\n", "Received valid signature for key %s\n",
GNUNET_h2s (&keys[i].h_denom_pub.hash)); GNUNET_h2s (&keys[i].h_denom_pub));
success = true; success = true;
break; break;
case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY: case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY:
@ -344,24 +362,27 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh)
/* check signing does not work if the key is unknown */ /* check signing does not work if the key is unknown */
{ {
struct TALER_DenominationHash rnd; struct GNUNET_HashCode rnd;
struct TALER_DenominationSignature ds;
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&rnd, &rnd,
sizeof (rnd)); sizeof (rnd));
(void) TALER_CRYPTO_helper_denom_sign (dh, ds = TALER_CRYPTO_helper_denom_sign (dh,
&rnd, &rnd,
"Hello", "Hello",
strlen ("Hello"), strlen ("Hello"),
&ec); &ec);
if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec) if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec)
{ {
if (TALER_EC_NONE == ec)
GNUNET_CRYPTO_rsa_signature_free (ds.rsa_signature);
GNUNET_break (0); GNUNET_break (0);
return 17; return 17;
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Signing with invalid key %s failed as desired\n", "Signing with invalid key %s failed as desired\n",
GNUNET_h2s (&rnd.hash)); GNUNET_h2s (&rnd));
} }
return 0; return 0;
} }
@ -374,18 +395,25 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh)
* @return 0 on success * @return 0 on success
*/ */
static int static int
perf_signing (struct TALER_CRYPTO_DenominationHelper *dh) perf_signing (struct TALER_CRYPTO_DenominationHelper *dh,
const char *type)
{ {
struct TALER_BlindedDenominationSignature ds; struct TALER_DenominationSignature ds;
enum TALER_ErrorCode ec; enum TALER_ErrorCode ec;
struct GNUNET_HashCode m_hash;
struct GNUNET_CRYPTO_RsaBlindingKeySecret bks;
struct GNUNET_TIME_Relative duration; struct GNUNET_TIME_Relative duration;
struct TALER_PlanchetSecretsP ps;
TALER_planchet_setup_random (&ps); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&bks,
sizeof (bks));
GNUNET_CRYPTO_hash ("Hello",
strlen ("Hello"),
&m_hash);
duration = GNUNET_TIME_UNIT_ZERO; duration = GNUNET_TIME_UNIT_ZERO;
for (unsigned int j = 0; j<NUM_SIGN_TESTS;) TALER_CRYPTO_helper_denom_poll (dh);
for (unsigned int j = 0; j<NUM_SIGN_PERFS;)
{ {
TALER_CRYPTO_helper_denom_poll (dh);
for (unsigned int i = 0; i<MAX_KEYS; i++) for (unsigned int i = 0; i<MAX_KEYS; i++)
{ {
if (! keys[i].valid) if (! keys[i].valid)
@ -397,14 +425,15 @@ perf_signing (struct TALER_CRYPTO_DenominationHelper *dh)
keys[i].validity_duration.rel_value_us) keys[i].validity_duration.rel_value_us)
continue; continue;
{ {
struct TALER_CoinPubHash c_hash; void *buf;
struct TALER_PlanchetDetail pd; size_t buf_size;
GNUNET_assert (GNUNET_YES == GNUNET_assert (GNUNET_YES ==
TALER_planchet_prepare (&keys[i].denom_pub, TALER_rsa_blind (&m_hash,
&ps, &bks,
&c_hash, keys[i].denom_pub.rsa_public_key,
&pd)); &buf,
&buf_size));
/* use this key as long as it works */ /* use this key as long as it works */
while (1) while (1)
{ {
@ -413,26 +442,83 @@ perf_signing (struct TALER_CRYPTO_DenominationHelper *dh)
ds = TALER_CRYPTO_helper_denom_sign (dh, ds = TALER_CRYPTO_helper_denom_sign (dh,
&keys[i].h_denom_pub, &keys[i].h_denom_pub,
pd.coin_ev, buf,
pd.coin_ev_size, buf_size,
&ec); &ec);
if (TALER_EC_NONE != ec) if (TALER_EC_NONE != ec)
break; break;
delay = GNUNET_TIME_absolute_get_duration (start); delay = GNUNET_TIME_absolute_get_duration (start);
duration = GNUNET_TIME_relative_add (duration, duration = GNUNET_TIME_relative_add (duration,
delay); delay);
TALER_blinded_denom_sig_free (&ds); GNUNET_CRYPTO_rsa_signature_free (ds.rsa_signature);
j++; j++;
if (NUM_SIGN_TESTS == j) if (NUM_SIGN_PERFS <= j)
break; break;
} }
GNUNET_free (pd.coin_ev); GNUNET_free (buf);
} }
} /* for i */ } /* for i */
} /* for j */ } /* for j */
fprintf (stderr, fprintf (stderr,
"%u (sequential) signature operations took %s\n", "%u (%s) signature operations took %s\n",
(unsigned int) NUM_SIGN_TESTS, (unsigned int) NUM_SIGN_PERFS,
type,
GNUNET_STRINGS_relative_time_to_string (duration,
GNUNET_YES));
return 0;
}
/**
* Parallel signing logic.
*
* @param esh handle to the helper
* @return 0 on success
*/
static int
par_signing (struct GNUNET_CONFIGURATION_Handle *cfg)
{
struct GNUNET_TIME_Absolute start;
struct GNUNET_TIME_Relative duration;
pid_t pids[NUM_CORES];
struct TALER_CRYPTO_DenominationHelper *dh;
start = GNUNET_TIME_absolute_get ();
for (unsigned int i = 0; i<NUM_CORES; i++)
{
pids[i] = fork ();
memset (keys,
0,
sizeof (keys));
num_keys = 0;
GNUNET_assert (-1 != pids[i]);
if (0 == pids[i])
{
int ret;
dh = TALER_CRYPTO_helper_denom_connect (cfg,
&key_cb,
NULL);
GNUNET_assert (NULL != dh);
ret = perf_signing (dh,
"parallel");
TALER_CRYPTO_helper_denom_disconnect (dh);
exit (ret);
}
}
for (unsigned int i = 0; i<NUM_CORES; i++)
{
int wstatus;
GNUNET_assert (pids[i] ==
waitpid (pids[i],
&wstatus,
0));
}
duration = GNUNET_TIME_absolute_get_duration (start);
fprintf (stderr,
"%u (parallel) signature operations took %s (total real time)\n",
(unsigned int) NUM_SIGN_PERFS * NUM_CORES,
GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_STRINGS_relative_time_to_string (duration,
GNUNET_YES)); GNUNET_YES));
return 0; return 0;
@ -461,62 +547,57 @@ run_test (void)
return 77; return 77;
} }
fprintf (stderr, "Waiting for helper client directory to become available "); fprintf (stderr, "Waiting for helper to start ... ");
for (unsigned int i = 0; i<1000; i++) for (unsigned int i = 0; i<100; i++)
{ {
nanosleep (&req,
NULL);
dh = TALER_CRYPTO_helper_denom_connect (cfg, dh = TALER_CRYPTO_helper_denom_connect (cfg,
&key_cb, &key_cb,
NULL); NULL);
if (NULL != dh) if (NULL != dh)
break; break;
nanosleep (&req, NULL);
fprintf (stderr, "."); fprintf (stderr, ".");
} }
GNUNET_CONFIGURATION_destroy (cfg);
if (NULL == dh) if (NULL == dh)
{ {
GNUNET_break (0); fprintf (stderr,
"\nFAILED: timeout trying to connect to helper\n");
GNUNET_CONFIGURATION_destroy (cfg);
return 1; return 1;
} }
fprintf (stderr, " done.\n");
/* wait for helper to start and give us keys */
fprintf (stderr, "Waiting for helper to start ");
for (unsigned int i = 0; i<1000; i++)
{
TALER_CRYPTO_helper_denom_poll (dh);
if (0 != num_keys)
break;
nanosleep (&req, NULL);
fprintf (stderr, ".");
}
if (0 == num_keys) if (0 == num_keys)
{ {
fprintf (stderr, fprintf (stderr,
"\nFAILED: timeout trying to connect to helper\n"); "\nFAILED: timeout trying to connect to helper\n");
TALER_CRYPTO_helper_denom_disconnect (dh); TALER_CRYPTO_helper_denom_disconnect (dh);
GNUNET_CONFIGURATION_destroy (cfg);
return 1; return 1;
} }
fprintf (stderr, fprintf (stderr,
"\nOK: Helper ready (%u keys)\n", " Done (%u keys)\n",
num_keys); num_keys);
ret = 0; ret = 0;
if (0 == ret) if (0 == ret)
ret = test_revocation (dh); ret = test_revocation (dh);
if (0 == ret) if (0 == ret)
ret = test_signing (dh); ret = test_signing (dh);
if (0 == ret) if (0 == ret)
ret = perf_signing (dh); ret = perf_signing (dh,
"sequential");
TALER_CRYPTO_helper_denom_disconnect (dh); TALER_CRYPTO_helper_denom_disconnect (dh);
if (0 == ret)
ret = par_signing (cfg);
/* clean up our state */ /* clean up our state */
for (unsigned int i = 0; i<MAX_KEYS; i++) for (unsigned int i = 0; i<MAX_KEYS; i++)
if (keys[i].valid) if (keys[i].valid)
{ {
TALER_denom_pub_free (&keys[i].denom_pub); GNUNET_CRYPTO_rsa_public_key_free (keys[i].denom_pub.rsa_public_key);
keys[i].denom_pub.rsa_public_key = NULL;
GNUNET_assert (num_keys > 0); GNUNET_assert (num_keys > 0);
num_keys--; num_keys--;
} }
GNUNET_CONFIGURATION_destroy (cfg);
return ret; return ret;
} }
@ -535,7 +616,7 @@ main (int argc,
(void) argc; (void) argc;
(void) argv; (void) argv;
GNUNET_log_setup ("test-helper-rsa", GNUNET_log_setup ("test-helper-rsa",
"INFO", "WARNING",
NULL); NULL);
GNUNET_OS_init (TALER_project_data_default ()); GNUNET_OS_init (TALER_project_data_default ());
libexec_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); libexec_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
@ -551,7 +632,7 @@ main (int argc,
"-c", "-c",
"test_helper_rsa.conf", "test_helper_rsa.conf",
"-L", "-L",
"INFO", "WARNING",
NULL); NULL);
if (NULL == helper) if (NULL == helper)
{ {