-sketch API for RSA parallel signing
This commit is contained in:
parent
d40da21e90
commit
7f902c0fc9
@ -1 +1 @@
|
|||||||
Subproject commit 99d8d9e0336bacebab5af4ae00c3f685ffd90f60
|
Subproject commit aebd5420308d7599aadb8818a82d9ffc89492334
|
@ -2010,6 +2010,11 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
|
|||||||
{
|
{
|
||||||
GNUNET_assert (0 ==
|
GNUNET_assert (0 ==
|
||||||
pthread_mutex_unlock (&h->big_lock));
|
pthread_mutex_unlock (&h->big_lock));
|
||||||
|
if (overflow)
|
||||||
|
return TALER_MHD_reply_with_ec (
|
||||||
|
connection,
|
||||||
|
TALER_EC_BANK_ANCIENT_TRANSACTION_GONE,
|
||||||
|
NULL);
|
||||||
return TALER_MHD_REPLY_JSON_PACK (
|
return TALER_MHD_REPLY_JSON_PACK (
|
||||||
connection,
|
connection,
|
||||||
MHD_HTTP_OK,
|
MHD_HTTP_OK,
|
||||||
@ -2213,14 +2218,19 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
|
|||||||
if ( (NULL == t) ||
|
if ( (NULL == t) ||
|
||||||
overflow)
|
overflow)
|
||||||
{
|
{
|
||||||
|
GNUNET_free (credit_payto);
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
"No transactions available, suspending request\n");
|
"No transactions available, suspending request\n");
|
||||||
GNUNET_free (credit_payto);
|
|
||||||
if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) &&
|
if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) &&
|
||||||
(0 < ha.delta))
|
(0 < ha.delta))
|
||||||
{
|
{
|
||||||
GNUNET_assert (0 ==
|
GNUNET_assert (0 ==
|
||||||
pthread_mutex_unlock (&h->big_lock));
|
pthread_mutex_unlock (&h->big_lock));
|
||||||
|
if (overflow)
|
||||||
|
return TALER_MHD_reply_with_ec (
|
||||||
|
connection,
|
||||||
|
TALER_EC_BANK_ANCIENT_TRANSACTION_GONE,
|
||||||
|
NULL);
|
||||||
return TALER_MHD_REPLY_JSON_PACK (connection,
|
return TALER_MHD_REPLY_JSON_PACK (connection,
|
||||||
MHD_HTTP_OK,
|
MHD_HTTP_OK,
|
||||||
GNUNET_JSON_pack_array_steal (
|
GNUNET_JSON_pack_array_steal (
|
||||||
|
@ -2575,12 +2575,18 @@ TEH_keys_denomination_sign_withdraw (
|
|||||||
{
|
{
|
||||||
case TALER_DENOMINATION_RSA:
|
case TALER_DENOMINATION_RSA:
|
||||||
TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_RSA]++;
|
TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_RSA]++;
|
||||||
|
{
|
||||||
|
struct TALER_CRYPTO_RsaSignRequest rsr = {
|
||||||
|
.h_rsa = &hd->h_details.h_rsa,
|
||||||
|
.msg = bp->details.rsa_blinded_planchet.blinded_msg,
|
||||||
|
.msg_size = bp->details.rsa_blinded_planchet.blinded_msg_size
|
||||||
|
};
|
||||||
|
|
||||||
return TALER_CRYPTO_helper_rsa_sign (
|
return TALER_CRYPTO_helper_rsa_sign (
|
||||||
ksh->helpers->rsadh,
|
ksh->helpers->rsadh,
|
||||||
&hd->h_details.h_rsa,
|
&rsr,
|
||||||
bp->details.rsa_blinded_planchet.blinded_msg,
|
|
||||||
bp->details.rsa_blinded_planchet.blinded_msg_size,
|
|
||||||
bs);
|
bs);
|
||||||
|
}
|
||||||
case TALER_DENOMINATION_CS:
|
case TALER_DENOMINATION_CS:
|
||||||
TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_CS]++;
|
TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_CS]++;
|
||||||
return TALER_CRYPTO_helper_cs_sign_withdraw (
|
return TALER_CRYPTO_helper_cs_sign_withdraw (
|
||||||
@ -2616,12 +2622,18 @@ TEH_keys_denomination_sign_melt (
|
|||||||
{
|
{
|
||||||
case TALER_DENOMINATION_RSA:
|
case TALER_DENOMINATION_RSA:
|
||||||
TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_RSA]++;
|
TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_RSA]++;
|
||||||
|
{
|
||||||
|
struct TALER_CRYPTO_RsaSignRequest rsr = {
|
||||||
|
.h_rsa = &hd->h_details.h_rsa,
|
||||||
|
.msg = bp->details.rsa_blinded_planchet.blinded_msg,
|
||||||
|
.msg_size = bp->details.rsa_blinded_planchet.blinded_msg_size
|
||||||
|
};
|
||||||
|
|
||||||
return TALER_CRYPTO_helper_rsa_sign (
|
return TALER_CRYPTO_helper_rsa_sign (
|
||||||
ksh->helpers->rsadh,
|
ksh->helpers->rsadh,
|
||||||
&hd->h_details.h_rsa,
|
&rsr,
|
||||||
bp->details.rsa_blinded_planchet.blinded_msg,
|
|
||||||
bp->details.rsa_blinded_planchet.blinded_msg_size,
|
|
||||||
bs);
|
bs);
|
||||||
|
}
|
||||||
case TALER_DENOMINATION_CS:
|
case TALER_DENOMINATION_CS:
|
||||||
TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_CS]++;
|
TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_CS]++;
|
||||||
return TALER_CRYPTO_helper_cs_sign_melt (
|
return TALER_CRYPTO_helper_cs_sign_melt (
|
||||||
|
@ -623,17 +623,15 @@ history_cb (void *cls,
|
|||||||
if (NULL == details)
|
if (NULL == details)
|
||||||
{
|
{
|
||||||
wa->hh = NULL;
|
wa->hh = NULL;
|
||||||
if (TALER_EC_NONE != ec)
|
if ( (TALER_EC_NONE != ec) ||
|
||||||
|
(MHD_HTTP_OK != http_status) )
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Error fetching history: ec=%u, http_status=%u\n",
|
"Error fetching history: %s (%u)\n",
|
||||||
(unsigned int) ec,
|
TALER_ErrorCode_get_hint (ec),
|
||||||
http_status);
|
http_status);
|
||||||
}
|
GNUNET_SCHEDULER_shutdown ();
|
||||||
else
|
return GNUNET_OK;
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
||||||
"History response complete\n");
|
|
||||||
}
|
}
|
||||||
if (wa->started_transaction)
|
if (wa->started_transaction)
|
||||||
{
|
{
|
||||||
@ -656,6 +654,8 @@ history_cb (void *cls,
|
|||||||
GNUNET_SCHEDULER_shutdown ();
|
GNUNET_SCHEDULER_shutdown ();
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
}
|
}
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
|
"No transactions in history response, moving on.\n");
|
||||||
account_completed (wa);
|
account_completed (wa);
|
||||||
return GNUNET_OK; /* will be ignored anyway */
|
return GNUNET_OK; /* will be ignored anyway */
|
||||||
}
|
}
|
||||||
@ -831,7 +831,7 @@ lock_shard (void *cls)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (wa->shard_open)
|
if (wa->shard_open)
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
"Shard not completed in time, will try to re-acquire\n");
|
"Shard not completed in time, will try to re-acquire\n");
|
||||||
/* How long we lock a shard depends on the number of
|
/* How long we lock a shard depends on the number of
|
||||||
workers expected, and how long we usually took to
|
workers expected, and how long we usually took to
|
||||||
|
@ -2326,8 +2326,30 @@ TALER_CRYPTO_helper_rsa_poll (struct TALER_CRYPTO_RsaDenominationHelper *dh);
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request helper @a dh to sign @a msg using the public key corresponding to
|
* Information needed for an RSA signature request.
|
||||||
* @a h_denom_pub.
|
*/
|
||||||
|
struct TALER_CRYPTO_RsaSignRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Hash of the RSA public key.
|
||||||
|
*/
|
||||||
|
const struct TALER_RsaPubHashP *h_rsa;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message to be (blindly) signed.
|
||||||
|
*/
|
||||||
|
const void *msg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of bytes in @e msg.
|
||||||
|
*/
|
||||||
|
size_t msg_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request helper @a dh to sign message in @a rsr using the public key
|
||||||
|
* corresponding to the key in @a rsr.
|
||||||
*
|
*
|
||||||
* This operation will block until the signature has been obtained. Should
|
* This operation will block until the signature has been obtained. Should
|
||||||
* this process receive a signal (that is not ignored) while the operation is
|
* this process receive a signal (that is not ignored) while the operation is
|
||||||
@ -2336,21 +2358,41 @@ TALER_CRYPTO_helper_rsa_poll (struct TALER_CRYPTO_RsaDenominationHelper *dh);
|
|||||||
* differences in the signature counters. Retrying in this case may work.
|
* differences in the signature counters. Retrying in this case may work.
|
||||||
*
|
*
|
||||||
* @param dh helper process connection
|
* @param dh helper process connection
|
||||||
* @param h_rsa hash of the RSA public key to use to sign
|
* @param rsr details about the requested signature
|
||||||
* @param msg message to sign
|
|
||||||
* @param msg_size number of bytes in @a msg
|
|
||||||
* @param[out] bs set to the blind signature
|
* @param[out] bs set to the blind signature
|
||||||
* @return #TALER_EC_NONE on success
|
* @return #TALER_EC_NONE on success
|
||||||
*/
|
*/
|
||||||
enum TALER_ErrorCode
|
enum TALER_ErrorCode
|
||||||
TALER_CRYPTO_helper_rsa_sign (
|
TALER_CRYPTO_helper_rsa_sign (
|
||||||
struct TALER_CRYPTO_RsaDenominationHelper *dh,
|
struct TALER_CRYPTO_RsaDenominationHelper *dh,
|
||||||
const struct TALER_RsaPubHashP *h_rsa,
|
const struct TALER_CRYPTO_RsaSignRequest *rsr,
|
||||||
const void *msg,
|
|
||||||
size_t msg_size,
|
|
||||||
struct TALER_BlindedDenominationSignature *bs);
|
struct TALER_BlindedDenominationSignature *bs);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request helper @a dh to batch sign messages in @a rsrs using the public key
|
||||||
|
* corresponding to the keys in @a rsrs.
|
||||||
|
*
|
||||||
|
* This operation will block until all the signatures have been obtained. Should
|
||||||
|
* this process receive a signal (that is not ignored) while the operation is
|
||||||
|
* pending, the operation will fail. Note that the helper may still believe
|
||||||
|
* that it created the signature. Thus, signals may result in a small
|
||||||
|
* differences in the signature counters. Retrying in this case may work.
|
||||||
|
*
|
||||||
|
* @param dh helper process connection
|
||||||
|
* @param rsrs array with details about the requested signatures
|
||||||
|
* @param rsrs_length length of the @a rsrs array
|
||||||
|
* @param[out] bss array set to the blind signatures, must be of length @a rsrs_length!
|
||||||
|
* @return #TALER_EC_NONE on success
|
||||||
|
*/
|
||||||
|
enum TALER_ErrorCode
|
||||||
|
TALER_CRYPTO_helper_rsa_batch_sign (
|
||||||
|
struct TALER_CRYPTO_RsaDenominationHelper *dh,
|
||||||
|
const struct TALER_CRYPTO_RsaSignRequest *rsrs,
|
||||||
|
unsigned int rsrs_length,
|
||||||
|
struct TALER_BlindedDenominationSignature *bss);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ask the helper to revoke the public key associated with @a h_denom_pub.
|
* Ask the helper to revoke the public key associated with @a h_denom_pub.
|
||||||
* Will cause the helper to tell all clients that the key is now unavailable,
|
* Will cause the helper to tell all clients that the key is now unavailable,
|
||||||
|
@ -390,9 +390,7 @@ more:
|
|||||||
enum TALER_ErrorCode
|
enum TALER_ErrorCode
|
||||||
TALER_CRYPTO_helper_rsa_sign (
|
TALER_CRYPTO_helper_rsa_sign (
|
||||||
struct TALER_CRYPTO_RsaDenominationHelper *dh,
|
struct TALER_CRYPTO_RsaDenominationHelper *dh,
|
||||||
const struct TALER_RsaPubHashP *h_rsa,
|
const struct TALER_CRYPTO_RsaSignRequest *rsr,
|
||||||
const void *msg,
|
|
||||||
size_t msg_size,
|
|
||||||
struct TALER_BlindedDenominationSignature *bs)
|
struct TALER_BlindedDenominationSignature *bs)
|
||||||
{
|
{
|
||||||
enum TALER_ErrorCode ec = TALER_EC_INVALID;
|
enum TALER_ErrorCode ec = TALER_EC_INVALID;
|
||||||
@ -411,17 +409,17 @@ TALER_CRYPTO_helper_rsa_sign (
|
|||||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||||
"Requesting signature\n");
|
"Requesting signature\n");
|
||||||
{
|
{
|
||||||
char buf[sizeof (struct TALER_CRYPTO_SignRequest) + msg_size];
|
char buf[sizeof (struct TALER_CRYPTO_SignRequest) + rsr->msg_size];
|
||||||
struct TALER_CRYPTO_SignRequest *sr
|
struct TALER_CRYPTO_SignRequest *sr
|
||||||
= (struct TALER_CRYPTO_SignRequest *) buf;
|
= (struct TALER_CRYPTO_SignRequest *) buf;
|
||||||
|
|
||||||
sr->header.size = htons (sizeof (buf));
|
sr->header.size = htons (sizeof (buf));
|
||||||
sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN);
|
sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN);
|
||||||
sr->reserved = htonl (0);
|
sr->reserved = htonl (0);
|
||||||
sr->h_rsa = *h_rsa;
|
sr->h_rsa = *rsr->h_rsa;
|
||||||
memcpy (&sr[1],
|
memcpy (&sr[1],
|
||||||
msg,
|
rsr->msg,
|
||||||
msg_size);
|
rsr->msg_size);
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_crypto_helper_send_all (dh->sock,
|
TALER_crypto_helper_send_all (dh->sock,
|
||||||
buf,
|
buf,
|
||||||
@ -596,6 +594,18 @@ end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum TALER_ErrorCode
|
||||||
|
TALER_CRYPTO_helper_rsa_batch_sign (
|
||||||
|
struct TALER_CRYPTO_RsaDenominationHelper *dh,
|
||||||
|
const struct TALER_CRYPTO_RsaSignRequest *rsrs,
|
||||||
|
unsigned int rsrs_length,
|
||||||
|
struct TALER_BlindedDenominationSignature *bss)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
return -1; /* FIXME: NOT IMPLEMENTED! */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TALER_CRYPTO_helper_rsa_revoke (
|
TALER_CRYPTO_helper_rsa_revoke (
|
||||||
struct TALER_CRYPTO_RsaDenominationHelper *dh,
|
struct TALER_CRYPTO_RsaDenominationHelper *dh,
|
||||||
|
@ -292,8 +292,9 @@ test_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh)
|
|||||||
if (TALER_DENOMINATION_RSA != keys[i].denom_pub.cipher)
|
if (TALER_DENOMINATION_RSA != keys[i].denom_pub.cipher)
|
||||||
continue;
|
continue;
|
||||||
{
|
{
|
||||||
struct TALER_PlanchetDetail pd;
|
struct TALER_PlanchetDetail pd = {
|
||||||
pd.blinded_planchet.cipher = TALER_DENOMINATION_RSA;
|
.blinded_planchet.cipher = TALER_DENOMINATION_RSA
|
||||||
|
};
|
||||||
|
|
||||||
GNUNET_assert (GNUNET_YES ==
|
GNUNET_assert (GNUNET_YES ==
|
||||||
TALER_planchet_prepare (&keys[i].denom_pub,
|
TALER_planchet_prepare (&keys[i].denom_pub,
|
||||||
@ -303,19 +304,23 @@ test_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh)
|
|||||||
&ach,
|
&ach,
|
||||||
&c_hash,
|
&c_hash,
|
||||||
&pd));
|
&pd));
|
||||||
|
{
|
||||||
|
struct TALER_CRYPTO_RsaSignRequest rsr = {
|
||||||
|
.h_rsa = &keys[i].h_rsa,
|
||||||
|
.msg =
|
||||||
|
pd.blinded_planchet.details.rsa_blinded_planchet.blinded_msg,
|
||||||
|
.msg_size =
|
||||||
|
pd.blinded_planchet.details.rsa_blinded_planchet.blinded_msg_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
|
(unsigned int) rsr.msg_size,
|
||||||
int) pd.blinded_planchet.details.rsa_blinded_planchet.
|
GNUNET_h2s (&rsr.h_rsa->hash));
|
||||||
blinded_msg_size,
|
|
||||||
GNUNET_h2s (&keys[i].h_rsa.hash));
|
|
||||||
ec = TALER_CRYPTO_helper_rsa_sign (dh,
|
ec = TALER_CRYPTO_helper_rsa_sign (dh,
|
||||||
&keys[i].h_rsa,
|
&rsr,
|
||||||
pd.blinded_planchet.details.
|
|
||||||
rsa_blinded_planchet.blinded_msg,
|
|
||||||
pd.blinded_planchet.details.
|
|
||||||
rsa_blinded_planchet.blinded_msg_size,
|
|
||||||
&ds);
|
&ds);
|
||||||
|
}
|
||||||
TALER_blinded_planchet_free (&pd.blinded_planchet);
|
TALER_blinded_planchet_free (&pd.blinded_planchet);
|
||||||
}
|
}
|
||||||
switch (ec)
|
switch (ec)
|
||||||
@ -391,8 +396,10 @@ test_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh)
|
|||||||
default:
|
default:
|
||||||
/* unexpected error */
|
/* unexpected error */
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Unexpected error %d\n",
|
"Unexpected error %d at %s:%u\n",
|
||||||
ec);
|
ec,
|
||||||
|
__FILE__,
|
||||||
|
__LINE__);
|
||||||
return 7;
|
return 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -406,14 +413,17 @@ test_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh)
|
|||||||
/* check signing does not work if the key is unknown */
|
/* check signing does not work if the key is unknown */
|
||||||
{
|
{
|
||||||
struct TALER_RsaPubHashP rnd;
|
struct TALER_RsaPubHashP rnd;
|
||||||
|
struct TALER_CRYPTO_RsaSignRequest rsr = {
|
||||||
|
.h_rsa = &rnd,
|
||||||
|
.msg = "Hello",
|
||||||
|
.msg_size = strlen ("Hello")
|
||||||
|
};
|
||||||
|
|
||||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
|
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
|
||||||
&rnd,
|
&rnd,
|
||||||
sizeof (rnd));
|
sizeof (rnd));
|
||||||
ec = TALER_CRYPTO_helper_rsa_sign (dh,
|
ec = TALER_CRYPTO_helper_rsa_sign (dh,
|
||||||
&rnd,
|
&rsr,
|
||||||
"Hello",
|
|
||||||
strlen ("Hello"),
|
|
||||||
&ds);
|
&ds);
|
||||||
if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec)
|
if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec)
|
||||||
{
|
{
|
||||||
@ -493,14 +503,16 @@ perf_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh,
|
|||||||
{
|
{
|
||||||
struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get ();
|
struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get ();
|
||||||
struct GNUNET_TIME_Relative delay;
|
struct GNUNET_TIME_Relative delay;
|
||||||
|
struct TALER_CRYPTO_RsaSignRequest rsr = {
|
||||||
|
.h_rsa = &keys[i].h_rsa,
|
||||||
|
.msg =
|
||||||
|
pd.blinded_planchet.details.rsa_blinded_planchet.blinded_msg,
|
||||||
|
.msg_size =
|
||||||
|
pd.blinded_planchet.details.rsa_blinded_planchet.blinded_msg_size
|
||||||
|
};
|
||||||
|
|
||||||
ec = TALER_CRYPTO_helper_rsa_sign (dh,
|
ec = TALER_CRYPTO_helper_rsa_sign (dh,
|
||||||
&keys[i].h_rsa,
|
&rsr,
|
||||||
pd.blinded_planchet.details.
|
|
||||||
rsa_blinded_planchet.blinded_msg,
|
|
||||||
pd.blinded_planchet.details.
|
|
||||||
rsa_blinded_planchet.
|
|
||||||
blinded_msg_size,
|
|
||||||
&ds);
|
&ds);
|
||||||
if (TALER_EC_NONE != ec)
|
if (TALER_EC_NONE != ec)
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user