-work purse_deposit conflict handling
This commit is contained in:
parent
3db8f0f22d
commit
d803d86bf9
@ -275,7 +275,7 @@ merge_transaction (void *cls,
|
|||||||
&merge_timestamp,
|
&merge_timestamp,
|
||||||
&partner_url,
|
&partner_url,
|
||||||
&reserve_pub);
|
&reserve_pub);
|
||||||
if (qs < 0)
|
if (qs <= 0)
|
||||||
{
|
{
|
||||||
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
|
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
|
||||||
return qs;
|
return qs;
|
||||||
|
@ -566,6 +566,8 @@ TEH_RESPONSE_reply_coin_insufficient_funds (
|
|||||||
connection,
|
connection,
|
||||||
TALER_ErrorCode_get_http_status_safe (ec),
|
TALER_ErrorCode_get_http_status_safe (ec),
|
||||||
TALER_JSON_pack_ec (ec),
|
TALER_JSON_pack_ec (ec),
|
||||||
|
GNUNET_JSON_pack_data_auto ("coin_pub",
|
||||||
|
coin_pub),
|
||||||
GNUNET_JSON_pack_array_steal ("history",
|
GNUNET_JSON_pack_array_steal ("history",
|
||||||
history));
|
history));
|
||||||
}
|
}
|
||||||
|
@ -3620,7 +3620,7 @@ prepare_statements (struct PostgresClosure *pg)
|
|||||||
",merge_timestamp"
|
",merge_timestamp"
|
||||||
",partner_base_url"
|
",partner_base_url"
|
||||||
" FROM purse_merges"
|
" FROM purse_merges"
|
||||||
" JOIN partners USING (partner_serial_id)"
|
" LEFT JOIN partners USING (partner_serial_id)"
|
||||||
" WHERE purse_pub=$1;",
|
" WHERE purse_pub=$1;",
|
||||||
1),
|
1),
|
||||||
/* Used in #postgres_do_account_merge() */
|
/* Used in #postgres_do_account_merge() */
|
||||||
|
@ -33,6 +33,28 @@
|
|||||||
#include "exchange_api_curl_defaults.h"
|
#include "exchange_api_curl_defaults.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information we track per coin.
|
||||||
|
*/
|
||||||
|
struct Coin
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Coin's public key.
|
||||||
|
*/
|
||||||
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coin's denomination.
|
||||||
|
*/
|
||||||
|
struct TALER_DenominationHashP h_denom_pub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How much did we say the coin contributed.
|
||||||
|
*/
|
||||||
|
struct TALER_Amount contribution;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A purse create with deposit handle
|
* @brief A purse create with deposit handle
|
||||||
*/
|
*/
|
||||||
@ -83,7 +105,7 @@ struct TALER_EXCHANGE_PurseDepositHandle
|
|||||||
/**
|
/**
|
||||||
* Array of @e num_deposits coins we are depositing.
|
* Array of @e num_deposits coins we are depositing.
|
||||||
*/
|
*/
|
||||||
struct TALER_CoinSpendPublicKeyP *coins;
|
struct Coin *coins;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of coins we are depositing.
|
* Number of coins we are depositing.
|
||||||
@ -122,7 +144,6 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
break;
|
break;
|
||||||
case MHD_HTTP_OK:
|
case MHD_HTTP_OK:
|
||||||
{
|
{
|
||||||
const struct TALER_EXCHANGE_Keys *key_state;
|
|
||||||
struct GNUNET_TIME_Timestamp etime;
|
struct GNUNET_TIME_Timestamp etime;
|
||||||
struct TALER_ExchangeSignatureP exchange_sig;
|
struct TALER_ExchangeSignatureP exchange_sig;
|
||||||
struct TALER_ExchangePublicKeyP exchange_pub;
|
struct TALER_ExchangePublicKeyP exchange_pub;
|
||||||
@ -158,9 +179,8 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
key_state = TALER_EXCHANGE_get_keys (pch->exchange);
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
TALER_EXCHANGE_test_signing_key (key_state,
|
TALER_EXCHANGE_test_signing_key (keys,
|
||||||
&exchange_pub))
|
&exchange_pub))
|
||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
@ -191,22 +211,23 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
/* This should never happen, either us or the exchange is buggy
|
/* This should never happen, either us or the exchange is buggy
|
||||||
(or API version conflict); just pass JSON reply to the application */
|
(or API version conflict); just pass JSON reply to the application */
|
||||||
dr.hr.ec = TALER_JSON_get_error_code (j);
|
dr.hr.ec = TALER_JSON_get_error_code (j);
|
||||||
dr.hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_FORBIDDEN:
|
case MHD_HTTP_FORBIDDEN:
|
||||||
dr.hr.ec = TALER_JSON_get_error_code (j);
|
dr.hr.ec = TALER_JSON_get_error_code (j);
|
||||||
dr.hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
/* Nothing really to verify, exchange says one of the signatures is
|
/* Nothing really to verify, exchange says one of the signatures is
|
||||||
invalid; as we checked them, this should never happen, we
|
invalid; as we checked them, this should never happen, we
|
||||||
should pass the JSON reply to the application */
|
should pass the JSON reply to the application */
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_NOT_FOUND:
|
case MHD_HTTP_NOT_FOUND:
|
||||||
dr.hr.ec = TALER_JSON_get_error_code (j);
|
dr.hr.ec = TALER_JSON_get_error_code (j);
|
||||||
dr.hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
/* Nothing really to verify, this should never
|
/* Nothing really to verify, this should never
|
||||||
happen, we should pass the JSON reply to the application */
|
happen, we should pass the JSON reply to the application */
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_CONFLICT:
|
case MHD_HTTP_CONFLICT:
|
||||||
|
dr.hr.ec = TALER_JSON_get_error_code (j);
|
||||||
|
switch (dr.hr.ec)
|
||||||
|
{
|
||||||
|
case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA:
|
||||||
{
|
{
|
||||||
const char *partner_url = NULL;
|
const char *partner_url = NULL;
|
||||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
@ -240,7 +261,7 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
}
|
}
|
||||||
for (unsigned int i = 0; i<pch->num_deposits; i++)
|
for (unsigned int i = 0; i<pch->num_deposits; i++)
|
||||||
if (0 == GNUNET_memcmp (&coin_pub,
|
if (0 == GNUNET_memcmp (&coin_pub,
|
||||||
&pch->coins[i]))
|
&pch->coins[i].coin_pub))
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
@ -268,8 +289,182 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* conflict is real! */
|
/* meta data conflict is real! */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
|
||||||
|
{
|
||||||
|
json_t *history;
|
||||||
|
struct TALER_Amount total;
|
||||||
|
struct TALER_DenominationHashP h_denom_pub;
|
||||||
|
const struct TALER_EXCHANGE_DenomPublicKey *dki;
|
||||||
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
|
GNUNET_JSON_spec_fixed_auto ("coin_pub",
|
||||||
|
&coin_pub),
|
||||||
|
GNUNET_JSON_spec_json ("history",
|
||||||
|
&history),
|
||||||
|
GNUNET_JSON_spec_end ()
|
||||||
|
};
|
||||||
|
bool found = false;
|
||||||
|
const struct Coin *my_coin;
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_JSON_parse (j,
|
||||||
|
spec,
|
||||||
|
NULL, NULL))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i<pch->num_deposits; i++)
|
||||||
|
{
|
||||||
|
if (0 == GNUNET_memcmp (&coin_pub,
|
||||||
|
&pch->coins[i].coin_pub))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
my_coin = &pch->coins[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! found)
|
||||||
|
{
|
||||||
|
/* proof is about a coin we did not even deposit */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dki = TALER_EXCHANGE_get_denomination_key_by_hash (
|
||||||
|
keys,
|
||||||
|
&my_coin->h_denom_pub);
|
||||||
|
if (NULL == dki)
|
||||||
|
{
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_verify_coin_history (dki,
|
||||||
|
dki->value.currency,
|
||||||
|
&coin_pub,
|
||||||
|
history,
|
||||||
|
&h_denom_pub,
|
||||||
|
&total))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
json_decref (history);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
json_decref (history);
|
||||||
|
if (0 >
|
||||||
|
TALER_amount_add (&total,
|
||||||
|
&total,
|
||||||
|
&my_coin->contribution))
|
||||||
|
{
|
||||||
|
/* clearly not OK if our transaction would have caused
|
||||||
|
the overflow... */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (0 >= TALER_amount_cmp (&total,
|
||||||
|
&dki->value))
|
||||||
|
{
|
||||||
|
/* transaction should have still fit */
|
||||||
|
GNUNET_break (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* everything OK, proof of double-spending was provided */
|
||||||
|
}
|
||||||
|
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
|
||||||
|
{
|
||||||
|
json_t *history;
|
||||||
|
struct TALER_Amount total;
|
||||||
|
struct TALER_DenominationHashP h_denom_pub;
|
||||||
|
const struct Coin *my_coin;
|
||||||
|
const struct TALER_EXCHANGE_DenomPublicKey *dki;
|
||||||
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||||
|
struct GNUNET_JSON_Specification spec[] = {
|
||||||
|
GNUNET_JSON_spec_fixed_auto ("coin_pub",
|
||||||
|
&coin_pub),
|
||||||
|
GNUNET_JSON_spec_json ("history",
|
||||||
|
&history),
|
||||||
|
GNUNET_JSON_spec_end ()
|
||||||
|
};
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_JSON_parse (j,
|
||||||
|
spec,
|
||||||
|
NULL, NULL))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i<pch->num_deposits; i++)
|
||||||
|
{
|
||||||
|
if (0 == GNUNET_memcmp (&coin_pub,
|
||||||
|
&pch->coins[i].coin_pub))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
my_coin = &pch->coins[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! found)
|
||||||
|
{
|
||||||
|
/* proof is about a coin we did not even deposit */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dki = TALER_EXCHANGE_get_denomination_key_by_hash (
|
||||||
|
keys,
|
||||||
|
&my_coin->h_denom_pub);
|
||||||
|
memset (&h_denom_pub,
|
||||||
|
0,
|
||||||
|
sizeof (h_denom_pub));
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_EXCHANGE_verify_coin_history (dki,
|
||||||
|
dki->value.currency,
|
||||||
|
&coin_pub,
|
||||||
|
history,
|
||||||
|
&h_denom_pub,
|
||||||
|
&total))
|
||||||
|
{
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
json_decref (history);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
json_decref (history);
|
||||||
|
if (0 == GNUNET_memcmp (&dki->h_key,
|
||||||
|
&h_denom_pub))
|
||||||
|
{
|
||||||
|
/* sorry, this proves nothing */
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* everything OK, proof of conflicting denomination was provided */
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
GNUNET_break_op (0);
|
||||||
|
dr.hr.http_status = 0;
|
||||||
|
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
|
||||||
|
break;
|
||||||
|
} /* ec switch */
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_GONE:
|
case MHD_HTTP_GONE:
|
||||||
/* could happen if denomination was revoked */
|
/* could happen if denomination was revoked */
|
||||||
@ -277,18 +472,15 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
signature here, alas tricky in case our /keys
|
signature here, alas tricky in case our /keys
|
||||||
is outdated => left to clients */
|
is outdated => left to clients */
|
||||||
dr.hr.ec = TALER_JSON_get_error_code (j);
|
dr.hr.ec = TALER_JSON_get_error_code (j);
|
||||||
dr.hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
break;
|
break;
|
||||||
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
||||||
dr.hr.ec = TALER_JSON_get_error_code (j);
|
dr.hr.ec = TALER_JSON_get_error_code (j);
|
||||||
dr.hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
/* Server had an internal issue; we should retry, but this API
|
/* Server had an internal issue; we should retry, but this API
|
||||||
leaves this to the application */
|
leaves this to the application */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* unexpected response code */
|
/* unexpected response code */
|
||||||
dr.hr.ec = TALER_JSON_get_error_code (j);
|
dr.hr.ec = TALER_JSON_get_error_code (j);
|
||||||
dr.hr.hint = TALER_JSON_get_error_hint (j);
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Unexpected response code %u/%d for exchange deposit\n",
|
"Unexpected response code %u/%d for exchange deposit\n",
|
||||||
(unsigned int) response_code,
|
(unsigned int) response_code,
|
||||||
@ -296,6 +488,10 @@ handle_purse_deposit_finished (void *cls,
|
|||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (TALER_EC_NONE == dr.hr.ec)
|
||||||
|
dr.hr.hint = NULL;
|
||||||
|
else
|
||||||
|
dr.hr.hint = TALER_ErrorCode_get_hint (dr.hr.ec);
|
||||||
pch->cb (pch->cb_cls,
|
pch->cb (pch->cb_cls,
|
||||||
&dr);
|
&dr);
|
||||||
TALER_EXCHANGE_purse_deposit_cancel (pch);
|
TALER_EXCHANGE_purse_deposit_cancel (pch);
|
||||||
@ -361,11 +557,11 @@ TALER_EXCHANGE_purse_deposit (
|
|||||||
"/");
|
"/");
|
||||||
pch->num_deposits = num_deposits;
|
pch->num_deposits = num_deposits;
|
||||||
pch->coins = GNUNET_new_array (num_deposits,
|
pch->coins = GNUNET_new_array (num_deposits,
|
||||||
struct TALER_CoinSpendPublicKeyP);
|
struct Coin);
|
||||||
for (unsigned int i = 0; i<num_deposits; i++)
|
for (unsigned int i = 0; i<num_deposits; i++)
|
||||||
{
|
{
|
||||||
const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
|
const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
|
||||||
struct TALER_CoinSpendPublicKeyP *coin_pub = &pch->coins[i];
|
struct Coin *coin = &pch->coins[i];
|
||||||
json_t *jdeposit;
|
json_t *jdeposit;
|
||||||
struct TALER_CoinSpendSignatureP coin_sig;
|
struct TALER_CoinSpendSignatureP coin_sig;
|
||||||
#if FIXME_OEC
|
#if FIXME_OEC
|
||||||
@ -390,7 +586,9 @@ TALER_EXCHANGE_purse_deposit (
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
GNUNET_CRYPTO_eddsa_key_get_public (&deposit->coin_priv.eddsa_priv,
|
GNUNET_CRYPTO_eddsa_key_get_public (&deposit->coin_priv.eddsa_priv,
|
||||||
&coin_pub->eddsa_pub);
|
&coin->coin_pub.eddsa_pub);
|
||||||
|
coin->h_denom_pub = deposit->h_denom_pub;
|
||||||
|
coin->contribution = deposit->amount;
|
||||||
TALER_wallet_purse_deposit_sign (
|
TALER_wallet_purse_deposit_sign (
|
||||||
pch->base_url,
|
pch->base_url,
|
||||||
&pch->purse_pub,
|
&pch->purse_pub,
|
||||||
@ -413,7 +611,7 @@ TALER_EXCHANGE_purse_deposit (
|
|||||||
TALER_JSON_pack_denom_sig ("ub_sig",
|
TALER_JSON_pack_denom_sig ("ub_sig",
|
||||||
&deposit->denom_sig),
|
&deposit->denom_sig),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_pub",
|
GNUNET_JSON_pack_data_auto ("coin_pub",
|
||||||
coin_pub),
|
&coin->coin_pub),
|
||||||
GNUNET_JSON_pack_data_auto ("coin_sig",
|
GNUNET_JSON_pack_data_auto ("coin_sig",
|
||||||
&coin_sig));
|
&coin_sig));
|
||||||
GNUNET_assert (0 ==
|
GNUNET_assert (0 ==
|
||||||
|
@ -118,7 +118,7 @@ make_payto (const char *exchange_url,
|
|||||||
|
|
||||||
end = GNUNET_STRINGS_data_to_string (
|
end = GNUNET_STRINGS_data_to_string (
|
||||||
reserve_pub,
|
reserve_pub,
|
||||||
sizeof (reserve_pub),
|
sizeof (*reserve_pub),
|
||||||
pub_str,
|
pub_str,
|
||||||
sizeof (pub_str));
|
sizeof (pub_str));
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
|
@ -112,6 +112,8 @@ run (void *cls,
|
|||||||
*/
|
*/
|
||||||
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
|
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
|
||||||
"EUR:5.01"),
|
"EUR:5.01"),
|
||||||
|
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-2",
|
||||||
|
"EUR:5.01"),
|
||||||
TALER_TESTING_cmd_reserve_poll ("poll-reserve-1",
|
TALER_TESTING_cmd_reserve_poll ("poll-reserve-1",
|
||||||
"create-reserve-1",
|
"create-reserve-1",
|
||||||
"EUR:5.01",
|
"EUR:5.01",
|
||||||
@ -122,6 +124,11 @@ run (void *cls,
|
|||||||
bc.user42_payto,
|
bc.user42_payto,
|
||||||
bc.exchange_payto,
|
bc.exchange_payto,
|
||||||
"create-reserve-1"),
|
"create-reserve-1"),
|
||||||
|
TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-2",
|
||||||
|
"EUR:5.01",
|
||||||
|
bc.user42_payto,
|
||||||
|
bc.exchange_payto,
|
||||||
|
"create-reserve-2"),
|
||||||
/**
|
/**
|
||||||
* Make a reserve exist, according to the previous
|
* Make a reserve exist, according to the previous
|
||||||
* transfer.
|
* transfer.
|
||||||
@ -193,6 +200,13 @@ run (void *cls,
|
|||||||
"EUR:1",
|
"EUR:1",
|
||||||
MHD_HTTP_OK),
|
MHD_HTTP_OK),
|
||||||
#endif
|
#endif
|
||||||
|
/* Test conflicting merge */
|
||||||
|
TALER_TESTING_cmd_purse_merge (
|
||||||
|
"purse-merge-into-reserve",
|
||||||
|
MHD_HTTP_CONFLICT,
|
||||||
|
"push-get-contract",
|
||||||
|
"create-reserve-2"),
|
||||||
|
|
||||||
TALER_TESTING_cmd_end ()
|
TALER_TESTING_cmd_end ()
|
||||||
};
|
};
|
||||||
struct TALER_TESTING_Command pull[] = {
|
struct TALER_TESTING_Command pull[] = {
|
||||||
@ -241,6 +255,24 @@ run (void *cls,
|
|||||||
"create-reserve-1",
|
"create-reserve-1",
|
||||||
"EUR:2",
|
"EUR:2",
|
||||||
MHD_HTTP_OK),
|
MHD_HTTP_OK),
|
||||||
|
#endif
|
||||||
|
/* create 2nd purse for a deposit conflict */
|
||||||
|
TALER_TESTING_cmd_purse_create_with_reserve (
|
||||||
|
"purse-create-with-reserve-2",
|
||||||
|
MHD_HTTP_OK,
|
||||||
|
"{\"amount\":\"EUR:4\",\"summary\":\"beer\"}",
|
||||||
|
true /* upload contract */,
|
||||||
|
GNUNET_TIME_UNIT_MINUTES, /* expiration */
|
||||||
|
"create-reserve-1"),
|
||||||
|
#if FIXME_RESERVE_HISTORY
|
||||||
|
TALER_TESTING_cmd_purse_deposit_coins (
|
||||||
|
"purse-deposit-coins-conflict",
|
||||||
|
MHD_HTTP_CONFLICT,
|
||||||
|
0 /* min age */,
|
||||||
|
"purse-create-with-reserve-2",
|
||||||
|
"withdraw-coin-1",
|
||||||
|
"EUR:4.01",
|
||||||
|
NULL),
|
||||||
#endif
|
#endif
|
||||||
TALER_TESTING_cmd_end ()
|
TALER_TESTING_cmd_end ()
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user