extending interpreter to cover refund (but not used yet)

This commit is contained in:
Christian Grothoff 2016-05-20 17:15:50 +02:00
parent e39beff272
commit 93aaf1d172
2 changed files with 200 additions and 31 deletions

View File

@ -144,7 +144,12 @@ enum OpCode
/**
* Check that the fakebank has not received any other transactions.
*/
OC_CHECK_BANK_TRANSFERS_EMPTY
OC_CHECK_BANK_TRANSFERS_EMPTY,
/**
* Refund some deposit.
*/
OC_REFUND
};
@ -601,6 +606,37 @@ struct Command
} check_bank_transfer;
struct {
/**
* Amount that should be refunded.
*/
const char *amount;
/**
* Expected refund fee.
*/
const char *fee;
/**
* Reference to the corresponding deposit operation.
* Used to obtain contract details, merchant keys,
* fee structure, etc.
*/
const char *deposit_ref;
/**
* Refund transaction identifier.
*/
uint64_t rtransaction_id;
/**
* Handle to the refund operation (while it is ongoing).
*/
struct TALER_EXCHANGE_RefundHandle *rh;
} refund;
} details;
};
@ -1533,6 +1569,82 @@ deposit_wtid_cb (void *cls,
}
/**
* Check the result for the refund request.
*
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
* 0 if the exchange's reply is bogus (fails to follow the protocol)
* @param obj the received JSON reply, should be kept as proof (and, in particular,
* be forwarded to the customer)
*/
static void
refund_cb (void *cls,
unsigned int http_status,
const json_t *obj)
{
struct InterpreterState *is = cls;
struct Command *cmd = &is->commands[is->ip];
cmd->details.refund.rh = NULL;
if (cmd->expected_response_code != http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s\n",
http_status,
cmd->label);
json_dumpf (obj, stderr, 0);
fail (is);
return;
}
switch (http_status)
{
case MHD_HTTP_OK:
break;
default:
break;
}
next_command (is);
}
/**
* Given a command that is used to withdraw coins,
* extract the corresponding public key of the coin.
*
* @param coin command relating to coin withdrawal or refresh
* @param idx index to use if we got multiple coins from the @a coin command
* @param[out] coin_pub where to store the public key of the coin
*/
static void
get_public_key_from_coin_command (const struct Command *coin,
unsigned int idx,
struct TALER_CoinSpendPublicKeyP *coin_pub)
{
switch (coin->oc)
{
case OC_WITHDRAW_SIGN:
GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.coin_priv.eddsa_priv,
&coin_pub->eddsa_pub);
break;
case OC_REFRESH_REVEAL:
{
const struct FreshCoin *fc;
GNUNET_assert (idx < coin->details.refresh_reveal.num_fresh_coins);
fc = &coin->details.refresh_reveal.fresh_coins[idx];
GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
&coin_pub->eddsa_pub);
}
break;
default:
GNUNET_assert (0);
}
}
/**
* Run the main interpreter loop that performs exchange operations.
*
@ -2038,29 +2150,9 @@ interpreter_run (void *cls)
coin = find_command (is,
ref->details.deposit.coin_ref);
GNUNET_assert (NULL != coin);
switch (coin->oc)
{
case OC_WITHDRAW_SIGN:
GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.coin_priv.eddsa_priv,
&coin_pub.eddsa_pub);
break;
case OC_REFRESH_REVEAL:
{
const struct FreshCoin *fc;
unsigned int idx;
idx = ref->details.deposit.coin_idx;
GNUNET_assert (idx < coin->details.refresh_reveal.num_fresh_coins);
fc = &coin->details.refresh_reveal.fresh_coins[idx];
GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
&coin_pub.eddsa_pub);
}
break;
default:
GNUNET_assert (0);
}
get_public_key_from_coin_command (coin,
ref->details.deposit.coin_idx,
&coin_pub);
wire = json_loads (ref->details.deposit.wire_details,
JSON_REJECT_DUPLICATES,
NULL);
@ -2150,6 +2242,72 @@ interpreter_run (void *cls)
next_command (is);
return;
}
case OC_REFUND:
{
const struct Command *coin;
struct GNUNET_HashCode h_contract;
json_t *contract;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_Amount refund_fee;
if (GNUNET_OK !=
TALER_string_to_amount (cmd->details.refund.amount,
&amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse amount `%s' at %u\n",
cmd->details.refund.amount,
is->ip);
fail (is);
return;
}
if (GNUNET_OK !=
TALER_string_to_amount (cmd->details.refund.fee,
&refund_fee))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse amount `%s' at %u\n",
cmd->details.refund.fee,
is->ip);
fail (is);
return;
}
ref = find_command (is,
cmd->details.refund.deposit_ref);
GNUNET_assert (NULL != ref);
contract = json_loads (cmd->details.deposit.contract,
JSON_REJECT_DUPLICATES,
NULL);
GNUNET_assert (NULL != contract);
TALER_JSON_hash (contract,
&h_contract);
json_decref (contract);
coin = find_command (is,
ref->details.deposit.coin_ref);
GNUNET_assert (NULL != coin);
get_public_key_from_coin_command (coin,
ref->details.deposit.coin_idx,
&coin_pub);
cmd->details.refund.rh
= TALER_EXCHANGE_refund (exchange,
&amount,
&refund_fee,
&h_contract,
ref->details.deposit.transaction_id,
&coin_pub,
cmd->details.refund.rtransaction_id,
&ref->details.deposit.merchant_priv,
&refund_cb,
is);
if (NULL == cmd->details.refund.rh)
{
GNUNET_break (0);
fail (is);
return;
}
return;
}
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unknown instruction %d at %u (%s)\n",
@ -2364,6 +2522,17 @@ do_shutdown (void *cls)
break;
case OC_CHECK_BANK_TRANSFERS_EMPTY:
break;
case OC_REFUND:
if (NULL != cmd->details.refund.rh)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Command %u (%s) did not complete\n",
i,
cmd->label);
TALER_EXCHANGE_refund_cancel (cmd->details.refund.rh);
cmd->details.refund.rh = NULL;
}
break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unknown instruction %d at %u (%s)\n",

View File

@ -475,7 +475,7 @@ struct TALER_EXCHANGE_RefundHandle;
/**
* Callbacks of this type are used to serve the result of submitting a
* deposit permission request to a exchange.
* refund request to an exchange.
*
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;