2015-01-08 18:37:20 +01:00
|
|
|
/*
|
|
|
|
This file is part of TALER
|
2017-03-02 06:26:12 +01:00
|
|
|
Copyright (C) 2014-2017 GNUnet e.V. and Inria
|
2015-01-08 18:37:20 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
Foundation; either version 3, or (at your option) any later version.
|
|
|
|
|
|
|
|
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
2016-07-07 17:55:25 +02:00
|
|
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
2015-01-08 18:37:20 +01:00
|
|
|
*/
|
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* @file exchange/test_exchange_api.c
|
|
|
|
* @brief testcase to test exchange's HTTP API interface
|
2015-01-08 18:37:20 +01:00
|
|
|
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
2015-06-18 11:39:53 +02:00
|
|
|
* @author Christian Grothoff
|
2015-01-08 18:37:20 +01:00
|
|
|
*/
|
|
|
|
#include "platform.h"
|
|
|
|
#include "taler_util.h"
|
2015-07-05 16:55:01 +02:00
|
|
|
#include "taler_signatures.h"
|
2016-03-01 15:35:04 +01:00
|
|
|
#include "taler_exchange_service.h"
|
2016-03-19 15:23:11 +01:00
|
|
|
#include "taler_json_lib.h"
|
2015-07-08 08:54:55 +02:00
|
|
|
#include <gnunet/gnunet_util_lib.h>
|
2015-07-04 18:45:51 +02:00
|
|
|
#include <microhttpd.h>
|
2016-06-08 11:35:28 +02:00
|
|
|
#include "taler_fakebank_lib.h"
|
2016-05-03 13:55:40 +02:00
|
|
|
|
2015-07-04 18:45:51 +02:00
|
|
|
|
2015-09-15 17:27:02 +02:00
|
|
|
/**
|
|
|
|
* Is the configuration file is set to include wire format 'test'?
|
|
|
|
*/
|
|
|
|
#define WIRE_TEST 1
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Is the configuration file is set to include wire format 'sepa'?
|
|
|
|
*/
|
2015-09-20 14:02:10 +02:00
|
|
|
#define WIRE_SEPA 1
|
2015-01-08 18:37:20 +01:00
|
|
|
|
2015-06-18 11:39:53 +02:00
|
|
|
/**
|
|
|
|
* Main execution context for the main loop.
|
|
|
|
*/
|
2016-04-17 17:45:15 +02:00
|
|
|
static struct GNUNET_CURL_Context *ctx;
|
2015-01-08 18:37:20 +01:00
|
|
|
|
2015-06-18 11:39:53 +02:00
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* Handle to access the exchange.
|
2015-06-18 11:39:53 +02:00
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
static struct TALER_EXCHANGE_Handle *exchange;
|
2015-01-08 18:37:20 +01:00
|
|
|
|
2015-06-18 11:39:53 +02:00
|
|
|
/**
|
2016-05-02 08:24:21 +02:00
|
|
|
* Context for running the CURL event loop.
|
2015-06-18 11:39:53 +02:00
|
|
|
*/
|
2016-05-02 08:24:21 +02:00
|
|
|
static struct GNUNET_CURL_RescheduleContext *rc;
|
2015-01-08 18:37:20 +01:00
|
|
|
|
2017-04-10 01:24:05 +02:00
|
|
|
/**
|
|
|
|
* Handle to the exchange process.
|
|
|
|
*/
|
|
|
|
static struct GNUNET_OS_Process *exchanged;
|
|
|
|
|
2015-06-18 11:39:53 +02:00
|
|
|
/**
|
2016-05-02 08:24:21 +02:00
|
|
|
* Task run on timeout.
|
2015-06-18 11:39:53 +02:00
|
|
|
*/
|
2016-05-02 08:24:21 +02:00
|
|
|
static struct GNUNET_SCHEDULER_Task *timeout_task;
|
2015-06-18 01:17:01 +02:00
|
|
|
|
2016-05-03 13:55:40 +02:00
|
|
|
/**
|
|
|
|
* Handle to our fakebank.
|
|
|
|
*/
|
2016-06-08 11:35:28 +02:00
|
|
|
static struct TALER_FAKEBANK_Handle *fakebank;
|
2016-05-03 13:55:40 +02:00
|
|
|
|
2015-06-18 11:39:53 +02:00
|
|
|
/**
|
|
|
|
* Result of the testcases, #GNUNET_OK on success
|
|
|
|
*/
|
2015-01-08 18:37:20 +01:00
|
|
|
static int result;
|
|
|
|
|
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
/**
|
|
|
|
* Opcodes for the interpreter.
|
|
|
|
*/
|
|
|
|
enum OpCode
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Termination code, stops the interpreter loop (with success).
|
|
|
|
*/
|
|
|
|
OC_END = 0,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add funds to a reserve by (faking) incoming wire transfer.
|
|
|
|
*/
|
|
|
|
OC_ADMIN_ADD_INCOMING,
|
|
|
|
|
2015-07-09 11:36:13 +02:00
|
|
|
/**
|
|
|
|
* Check status of a reserve.
|
|
|
|
*/
|
|
|
|
OC_WITHDRAW_STATUS,
|
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
/**
|
|
|
|
* Withdraw a coin from a reserve.
|
|
|
|
*/
|
|
|
|
OC_WITHDRAW_SIGN,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Deposit a coin (pay with it).
|
|
|
|
*/
|
2015-08-08 23:21:00 +02:00
|
|
|
OC_DEPOSIT,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Melt a (set of) coins.
|
|
|
|
*/
|
|
|
|
OC_REFRESH_MELT,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Complete melting session by withdrawing melted coins.
|
|
|
|
*/
|
|
|
|
OC_REFRESH_REVEAL,
|
|
|
|
|
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* Verify exchange's /refresh/link by linking original private key to
|
2015-08-08 23:21:00 +02:00
|
|
|
* results from #OC_REFRESH_REVEAL step.
|
|
|
|
*/
|
2015-09-15 10:00:21 +02:00
|
|
|
OC_REFRESH_LINK,
|
|
|
|
|
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* Verify the exchange's /wire-method.
|
2015-09-15 10:00:21 +02:00
|
|
|
*/
|
2016-01-22 15:29:31 +01:00
|
|
|
OC_WIRE,
|
|
|
|
|
|
|
|
/**
|
2016-06-09 19:18:13 +02:00
|
|
|
* Verify exchange's /track/transfer method.
|
2016-01-22 15:29:31 +01:00
|
|
|
*/
|
|
|
|
OC_WIRE_DEPOSITS,
|
|
|
|
|
|
|
|
/**
|
2016-06-09 19:18:13 +02:00
|
|
|
* Verify exchange's /track/transaction method.
|
2016-01-22 15:29:31 +01:00
|
|
|
*/
|
2016-05-03 07:57:49 +02:00
|
|
|
OC_DEPOSIT_WTID,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Run the aggregator to execute deposits.
|
|
|
|
*/
|
2016-05-03 13:55:40 +02:00
|
|
|
OC_RUN_AGGREGATOR,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check that the fakebank has received a certain transaction.
|
|
|
|
*/
|
2016-05-04 05:38:29 +02:00
|
|
|
OC_CHECK_BANK_TRANSFER,
|
2016-05-03 13:55:40 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check that the fakebank has not received any other transactions.
|
|
|
|
*/
|
2016-05-20 17:15:50 +02:00
|
|
|
OC_CHECK_BANK_TRANSFERS_EMPTY,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Refund some deposit.
|
|
|
|
*/
|
2017-04-10 01:24:05 +02:00
|
|
|
OC_REFUND,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Revoke some denomination key.
|
|
|
|
*/
|
|
|
|
OC_REVOKE,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Payback some coin.
|
|
|
|
*/
|
|
|
|
OC_PAYBACK
|
2015-07-04 17:30:38 +02:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-08-08 23:35:51 +02:00
|
|
|
/**
|
|
|
|
* Structure specifying details about a coin to be melted.
|
|
|
|
* Used in a NULL-terminated array as part of command
|
|
|
|
* specification.
|
|
|
|
*/
|
|
|
|
struct MeltDetails
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Amount to melt (including fee).
|
|
|
|
*/
|
|
|
|
const char *amount;
|
|
|
|
|
|
|
|
/**
|
2015-09-19 22:08:49 +02:00
|
|
|
* Reference to reserve_withdraw operations for coin to
|
2015-08-08 23:35:51 +02:00
|
|
|
* be used for the /refresh/melt operation.
|
|
|
|
*/
|
|
|
|
const char *coin_ref;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-08-09 16:21:49 +02:00
|
|
|
/**
|
|
|
|
* Information about a fresh coin generated by the refresh operation.
|
|
|
|
*/
|
|
|
|
struct FreshCoin
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If @e amount is NULL, this specifies the denomination key to
|
|
|
|
* use. Otherwise, this will be set (by the interpreter) to the
|
|
|
|
* denomination PK matching @e amount.
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
const struct TALER_EXCHANGE_DenomPublicKey *pk;
|
2015-08-09 16:21:49 +02:00
|
|
|
|
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* Set (by the interpreter) to the exchange's signature over the
|
2015-08-09 16:21:49 +02:00
|
|
|
* coin's public key.
|
|
|
|
*/
|
|
|
|
struct TALER_DenominationSignature sig;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set (by the interpreter) to the coin's private key.
|
|
|
|
*/
|
|
|
|
struct TALER_CoinSpendPrivateKeyP coin_priv;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* Details for a exchange operation to execute.
|
2015-07-04 17:30:38 +02:00
|
|
|
*/
|
|
|
|
struct Command
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Opcode of the command.
|
|
|
|
*/
|
|
|
|
enum OpCode oc;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Label for the command, can be NULL.
|
|
|
|
*/
|
|
|
|
const char *label;
|
|
|
|
|
2015-07-09 12:22:07 +02:00
|
|
|
/**
|
|
|
|
* Which response code do we expect for this command?
|
|
|
|
*/
|
|
|
|
unsigned int expected_response_code;
|
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
/**
|
|
|
|
* Details about the command.
|
|
|
|
*/
|
|
|
|
union
|
|
|
|
{
|
|
|
|
|
2015-08-08 23:21:00 +02:00
|
|
|
/**
|
|
|
|
* Information for a #OC_ADMIN_ADD_INCOMING command.
|
|
|
|
*/
|
2015-07-04 17:30:38 +02:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Label to another admin_add_incoming command if we
|
|
|
|
* should deposit into an existing reserve, NULL if
|
|
|
|
* a fresh reserve should be created.
|
|
|
|
*/
|
|
|
|
const char *reserve_reference;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* String describing the amount to add to the reserve.
|
|
|
|
*/
|
|
|
|
const char *amount;
|
|
|
|
|
2015-07-04 18:45:51 +02:00
|
|
|
/**
|
2016-05-26 16:38:59 +02:00
|
|
|
* Sender account details (JSON).
|
2015-07-04 18:45:51 +02:00
|
|
|
*/
|
2016-05-26 16:38:59 +02:00
|
|
|
const char *sender_details;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Transfer information identifier (JSON).
|
|
|
|
*/
|
|
|
|
const char *transfer_details;
|
2015-07-04 18:45:51 +02:00
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
/**
|
|
|
|
* Set (by the interpreter) to the reserve's private key
|
|
|
|
* we used to fill the reserve.
|
|
|
|
*/
|
|
|
|
struct TALER_ReservePrivateKeyP reserve_priv;
|
|
|
|
|
2015-07-04 18:45:51 +02:00
|
|
|
/**
|
|
|
|
* Set to the API's handle during the operation.
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
struct TALER_EXCHANGE_AdminAddIncomingHandle *aih;
|
2015-07-04 18:45:51 +02:00
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
} admin_add_incoming;
|
|
|
|
|
2015-08-08 23:21:00 +02:00
|
|
|
/**
|
|
|
|
* Information for a #OC_WITHDRAW_STATUS command.
|
|
|
|
*/
|
2015-07-09 11:36:13 +02:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Label to the #OC_ADMIN_ADD_INCOMING command which
|
|
|
|
* created the reserve.
|
|
|
|
*/
|
|
|
|
const char *reserve_reference;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set to the API's handle during the operation.
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
struct TALER_EXCHANGE_ReserveStatusHandle *wsh;
|
2015-07-09 11:36:13 +02:00
|
|
|
|
2015-07-09 12:11:01 +02:00
|
|
|
/**
|
|
|
|
* Expected reserve balance.
|
|
|
|
*/
|
|
|
|
const char *expected_balance;
|
|
|
|
|
2015-09-19 22:08:49 +02:00
|
|
|
} reserve_status;
|
2015-07-09 11:36:13 +02:00
|
|
|
|
2015-08-08 23:21:00 +02:00
|
|
|
/**
|
|
|
|
* Information for a #OC_WITHDRAW_SIGN command.
|
|
|
|
*/
|
2015-07-04 17:30:38 +02:00
|
|
|
struct
|
|
|
|
{
|
2015-08-08 23:21:00 +02:00
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
/**
|
|
|
|
* Which reserve should we withdraw from?
|
|
|
|
*/
|
|
|
|
const char *reserve_reference;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* String describing the denomination value we should withdraw.
|
2016-03-01 15:35:04 +01:00
|
|
|
* A corresponding denomination key must exist in the exchange's
|
2015-07-04 17:30:38 +02:00
|
|
|
* offerings. Can be NULL if @e pk is set instead.
|
|
|
|
*/
|
|
|
|
const char *amount;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If @e amount is NULL, this specifies the denomination key to
|
|
|
|
* use. Otherwise, this will be set (by the interpreter) to the
|
|
|
|
* denomination PK matching @e amount.
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
const struct TALER_EXCHANGE_DenomPublicKey *pk;
|
2015-07-04 17:30:38 +02:00
|
|
|
|
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* Set (by the interpreter) to the exchange's signature over the
|
2015-07-04 17:30:38 +02:00
|
|
|
* coin's public key.
|
|
|
|
*/
|
|
|
|
struct TALER_DenominationSignature sig;
|
|
|
|
|
|
|
|
/**
|
2017-10-31 14:02:54 +01:00
|
|
|
* Private key material of the coin, set by the interpreter.
|
2015-07-04 17:30:38 +02:00
|
|
|
*/
|
2017-10-31 14:02:54 +01:00
|
|
|
struct TALER_PlanchetSecretsP ps;
|
2015-07-04 22:35:30 +02:00
|
|
|
|
2015-07-04 22:00:29 +02:00
|
|
|
/**
|
|
|
|
* Withdraw handle (while operation is running).
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
|
2015-07-04 22:00:29 +02:00
|
|
|
|
2015-09-19 22:08:49 +02:00
|
|
|
} reserve_withdraw;
|
2015-07-04 17:30:38 +02:00
|
|
|
|
2015-08-08 23:21:00 +02:00
|
|
|
/**
|
|
|
|
* Information for a #OC_DEPOSIT command.
|
|
|
|
*/
|
2015-07-04 17:30:38 +02:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Amount to deposit.
|
|
|
|
*/
|
|
|
|
const char *amount;
|
|
|
|
|
|
|
|
/**
|
2015-09-19 22:08:49 +02:00
|
|
|
* Reference to a reserve_withdraw operation for a coin to
|
2015-07-04 17:30:38 +02:00
|
|
|
* be used for the /deposit operation.
|
|
|
|
*/
|
|
|
|
const char *coin_ref;
|
|
|
|
|
2015-08-08 23:35:51 +02:00
|
|
|
/**
|
|
|
|
* If this @e coin_ref refers to an operation that generated
|
|
|
|
* an array of coins, this value determines which coin to use.
|
|
|
|
*/
|
|
|
|
unsigned int coin_idx;
|
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
/**
|
|
|
|
* JSON string describing the merchant's "wire details".
|
|
|
|
*/
|
|
|
|
const char *wire_details;
|
|
|
|
|
|
|
|
/**
|
2017-02-06 15:41:39 +01:00
|
|
|
* JSON string describing what a proposal is about.
|
2015-07-04 17:30:38 +02:00
|
|
|
*/
|
2017-05-29 01:15:41 +02:00
|
|
|
const char *contract_terms;
|
2015-07-04 17:30:38 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Relative time (to add to 'now') to compute the refund deadline.
|
|
|
|
* Zero for no refunds.
|
|
|
|
*/
|
|
|
|
struct GNUNET_TIME_Relative refund_deadline;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set (by the interpreter) to a fresh private key of the merchant,
|
|
|
|
* if @e refund_deadline is non-zero.
|
|
|
|
*/
|
2015-07-05 14:32:26 +02:00
|
|
|
struct TALER_MerchantPrivateKeyP merchant_priv;
|
2015-07-04 17:30:38 +02:00
|
|
|
|
2015-07-04 22:00:29 +02:00
|
|
|
/**
|
|
|
|
* Deposit handle while operation is running.
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
struct TALER_EXCHANGE_DepositHandle *dh;
|
2015-07-04 22:00:29 +02:00
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
} deposit;
|
|
|
|
|
2015-08-08 23:21:00 +02:00
|
|
|
/**
|
|
|
|
* Information for a #OC_REFRESH_MELT command.
|
|
|
|
*/
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Information about coins to be melted.
|
|
|
|
*/
|
2016-05-16 11:55:47 +02:00
|
|
|
struct MeltDetails melted_coin;
|
2015-08-08 23:21:00 +02:00
|
|
|
|
|
|
|
/**
|
2015-08-09 14:55:38 +02:00
|
|
|
* Denominations of the fresh coins to withdraw.
|
2015-08-08 23:21:00 +02:00
|
|
|
*/
|
2015-08-09 14:55:38 +02:00
|
|
|
const char **fresh_amounts;
|
2015-08-08 23:21:00 +02:00
|
|
|
|
2015-08-09 16:21:49 +02:00
|
|
|
/**
|
|
|
|
* Array of the public keys corresponding to
|
|
|
|
* the @e fresh_amounts, set by the interpreter.
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
const struct TALER_EXCHANGE_DenomPublicKey **fresh_pks;
|
2015-08-09 16:21:49 +02:00
|
|
|
|
2015-08-08 23:21:00 +02:00
|
|
|
/**
|
|
|
|
* Melt handle while operation is running.
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
struct TALER_EXCHANGE_RefreshMeltHandle *rmh;
|
2015-08-08 23:21:00 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Data used in the refresh operation, set by the interpreter.
|
|
|
|
*/
|
|
|
|
char *refresh_data;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Number of bytes in @e refresh_data, set by the interpreter.
|
|
|
|
*/
|
|
|
|
size_t refresh_data_length;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set by the interpreter (upon completion) to the noreveal
|
2016-03-01 15:35:04 +01:00
|
|
|
* index selected by the exchange.
|
2015-08-08 23:21:00 +02:00
|
|
|
*/
|
|
|
|
uint16_t noreveal_index;
|
|
|
|
|
|
|
|
} refresh_melt;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Information for a #OC_REFRESH_REVEAL command.
|
|
|
|
*/
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Melt operation this is the matching reveal for.
|
|
|
|
*/
|
|
|
|
const char *melt_ref;
|
|
|
|
|
2015-08-09 15:24:02 +02:00
|
|
|
/**
|
|
|
|
* Reveal handle while operation is running.
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
struct TALER_EXCHANGE_RefreshRevealHandle *rrh;
|
2015-08-09 15:24:02 +02:00
|
|
|
|
2015-08-08 23:21:00 +02:00
|
|
|
/**
|
|
|
|
* Number of fresh coins withdrawn, set by the interpreter.
|
|
|
|
* Length of the @e fresh_coins array.
|
|
|
|
*/
|
|
|
|
unsigned int num_fresh_coins;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Information about coins withdrawn, set by the interpreter.
|
|
|
|
*/
|
2015-08-09 16:21:49 +02:00
|
|
|
struct FreshCoin *fresh_coins;
|
2015-08-08 23:21:00 +02:00
|
|
|
|
|
|
|
} refresh_reveal;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Information for a #OC_REFRESH_LINK command.
|
|
|
|
*/
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reveal operation this is the matching link for.
|
|
|
|
*/
|
|
|
|
const char *reveal_ref;
|
|
|
|
|
2015-08-09 15:24:02 +02:00
|
|
|
/**
|
|
|
|
* Link handle while operation is running.
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
struct TALER_EXCHANGE_RefreshLinkHandle *rlh;
|
2015-08-09 15:24:02 +02:00
|
|
|
|
2015-08-09 15:33:38 +02:00
|
|
|
/**
|
|
|
|
* Which of the melted coins should be used for the linkage?
|
|
|
|
*/
|
|
|
|
unsigned int coin_idx;
|
|
|
|
|
2015-08-08 23:21:00 +02:00
|
|
|
} refresh_link;
|
|
|
|
|
2015-09-15 10:00:21 +02:00
|
|
|
/**
|
|
|
|
* Information for the /wire command.
|
|
|
|
*/
|
|
|
|
struct {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle to the wire request.
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
struct TALER_EXCHANGE_WireHandle *wh;
|
2015-09-15 10:00:21 +02:00
|
|
|
|
2015-09-20 14:02:10 +02:00
|
|
|
/**
|
|
|
|
* Format we expect to see, others will be *ignored*.
|
|
|
|
*/
|
|
|
|
const char *format;
|
|
|
|
|
2017-03-06 17:36:10 +01:00
|
|
|
/**
|
|
|
|
* Expected wire fee.
|
|
|
|
*/
|
|
|
|
const char *expected_fee;
|
|
|
|
|
2015-09-15 10:00:21 +02:00
|
|
|
} wire;
|
|
|
|
|
2016-01-22 15:29:31 +01:00
|
|
|
/**
|
2016-06-09 19:18:13 +02:00
|
|
|
* Information for the /track/transfer's command.
|
2016-01-22 15:29:31 +01:00
|
|
|
*/
|
|
|
|
struct {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle to the wire deposits request.
|
|
|
|
*/
|
2016-06-09 19:18:13 +02:00
|
|
|
struct TALER_EXCHANGE_TrackTransferHandle *wdh;
|
2016-01-22 15:29:31 +01:00
|
|
|
|
|
|
|
/**
|
2016-05-04 06:10:41 +02:00
|
|
|
* Reference to a command providing a WTID. If set, we use the
|
|
|
|
* WTID from that command. The command can be either an
|
|
|
|
* #OC_DEPOSIT_WTID or an #OC_CHECK_BANK_TRANSFER. In the
|
|
|
|
* case of the bank transfer, we check that the total amount
|
|
|
|
* claimed by the exchange matches the total amount transferred
|
2016-06-09 19:18:13 +02:00
|
|
|
* by the bank. In the case of a /track/transaction, we check
|
2016-05-04 06:10:41 +02:00
|
|
|
* that the wire details match.
|
2016-01-22 15:29:31 +01:00
|
|
|
*/
|
|
|
|
const char *wtid_ref;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* WTID to use (used if @e wtid_ref is NULL).
|
|
|
|
*/
|
|
|
|
struct TALER_WireTransferIdentifierRawP wtid;
|
|
|
|
|
2016-05-04 06:10:41 +02:00
|
|
|
/**
|
|
|
|
* What is the expected total amount? Only used if
|
|
|
|
* @e expected_response_code was #MHD_HTTP_OK.
|
|
|
|
*/
|
|
|
|
const char *total_amount_expected;
|
|
|
|
|
2017-03-04 16:49:33 +01:00
|
|
|
/**
|
|
|
|
* What is the expected wire fee? Only used if
|
|
|
|
* @e expected_response_code was #MHD_HTTP_OK.
|
|
|
|
*/
|
|
|
|
const char *wire_fee_expected;
|
|
|
|
|
2016-05-04 06:10:41 +02:00
|
|
|
|
2016-01-22 15:29:31 +01:00
|
|
|
/* TODO: may want to add list of deposits we expected
|
|
|
|
to see aggregated here in the future. */
|
|
|
|
|
|
|
|
} wire_deposits;
|
|
|
|
|
|
|
|
/**
|
2016-06-09 19:18:13 +02:00
|
|
|
* Information for the /track/transaction command.
|
2016-01-22 15:29:31 +01:00
|
|
|
*/
|
|
|
|
struct {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle to the deposit wtid request.
|
|
|
|
*/
|
2016-06-09 19:18:13 +02:00
|
|
|
struct TALER_EXCHANGE_TrackTransactionHandle *dwh;
|
2016-01-22 15:29:31 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Which /deposit operation should we obtain WTID data for?
|
|
|
|
*/
|
|
|
|
const char *deposit_ref;
|
|
|
|
|
2016-05-04 05:36:23 +02:00
|
|
|
/**
|
2016-05-04 05:38:29 +02:00
|
|
|
* Which #OC_CHECK_BANK_TRANSFER wtid should this match? NULL for none.
|
2016-05-04 05:36:23 +02:00
|
|
|
*/
|
|
|
|
const char *bank_transfer_ref;
|
|
|
|
|
2016-01-22 15:29:31 +01:00
|
|
|
/**
|
|
|
|
* Wire transfer identifier, set if #MHD_HTTP_OK was the response code.
|
|
|
|
*/
|
|
|
|
struct TALER_WireTransferIdentifierRawP wtid;
|
|
|
|
|
|
|
|
} deposit_wtid;
|
|
|
|
|
2016-05-03 07:57:49 +02:00
|
|
|
struct {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process for the aggregator.
|
|
|
|
*/
|
|
|
|
struct GNUNET_OS_Process *aggregator_proc;
|
|
|
|
|
2016-06-09 15:20:24 +02:00
|
|
|
/**
|
|
|
|
* ID of task called whenever we get a SIGCHILD.
|
|
|
|
*/
|
|
|
|
struct GNUNET_SCHEDULER_Task *child_death_task;
|
|
|
|
|
2016-05-03 07:57:49 +02:00
|
|
|
} run_aggregator;
|
|
|
|
|
2016-05-03 13:55:40 +02:00
|
|
|
struct {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Which amount do we expect to see transferred?
|
|
|
|
*/
|
|
|
|
const char *amount;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Which account do we expect to be debited?
|
|
|
|
*/
|
|
|
|
uint64_t account_debit;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Which account do we expect to be credited?
|
|
|
|
*/
|
|
|
|
uint64_t account_credit;
|
|
|
|
|
2017-03-02 06:26:12 +01:00
|
|
|
/**
|
|
|
|
* Which exchange base URL is expected?
|
|
|
|
*/
|
|
|
|
const char *exchange_base_url;
|
|
|
|
|
2016-05-03 13:55:40 +02:00
|
|
|
/**
|
2017-06-11 15:25:59 +02:00
|
|
|
* Set (!) to the wire transfer subject observed.
|
2016-05-03 13:55:40 +02:00
|
|
|
*/
|
2017-06-11 15:25:59 +02:00
|
|
|
char *subject;
|
2016-05-03 13:55:40 +02:00
|
|
|
|
2016-05-04 05:38:29 +02:00
|
|
|
} check_bank_transfer;
|
2016-05-03 13:55:40 +02:00
|
|
|
|
2016-05-20 17:15:50 +02:00
|
|
|
struct {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Amount that should be refunded.
|
|
|
|
*/
|
|
|
|
const char *amount;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Expected refund fee.
|
|
|
|
*/
|
|
|
|
const char *fee;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reference to the corresponding deposit operation.
|
2017-02-06 15:41:39 +01:00
|
|
|
* Used to obtain proposal details, merchant keys,
|
2016-05-20 17:15:50 +02:00
|
|
|
* 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;
|
|
|
|
|
2017-04-10 01:24:05 +02:00
|
|
|
struct {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reference to a _coin's_ withdraw operation where the coin's denomination key
|
|
|
|
* is the denomination key to be revoked.
|
|
|
|
*/
|
|
|
|
const char *ref;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process for the aggregator.
|
|
|
|
*/
|
|
|
|
struct GNUNET_OS_Process *revoke_proc;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ID of task called whenever we get a SIGCHILD.
|
|
|
|
*/
|
|
|
|
struct GNUNET_SCHEDULER_Task *child_death_task;
|
|
|
|
|
|
|
|
} revoke;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reference to the _coin's_ withdraw operation.
|
|
|
|
*/
|
|
|
|
const char *ref;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Amount that should be paid back.
|
|
|
|
*/
|
|
|
|
const char *amount;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle to the ongoing /payback operation.
|
|
|
|
*/
|
|
|
|
struct TALER_EXCHANGE_PaybackHandle *ph;
|
|
|
|
|
|
|
|
} payback;
|
|
|
|
|
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
} details;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* State of the interpreter loop.
|
|
|
|
*/
|
|
|
|
struct InterpreterState
|
|
|
|
{
|
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* Keys from the exchange.
|
2015-07-04 17:30:38 +02:00
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
const struct TALER_EXCHANGE_Keys *keys;
|
2015-07-04 17:30:38 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Commands the interpreter will run.
|
|
|
|
*/
|
|
|
|
struct Command *commands;
|
|
|
|
|
2015-07-04 20:47:39 +02:00
|
|
|
/**
|
|
|
|
* Interpreter task (if one is scheduled).
|
|
|
|
*/
|
|
|
|
struct GNUNET_SCHEDULER_Task *task;
|
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
/**
|
|
|
|
* Instruction pointer. Tells #interpreter_run() which
|
|
|
|
* instruction to run next.
|
|
|
|
*/
|
|
|
|
unsigned int ip;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-05-04 05:16:32 +02:00
|
|
|
/**
|
|
|
|
* Pipe used to communicate child death via signal.
|
|
|
|
*/
|
|
|
|
static struct GNUNET_DISK_PipeHandle *sigpipe;
|
|
|
|
|
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
/**
|
|
|
|
* The testcase failed, return with an error code.
|
|
|
|
*
|
|
|
|
* @param is interpreter state to clean up
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
fail (struct InterpreterState *is)
|
|
|
|
{
|
|
|
|
result = GNUNET_SYSERR;
|
|
|
|
GNUNET_SCHEDULER_shutdown ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-04 18:45:51 +02:00
|
|
|
/**
|
|
|
|
* Find a command by label.
|
|
|
|
*
|
|
|
|
* @param is interpreter state to search
|
|
|
|
* @param label label to look for
|
|
|
|
* @return NULL if command was not found
|
|
|
|
*/
|
|
|
|
static const struct Command *
|
|
|
|
find_command (const struct InterpreterState *is,
|
|
|
|
const char *label)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
const struct Command *cmd;
|
|
|
|
|
2015-07-04 20:47:39 +02:00
|
|
|
if (NULL == label)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Attempt to lookup command for empty label\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-07-04 18:45:51 +02:00
|
|
|
for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
|
|
|
|
if ( (NULL != cmd->label) &&
|
|
|
|
(0 == strcmp (cmd->label,
|
|
|
|
label)) )
|
|
|
|
return cmd;
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Command not found: %s\n",
|
|
|
|
label);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* Run the main interpreter loop that performs exchange operations.
|
2015-07-04 18:45:51 +02:00
|
|
|
*
|
|
|
|
* @param cls contains the `struct InterpreterState`
|
|
|
|
*/
|
|
|
|
static void
|
2016-04-10 00:57:20 +02:00
|
|
|
interpreter_run (void *cls);
|
2015-07-04 18:45:51 +02:00
|
|
|
|
|
|
|
|
2016-05-03 07:57:49 +02:00
|
|
|
/**
|
|
|
|
* Run the next command with the interpreter.
|
|
|
|
*
|
|
|
|
* @param is current interpeter state.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
next_command (struct InterpreterState *is)
|
|
|
|
{
|
2017-03-06 17:36:10 +01:00
|
|
|
if (GNUNET_SYSERR == result)
|
|
|
|
return; /* ignore, we already failed! */
|
2016-05-03 07:57:49 +02:00
|
|
|
is->ip++;
|
|
|
|
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
|
|
|
is);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-04 18:45:51 +02:00
|
|
|
/**
|
2015-07-04 22:35:30 +02:00
|
|
|
* Function called upon completion of our /admin/add/incoming request.
|
2015-07-04 18:45:51 +02:00
|
|
|
*
|
|
|
|
* @param cls closure with the interpreter state
|
|
|
|
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
2016-03-01 15:35:04 +01:00
|
|
|
* 0 if the exchange's reply is bogus (fails to follow the protocol)
|
2016-10-20 21:00:40 +02:00
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param full_response full response from the exchange (for logging, in case of errors)
|
2015-07-04 18:45:51 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
add_incoming_cb (void *cls,
|
|
|
|
unsigned int http_status,
|
2016-10-20 21:00:40 +02:00
|
|
|
enum TALER_ErrorCode ec,
|
2016-04-17 17:45:15 +02:00
|
|
|
const json_t *full_response)
|
2015-07-04 18:45:51 +02:00
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
|
|
|
|
|
|
|
cmd->details.admin_add_incoming.aih = NULL;
|
|
|
|
if (MHD_HTTP_OK != http_status)
|
|
|
|
{
|
2015-07-05 13:05:58 +02:00
|
|
|
GNUNET_break (0);
|
2015-07-04 18:45:51 +02:00
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-05-03 07:57:49 +02:00
|
|
|
next_command (is);
|
2015-07-04 18:45:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-09 12:02:01 +02:00
|
|
|
/**
|
|
|
|
* Check if the given historic event @a h corresponds to the given
|
|
|
|
* command @a cmd.
|
|
|
|
*
|
|
|
|
* @param h event in history
|
|
|
|
* @param cmd an #OC_ADMIN_ADD_INCOMING command
|
|
|
|
* @return #GNUNET_OK if they match, #GNUNET_SYSERR if not
|
|
|
|
*/
|
|
|
|
static int
|
2016-03-01 15:35:04 +01:00
|
|
|
compare_admin_add_incoming_history (const struct TALER_EXCHANGE_ReserveHistory *h,
|
2015-07-09 12:02:01 +02:00
|
|
|
const struct Command *cmd)
|
|
|
|
{
|
|
|
|
struct TALER_Amount amount;
|
|
|
|
|
2016-03-01 15:35:04 +01:00
|
|
|
if (TALER_EXCHANGE_RTT_DEPOSIT != h->type)
|
2015-07-09 12:02:01 +02:00
|
|
|
{
|
|
|
|
GNUNET_break_op (0);
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
|
|
|
GNUNET_assert (GNUNET_OK ==
|
|
|
|
TALER_string_to_amount (cmd->details.admin_add_incoming.amount,
|
|
|
|
&amount));
|
|
|
|
if (0 != TALER_amount_cmp (&amount,
|
|
|
|
&h->amount))
|
|
|
|
{
|
|
|
|
GNUNET_break_op (0);
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the given historic event @a h corresponds to the given
|
|
|
|
* command @a cmd.
|
|
|
|
*
|
|
|
|
* @param h event in history
|
|
|
|
* @param cmd an #OC_WITHDRAW_SIGN command
|
|
|
|
* @return #GNUNET_OK if they match, #GNUNET_SYSERR if not
|
|
|
|
*/
|
|
|
|
static int
|
2016-03-01 15:35:04 +01:00
|
|
|
compare_reserve_withdraw_history (const struct TALER_EXCHANGE_ReserveHistory *h,
|
2015-09-19 22:08:49 +02:00
|
|
|
const struct Command *cmd)
|
2015-07-09 12:02:01 +02:00
|
|
|
{
|
|
|
|
struct TALER_Amount amount;
|
2015-07-09 12:11:01 +02:00
|
|
|
struct TALER_Amount amount_with_fee;
|
2015-07-09 12:02:01 +02:00
|
|
|
|
2016-03-01 15:35:04 +01:00
|
|
|
if (TALER_EXCHANGE_RTT_WITHDRAWAL != h->type)
|
2015-07-09 12:02:01 +02:00
|
|
|
{
|
|
|
|
GNUNET_break_op (0);
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
|
|
|
GNUNET_assert (GNUNET_OK ==
|
2015-09-19 22:08:49 +02:00
|
|
|
TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
|
2015-07-09 12:02:01 +02:00
|
|
|
&amount));
|
2015-07-09 12:11:01 +02:00
|
|
|
GNUNET_assert (GNUNET_OK ==
|
|
|
|
TALER_amount_add (&amount_with_fee,
|
|
|
|
&amount,
|
2015-09-19 22:08:49 +02:00
|
|
|
&cmd->details.reserve_withdraw.pk->fee_withdraw));
|
2015-07-09 12:11:01 +02:00
|
|
|
if (0 != TALER_amount_cmp (&amount_with_fee,
|
2015-07-09 12:02:01 +02:00
|
|
|
&h->amount))
|
|
|
|
{
|
|
|
|
GNUNET_break_op (0);
|
2015-07-09 12:11:01 +02:00
|
|
|
return GNUNET_SYSERR;
|
2015-07-09 12:02:01 +02:00
|
|
|
}
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-10 17:59:33 +02:00
|
|
|
/**
|
|
|
|
* Check if the given historic event @a h corresponds to the given
|
|
|
|
* command @a cmd.
|
|
|
|
*
|
|
|
|
* @param h event in history
|
|
|
|
* @param cmd an #OC_WITHDRAW_SIGN command
|
|
|
|
* @return #GNUNET_OK if they match, #GNUNET_SYSERR if not
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
compare_reserve_payback_history (const struct TALER_EXCHANGE_ReserveHistory *h,
|
|
|
|
const struct Command *cmd)
|
|
|
|
{
|
|
|
|
struct TALER_Amount amount;
|
|
|
|
|
|
|
|
if (TALER_EXCHANGE_RTT_PAYBACK != h->type)
|
|
|
|
{
|
|
|
|
GNUNET_break_op (0);
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
|
|
|
GNUNET_assert (GNUNET_OK ==
|
|
|
|
TALER_string_to_amount (cmd->details.payback.amount,
|
|
|
|
&amount));
|
|
|
|
if (0 != TALER_amount_cmp (&amount,
|
|
|
|
&h->amount))
|
|
|
|
{
|
|
|
|
GNUNET_break_op (0);
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-09 11:36:13 +02:00
|
|
|
/**
|
2015-09-19 22:08:49 +02:00
|
|
|
* Function called with the result of a /reserve/status request.
|
2015-07-09 11:36:13 +02:00
|
|
|
*
|
|
|
|
* @param cls closure with the interpreter state
|
|
|
|
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
2016-03-01 15:35:04 +01:00
|
|
|
* 0 if the exchange's reply is bogus (fails to follow the protocol)
|
2016-10-20 21:00:40 +02:00
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
2015-07-09 11:36:13 +02:00
|
|
|
* @param[in] json original response in JSON format (useful only for diagnostics)
|
|
|
|
* @param balance current balance in the reserve, NULL on error
|
|
|
|
* @param history_length number of entries in the transaction history, 0 on error
|
|
|
|
* @param history detailed transaction history, NULL on error
|
|
|
|
*/
|
|
|
|
static void
|
2015-09-19 22:08:49 +02:00
|
|
|
reserve_status_cb (void *cls,
|
|
|
|
unsigned int http_status,
|
2016-10-20 21:00:40 +02:00
|
|
|
enum TALER_ErrorCode ec,
|
2016-04-17 17:45:15 +02:00
|
|
|
const json_t *json,
|
2015-09-19 22:08:49 +02:00
|
|
|
const struct TALER_Amount *balance,
|
|
|
|
unsigned int history_length,
|
2016-03-01 15:35:04 +01:00
|
|
|
const struct TALER_EXCHANGE_ReserveHistory *history)
|
2015-07-09 11:36:13 +02:00
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
2015-07-09 12:02:01 +02:00
|
|
|
struct Command *rel;
|
2017-04-10 17:59:33 +02:00
|
|
|
const struct Command *xrel;
|
2015-07-09 12:02:01 +02:00
|
|
|
unsigned int i;
|
|
|
|
unsigned int j;
|
2015-07-09 12:11:01 +02:00
|
|
|
struct TALER_Amount amount;
|
2015-07-09 11:36:13 +02:00
|
|
|
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_status.wsh = NULL;
|
2015-07-09 12:22:07 +02:00
|
|
|
if (cmd->expected_response_code != http_status)
|
2015-07-09 12:02:01 +02:00
|
|
|
{
|
2015-07-09 12:47:49 +02:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Unexpected response code %u to command %s\n",
|
|
|
|
http_status,
|
|
|
|
cmd->label);
|
2015-07-09 12:02:01 +02:00
|
|
|
GNUNET_break (0);
|
2015-08-14 15:19:50 +02:00
|
|
|
json_dumpf (json, stderr, 0);
|
2015-07-09 12:02:01 +02:00
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-07-09 12:22:07 +02:00
|
|
|
switch (http_status)
|
2015-07-09 12:02:01 +02:00
|
|
|
{
|
2015-07-09 12:22:07 +02:00
|
|
|
case MHD_HTTP_OK:
|
|
|
|
/* FIXME: note that history events may come in a different
|
2015-07-09 13:02:40 +02:00
|
|
|
order than the commands. However, for now this works... */
|
2015-07-09 12:22:07 +02:00
|
|
|
j = 0;
|
|
|
|
for (i=0;i<is->ip;i++)
|
2015-07-09 12:02:01 +02:00
|
|
|
{
|
2015-07-09 12:22:07 +02:00
|
|
|
switch ((rel = &is->commands[i])->oc)
|
2015-07-09 12:02:01 +02:00
|
|
|
{
|
2015-07-09 12:22:07 +02:00
|
|
|
case OC_ADMIN_ADD_INCOMING:
|
|
|
|
if ( ( (NULL != rel->label) &&
|
2015-09-19 22:08:49 +02:00
|
|
|
(0 == strcmp (cmd->details.reserve_status.reserve_reference,
|
2015-07-09 12:22:07 +02:00
|
|
|
rel->label) ) ) ||
|
|
|
|
( (NULL != rel->details.admin_add_incoming.reserve_reference) &&
|
2015-09-19 22:08:49 +02:00
|
|
|
(0 == strcmp (cmd->details.reserve_status.reserve_reference,
|
2015-07-09 12:22:07 +02:00
|
|
|
rel->details.admin_add_incoming.reserve_reference) ) ) )
|
2015-07-09 12:02:01 +02:00
|
|
|
{
|
2017-03-02 06:26:12 +01:00
|
|
|
if ( (j >= history_length) ||
|
|
|
|
(GNUNET_OK !=
|
|
|
|
compare_admin_add_incoming_history (&history[j],
|
|
|
|
rel)) )
|
2015-07-09 12:22:07 +02:00
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
j++;
|
2015-07-09 12:02:01 +02:00
|
|
|
}
|
2015-07-09 12:22:07 +02:00
|
|
|
break;
|
|
|
|
case OC_WITHDRAW_SIGN:
|
2015-09-19 22:08:49 +02:00
|
|
|
if (0 == strcmp (cmd->details.reserve_status.reserve_reference,
|
|
|
|
rel->details.reserve_withdraw.reserve_reference))
|
2015-07-09 12:02:01 +02:00
|
|
|
{
|
2017-03-02 06:26:12 +01:00
|
|
|
if ( (j >= history_length) ||
|
|
|
|
(GNUNET_OK !=
|
|
|
|
compare_reserve_withdraw_history (&history[j],
|
|
|
|
rel)) )
|
2015-07-09 12:22:07 +02:00
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
j++;
|
2015-07-09 12:02:01 +02:00
|
|
|
}
|
2015-07-09 12:22:07 +02:00
|
|
|
break;
|
2017-04-10 17:59:33 +02:00
|
|
|
case OC_PAYBACK:
|
|
|
|
xrel = find_command (is,
|
|
|
|
rel->details.payback.ref);
|
2017-06-05 18:05:01 +02:00
|
|
|
GNUNET_assert (NULL != xrel);
|
2017-04-10 17:59:33 +02:00
|
|
|
if (0 == strcmp (cmd->details.reserve_status.reserve_reference,
|
|
|
|
xrel->details.reserve_withdraw.reserve_reference))
|
|
|
|
{
|
|
|
|
if ( (j >= history_length) ||
|
|
|
|
(GNUNET_OK !=
|
|
|
|
compare_reserve_payback_history (&history[j],
|
|
|
|
rel)) )
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
break;
|
2015-07-09 12:22:07 +02:00
|
|
|
default:
|
|
|
|
/* unreleated, just skip */
|
|
|
|
break;
|
2015-07-09 12:02:01 +02:00
|
|
|
}
|
|
|
|
}
|
2015-07-09 12:22:07 +02:00
|
|
|
if (j != history_length)
|
2015-07-09 12:11:01 +02:00
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-09-19 22:08:49 +02:00
|
|
|
if (NULL != cmd->details.reserve_status.expected_balance)
|
2015-07-09 12:22:07 +02:00
|
|
|
{
|
|
|
|
GNUNET_assert (GNUNET_OK ==
|
2015-09-19 22:08:49 +02:00
|
|
|
TALER_string_to_amount (cmd->details.reserve_status.expected_balance,
|
2015-07-09 12:22:07 +02:00
|
|
|
&amount));
|
|
|
|
if (0 != TALER_amount_cmp (&amount,
|
|
|
|
balance))
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-07-09 12:47:49 +02:00
|
|
|
break;
|
2015-07-09 12:22:07 +02:00
|
|
|
default:
|
|
|
|
/* Unsupported status code (by test harness) */
|
|
|
|
GNUNET_break (0);
|
|
|
|
break;
|
2015-07-09 12:11:01 +02:00
|
|
|
}
|
2016-05-03 07:57:49 +02:00
|
|
|
next_command (is);
|
2015-07-09 11:36:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-04 22:35:30 +02:00
|
|
|
/**
|
2015-09-19 22:08:49 +02:00
|
|
|
* Function called upon completion of our /reserve/withdraw request.
|
2015-07-04 22:35:30 +02:00
|
|
|
*
|
|
|
|
* @param cls closure with the interpreter state
|
|
|
|
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
2016-03-01 15:35:04 +01:00
|
|
|
* 0 if the exchange's reply is bogus (fails to follow the protocol)
|
2016-10-20 21:00:40 +02:00
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
2015-07-04 22:35:30 +02:00
|
|
|
* @param sig signature over the coin, NULL on error
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param full_response full response from the exchange (for logging, in case of errors)
|
2015-07-04 22:35:30 +02:00
|
|
|
*/
|
|
|
|
static void
|
2015-09-19 22:08:49 +02:00
|
|
|
reserve_withdraw_cb (void *cls,
|
|
|
|
unsigned int http_status,
|
2016-10-20 21:00:40 +02:00
|
|
|
enum TALER_ErrorCode ec,
|
2015-09-19 22:08:49 +02:00
|
|
|
const struct TALER_DenominationSignature *sig,
|
2016-04-17 17:45:15 +02:00
|
|
|
const json_t *full_response)
|
2015-07-04 22:35:30 +02:00
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
|
|
|
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_withdraw.wsh = NULL;
|
2015-07-09 12:22:07 +02:00
|
|
|
if (cmd->expected_response_code != http_status)
|
2015-07-04 22:35:30 +02:00
|
|
|
{
|
2015-07-09 12:47:49 +02:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Unexpected response code %u to command %s\n",
|
|
|
|
http_status,
|
|
|
|
cmd->label);
|
2015-08-14 15:19:50 +02:00
|
|
|
json_dumpf (full_response, stderr, 0);
|
2015-07-05 13:05:58 +02:00
|
|
|
GNUNET_break (0);
|
2015-07-04 22:35:30 +02:00
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-07-09 12:22:07 +02:00
|
|
|
switch (http_status)
|
|
|
|
{
|
|
|
|
case MHD_HTTP_OK:
|
|
|
|
if (NULL == sig)
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_withdraw.sig.rsa_signature
|
2015-07-09 12:22:07 +02:00
|
|
|
= GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
|
|
|
|
break;
|
2016-10-18 23:05:29 +02:00
|
|
|
case MHD_HTTP_FORBIDDEN:
|
2015-07-09 12:47:49 +02:00
|
|
|
/* nothing to check */
|
|
|
|
break;
|
2017-04-10 17:59:33 +02:00
|
|
|
case MHD_HTTP_NOT_FOUND:
|
|
|
|
/* nothing to check */
|
|
|
|
break;
|
2015-07-09 12:22:07 +02:00
|
|
|
default:
|
|
|
|
/* Unsupported status code (by test harness) */
|
|
|
|
GNUNET_break (0);
|
|
|
|
break;
|
|
|
|
}
|
2016-05-03 07:57:49 +02:00
|
|
|
next_command (is);
|
2015-07-04 22:35:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-05 14:32:26 +02:00
|
|
|
/**
|
|
|
|
* Function called with the result of a /deposit operation.
|
|
|
|
*
|
|
|
|
* @param cls closure with the interpreter state
|
|
|
|
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
|
2016-03-01 15:35:04 +01:00
|
|
|
* 0 if the exchange's reply is bogus (fails to follow the protocol)
|
2016-10-20 21:00:40 +02:00
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
2016-06-07 15:14:44 +02:00
|
|
|
* @param exchange_pub public key the exchange used for signing
|
2015-07-05 14:32:26 +02:00
|
|
|
* @param obj the received JSON reply, should be kept as proof (and, in case of errors,
|
|
|
|
* be forwarded to the customer)
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
deposit_cb (void *cls,
|
|
|
|
unsigned int http_status,
|
2016-10-20 21:00:40 +02:00
|
|
|
enum TALER_ErrorCode ec,
|
2016-06-07 15:14:44 +02:00
|
|
|
const struct TALER_ExchangePublicKeyP *exchange_pub,
|
2016-04-17 17:45:15 +02:00
|
|
|
const json_t *obj)
|
2015-07-05 14:32:26 +02:00
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
|
|
|
|
|
|
|
cmd->details.deposit.dh = NULL;
|
2015-07-09 12:22:07 +02:00
|
|
|
if (cmd->expected_response_code != http_status)
|
2015-07-05 14:32:26 +02:00
|
|
|
{
|
2015-07-09 12:47:49 +02:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Unexpected response code %u to command %s\n",
|
|
|
|
http_status,
|
|
|
|
cmd->label);
|
2015-08-14 15:19:50 +02:00
|
|
|
json_dumpf (obj, stderr, 0);
|
2015-07-05 14:32:26 +02:00
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-05-03 07:57:49 +02:00
|
|
|
next_command (is);
|
2015-08-09 14:55:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function called with the result of the /refresh/melt operation.
|
|
|
|
*
|
|
|
|
* @param cls closure with the interpreter state
|
|
|
|
* @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped.
|
2016-03-01 15:35:04 +01:00
|
|
|
* 0 if the exchange's reply is bogus (fails to follow the protocol)
|
2016-10-20 21:00:40 +02:00
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param noreveal_index choice by the exchange in the cut-and-choose protocol,
|
2015-08-09 14:55:38 +02:00
|
|
|
* UINT16_MAX on error
|
2016-06-07 15:14:44 +02:00
|
|
|
* @param exchange_pub public key the exchange used for signing
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param full_response full response from the exchange (for logging, in case of errors)
|
2015-08-09 14:55:38 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
melt_cb (void *cls,
|
|
|
|
unsigned int http_status,
|
2016-10-20 21:00:40 +02:00
|
|
|
enum TALER_ErrorCode ec,
|
2017-11-27 23:42:17 +01:00
|
|
|
uint32_t noreveal_index,
|
2016-06-07 15:14:44 +02:00
|
|
|
const struct TALER_ExchangePublicKeyP *exchange_pub,
|
2016-04-17 17:45:15 +02:00
|
|
|
const json_t *full_response)
|
2015-08-09 14:55:38 +02:00
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
2015-07-05 14:32:26 +02:00
|
|
|
|
2015-08-09 14:55:38 +02:00
|
|
|
cmd->details.refresh_melt.rmh = 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);
|
2015-08-14 15:19:50 +02:00
|
|
|
json_dumpf (full_response, stderr, 0);
|
2015-08-09 14:55:38 +02:00
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cmd->details.refresh_melt.noreveal_index = noreveal_index;
|
2016-05-03 07:57:49 +02:00
|
|
|
next_command (is);
|
2015-07-05 14:32:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-09 15:24:02 +02:00
|
|
|
/**
|
|
|
|
* Function called with the result of the /refresh/reveal operation.
|
|
|
|
*
|
|
|
|
* @param cls closure with the interpreter state
|
|
|
|
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
2016-03-01 15:35:04 +01:00
|
|
|
* 0 if the exchange's reply is bogus (fails to follow the protocol)
|
2016-10-20 21:00:40 +02:00
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
2015-08-09 15:24:02 +02:00
|
|
|
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
|
|
|
|
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
|
|
|
|
* @param sigs array of signature over @a num_coins coins, NULL on error
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param full_response full response from the exchange (for logging, in case of errors)
|
2015-08-09 15:24:02 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
reveal_cb (void *cls,
|
|
|
|
unsigned int http_status,
|
2016-10-20 21:00:40 +02:00
|
|
|
enum TALER_ErrorCode ec,
|
2015-08-09 15:24:02 +02:00
|
|
|
unsigned int num_coins,
|
|
|
|
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
|
|
|
|
const struct TALER_DenominationSignature *sigs,
|
2016-04-17 17:45:15 +02:00
|
|
|
const json_t *full_response)
|
2015-08-09 15:24:02 +02:00
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
2015-08-09 16:21:49 +02:00
|
|
|
const struct Command *ref;
|
2015-08-09 15:24:02 +02:00
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
cmd->details.refresh_reveal.rrh = 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);
|
2015-08-14 15:19:50 +02:00
|
|
|
json_dumpf (full_response, stderr, 0);
|
2015-08-09 15:24:02 +02:00
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-08-09 16:21:49 +02:00
|
|
|
ref = find_command (is,
|
|
|
|
cmd->details.refresh_reveal.melt_ref);
|
2016-03-19 19:14:19 +01:00
|
|
|
GNUNET_assert (NULL != ref);
|
2015-08-09 15:24:02 +02:00
|
|
|
cmd->details.refresh_reveal.num_fresh_coins = num_coins;
|
2015-08-09 15:33:38 +02:00
|
|
|
switch (http_status)
|
|
|
|
{
|
|
|
|
case MHD_HTTP_OK:
|
2015-08-09 16:21:49 +02:00
|
|
|
cmd->details.refresh_reveal.fresh_coins
|
|
|
|
= GNUNET_new_array (num_coins,
|
|
|
|
struct FreshCoin);
|
|
|
|
for (i=0;i<num_coins;i++)
|
|
|
|
{
|
|
|
|
struct FreshCoin *fc = &cmd->details.refresh_reveal.fresh_coins[i];
|
|
|
|
|
|
|
|
fc->pk = ref->details.refresh_melt.fresh_pks[i];
|
|
|
|
fc->coin_priv = coin_privs[i];
|
|
|
|
fc->sig.rsa_signature
|
|
|
|
= GNUNET_CRYPTO_rsa_signature_dup (sigs[i].rsa_signature);
|
|
|
|
}
|
2015-08-09 15:33:38 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-05-03 07:57:49 +02:00
|
|
|
next_command (is);
|
2015-08-09 15:33:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function called with the result of a /refresh/link operation.
|
|
|
|
*
|
|
|
|
* @param cls closure with the interpreter state
|
|
|
|
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
2016-03-01 15:35:04 +01:00
|
|
|
* 0 if the exchange's reply is bogus (fails to follow the protocol)
|
2016-10-20 21:00:40 +02:00
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
2015-08-09 15:33:38 +02:00
|
|
|
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
|
|
|
|
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
|
|
|
|
* @param sigs array of signature over @a num_coins coins, NULL on error
|
|
|
|
* @param pubs array of public keys for the @a sigs, NULL on error
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param full_response full response from the exchange (for logging, in case of errors)
|
2015-08-09 15:33:38 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
link_cb (void *cls,
|
|
|
|
unsigned int http_status,
|
2016-10-20 21:00:40 +02:00
|
|
|
enum TALER_ErrorCode ec,
|
2015-08-09 15:33:38 +02:00
|
|
|
unsigned int num_coins,
|
|
|
|
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
|
|
|
|
const struct TALER_DenominationSignature *sigs,
|
|
|
|
const struct TALER_DenominationPublicKey *pubs,
|
2016-04-17 17:45:15 +02:00
|
|
|
const json_t *full_response)
|
2015-08-09 15:33:38 +02:00
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
2015-08-09 16:34:40 +02:00
|
|
|
const struct Command *ref;
|
2015-08-18 12:24:51 +02:00
|
|
|
unsigned int found;
|
2015-08-09 15:33:38 +02:00
|
|
|
|
|
|
|
cmd->details.refresh_link.rlh = 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);
|
2015-08-14 15:19:50 +02:00
|
|
|
json_dumpf (full_response, stderr, 0);
|
2015-08-09 15:33:38 +02:00
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-08-09 16:34:40 +02:00
|
|
|
ref = find_command (is,
|
|
|
|
cmd->details.refresh_link.reveal_ref);
|
2016-03-19 19:14:19 +01:00
|
|
|
GNUNET_assert (NULL != ref);
|
2015-08-09 15:33:38 +02:00
|
|
|
switch (http_status)
|
|
|
|
{
|
|
|
|
case MHD_HTTP_OK:
|
2015-08-09 16:34:40 +02:00
|
|
|
/* check that number of coins returned matches */
|
|
|
|
if (num_coins != ref->details.refresh_reveal.num_fresh_coins)
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* check that the coins match */
|
2017-11-27 23:42:17 +01:00
|
|
|
for (unsigned int i=0;i<num_coins;i++)
|
|
|
|
for (unsigned int j=i+1;j<num_coins;j++)
|
2015-08-18 12:24:51 +02:00
|
|
|
if (0 == memcmp (&coin_privs[i],
|
|
|
|
&coin_privs[j],
|
|
|
|
sizeof (struct TALER_CoinSpendPrivateKeyP)))
|
|
|
|
GNUNET_break (0);
|
|
|
|
/* Note: coins might be legitimately permutated in here... */
|
|
|
|
found = 0;
|
2017-11-27 23:42:17 +01:00
|
|
|
for (unsigned int i=0;i<num_coins;i++)
|
|
|
|
for (unsigned int j=0;j<num_coins;j++)
|
2015-08-09 16:34:40 +02:00
|
|
|
{
|
2015-08-18 12:24:51 +02:00
|
|
|
const struct FreshCoin *fc;
|
2015-09-15 10:00:21 +02:00
|
|
|
|
2015-08-18 12:24:51 +02:00
|
|
|
fc = &ref->details.refresh_reveal.fresh_coins[j];
|
|
|
|
if ( (0 == memcmp (&coin_privs[i],
|
|
|
|
&fc->coin_priv,
|
|
|
|
sizeof (struct TALER_CoinSpendPrivateKeyP))) &&
|
|
|
|
(0 == GNUNET_CRYPTO_rsa_signature_cmp (fc->sig.rsa_signature,
|
|
|
|
sigs[i].rsa_signature)) &&
|
|
|
|
(0 == GNUNET_CRYPTO_rsa_public_key_cmp (fc->pk->key.rsa_public_key,
|
|
|
|
pubs[i].rsa_public_key)) )
|
|
|
|
{
|
|
|
|
found++;
|
|
|
|
break;
|
|
|
|
}
|
2015-08-09 16:34:40 +02:00
|
|
|
}
|
2015-08-18 12:24:51 +02:00
|
|
|
if (found != num_coins)
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"Only %u/%u coins match expectations\n",
|
|
|
|
found,
|
|
|
|
num_coins);
|
|
|
|
GNUNET_break (0);
|
2015-09-15 10:00:21 +02:00
|
|
|
fail (is);
|
|
|
|
return;
|
2015-08-09 16:34:40 +02:00
|
|
|
}
|
2015-08-09 15:33:38 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-05-03 07:57:49 +02:00
|
|
|
next_command (is);
|
2015-08-09 15:24:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-04 05:16:32 +02:00
|
|
|
/**
|
|
|
|
* Task triggered whenever we receive a SIGCHLD (child
|
|
|
|
* process died).
|
|
|
|
*
|
|
|
|
* @param cls closure, NULL if we need to self-restart
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
maint_child_death (void *cls)
|
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
|
|
|
const struct GNUNET_DISK_FileHandle *pr;
|
|
|
|
char c[16];
|
|
|
|
|
2017-04-10 01:24:05 +02:00
|
|
|
switch (cmd->oc) {
|
|
|
|
case OC_RUN_AGGREGATOR:
|
|
|
|
cmd->details.run_aggregator.child_death_task = NULL;
|
|
|
|
pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
|
|
|
|
GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
|
|
|
|
GNUNET_OS_process_wait (cmd->details.run_aggregator.aggregator_proc);
|
|
|
|
GNUNET_OS_process_destroy (cmd->details.run_aggregator.aggregator_proc);
|
|
|
|
cmd->details.run_aggregator.aggregator_proc = NULL;
|
|
|
|
break;
|
|
|
|
case OC_REVOKE:
|
|
|
|
cmd->details.revoke.child_death_task = NULL;
|
|
|
|
pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
|
|
|
|
GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
|
|
|
|
GNUNET_OS_process_wait (cmd->details.revoke.revoke_proc);
|
|
|
|
GNUNET_OS_process_destroy (cmd->details.revoke.revoke_proc);
|
|
|
|
cmd->details.revoke.revoke_proc = NULL;
|
|
|
|
/* trigger reload of denomination key information */
|
|
|
|
GNUNET_break (0 ==
|
|
|
|
GNUNET_OS_process_kill (exchanged,
|
|
|
|
SIGUSR1));
|
2017-04-10 16:37:08 +02:00
|
|
|
sleep (5); /* make sure signal was received and processed */
|
2017-04-10 01:24:05 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-05-04 05:16:32 +02:00
|
|
|
next_command (is);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-04 22:35:30 +02:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2016-03-01 15:35:04 +01:00
|
|
|
static const struct TALER_EXCHANGE_DenomPublicKey *
|
|
|
|
find_pk (const struct TALER_EXCHANGE_Keys *keys,
|
2015-07-04 22:35:30 +02:00
|
|
|
const struct TALER_Amount *amount)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
struct GNUNET_TIME_Absolute now;
|
2016-03-01 15:35:04 +01:00
|
|
|
struct TALER_EXCHANGE_DenomPublicKey *pk;
|
2015-07-04 22:35:30 +02:00
|
|
|
char *str;
|
|
|
|
|
|
|
|
now = GNUNET_TIME_absolute_get ();
|
|
|
|
for (i=0;i<keys->num_denom_keys;i++)
|
|
|
|
{
|
|
|
|
pk = &keys->denom_keys[i];
|
|
|
|
if ( (0 == TALER_amount_cmp (amount,
|
|
|
|
&pk->value)) &&
|
|
|
|
(now.abs_value_us >= pk->valid_from.abs_value_us) &&
|
|
|
|
(now.abs_value_us < pk->withdraw_valid_until.abs_value_us) )
|
|
|
|
return pk;
|
2015-07-05 11:54:14 +02:00
|
|
|
}
|
|
|
|
/* do 2nd pass to check if expiration times are to blame for failure */
|
|
|
|
str = TALER_amount_to_string (amount);
|
|
|
|
for (i=0;i<keys->num_denom_keys;i++)
|
|
|
|
{
|
2015-07-20 14:04:23 +02:00
|
|
|
pk = &keys->denom_keys[i];
|
2015-07-04 22:41:05 +02:00
|
|
|
if ( (0 == TALER_amount_cmp (amount,
|
|
|
|
&pk->value)) &&
|
|
|
|
( (now.abs_value_us < pk->valid_from.abs_value_us) ||
|
|
|
|
(now.abs_value_us > pk->withdraw_valid_until.abs_value_us) ) )
|
2015-07-05 11:54:14 +02:00
|
|
|
{
|
2015-07-04 22:41:05 +02:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
2015-07-05 11:54:14 +02:00
|
|
|
"Have denomination key for `%s', but with wrong expiration range %llu vs [%llu,%llu)\n",
|
|
|
|
str,
|
2016-05-04 13:21:22 +02:00
|
|
|
(unsigned long long) now.abs_value_us,
|
|
|
|
(unsigned long long) pk->valid_from.abs_value_us,
|
|
|
|
(unsigned long long) pk->withdraw_valid_until.abs_value_us);
|
2015-07-05 11:54:14 +02:00
|
|
|
GNUNET_free (str);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-07-04 22:35:30 +02:00
|
|
|
}
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"No denomination key for amount %s found\n",
|
|
|
|
str);
|
|
|
|
GNUNET_free (str);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-06 17:07:31 +01:00
|
|
|
/**
|
|
|
|
* Function called with information about the wire fees
|
|
|
|
* for each wire method.
|
|
|
|
*
|
|
|
|
* @param cls closure
|
|
|
|
* @param wire_method name of the wire method (i.e. "sepa")
|
|
|
|
* @param fees fee structure for this method
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
check_fee_cb (void *cls,
|
|
|
|
const char *wire_method,
|
|
|
|
const struct TALER_EXCHANGE_WireAggregateFees *fees)
|
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
2017-03-06 17:36:10 +01:00
|
|
|
struct TALER_Amount expected_amount;
|
2017-03-06 17:07:31 +01:00
|
|
|
|
2017-03-06 17:36:10 +01:00
|
|
|
GNUNET_break ( (0 == strcasecmp ("test",
|
|
|
|
wire_method)) ||
|
|
|
|
(0 == strcasecmp ("sepa",
|
|
|
|
wire_method)) );
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
TALER_string_to_amount (cmd->details.wire.expected_fee,
|
|
|
|
&expected_amount))
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (NULL != fees)
|
|
|
|
{
|
|
|
|
if (0 != TALER_amount_cmp (&fees->wire_fee,
|
|
|
|
&expected_amount))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Wire fee missmatch to command %s\n",
|
|
|
|
cmd->label);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fees = fees->next;
|
|
|
|
}
|
2017-03-06 17:07:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-15 10:00:21 +02:00
|
|
|
/**
|
|
|
|
* Callbacks called with the result(s) of a
|
2016-03-01 15:35:04 +01:00
|
|
|
* wire format inquiry request to the exchange.
|
2015-09-15 10:00:21 +02:00
|
|
|
*
|
|
|
|
* @param cls closure with the interpreter state
|
|
|
|
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
|
2016-03-01 15:35:04 +01:00
|
|
|
* 0 if the exchange's reply is bogus (fails to follow the protocol)
|
2016-10-20 21:00:40 +02:00
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
2015-09-15 10:00:21 +02:00
|
|
|
* @param obj the received JSON reply, if successful this should be the wire
|
2016-04-01 16:15:35 +02:00
|
|
|
* format details as provided by /wire.
|
2015-09-15 10:00:21 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
wire_cb (void *cls,
|
|
|
|
unsigned int http_status,
|
2016-10-20 21:00:40 +02:00
|
|
|
enum TALER_ErrorCode ec,
|
2016-04-17 17:45:15 +02:00
|
|
|
const json_t *obj)
|
2015-09-15 10:00:21 +02:00
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
|
|
|
|
2016-04-01 17:32:10 +02:00
|
|
|
cmd->details.wire.wh = NULL;
|
2015-09-15 10:00:21 +02:00
|
|
|
if (cmd->expected_response_code != http_status)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
2016-04-01 16:15:35 +02:00
|
|
|
"Unexpected response code %u to command %s\n",
|
2015-09-15 10:00:21 +02:00
|
|
|
http_status,
|
2016-04-01 16:15:35 +02:00
|
|
|
cmd->label);
|
2015-09-15 10:00:21 +02:00
|
|
|
json_dumpf (obj, stderr, 0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-04-01 16:15:35 +02:00
|
|
|
switch (http_status)
|
2015-09-15 10:00:21 +02:00
|
|
|
{
|
2016-04-01 16:15:35 +02:00
|
|
|
case MHD_HTTP_OK:
|
|
|
|
{
|
|
|
|
json_t *method;
|
|
|
|
|
|
|
|
method = json_object_get (obj,
|
|
|
|
cmd->details.wire.format);
|
|
|
|
if (NULL == method)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Expected method `%s' not included in response to command %s\n",
|
|
|
|
cmd->details.wire.format,
|
|
|
|
cmd->label);
|
2017-03-06 17:07:31 +01:00
|
|
|
json_dumpf (obj, stderr, 0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
TALER_EXCHANGE_wire_get_fees (&TALER_EXCHANGE_get_keys (exchange)->master_pub,
|
|
|
|
obj,
|
|
|
|
&check_fee_cb,
|
|
|
|
is))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Wire fee extraction in command %s failed\n",
|
|
|
|
cmd->label);
|
2016-04-01 16:15:35 +02:00
|
|
|
json_dumpf (obj, stderr, 0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2015-09-15 10:00:21 +02:00
|
|
|
}
|
2016-05-03 07:57:49 +02:00
|
|
|
next_command (is);
|
2015-09-15 10:00:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-22 15:29:31 +01:00
|
|
|
/**
|
|
|
|
* Function called with detailed wire transfer data, including all
|
|
|
|
* of the coin transactions that were combined into the wire transfer.
|
|
|
|
*
|
|
|
|
* @param cls closure
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param http_status HTTP status code we got, 0 on exchange protocol violation
|
2016-10-20 21:00:40 +02:00
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
2016-06-07 15:14:44 +02:00
|
|
|
* @param exchange_pub public key the exchange used for signing
|
2016-01-22 15:29:31 +01:00
|
|
|
* @param json original json reply (may include signatures, those have then been
|
|
|
|
* validated already)
|
2016-09-26 14:58:44 +02:00
|
|
|
* @param h_wire hash of the wire transfer address the transfer went to, or NULL on error
|
|
|
|
* @param execution_time time when the exchange claims to have performed the wire transfer
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param total_amount total amount of the wire transfer, or NULL if the exchange could
|
2016-01-22 15:29:31 +01:00
|
|
|
* not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
|
2017-03-04 16:49:33 +01:00
|
|
|
* @param wire_fee wire fee that was charged by the exchange
|
2016-01-22 15:29:31 +01:00
|
|
|
* @param details_length length of the @a details array
|
|
|
|
* @param details array with details about the combined transactions
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
wire_deposits_cb (void *cls,
|
|
|
|
unsigned int http_status,
|
2016-10-20 21:00:40 +02:00
|
|
|
enum TALER_ErrorCode ec,
|
2016-06-07 15:14:44 +02:00
|
|
|
const struct TALER_ExchangePublicKeyP *exchange_pub,
|
2016-04-17 17:45:15 +02:00
|
|
|
const json_t *json,
|
2016-01-22 15:29:31 +01:00
|
|
|
const struct GNUNET_HashCode *h_wire,
|
2016-09-26 14:58:44 +02:00
|
|
|
struct GNUNET_TIME_Absolute execution_time,
|
2016-01-22 15:29:31 +01:00
|
|
|
const struct TALER_Amount *total_amount,
|
2017-03-04 16:49:33 +01:00
|
|
|
const struct TALER_Amount *wire_fee,
|
2016-01-22 15:29:31 +01:00
|
|
|
unsigned int details_length,
|
2016-06-09 19:18:13 +02:00
|
|
|
const struct TALER_TrackTransferDetails *details)
|
2016-01-22 15:29:31 +01:00
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
|
|
|
const struct Command *ref;
|
2016-05-04 06:10:41 +02:00
|
|
|
struct TALER_Amount expected_amount;
|
2016-01-22 15:29:31 +01:00
|
|
|
|
2016-01-22 15:50:45 +01:00
|
|
|
cmd->details.wire_deposits.wdh = NULL;
|
2016-01-22 15:29:31 +01:00
|
|
|
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 (json, stderr, 0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (http_status)
|
|
|
|
{
|
|
|
|
case MHD_HTTP_OK:
|
2016-05-04 06:10:41 +02:00
|
|
|
if (GNUNET_OK !=
|
|
|
|
TALER_string_to_amount (cmd->details.wire_deposits.total_amount_expected,
|
|
|
|
&expected_amount))
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-01-22 15:29:31 +01:00
|
|
|
if (0 != TALER_amount_cmp (total_amount,
|
2016-05-04 06:10:41 +02:00
|
|
|
&expected_amount))
|
2016-01-22 15:29:31 +01:00
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Total amount missmatch to command %s\n",
|
|
|
|
cmd->label);
|
|
|
|
json_dumpf (json, stderr, 0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2017-03-04 16:49:33 +01:00
|
|
|
if (GNUNET_OK !=
|
|
|
|
TALER_string_to_amount (cmd->details.wire_deposits.wire_fee_expected,
|
|
|
|
&expected_amount))
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (0 != TALER_amount_cmp (wire_fee,
|
|
|
|
&expected_amount))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Wire fee missmatch to command %s\n",
|
|
|
|
cmd->label);
|
|
|
|
json_dumpf (json, stderr, 0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-05-04 06:10:41 +02:00
|
|
|
ref = find_command (is,
|
|
|
|
cmd->details.wire_deposits.wtid_ref);
|
|
|
|
GNUNET_assert (NULL != ref);
|
|
|
|
switch (ref->oc)
|
2016-01-22 15:29:31 +01:00
|
|
|
{
|
2016-05-04 06:10:41 +02:00
|
|
|
case OC_DEPOSIT_WTID:
|
|
|
|
if (NULL != ref->details.deposit_wtid.deposit_ref)
|
|
|
|
{
|
|
|
|
const struct Command *dep;
|
|
|
|
struct GNUNET_HashCode hw;
|
|
|
|
json_t *wire;
|
|
|
|
|
|
|
|
dep = find_command (is,
|
|
|
|
ref->details.deposit_wtid.deposit_ref);
|
|
|
|
GNUNET_assert (NULL != dep);
|
|
|
|
wire = json_loads (dep->details.deposit.wire_details,
|
|
|
|
JSON_REJECT_DUPLICATES,
|
|
|
|
NULL);
|
2017-10-06 20:02:28 +02:00
|
|
|
GNUNET_assert (GNUNET_OK ==
|
|
|
|
TALER_JSON_hash (wire,
|
|
|
|
&hw));
|
2016-05-04 06:10:41 +02:00
|
|
|
json_decref (wire);
|
|
|
|
if (0 != memcmp (&hw,
|
|
|
|
h_wire,
|
|
|
|
sizeof (struct GNUNET_HashCode)))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Wire hash missmatch to command %s\n",
|
|
|
|
cmd->label);
|
|
|
|
json_dumpf (json, stderr, 0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OC_CHECK_BANK_TRANSFER:
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
TALER_string_to_amount (ref->details.check_bank_transfer.amount,
|
|
|
|
&expected_amount))
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (0 != TALER_amount_cmp (total_amount,
|
|
|
|
&expected_amount))
|
2016-01-22 15:29:31 +01:00
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
2016-05-04 06:10:41 +02:00
|
|
|
"Total amount missmatch to command %s\n",
|
2016-01-22 15:29:31 +01:00
|
|
|
cmd->label);
|
|
|
|
json_dumpf (json, stderr, 0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-05-04 06:10:41 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
2016-01-22 15:29:31 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-05-03 07:57:49 +02:00
|
|
|
next_command (is);
|
2016-01-22 15:29:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function called with detailed wire transfer data.
|
|
|
|
*
|
|
|
|
* @param cls closure
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param http_status HTTP status code we got, 0 on exchange protocol violation
|
2016-10-20 21:00:40 +02:00
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
2016-06-07 15:14:44 +02:00
|
|
|
* @param exchange_pub public key the exchange used for signing
|
2016-01-22 15:29:31 +01:00
|
|
|
* @param json original json reply (may include signatures, those have then been
|
|
|
|
* validated already)
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param wtid wire transfer identifier used by the exchange, NULL if exchange did not
|
2016-01-22 15:29:31 +01:00
|
|
|
* yet execute the transaction
|
|
|
|
* @param execution_time actual or planned execution time for the wire transfer
|
|
|
|
* @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL)
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param total_amount total amount of the wire transfer, or NULL if the exchange could
|
2016-01-22 15:29:31 +01:00
|
|
|
* not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
deposit_wtid_cb (void *cls,
|
|
|
|
unsigned int http_status,
|
2016-10-20 21:00:40 +02:00
|
|
|
enum TALER_ErrorCode ec,
|
2016-06-07 15:14:44 +02:00
|
|
|
const struct TALER_ExchangePublicKeyP *exchange_pub,
|
2016-04-17 17:45:15 +02:00
|
|
|
const json_t *json,
|
2016-01-22 15:29:31 +01:00
|
|
|
const struct TALER_WireTransferIdentifierRawP *wtid,
|
|
|
|
struct GNUNET_TIME_Absolute execution_time,
|
2016-02-07 15:02:49 +01:00
|
|
|
const struct TALER_Amount *coin_contribution)
|
2016-01-22 15:29:31 +01:00
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
|
|
|
|
2016-01-22 15:50:45 +01:00
|
|
|
cmd->details.deposit_wtid.dwh = NULL;
|
2016-01-22 15:29:31 +01:00
|
|
|
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 (json, stderr, 0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (http_status)
|
|
|
|
{
|
|
|
|
case MHD_HTTP_OK:
|
|
|
|
cmd->details.deposit_wtid.wtid = *wtid;
|
2016-05-04 05:36:23 +02:00
|
|
|
if (NULL != cmd->details.deposit_wtid.bank_transfer_ref)
|
|
|
|
{
|
|
|
|
const struct Command *ref;
|
2017-06-11 15:25:59 +02:00
|
|
|
char *ws;
|
|
|
|
|
|
|
|
ws = GNUNET_STRINGS_data_to_string_alloc (wtid,
|
|
|
|
sizeof (*wtid));
|
|
|
|
|
2016-05-04 05:36:23 +02:00
|
|
|
|
|
|
|
ref = find_command (is,
|
|
|
|
cmd->details.deposit_wtid.bank_transfer_ref);
|
|
|
|
GNUNET_assert (NULL != ref);
|
2017-06-11 15:25:59 +02:00
|
|
|
if (0 != strcmp (ws,
|
|
|
|
ref->details.check_bank_transfer.subject))
|
2016-05-04 05:36:23 +02:00
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
2017-06-11 15:25:59 +02:00
|
|
|
GNUNET_free (ws);
|
2016-05-04 05:36:23 +02:00
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2017-06-11 15:25:59 +02:00
|
|
|
GNUNET_free (ws);
|
2016-05-04 05:36:23 +02:00
|
|
|
}
|
2016-01-22 15:29:31 +01:00
|
|
|
break;
|
2017-02-08 08:02:01 +01:00
|
|
|
case MHD_HTTP_ACCEPTED:
|
|
|
|
/* allowed, nothing to check here */
|
|
|
|
break;
|
|
|
|
case MHD_HTTP_NOT_FOUND:
|
|
|
|
/* allowed, nothing to check here */
|
|
|
|
break;
|
2016-01-22 15:29:31 +01:00
|
|
|
default:
|
2016-11-18 18:29:18 +01:00
|
|
|
GNUNET_break (0);
|
2016-01-22 15:29:31 +01:00
|
|
|
break;
|
|
|
|
}
|
2016-05-03 07:57:49 +02:00
|
|
|
next_command (is);
|
2016-01-22 15:29:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-20 17:15:50 +02:00
|
|
|
/**
|
|
|
|
* 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)
|
2016-10-20 21:00:40 +02:00
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
2016-06-07 15:14:44 +02:00
|
|
|
* @param exchange_pub public key the exchange used for signing @a obj
|
2016-05-20 17:15:50 +02:00
|
|
|
* @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,
|
2016-10-20 21:00:40 +02:00
|
|
|
enum TALER_ErrorCode ec,
|
2016-06-07 15:14:44 +02:00
|
|
|
const struct TALER_ExchangePublicKeyP *exchange_pub,
|
2016-05-20 17:15:50 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-10 01:24:05 +02:00
|
|
|
/**
|
|
|
|
* Check the result of the payback request.
|
|
|
|
*
|
|
|
|
* @param cls closure
|
|
|
|
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
|
|
|
* 0 if the exchange's reply is bogus (fails to follow the protocol)
|
|
|
|
* @param ec taler-specific error code, #TALER_EC_NONE on success
|
|
|
|
* @param amount amount the exchange will wire back for this coin
|
|
|
|
* @param timestamp what time did the exchange receive the /payback request
|
|
|
|
* @param reserve_pub public key of the reserve receiving the payback
|
|
|
|
* @param full_response full response from the exchange (for logging, in case of errors)
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
payback_cb (void *cls,
|
|
|
|
unsigned int http_status,
|
|
|
|
enum TALER_ErrorCode ec,
|
|
|
|
const struct TALER_Amount *amount,
|
|
|
|
struct GNUNET_TIME_Absolute timestamp,
|
|
|
|
const struct TALER_ReservePublicKeyP *reserve_pub,
|
|
|
|
const json_t *full_response)
|
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
|
|
|
const struct Command *withdraw;
|
|
|
|
const struct Command *reserve;
|
|
|
|
struct TALER_Amount expected_amount;
|
|
|
|
struct TALER_ReservePublicKeyP rp;
|
|
|
|
|
|
|
|
cmd->details.payback.ph = 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 (full_response, stderr, 0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
withdraw = find_command (is,
|
|
|
|
cmd->details.payback.ref);
|
2017-06-05 18:05:01 +02:00
|
|
|
GNUNET_assert (NULL != withdraw);
|
2017-04-10 01:24:05 +02:00
|
|
|
reserve = find_command (is,
|
|
|
|
withdraw->details.reserve_withdraw.reserve_reference);
|
2017-06-05 18:05:01 +02:00
|
|
|
GNUNET_assert (NULL != reserve);
|
2017-04-10 01:24:05 +02:00
|
|
|
GNUNET_CRYPTO_eddsa_key_get_public (&reserve->details.admin_add_incoming.reserve_priv.eddsa_priv,
|
|
|
|
&rp.eddsa_pub);
|
|
|
|
switch (http_status)
|
|
|
|
{
|
|
|
|
case MHD_HTTP_OK:
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
TALER_string_to_amount (cmd->details.payback.amount,
|
|
|
|
&expected_amount))
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (0 != TALER_amount_cmp (amount,
|
|
|
|
&expected_amount))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Total amount missmatch to command %s\n",
|
|
|
|
cmd->label);
|
|
|
|
json_dumpf (full_response, stderr, 0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (0 != memcmp (reserve_pub,
|
|
|
|
&rp,
|
|
|
|
sizeof (rp)))
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
next_command (is);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-20 17:15:50 +02:00
|
|
|
/**
|
|
|
|
* 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:
|
2017-10-31 14:02:54 +01:00
|
|
|
GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.ps.coin_priv.eddsa_priv,
|
2016-05-20 17:15:50 +02:00
|
|
|
&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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* Run the main interpreter loop that performs exchange operations.
|
2015-07-04 17:30:38 +02:00
|
|
|
*
|
|
|
|
* @param cls contains the `struct InterpreterState`
|
|
|
|
*/
|
|
|
|
static void
|
2016-04-10 00:57:20 +02:00
|
|
|
interpreter_run (void *cls)
|
2015-07-04 17:30:38 +02:00
|
|
|
{
|
|
|
|
struct InterpreterState *is = cls;
|
2015-07-04 18:45:51 +02:00
|
|
|
struct Command *cmd = &is->commands[is->ip];
|
|
|
|
const struct Command *ref;
|
|
|
|
struct TALER_ReservePublicKeyP reserve_pub;
|
|
|
|
struct TALER_Amount amount;
|
2015-07-05 16:55:01 +02:00
|
|
|
struct GNUNET_TIME_Absolute execution_date;
|
2016-05-26 16:38:59 +02:00
|
|
|
json_t *sender_details;
|
|
|
|
json_t *transfer_details;
|
2016-04-10 00:57:20 +02:00
|
|
|
const struct GNUNET_SCHEDULER_TaskContext *tc;
|
2015-07-04 17:30:38 +02:00
|
|
|
|
2015-07-04 20:47:39 +02:00
|
|
|
is->task = NULL;
|
2016-04-10 00:57:20 +02:00
|
|
|
tc = GNUNET_SCHEDULER_get_task_context ();
|
2015-07-04 17:30:38 +02:00
|
|
|
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"Test aborted by shutdown request\n");
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-11-17 16:37:40 +01:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
|
|
|
"Running command `%s'\n",
|
|
|
|
cmd->label);
|
2015-07-04 17:30:38 +02:00
|
|
|
switch (cmd->oc)
|
|
|
|
{
|
|
|
|
case OC_END:
|
|
|
|
result = GNUNET_OK;
|
|
|
|
GNUNET_SCHEDULER_shutdown ();
|
|
|
|
return;
|
|
|
|
case OC_ADMIN_ADD_INCOMING:
|
2015-07-04 20:47:39 +02:00
|
|
|
if (NULL !=
|
|
|
|
cmd->details.admin_add_incoming.reserve_reference)
|
2015-07-04 18:45:51 +02:00
|
|
|
{
|
2015-07-04 20:47:39 +02:00
|
|
|
ref = find_command (is,
|
|
|
|
cmd->details.admin_add_incoming.reserve_reference);
|
|
|
|
GNUNET_assert (NULL != ref);
|
2015-07-04 18:45:51 +02:00
|
|
|
GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
|
|
|
|
cmd->details.admin_add_incoming.reserve_priv
|
|
|
|
= ref->details.admin_add_incoming.reserve_priv;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
|
|
|
|
|
|
|
|
priv = GNUNET_CRYPTO_eddsa_key_create ();
|
|
|
|
cmd->details.admin_add_incoming.reserve_priv.eddsa_priv = *priv;
|
|
|
|
GNUNET_free (priv);
|
|
|
|
}
|
|
|
|
GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.admin_add_incoming.reserve_priv.eddsa_priv,
|
|
|
|
&reserve_pub.eddsa_pub);
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
TALER_string_to_amount (cmd->details.admin_add_incoming.amount,
|
|
|
|
&amount))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Failed to parse amount `%s' at %u\n",
|
|
|
|
cmd->details.admin_add_incoming.amount,
|
|
|
|
is->ip);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-05-26 16:38:59 +02:00
|
|
|
sender_details = json_loads (cmd->details.admin_add_incoming.sender_details,
|
|
|
|
JSON_REJECT_DUPLICATES,
|
|
|
|
NULL);
|
|
|
|
if (NULL == sender_details)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Failed to parse sender details `%s' at %u\n",
|
|
|
|
cmd->details.admin_add_incoming.sender_details,
|
|
|
|
is->ip);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
transfer_details = json_loads (cmd->details.admin_add_incoming.transfer_details,
|
|
|
|
JSON_REJECT_DUPLICATES,
|
|
|
|
NULL);
|
|
|
|
if (NULL == transfer_details)
|
2015-07-04 18:45:51 +02:00
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
2016-05-26 16:38:59 +02:00
|
|
|
"Failed to parse transfer details `%s' at %u\n",
|
|
|
|
cmd->details.admin_add_incoming.transfer_details,
|
2015-07-04 18:45:51 +02:00
|
|
|
is->ip);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-07-05 16:55:01 +02:00
|
|
|
execution_date = GNUNET_TIME_absolute_get ();
|
2016-03-19 15:23:11 +01:00
|
|
|
GNUNET_TIME_round_abs (&execution_date);
|
2015-07-04 18:45:51 +02:00
|
|
|
cmd->details.admin_add_incoming.aih
|
2016-03-01 15:35:04 +01:00
|
|
|
= TALER_EXCHANGE_admin_add_incoming (exchange,
|
2016-06-13 16:36:10 +02:00
|
|
|
"http://localhost:18080/",
|
2016-05-20 17:15:50 +02:00
|
|
|
&reserve_pub,
|
|
|
|
&amount,
|
|
|
|
execution_date,
|
2016-05-26 16:38:59 +02:00
|
|
|
sender_details,
|
|
|
|
transfer_details,
|
2016-05-20 17:15:50 +02:00
|
|
|
&add_incoming_cb,
|
|
|
|
is);
|
2016-05-26 16:38:59 +02:00
|
|
|
json_decref (sender_details);
|
|
|
|
json_decref (transfer_details);
|
2015-07-05 16:55:01 +02:00
|
|
|
if (NULL == cmd->details.admin_add_incoming.aih)
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-07-04 18:45:51 +02:00
|
|
|
return;
|
2015-07-09 11:36:13 +02:00
|
|
|
case OC_WITHDRAW_STATUS:
|
|
|
|
GNUNET_assert (NULL !=
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_status.reserve_reference);
|
2015-07-09 11:36:13 +02:00
|
|
|
ref = find_command (is,
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_status.reserve_reference);
|
2015-07-09 11:36:13 +02:00
|
|
|
GNUNET_assert (NULL != ref);
|
|
|
|
GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
|
|
|
|
GNUNET_CRYPTO_eddsa_key_get_public (&ref->details.admin_add_incoming.reserve_priv.eddsa_priv,
|
|
|
|
&reserve_pub.eddsa_pub);
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_status.wsh
|
2016-03-01 15:35:04 +01:00
|
|
|
= TALER_EXCHANGE_reserve_status (exchange,
|
2016-10-17 23:51:09 +02:00
|
|
|
&reserve_pub,
|
|
|
|
&reserve_status_cb,
|
|
|
|
is);
|
2015-07-09 11:36:13 +02:00
|
|
|
return;
|
2015-07-04 17:30:38 +02:00
|
|
|
case OC_WITHDRAW_SIGN:
|
2015-07-04 22:35:30 +02:00
|
|
|
GNUNET_assert (NULL !=
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_withdraw.reserve_reference);
|
2015-07-04 22:35:30 +02:00
|
|
|
ref = find_command (is,
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_withdraw.reserve_reference);
|
2015-07-04 22:35:30 +02:00
|
|
|
GNUNET_assert (NULL != ref);
|
|
|
|
GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
|
2015-09-19 22:08:49 +02:00
|
|
|
if (NULL != cmd->details.reserve_withdraw.amount)
|
2015-07-04 22:35:30 +02:00
|
|
|
{
|
|
|
|
if (GNUNET_OK !=
|
2015-09-19 22:08:49 +02:00
|
|
|
TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
|
2015-07-04 22:35:30 +02:00
|
|
|
&amount))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Failed to parse amount `%s' at %u\n",
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_withdraw.amount,
|
2015-07-04 22:35:30 +02:00
|
|
|
is->ip);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_withdraw.pk = find_pk (is->keys,
|
|
|
|
&amount);
|
2015-07-04 22:35:30 +02:00
|
|
|
}
|
2015-09-19 22:08:49 +02:00
|
|
|
if (NULL == cmd->details.reserve_withdraw.pk)
|
2015-07-04 22:35:30 +02:00
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Failed to determine denomination key at %u\n",
|
|
|
|
is->ip);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-31 14:02:54 +01:00
|
|
|
TALER_planchet_setup_random (&cmd->details.reserve_withdraw.ps);
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_withdraw.wsh
|
2016-03-01 15:35:04 +01:00
|
|
|
= TALER_EXCHANGE_reserve_withdraw (exchange,
|
2017-10-31 14:02:54 +01:00
|
|
|
cmd->details.reserve_withdraw.pk,
|
|
|
|
&ref->details.admin_add_incoming.reserve_priv,
|
|
|
|
&cmd->details.reserve_withdraw.ps,
|
|
|
|
&reserve_withdraw_cb,
|
|
|
|
is);
|
2015-09-19 22:08:49 +02:00
|
|
|
if (NULL == cmd->details.reserve_withdraw.wsh)
|
2015-07-05 16:55:01 +02:00
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-07-04 22:35:30 +02:00
|
|
|
return;
|
2015-07-04 17:30:38 +02:00
|
|
|
case OC_DEPOSIT:
|
2015-07-05 14:32:26 +02:00
|
|
|
{
|
2017-05-29 01:15:41 +02:00
|
|
|
struct GNUNET_HashCode h_contract_terms;
|
2015-08-09 16:29:32 +02:00
|
|
|
const struct TALER_CoinSpendPrivateKeyP *coin_priv;
|
2016-03-01 15:35:04 +01:00
|
|
|
const struct TALER_EXCHANGE_DenomPublicKey *coin_pk;
|
2015-08-09 16:29:32 +02:00
|
|
|
const struct TALER_DenominationSignature *coin_pk_sig;
|
2015-07-05 14:32:26 +02:00
|
|
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
|
|
|
struct TALER_CoinSpendSignatureP coin_sig;
|
|
|
|
struct GNUNET_TIME_Absolute refund_deadline;
|
2015-10-28 21:06:23 +01:00
|
|
|
struct GNUNET_TIME_Absolute wire_deadline;
|
2015-07-05 14:32:26 +02:00
|
|
|
struct GNUNET_TIME_Absolute timestamp;
|
2016-01-22 17:21:42 +01:00
|
|
|
struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
|
2015-07-05 14:32:26 +02:00
|
|
|
struct TALER_MerchantPublicKeyP merchant_pub;
|
2017-05-29 01:15:41 +02:00
|
|
|
json_t *contract_terms;
|
2015-07-05 14:32:26 +02:00
|
|
|
json_t *wire;
|
|
|
|
|
|
|
|
GNUNET_assert (NULL !=
|
|
|
|
cmd->details.deposit.coin_ref);
|
|
|
|
ref = find_command (is,
|
|
|
|
cmd->details.deposit.coin_ref);
|
|
|
|
GNUNET_assert (NULL != ref);
|
2015-08-09 16:29:32 +02:00
|
|
|
switch (ref->oc)
|
|
|
|
{
|
|
|
|
case OC_WITHDRAW_SIGN:
|
2017-10-31 14:02:54 +01:00
|
|
|
coin_priv = &ref->details.reserve_withdraw.ps.coin_priv;
|
2015-09-19 22:08:49 +02:00
|
|
|
coin_pk = ref->details.reserve_withdraw.pk;
|
|
|
|
coin_pk_sig = &ref->details.reserve_withdraw.sig;
|
2015-08-09 16:29:32 +02:00
|
|
|
break;
|
|
|
|
case OC_REFRESH_REVEAL:
|
|
|
|
{
|
|
|
|
const struct FreshCoin *fc;
|
|
|
|
unsigned int idx;
|
|
|
|
|
|
|
|
idx = cmd->details.deposit.coin_idx;
|
|
|
|
GNUNET_assert (idx < ref->details.refresh_reveal.num_fresh_coins);
|
|
|
|
fc = &ref->details.refresh_reveal.fresh_coins[idx];
|
|
|
|
|
|
|
|
coin_priv = &fc->coin_priv;
|
|
|
|
coin_pk = fc->pk;
|
|
|
|
coin_pk_sig = &fc->sig;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
GNUNET_assert (0);
|
|
|
|
}
|
2015-07-05 14:32:26 +02:00
|
|
|
if (GNUNET_OK !=
|
|
|
|
TALER_string_to_amount (cmd->details.deposit.amount,
|
|
|
|
&amount))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Failed to parse amount `%s' at %u\n",
|
|
|
|
cmd->details.deposit.amount,
|
|
|
|
is->ip);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2017-05-29 01:15:41 +02:00
|
|
|
contract_terms = json_loads (cmd->details.deposit.contract_terms,
|
2016-01-22 17:21:42 +01:00
|
|
|
JSON_REJECT_DUPLICATES,
|
|
|
|
NULL);
|
2017-05-29 01:15:41 +02:00
|
|
|
if (NULL == contract_terms)
|
2016-01-22 17:21:42 +01:00
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
2017-02-06 15:41:39 +01:00
|
|
|
"Failed to parse proposal data `%s' at %u/%s\n",
|
2017-05-29 01:15:41 +02:00
|
|
|
cmd->details.deposit.contract_terms,
|
2016-01-22 17:21:42 +01:00
|
|
|
is->ip,
|
|
|
|
cmd->label);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2017-10-06 20:02:28 +02:00
|
|
|
GNUNET_assert (GNUNET_OK ==
|
|
|
|
TALER_JSON_hash (contract_terms,
|
|
|
|
&h_contract_terms));
|
2017-05-29 01:15:41 +02:00
|
|
|
json_decref (contract_terms);
|
2015-07-05 14:32:26 +02:00
|
|
|
wire = json_loads (cmd->details.deposit.wire_details,
|
|
|
|
JSON_REJECT_DUPLICATES,
|
|
|
|
NULL);
|
|
|
|
if (NULL == wire)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
2016-01-22 17:21:42 +01:00
|
|
|
"Failed to parse wire details `%s' at %u/%s\n",
|
2015-07-05 14:32:26 +02:00
|
|
|
cmd->details.deposit.wire_details,
|
2016-01-22 17:21:42 +01:00
|
|
|
is->ip,
|
|
|
|
cmd->label);
|
2015-07-05 14:32:26 +02:00
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-08-09 16:29:32 +02:00
|
|
|
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
|
2015-07-05 14:32:26 +02:00
|
|
|
&coin_pub.eddsa_pub);
|
|
|
|
|
2016-01-22 17:21:42 +01:00
|
|
|
priv = GNUNET_CRYPTO_eddsa_key_create ();
|
|
|
|
cmd->details.deposit.merchant_priv.eddsa_priv = *priv;
|
|
|
|
GNUNET_free (priv);
|
2015-07-05 14:32:26 +02:00
|
|
|
if (0 != cmd->details.deposit.refund_deadline.rel_value_us)
|
|
|
|
{
|
|
|
|
refund_deadline = GNUNET_TIME_relative_to_absolute (cmd->details.deposit.refund_deadline);
|
2016-05-21 18:36:12 +02:00
|
|
|
wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (cmd->details.deposit.refund_deadline, 2));
|
2015-07-05 14:32:26 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
refund_deadline = GNUNET_TIME_UNIT_ZERO_ABS;
|
2016-05-21 18:36:12 +02:00
|
|
|
wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_ZERO);
|
2015-07-05 14:32:26 +02:00
|
|
|
}
|
2016-01-22 17:21:42 +01:00
|
|
|
GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.deposit.merchant_priv.eddsa_priv,
|
|
|
|
&merchant_pub.eddsa_pub);
|
|
|
|
|
2015-07-05 14:32:26 +02:00
|
|
|
timestamp = GNUNET_TIME_absolute_get ();
|
2016-03-19 15:23:11 +01:00
|
|
|
GNUNET_TIME_round_abs (×tamp);
|
2016-05-21 18:36:12 +02:00
|
|
|
GNUNET_TIME_round_abs (&refund_deadline);
|
|
|
|
GNUNET_TIME_round_abs (&wire_deadline);
|
2015-07-05 16:55:01 +02:00
|
|
|
{
|
|
|
|
struct TALER_DepositRequestPS dr;
|
|
|
|
|
2015-09-15 17:27:02 +02:00
|
|
|
memset (&dr, 0, sizeof (dr));
|
2015-07-05 16:55:01 +02:00
|
|
|
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
|
|
|
|
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
|
2017-05-29 01:15:41 +02:00
|
|
|
dr.h_contract_terms = h_contract_terms;
|
2017-10-06 20:02:28 +02:00
|
|
|
GNUNET_assert (GNUNET_OK ==
|
|
|
|
TALER_JSON_hash (wire,
|
|
|
|
&dr.h_wire));
|
2015-07-05 16:55:01 +02:00
|
|
|
dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
|
|
|
|
dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
|
|
|
|
TALER_amount_hton (&dr.amount_with_fee,
|
|
|
|
&amount);
|
|
|
|
TALER_amount_hton (&dr.deposit_fee,
|
2015-08-09 16:29:32 +02:00
|
|
|
&coin_pk->fee_deposit);
|
2015-07-05 16:55:01 +02:00
|
|
|
dr.merchant = merchant_pub;
|
|
|
|
dr.coin_pub = coin_pub;
|
|
|
|
GNUNET_assert (GNUNET_OK ==
|
2015-08-09 16:29:32 +02:00
|
|
|
GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
|
2015-07-05 16:55:01 +02:00
|
|
|
&dr.purpose,
|
|
|
|
&coin_sig.eddsa_signature));
|
|
|
|
}
|
2015-07-05 14:32:26 +02:00
|
|
|
cmd->details.deposit.dh
|
2016-03-01 15:35:04 +01:00
|
|
|
= TALER_EXCHANGE_deposit (exchange,
|
2016-05-03 13:55:40 +02:00
|
|
|
&amount,
|
|
|
|
wire_deadline,
|
|
|
|
wire,
|
2017-05-29 01:15:41 +02:00
|
|
|
&h_contract_terms,
|
2016-05-03 13:55:40 +02:00
|
|
|
&coin_pub,
|
|
|
|
coin_pk_sig,
|
|
|
|
&coin_pk->key,
|
|
|
|
timestamp,
|
|
|
|
&merchant_pub,
|
|
|
|
refund_deadline,
|
|
|
|
&coin_sig,
|
|
|
|
&deposit_cb,
|
|
|
|
is);
|
2015-07-05 14:32:26 +02:00
|
|
|
if (NULL == cmd->details.deposit.dh)
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
json_decref (wire);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-12-20 13:00:06 +01:00
|
|
|
json_decref (wire);
|
2015-07-05 14:32:26 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-08-08 23:21:00 +02:00
|
|
|
case OC_REFRESH_MELT:
|
2015-08-09 14:55:38 +02:00
|
|
|
{
|
|
|
|
unsigned int num_fresh_coins;
|
|
|
|
|
|
|
|
cmd->details.refresh_melt.noreveal_index = UINT16_MAX;
|
|
|
|
for (num_fresh_coins=0;
|
|
|
|
NULL != cmd->details.refresh_melt.fresh_amounts[num_fresh_coins];
|
|
|
|
num_fresh_coins++) ;
|
|
|
|
|
2015-08-09 16:21:49 +02:00
|
|
|
cmd->details.refresh_melt.fresh_pks
|
|
|
|
= GNUNET_new_array (num_fresh_coins,
|
2016-03-01 15:35:04 +01:00
|
|
|
const struct TALER_EXCHANGE_DenomPublicKey *);
|
2015-08-09 14:55:38 +02:00
|
|
|
{
|
2016-05-16 11:55:47 +02:00
|
|
|
struct TALER_CoinSpendPrivateKeyP melt_priv;
|
|
|
|
struct TALER_Amount melt_amount;
|
|
|
|
struct TALER_DenominationSignature melt_sig;
|
|
|
|
struct TALER_EXCHANGE_DenomPublicKey melt_pk;
|
2016-03-01 15:35:04 +01:00
|
|
|
struct TALER_EXCHANGE_DenomPublicKey fresh_pks[num_fresh_coins];
|
2015-08-09 14:55:38 +02:00
|
|
|
unsigned int i;
|
|
|
|
|
2016-05-16 11:55:47 +02:00
|
|
|
const struct MeltDetails *md = &cmd->details.refresh_melt.melted_coin;
|
|
|
|
ref = find_command (is,
|
|
|
|
md->coin_ref);
|
|
|
|
GNUNET_assert (NULL != ref);
|
|
|
|
GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
|
2015-08-09 14:55:38 +02:00
|
|
|
|
2017-10-31 14:02:54 +01:00
|
|
|
melt_priv = ref->details.reserve_withdraw.ps.coin_priv;
|
2016-05-16 11:55:47 +02:00
|
|
|
if (GNUNET_OK !=
|
|
|
|
TALER_string_to_amount (md->amount,
|
|
|
|
&melt_amount))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Failed to parse amount `%s' at %u\n",
|
|
|
|
md->amount,
|
|
|
|
is->ip);
|
|
|
|
fail (is);
|
|
|
|
return;
|
2015-08-09 14:55:38 +02:00
|
|
|
}
|
2016-05-16 11:55:47 +02:00
|
|
|
melt_sig = ref->details.reserve_withdraw.sig;
|
|
|
|
melt_pk = *ref->details.reserve_withdraw.pk;
|
2015-08-09 14:55:38 +02:00
|
|
|
for (i=0;i<num_fresh_coins;i++)
|
|
|
|
{
|
2015-08-09 15:24:02 +02:00
|
|
|
if (GNUNET_OK !=
|
|
|
|
TALER_string_to_amount (cmd->details.refresh_melt.fresh_amounts[i],
|
|
|
|
&amount))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Failed to parse amount `%s' at %u\n",
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_withdraw.amount,
|
2015-08-09 15:24:02 +02:00
|
|
|
is->ip);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2015-08-09 16:21:49 +02:00
|
|
|
cmd->details.refresh_melt.fresh_pks[i]
|
|
|
|
= find_pk (is->keys,
|
|
|
|
&amount);
|
|
|
|
fresh_pks[i] = *cmd->details.refresh_melt.fresh_pks[i];
|
2015-08-09 14:55:38 +02:00
|
|
|
}
|
|
|
|
cmd->details.refresh_melt.refresh_data
|
2016-05-16 11:55:47 +02:00
|
|
|
= TALER_EXCHANGE_refresh_prepare (&melt_priv,
|
|
|
|
&melt_amount,
|
|
|
|
&melt_sig,
|
|
|
|
&melt_pk,
|
|
|
|
GNUNET_YES,
|
|
|
|
num_fresh_coins,
|
|
|
|
fresh_pks,
|
|
|
|
&cmd->details.refresh_melt.refresh_data_length);
|
2015-08-09 14:55:38 +02:00
|
|
|
if (NULL == cmd->details.refresh_melt.refresh_data)
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cmd->details.refresh_melt.rmh
|
2016-03-01 15:35:04 +01:00
|
|
|
= TALER_EXCHANGE_refresh_melt (exchange,
|
2015-08-09 15:24:02 +02:00
|
|
|
cmd->details.refresh_melt.refresh_data_length,
|
|
|
|
cmd->details.refresh_melt.refresh_data,
|
|
|
|
&melt_cb,
|
|
|
|
is);
|
2015-08-09 14:55:38 +02:00
|
|
|
if (NULL == cmd->details.refresh_melt.rmh)
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-08-09 15:33:38 +02:00
|
|
|
return;
|
2015-08-08 23:21:00 +02:00
|
|
|
case OC_REFRESH_REVEAL:
|
2015-08-09 15:24:02 +02:00
|
|
|
ref = find_command (is,
|
|
|
|
cmd->details.refresh_reveal.melt_ref);
|
2016-03-19 19:14:19 +01:00
|
|
|
GNUNET_assert (NULL != ref);
|
2015-08-09 15:24:02 +02:00
|
|
|
cmd->details.refresh_reveal.rrh
|
2016-03-01 15:35:04 +01:00
|
|
|
= TALER_EXCHANGE_refresh_reveal (exchange,
|
2016-03-19 19:14:19 +01:00
|
|
|
ref->details.refresh_melt.refresh_data_length,
|
|
|
|
ref->details.refresh_melt.refresh_data,
|
|
|
|
ref->details.refresh_melt.noreveal_index,
|
|
|
|
&reveal_cb,
|
|
|
|
is);
|
2015-08-09 15:24:02 +02:00
|
|
|
if (NULL == cmd->details.refresh_reveal.rrh)
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return;
|
2015-08-08 23:21:00 +02:00
|
|
|
case OC_REFRESH_LINK:
|
2015-08-09 15:33:38 +02:00
|
|
|
/* find reveal command */
|
|
|
|
ref = find_command (is,
|
|
|
|
cmd->details.refresh_link.reveal_ref);
|
2016-03-19 19:14:19 +01:00
|
|
|
GNUNET_assert (NULL != ref);
|
2015-08-09 15:33:38 +02:00
|
|
|
/* find melt command */
|
|
|
|
ref = find_command (is,
|
|
|
|
ref->details.refresh_reveal.melt_ref);
|
2016-03-19 19:14:19 +01:00
|
|
|
GNUNET_assert (NULL != ref);
|
2015-09-19 22:08:49 +02:00
|
|
|
/* find reserve_withdraw command */
|
2015-08-09 15:33:38 +02:00
|
|
|
{
|
|
|
|
const struct MeltDetails *md;
|
2016-05-16 11:55:47 +02:00
|
|
|
|
|
|
|
md = &ref->details.refresh_melt.melted_coin;
|
2015-08-09 15:33:38 +02:00
|
|
|
ref = find_command (is,
|
|
|
|
md->coin_ref);
|
2016-03-19 19:14:19 +01:00
|
|
|
GNUNET_assert (NULL != ref);
|
2015-08-09 15:33:38 +02:00
|
|
|
}
|
2015-08-14 23:09:34 +02:00
|
|
|
GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
|
2015-08-09 15:33:38 +02:00
|
|
|
/* finally, use private key from withdraw sign command */
|
|
|
|
cmd->details.refresh_link.rlh
|
2016-03-01 15:35:04 +01:00
|
|
|
= TALER_EXCHANGE_refresh_link (exchange,
|
2017-10-31 14:02:54 +01:00
|
|
|
&ref->details.reserve_withdraw.ps.coin_priv,
|
2016-04-01 16:15:35 +02:00
|
|
|
&link_cb,
|
|
|
|
is);
|
2015-08-09 15:33:38 +02:00
|
|
|
if (NULL == cmd->details.refresh_link.rlh)
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return;
|
2015-09-15 10:00:21 +02:00
|
|
|
case OC_WIRE:
|
2016-03-01 15:35:04 +01:00
|
|
|
cmd->details.wire.wh = TALER_EXCHANGE_wire (exchange,
|
2016-04-01 16:15:35 +02:00
|
|
|
&wire_cb,
|
|
|
|
is);
|
2015-09-15 10:00:21 +02:00
|
|
|
return;
|
2016-01-22 15:29:31 +01:00
|
|
|
case OC_WIRE_DEPOSITS:
|
|
|
|
if (NULL != cmd->details.wire_deposits.wtid_ref)
|
|
|
|
{
|
|
|
|
ref = find_command (is,
|
|
|
|
cmd->details.wire_deposits.wtid_ref);
|
|
|
|
GNUNET_assert (NULL != ref);
|
2016-05-03 13:55:40 +02:00
|
|
|
switch (ref->oc)
|
|
|
|
{
|
|
|
|
case OC_DEPOSIT_WTID:
|
|
|
|
cmd->details.wire_deposits.wtid = ref->details.deposit_wtid.wtid;
|
|
|
|
break;
|
2016-05-04 05:38:29 +02:00
|
|
|
case OC_CHECK_BANK_TRANSFER:
|
2017-06-11 15:25:59 +02:00
|
|
|
GNUNET_assert (GNUNET_OK ==
|
|
|
|
GNUNET_STRINGS_string_to_data (ref->details.check_bank_transfer.subject,
|
|
|
|
strlen (ref->details.check_bank_transfer.subject),
|
|
|
|
&cmd->details.wire_deposits.wtid,
|
|
|
|
sizeof (cmd->details.wire_deposits.wtid)));
|
2016-05-03 13:55:40 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-01-22 15:29:31 +01:00
|
|
|
}
|
|
|
|
cmd->details.wire_deposits.wdh
|
2016-06-09 19:18:13 +02:00
|
|
|
= TALER_EXCHANGE_track_transfer (exchange,
|
2016-04-01 16:15:35 +02:00
|
|
|
&cmd->details.wire_deposits.wtid,
|
|
|
|
&wire_deposits_cb,
|
|
|
|
is);
|
2016-01-22 15:29:31 +01:00
|
|
|
return;
|
|
|
|
case OC_DEPOSIT_WTID:
|
|
|
|
{
|
|
|
|
struct GNUNET_HashCode h_wire;
|
2017-05-29 01:15:41 +02:00
|
|
|
struct GNUNET_HashCode h_contract_terms;
|
2016-01-22 15:29:31 +01:00
|
|
|
json_t *wire;
|
2017-05-29 01:15:41 +02:00
|
|
|
json_t *contract_terms;
|
2016-01-22 15:29:31 +01:00
|
|
|
const struct Command *coin;
|
|
|
|
struct TALER_CoinSpendPublicKeyP coin_pub;
|
|
|
|
|
|
|
|
ref = find_command (is,
|
|
|
|
cmd->details.deposit_wtid.deposit_ref);
|
|
|
|
GNUNET_assert (NULL != ref);
|
|
|
|
coin = find_command (is,
|
|
|
|
ref->details.deposit.coin_ref);
|
|
|
|
GNUNET_assert (NULL != coin);
|
2016-05-20 17:15:50 +02:00
|
|
|
get_public_key_from_coin_command (coin,
|
|
|
|
ref->details.deposit.coin_idx,
|
|
|
|
&coin_pub);
|
2016-01-22 15:29:31 +01:00
|
|
|
wire = json_loads (ref->details.deposit.wire_details,
|
|
|
|
JSON_REJECT_DUPLICATES,
|
|
|
|
NULL);
|
|
|
|
GNUNET_assert (NULL != wire);
|
2017-10-06 20:02:28 +02:00
|
|
|
GNUNET_assert (GNUNET_OK ==
|
|
|
|
TALER_JSON_hash (wire,
|
|
|
|
&h_wire));
|
2016-01-22 15:29:31 +01:00
|
|
|
json_decref (wire);
|
2017-05-29 01:15:41 +02:00
|
|
|
contract_terms = json_loads (ref->details.deposit.contract_terms,
|
2016-01-22 15:29:31 +01:00
|
|
|
JSON_REJECT_DUPLICATES,
|
|
|
|
NULL);
|
2017-05-29 01:15:41 +02:00
|
|
|
GNUNET_assert (NULL != contract_terms);
|
2017-10-06 20:02:28 +02:00
|
|
|
GNUNET_assert (GNUNET_OK ==
|
|
|
|
TALER_JSON_hash (contract_terms,
|
|
|
|
&h_contract_terms));
|
2017-05-29 01:15:41 +02:00
|
|
|
json_decref (contract_terms);
|
2016-01-22 15:29:31 +01:00
|
|
|
cmd->details.deposit_wtid.dwh
|
2017-02-07 15:09:10 +01:00
|
|
|
= TALER_EXCHANGE_track_transaction (exchange,
|
|
|
|
&ref->details.deposit.merchant_priv,
|
|
|
|
&h_wire,
|
2017-05-29 01:15:41 +02:00
|
|
|
&h_contract_terms,
|
2017-02-07 15:09:10 +01:00
|
|
|
&coin_pub,
|
|
|
|
&deposit_wtid_cb,
|
|
|
|
is);
|
2016-01-22 15:29:31 +01:00
|
|
|
}
|
|
|
|
return;
|
2016-05-03 07:57:49 +02:00
|
|
|
case OC_RUN_AGGREGATOR:
|
|
|
|
{
|
2016-05-04 05:16:32 +02:00
|
|
|
const struct GNUNET_DISK_FileHandle *pr;
|
|
|
|
|
2016-05-03 07:57:49 +02:00
|
|
|
cmd->details.run_aggregator.aggregator_proc
|
|
|
|
= GNUNET_OS_start_process (GNUNET_NO,
|
|
|
|
GNUNET_OS_INHERIT_STD_ALL,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
"taler-exchange-aggregator",
|
|
|
|
"taler-exchange-aggregator",
|
|
|
|
"-c", "test_exchange_api.conf",
|
|
|
|
"-t", /* exit when done */
|
|
|
|
NULL);
|
|
|
|
if (NULL == cmd->details.run_aggregator.aggregator_proc)
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-05-04 05:16:32 +02:00
|
|
|
pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
|
2016-06-09 15:20:24 +02:00
|
|
|
cmd->details.run_aggregator.child_death_task
|
|
|
|
= GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
|
|
|
|
pr,
|
|
|
|
&maint_child_death, is);
|
2016-05-03 07:57:49 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-05-04 05:38:29 +02:00
|
|
|
case OC_CHECK_BANK_TRANSFER:
|
2016-05-03 13:55:40 +02:00
|
|
|
{
|
|
|
|
if (GNUNET_OK !=
|
2016-05-04 05:38:29 +02:00
|
|
|
TALER_string_to_amount (cmd->details.check_bank_transfer.amount,
|
2016-05-03 13:55:40 +02:00
|
|
|
&amount))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Failed to parse amount `%s' at %u\n",
|
|
|
|
cmd->details.reserve_withdraw.amount,
|
|
|
|
is->ip);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (GNUNET_OK !=
|
2016-06-08 11:35:28 +02:00
|
|
|
TALER_FAKEBANK_check (fakebank,
|
2017-03-02 06:26:12 +01:00
|
|
|
&amount,
|
|
|
|
cmd->details.check_bank_transfer.account_debit,
|
|
|
|
cmd->details.check_bank_transfer.account_credit,
|
|
|
|
cmd->details.check_bank_transfer.exchange_base_url,
|
2017-06-11 15:25:59 +02:00
|
|
|
&cmd->details.check_bank_transfer.subject))
|
2016-05-03 13:55:40 +02:00
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
next_command (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-05-04 05:38:29 +02:00
|
|
|
case OC_CHECK_BANK_TRANSFERS_EMPTY:
|
2016-05-03 13:55:40 +02:00
|
|
|
{
|
|
|
|
if (GNUNET_OK !=
|
2016-06-08 11:35:28 +02:00
|
|
|
TALER_FAKEBANK_check_empty (fakebank))
|
2016-05-03 13:55:40 +02:00
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
next_command (is);
|
|
|
|
return;
|
|
|
|
}
|
2016-05-20 17:15:50 +02:00
|
|
|
case OC_REFUND:
|
|
|
|
{
|
|
|
|
const struct Command *coin;
|
2017-05-29 01:15:41 +02:00
|
|
|
struct GNUNET_HashCode h_contract_terms;
|
|
|
|
json_t *contract_terms;
|
2016-05-20 17:15:50 +02:00
|
|
|
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);
|
2017-05-29 01:15:41 +02:00
|
|
|
contract_terms = json_loads (ref->details.deposit.contract_terms,
|
2016-05-20 17:15:50 +02:00
|
|
|
JSON_REJECT_DUPLICATES,
|
|
|
|
NULL);
|
2017-05-29 01:15:41 +02:00
|
|
|
GNUNET_assert (NULL != contract_terms);
|
2017-10-06 20:02:28 +02:00
|
|
|
GNUNET_assert (GNUNET_OK ==
|
|
|
|
TALER_JSON_hash (contract_terms,
|
|
|
|
&h_contract_terms));
|
2017-05-29 01:15:41 +02:00
|
|
|
json_decref (contract_terms);
|
2016-05-20 17:15:50 +02:00
|
|
|
|
|
|
|
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,
|
2017-05-29 01:15:41 +02:00
|
|
|
&h_contract_terms,
|
2016-05-20 17:15:50 +02:00
|
|
|
&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;
|
|
|
|
}
|
2017-04-10 01:24:05 +02:00
|
|
|
case OC_REVOKE:
|
|
|
|
{
|
|
|
|
const struct GNUNET_DISK_FileHandle *pr;
|
|
|
|
char *dhks;
|
|
|
|
const struct Command *ref;
|
|
|
|
|
|
|
|
ref = find_command (is,
|
|
|
|
cmd->details.revoke.ref);
|
|
|
|
GNUNET_assert (NULL != ref);
|
|
|
|
dhks = GNUNET_STRINGS_data_to_string_alloc (&ref->details.reserve_withdraw.pk->h_key,
|
|
|
|
sizeof (struct GNUNET_HashCode));
|
|
|
|
cmd->details.revoke.revoke_proc
|
|
|
|
= GNUNET_OS_start_process (GNUNET_NO,
|
|
|
|
GNUNET_OS_INHERIT_STD_ALL,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
"taler-exchange-keyup",
|
|
|
|
"taler-exchange-keyup",
|
|
|
|
"-c", "test_exchange_api.conf",
|
|
|
|
"-r", dhks,
|
|
|
|
NULL);
|
|
|
|
GNUNET_free (dhks);
|
|
|
|
if (NULL == cmd->details.revoke.revoke_proc)
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
|
|
|
|
cmd->details.revoke.child_death_task
|
|
|
|
= GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
|
|
|
|
pr,
|
|
|
|
&maint_child_death,
|
|
|
|
is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case OC_PAYBACK:
|
|
|
|
{
|
|
|
|
const struct Command *ref;
|
|
|
|
|
|
|
|
ref = find_command (is,
|
2017-04-10 17:59:33 +02:00
|
|
|
cmd->details.payback.ref);
|
2017-04-10 01:24:05 +02:00
|
|
|
GNUNET_assert (NULL != ref);
|
|
|
|
cmd->details.payback.ph
|
|
|
|
= TALER_EXCHANGE_payback (exchange,
|
|
|
|
ref->details.reserve_withdraw.pk,
|
|
|
|
&ref->details.reserve_withdraw.sig,
|
2017-10-31 14:02:54 +01:00
|
|
|
&ref->details.reserve_withdraw.ps,
|
2017-04-10 01:24:05 +02:00
|
|
|
&payback_cb,
|
|
|
|
is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-07-04 17:30:38 +02:00
|
|
|
default:
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Unknown instruction %d at %u (%s)\n",
|
|
|
|
cmd->oc,
|
2015-07-04 20:47:39 +02:00
|
|
|
is->ip,
|
2015-07-04 17:30:38 +02:00
|
|
|
cmd->label);
|
|
|
|
fail (is);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-04 05:16:32 +02:00
|
|
|
/**
|
|
|
|
* Signal handler called for SIGCHLD. Triggers the
|
|
|
|
* respective handler by writing to the trigger pipe.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sighandler_child_death ()
|
|
|
|
{
|
|
|
|
static char c;
|
|
|
|
int old_errno = errno; /* back-up errno */
|
|
|
|
|
|
|
|
GNUNET_break (1 ==
|
|
|
|
GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
|
|
|
|
(sigpipe, GNUNET_DISK_PIPE_END_WRITE),
|
|
|
|
&c, sizeof (c)));
|
|
|
|
errno = old_errno; /* restore errno */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-02 02:33:14 +02:00
|
|
|
/**
|
|
|
|
* Function run when the test terminates (good or bad) with timeout.
|
|
|
|
*
|
|
|
|
* @param cls NULL
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
do_timeout (void *cls)
|
|
|
|
{
|
|
|
|
timeout_task = NULL;
|
|
|
|
GNUNET_SCHEDULER_shutdown ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-18 11:39:53 +02:00
|
|
|
/**
|
|
|
|
* Function run when the test terminates (good or bad).
|
|
|
|
* Cleans up our state.
|
|
|
|
*
|
2015-07-04 20:47:39 +02:00
|
|
|
* @param cls the interpreter state.
|
2015-06-18 11:39:53 +02:00
|
|
|
*/
|
2015-01-08 18:37:20 +01:00
|
|
|
static void
|
2016-04-10 00:57:20 +02:00
|
|
|
do_shutdown (void *cls)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-07-04 20:47:39 +02:00
|
|
|
struct InterpreterState *is = cls;
|
|
|
|
struct Command *cmd;
|
|
|
|
unsigned int i;
|
|
|
|
|
2016-11-18 18:29:18 +01:00
|
|
|
fprintf (stderr,
|
|
|
|
"Executing shutdown at `%s'\n",
|
|
|
|
is->commands[is->ip].label);
|
|
|
|
|
2015-07-04 20:47:39 +02:00
|
|
|
for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
|
|
|
|
{
|
|
|
|
switch (cmd->oc)
|
|
|
|
{
|
|
|
|
case OC_END:
|
|
|
|
GNUNET_assert (0);
|
|
|
|
break;
|
|
|
|
case OC_ADMIN_ADD_INCOMING:
|
|
|
|
if (NULL != cmd->details.admin_add_incoming.aih)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Command %u (%s) did not complete\n",
|
|
|
|
i,
|
|
|
|
cmd->label);
|
2016-03-01 15:35:04 +01:00
|
|
|
TALER_EXCHANGE_admin_add_incoming_cancel (cmd->details.admin_add_incoming.aih);
|
2015-07-04 20:47:39 +02:00
|
|
|
cmd->details.admin_add_incoming.aih = NULL;
|
|
|
|
}
|
|
|
|
break;
|
2015-07-09 11:36:13 +02:00
|
|
|
case OC_WITHDRAW_STATUS:
|
2015-09-19 22:08:49 +02:00
|
|
|
if (NULL != cmd->details.reserve_status.wsh)
|
2015-07-09 11:36:13 +02:00
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Command %u (%s) did not complete\n",
|
|
|
|
i,
|
|
|
|
cmd->label);
|
2016-03-01 15:35:04 +01:00
|
|
|
TALER_EXCHANGE_reserve_status_cancel (cmd->details.reserve_status.wsh);
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_status.wsh = NULL;
|
2015-07-09 11:36:13 +02:00
|
|
|
}
|
|
|
|
break;
|
2015-07-04 20:47:39 +02:00
|
|
|
case OC_WITHDRAW_SIGN:
|
2015-09-19 22:08:49 +02:00
|
|
|
if (NULL != cmd->details.reserve_withdraw.wsh)
|
2015-07-04 22:00:29 +02:00
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Command %u (%s) did not complete\n",
|
|
|
|
i,
|
|
|
|
cmd->label);
|
2016-03-01 15:35:04 +01:00
|
|
|
TALER_EXCHANGE_reserve_withdraw_cancel (cmd->details.reserve_withdraw.wsh);
|
2015-09-19 22:08:49 +02:00
|
|
|
cmd->details.reserve_withdraw.wsh = NULL;
|
2015-07-04 22:00:29 +02:00
|
|
|
}
|
2015-09-19 22:08:49 +02:00
|
|
|
if (NULL != cmd->details.reserve_withdraw.sig.rsa_signature)
|
2015-07-04 22:35:30 +02:00
|
|
|
{
|
2015-09-19 22:08:49 +02:00
|
|
|
GNUNET_CRYPTO_rsa_signature_free (cmd->details.reserve_withdraw.sig.rsa_signature);
|
|
|
|
cmd->details.reserve_withdraw.sig.rsa_signature = NULL;
|
2015-07-04 22:35:30 +02:00
|
|
|
}
|
2015-07-04 20:47:39 +02:00
|
|
|
break;
|
|
|
|
case OC_DEPOSIT:
|
2015-07-04 22:00:29 +02:00
|
|
|
if (NULL != cmd->details.deposit.dh)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Command %u (%s) did not complete\n",
|
|
|
|
i,
|
|
|
|
cmd->label);
|
2016-03-01 15:35:04 +01:00
|
|
|
TALER_EXCHANGE_deposit_cancel (cmd->details.deposit.dh);
|
2015-07-04 22:00:29 +02:00
|
|
|
cmd->details.deposit.dh = NULL;
|
|
|
|
}
|
2015-07-04 20:47:39 +02:00
|
|
|
break;
|
2015-08-09 14:55:38 +02:00
|
|
|
case OC_REFRESH_MELT:
|
|
|
|
if (NULL != cmd->details.refresh_melt.rmh)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Command %u (%s) did not complete\n",
|
|
|
|
i,
|
|
|
|
cmd->label);
|
2016-03-01 15:35:04 +01:00
|
|
|
TALER_EXCHANGE_refresh_melt_cancel (cmd->details.refresh_melt.rmh);
|
2015-08-09 14:55:38 +02:00
|
|
|
cmd->details.refresh_melt.rmh = NULL;
|
|
|
|
}
|
2015-08-09 16:21:49 +02:00
|
|
|
GNUNET_free_non_null (cmd->details.refresh_melt.fresh_pks);
|
|
|
|
cmd->details.refresh_melt.fresh_pks = NULL;
|
2015-08-09 14:55:38 +02:00
|
|
|
GNUNET_free_non_null (cmd->details.refresh_melt.refresh_data);
|
|
|
|
cmd->details.refresh_melt.refresh_data = NULL;
|
|
|
|
cmd->details.refresh_melt.refresh_data_length = 0;
|
|
|
|
break;
|
|
|
|
case OC_REFRESH_REVEAL:
|
|
|
|
if (NULL != cmd->details.refresh_reveal.rrh)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Command %u (%s) did not complete\n",
|
|
|
|
i,
|
|
|
|
cmd->label);
|
2016-03-01 15:35:04 +01:00
|
|
|
TALER_EXCHANGE_refresh_reveal_cancel (cmd->details.refresh_reveal.rrh);
|
2015-08-09 14:55:38 +02:00
|
|
|
cmd->details.refresh_reveal.rrh = NULL;
|
|
|
|
}
|
2015-08-09 16:21:49 +02:00
|
|
|
{
|
|
|
|
unsigned int j;
|
|
|
|
struct FreshCoin *fresh_coins;
|
|
|
|
|
|
|
|
fresh_coins = cmd->details.refresh_reveal.fresh_coins;
|
|
|
|
for (j=0;j<cmd->details.refresh_reveal.num_fresh_coins;j++)
|
|
|
|
GNUNET_CRYPTO_rsa_signature_free (fresh_coins[j].sig.rsa_signature);
|
|
|
|
}
|
|
|
|
GNUNET_free_non_null (cmd->details.refresh_reveal.fresh_coins);
|
|
|
|
cmd->details.refresh_reveal.fresh_coins = NULL;
|
|
|
|
cmd->details.refresh_reveal.num_fresh_coins = 0;
|
2015-08-09 14:55:38 +02:00
|
|
|
break;
|
|
|
|
case OC_REFRESH_LINK:
|
2015-08-09 15:24:02 +02:00
|
|
|
if (NULL != cmd->details.refresh_link.rlh)
|
2015-08-09 14:55:38 +02:00
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Command %u (%s) did not complete\n",
|
|
|
|
i,
|
|
|
|
cmd->label);
|
2016-03-01 15:35:04 +01:00
|
|
|
TALER_EXCHANGE_refresh_link_cancel (cmd->details.refresh_link.rlh);
|
2015-08-09 14:55:38 +02:00
|
|
|
cmd->details.refresh_link.rlh = NULL;
|
|
|
|
}
|
|
|
|
break;
|
2015-09-15 10:00:21 +02:00
|
|
|
case OC_WIRE:
|
|
|
|
if (NULL != cmd->details.wire.wh)
|
|
|
|
{
|
2016-01-22 17:21:42 +01:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Command %u (%s) did not complete\n",
|
|
|
|
i,
|
|
|
|
cmd->label);
|
2016-03-01 15:35:04 +01:00
|
|
|
TALER_EXCHANGE_wire_cancel (cmd->details.wire.wh);
|
2015-09-15 10:00:21 +02:00
|
|
|
cmd->details.wire.wh = NULL;
|
|
|
|
}
|
|
|
|
break;
|
2016-01-22 15:29:31 +01:00
|
|
|
case OC_WIRE_DEPOSITS:
|
|
|
|
if (NULL != cmd->details.wire_deposits.wdh)
|
|
|
|
{
|
2016-01-22 17:21:42 +01:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Command %u (%s) did not complete\n",
|
|
|
|
i,
|
|
|
|
cmd->label);
|
2016-06-09 19:18:13 +02:00
|
|
|
TALER_EXCHANGE_track_transfer_cancel (cmd->details.wire_deposits.wdh);
|
2016-01-22 15:29:31 +01:00
|
|
|
cmd->details.wire_deposits.wdh = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OC_DEPOSIT_WTID:
|
|
|
|
if (NULL != cmd->details.deposit_wtid.dwh)
|
|
|
|
{
|
2016-01-22 17:21:42 +01:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
|
|
"Command %u (%s) did not complete\n",
|
|
|
|
i,
|
|
|
|
cmd->label);
|
2016-06-09 19:18:13 +02:00
|
|
|
TALER_EXCHANGE_track_transaction_cancel (cmd->details.deposit_wtid.dwh);
|
2016-01-22 15:29:31 +01:00
|
|
|
cmd->details.deposit_wtid.dwh = NULL;
|
|
|
|
}
|
|
|
|
break;
|
2016-05-03 07:57:49 +02:00
|
|
|
case OC_RUN_AGGREGATOR:
|
|
|
|
if (NULL != cmd->details.run_aggregator.aggregator_proc)
|
|
|
|
{
|
|
|
|
GNUNET_break (0 ==
|
|
|
|
GNUNET_OS_process_kill (cmd->details.run_aggregator.aggregator_proc,
|
|
|
|
SIGKILL));
|
|
|
|
GNUNET_OS_process_wait (cmd->details.run_aggregator.aggregator_proc);
|
|
|
|
GNUNET_OS_process_destroy (cmd->details.run_aggregator.aggregator_proc);
|
|
|
|
cmd->details.run_aggregator.aggregator_proc = NULL;
|
|
|
|
}
|
2016-06-09 15:20:24 +02:00
|
|
|
if (NULL != cmd->details.run_aggregator.child_death_task)
|
|
|
|
{
|
|
|
|
GNUNET_SCHEDULER_cancel (cmd->details.run_aggregator.child_death_task);
|
|
|
|
cmd->details.run_aggregator.child_death_task = NULL;
|
|
|
|
}
|
2016-05-03 07:57:49 +02:00
|
|
|
break;
|
2016-05-04 05:38:29 +02:00
|
|
|
case OC_CHECK_BANK_TRANSFER:
|
2017-06-11 15:25:59 +02:00
|
|
|
GNUNET_free_non_null (cmd->details.check_bank_transfer.subject);
|
|
|
|
cmd->details.check_bank_transfer.subject = NULL;
|
2016-05-03 13:55:40 +02:00
|
|
|
break;
|
2016-05-04 05:38:29 +02:00
|
|
|
case OC_CHECK_BANK_TRANSFERS_EMPTY:
|
2016-05-03 13:55:40 +02:00
|
|
|
break;
|
2016-05-20 17:15:50 +02:00
|
|
|
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;
|
2017-04-10 01:24:05 +02:00
|
|
|
case OC_REVOKE:
|
|
|
|
if (NULL != cmd->details.revoke.revoke_proc)
|
|
|
|
{
|
|
|
|
GNUNET_break (0 ==
|
|
|
|
GNUNET_OS_process_kill (cmd->details.revoke.revoke_proc,
|
|
|
|
SIGKILL));
|
|
|
|
GNUNET_OS_process_wait (cmd->details.revoke.revoke_proc);
|
|
|
|
GNUNET_OS_process_destroy (cmd->details.revoke.revoke_proc);
|
|
|
|
cmd->details.revoke.revoke_proc = NULL;
|
|
|
|
}
|
|
|
|
if (NULL != cmd->details.revoke.child_death_task)
|
|
|
|
{
|
|
|
|
GNUNET_SCHEDULER_cancel (cmd->details.revoke.child_death_task);
|
|
|
|
cmd->details.revoke.child_death_task = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OC_PAYBACK:
|
|
|
|
if (NULL != cmd->details.payback.ph)
|
|
|
|
{
|
|
|
|
TALER_EXCHANGE_payback_cancel (cmd->details.payback.ph);
|
|
|
|
cmd->details.payback.ph = NULL;
|
|
|
|
}
|
|
|
|
break;
|
2015-07-04 20:47:39 +02:00
|
|
|
default:
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Unknown instruction %d at %u (%s)\n",
|
|
|
|
cmd->oc,
|
|
|
|
i,
|
|
|
|
cmd->label);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NULL != is->task)
|
|
|
|
{
|
|
|
|
GNUNET_SCHEDULER_cancel (is->task);
|
|
|
|
is->task = NULL;
|
|
|
|
}
|
|
|
|
GNUNET_free (is);
|
2016-05-03 13:55:40 +02:00
|
|
|
if (NULL != fakebank)
|
|
|
|
{
|
2016-06-08 11:35:28 +02:00
|
|
|
TALER_FAKEBANK_stop (fakebank);
|
2016-05-03 13:55:40 +02:00
|
|
|
fakebank = NULL;
|
|
|
|
}
|
2016-03-01 15:35:04 +01:00
|
|
|
if (NULL != exchange)
|
2015-06-18 01:17:01 +02:00
|
|
|
{
|
2016-03-01 15:35:04 +01:00
|
|
|
TALER_EXCHANGE_disconnect (exchange);
|
|
|
|
exchange = NULL;
|
2015-06-18 01:17:01 +02:00
|
|
|
}
|
|
|
|
if (NULL != ctx)
|
|
|
|
{
|
2016-04-17 17:45:15 +02:00
|
|
|
GNUNET_CURL_fini (ctx);
|
2015-06-18 01:17:01 +02:00
|
|
|
ctx = NULL;
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
2016-05-02 08:24:21 +02:00
|
|
|
if (NULL != rc)
|
2016-05-02 02:33:14 +02:00
|
|
|
{
|
2016-05-02 08:24:21 +02:00
|
|
|
GNUNET_CURL_gnunet_rc_destroy (rc);
|
|
|
|
rc = NULL;
|
2016-05-02 02:33:14 +02:00
|
|
|
}
|
|
|
|
if (NULL != timeout_task)
|
|
|
|
{
|
|
|
|
GNUNET_SCHEDULER_cancel (timeout_task);
|
|
|
|
timeout_task = NULL;
|
|
|
|
}
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
2015-06-18 01:17:01 +02:00
|
|
|
|
|
|
|
|
2015-01-08 18:37:20 +01:00
|
|
|
/**
|
2015-06-18 01:17:01 +02:00
|
|
|
* Functions of this type are called to provide the retrieved signing and
|
2016-03-01 15:35:04 +01:00
|
|
|
* denomination keys of the exchange. No TALER_EXCHANGE_*() functions should be called
|
2015-06-18 01:17:01 +02:00
|
|
|
* in this callback.
|
2015-01-08 18:37:20 +01:00
|
|
|
*
|
|
|
|
* @param cls closure
|
2016-03-01 15:35:04 +01:00
|
|
|
* @param keys information about keys of the exchange
|
2017-07-01 14:15:26 +02:00
|
|
|
* @param vc version compatibility
|
2015-01-08 18:37:20 +01:00
|
|
|
*/
|
|
|
|
static void
|
2015-06-18 01:17:01 +02:00
|
|
|
cert_cb (void *cls,
|
2017-07-01 14:15:26 +02:00
|
|
|
const struct TALER_EXCHANGE_Keys *keys,
|
|
|
|
enum TALER_EXCHANGE_VersionCompatibility vc)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-07-04 20:47:39 +02:00
|
|
|
struct InterpreterState *is = cls;
|
2015-07-04 17:30:38 +02:00
|
|
|
|
2015-07-05 13:21:53 +02:00
|
|
|
/* check that keys is OK */
|
2015-06-18 01:17:01 +02:00
|
|
|
#define ERR(cond) do { if(!(cond)) break; GNUNET_break (0); GNUNET_SCHEDULER_shutdown(); return; } while (0)
|
|
|
|
ERR (NULL == keys);
|
|
|
|
ERR (0 == keys->num_sign_keys);
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
|
|
|
"Read %u signing keys\n",
|
|
|
|
keys->num_sign_keys);
|
|
|
|
ERR (0 == keys->num_denom_keys);
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
|
|
|
"Read %u denomination keys\n",
|
|
|
|
keys->num_denom_keys);
|
|
|
|
#undef ERR
|
2015-07-04 17:30:38 +02:00
|
|
|
|
2015-07-05 13:21:53 +02:00
|
|
|
/* run actual tests via interpreter-loop */
|
2015-07-04 17:30:38 +02:00
|
|
|
is->keys = keys;
|
2015-07-04 20:47:39 +02:00
|
|
|
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
|
|
|
is);
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Main function that will be run by the scheduler.
|
|
|
|
*
|
|
|
|
* @param cls closure
|
|
|
|
*/
|
|
|
|
static void
|
2016-04-10 00:57:20 +02:00
|
|
|
run (void *cls)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-07-04 20:47:39 +02:00
|
|
|
struct InterpreterState *is;
|
2015-08-09 14:55:38 +02:00
|
|
|
static const char *melt_fresh_amounts_1[] = {
|
2015-08-09 17:18:09 +02:00
|
|
|
"EUR:1",
|
|
|
|
"EUR:1",
|
|
|
|
"EUR:1",
|
|
|
|
"EUR:0.1",
|
|
|
|
"EUR:0.1",
|
|
|
|
"EUR:0.1",
|
|
|
|
"EUR:0.1",
|
|
|
|
"EUR:0.1",
|
|
|
|
"EUR:0.1",
|
|
|
|
"EUR:0.1",
|
2015-08-09 21:38:04 +02:00
|
|
|
"EUR:0.1",
|
|
|
|
"EUR:0.01",
|
|
|
|
"EUR:0.01",
|
|
|
|
"EUR:0.01",
|
|
|
|
"EUR:0.01",
|
|
|
|
"EUR:0.01",
|
|
|
|
"EUR:0.01",
|
|
|
|
/* with 0.01 withdraw fees (except for 1ct coins),
|
|
|
|
this totals up to exactly EUR:3.97, and with
|
|
|
|
the 0.03 refresh fee, to EUR:4.0*/
|
2015-08-08 23:35:51 +02:00
|
|
|
NULL
|
|
|
|
};
|
2015-07-04 20:47:39 +02:00
|
|
|
static struct Command commands[] =
|
|
|
|
{
|
2015-09-15 17:27:02 +02:00
|
|
|
/* *************** start of /wire testing ************** */
|
|
|
|
|
|
|
|
#if WIRE_TEST
|
|
|
|
{ .oc = OC_WIRE,
|
2015-09-20 13:48:15 +02:00
|
|
|
.label = "wire-test",
|
2016-04-01 16:15:35 +02:00
|
|
|
/* expecting 'test' method in response */
|
2016-03-04 11:57:57 +01:00
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2017-03-06 17:36:10 +01:00
|
|
|
.details.wire.format = "test",
|
|
|
|
.details.wire.expected_fee = "EUR:0.01" },
|
2015-09-15 17:27:02 +02:00
|
|
|
#endif
|
|
|
|
#if WIRE_SEPA
|
2015-09-20 14:02:10 +02:00
|
|
|
{ .oc = OC_WIRE,
|
2015-09-20 13:48:15 +02:00
|
|
|
.label = "wire-sepa",
|
2016-04-01 16:15:35 +02:00
|
|
|
/* expecting 'sepa' method in response */
|
2015-09-20 14:02:10 +02:00
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2017-03-06 17:36:10 +01:00
|
|
|
.details.wire.format = "sepa",
|
|
|
|
.details.wire.expected_fee = "EUR:0.01" },
|
2015-09-15 17:27:02 +02:00
|
|
|
#endif
|
|
|
|
/* *************** end of /wire testing ************** */
|
|
|
|
|
|
|
|
#if WIRE_TEST
|
|
|
|
/* None of this works if 'test' is not allowed as we do
|
|
|
|
/admin/add/incoming with format 'test' */
|
|
|
|
|
2015-07-05 13:21:53 +02:00
|
|
|
/* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */
|
2015-07-04 20:47:39 +02:00
|
|
|
{ .oc = OC_ADMIN_ADD_INCOMING,
|
|
|
|
.label = "create-reserve-1",
|
2015-07-09 12:22:07 +02:00
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2016-05-26 16:38:59 +02:00
|
|
|
.details.admin_add_incoming.sender_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42}",
|
|
|
|
.details.admin_add_incoming.transfer_details = "{ \"uuid\":1 }",
|
2015-07-05 13:18:49 +02:00
|
|
|
.details.admin_add_incoming.amount = "EUR:5.01" },
|
2015-07-09 12:47:49 +02:00
|
|
|
/* Withdraw a 5 EUR coin, at fee of 1 ct */
|
2015-07-04 20:47:39 +02:00
|
|
|
{ .oc = OC_WITHDRAW_SIGN,
|
|
|
|
.label = "withdraw-coin-1",
|
2015-07-09 12:22:07 +02:00
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2015-09-19 22:08:49 +02:00
|
|
|
.details.reserve_withdraw.reserve_reference = "create-reserve-1",
|
|
|
|
.details.reserve_withdraw.amount = "EUR:5" },
|
2015-07-09 12:47:49 +02:00
|
|
|
/* Check that deposit and withdraw operation are in history, and
|
|
|
|
that the balance is now at zero */
|
2015-07-09 11:36:13 +02:00
|
|
|
{ .oc = OC_WITHDRAW_STATUS,
|
|
|
|
.label = "withdraw-status-1",
|
2015-07-09 12:22:07 +02:00
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2015-09-19 22:08:49 +02:00
|
|
|
.details.reserve_status.reserve_reference = "create-reserve-1",
|
|
|
|
.details.reserve_status.expected_balance = "EUR:0" },
|
2015-07-09 12:47:49 +02:00
|
|
|
/* Try to deposit the 5 EUR coin (in full) */
|
2015-07-04 20:47:39 +02:00
|
|
|
{ .oc = OC_DEPOSIT,
|
|
|
|
.label = "deposit-simple",
|
2015-07-09 12:22:07 +02:00
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2015-07-04 20:47:39 +02:00
|
|
|
.details.deposit.amount = "EUR:5",
|
|
|
|
.details.deposit.coin_ref = "withdraw-coin-1",
|
2016-04-11 02:37:56 +02:00
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }" },
|
2015-07-09 12:47:49 +02:00
|
|
|
|
|
|
|
/* Try to overdraw funds ... */
|
|
|
|
{ .oc = OC_WITHDRAW_SIGN,
|
|
|
|
.label = "withdraw-coin-2",
|
2016-10-18 23:05:29 +02:00
|
|
|
.expected_response_code = MHD_HTTP_FORBIDDEN,
|
2015-09-19 22:08:49 +02:00
|
|
|
.details.reserve_withdraw.reserve_reference = "create-reserve-1",
|
|
|
|
.details.reserve_withdraw.amount = "EUR:5" },
|
2015-08-09 18:11:30 +02:00
|
|
|
|
2015-07-09 12:47:49 +02:00
|
|
|
/* Try to double-spend the 5 EUR coin with different wire details */
|
|
|
|
{ .oc = OC_DEPOSIT,
|
|
|
|
.label = "deposit-double-1",
|
|
|
|
.expected_response_code = MHD_HTTP_FORBIDDEN,
|
|
|
|
.details.deposit.amount = "EUR:5",
|
|
|
|
.details.deposit.coin_ref = "withdraw-coin-1",
|
2016-04-11 02:37:56 +02:00
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":43 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }" },
|
2015-07-09 12:47:49 +02:00
|
|
|
/* Try to double-spend the 5 EUR coin at the same merchant (but different
|
|
|
|
transaction ID) */
|
|
|
|
{ .oc = OC_DEPOSIT,
|
|
|
|
.label = "deposit-double-2",
|
|
|
|
.expected_response_code = MHD_HTTP_FORBIDDEN,
|
|
|
|
.details.deposit.amount = "EUR:5",
|
|
|
|
.details.deposit.coin_ref = "withdraw-coin-1",
|
2016-04-11 02:37:56 +02:00
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }" },
|
2015-07-09 12:47:49 +02:00
|
|
|
/* Try to double-spend the 5 EUR coin at the same merchant (but different
|
2017-02-06 15:41:39 +01:00
|
|
|
proposal) */
|
2015-07-09 12:47:49 +02:00
|
|
|
{ .oc = OC_DEPOSIT,
|
|
|
|
.label = "deposit-double-3",
|
|
|
|
.expected_response_code = MHD_HTTP_FORBIDDEN,
|
|
|
|
.details.deposit.amount = "EUR:5",
|
|
|
|
.details.deposit.coin_ref = "withdraw-coin-1",
|
2016-04-11 02:37:56 +02:00
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\":[{ \"name\":\"ice cream\", \"value\":2 } ] }" },
|
2015-07-09 12:47:49 +02:00
|
|
|
|
2015-08-09 17:18:09 +02:00
|
|
|
/* ***************** /refresh testing ******************** */
|
|
|
|
|
|
|
|
/* Fill reserve with EUR:5.01, as withdraw fee is 1 ct */
|
|
|
|
{ .oc = OC_ADMIN_ADD_INCOMING,
|
|
|
|
.label = "refresh-create-reserve-1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2016-05-26 16:38:59 +02:00
|
|
|
.details.admin_add_incoming.sender_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":424 }",
|
|
|
|
.details.admin_add_incoming.transfer_details = "{ \"uuid\":2 }",
|
2015-08-09 17:18:09 +02:00
|
|
|
.details.admin_add_incoming.amount = "EUR:5.01" },
|
|
|
|
/* Withdraw a 5 EUR coin, at fee of 1 ct */
|
|
|
|
{ .oc = OC_WITHDRAW_SIGN,
|
|
|
|
.label = "refresh-withdraw-coin-1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2015-09-19 22:08:49 +02:00
|
|
|
.details.reserve_withdraw.reserve_reference = "refresh-create-reserve-1",
|
|
|
|
.details.reserve_withdraw.amount = "EUR:5" },
|
2015-08-09 17:18:09 +02:00
|
|
|
/* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full)
|
|
|
|
(merchant would receive EUR:0.99 due to 1 ct deposit fee) */
|
|
|
|
{ .oc = OC_DEPOSIT,
|
|
|
|
.label = "refresh-deposit-partial",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.deposit.amount = "EUR:1",
|
|
|
|
.details.deposit.coin_ref = "refresh-withdraw-coin-1",
|
2016-04-11 02:37:56 +02:00
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:1\" } ] }" },
|
2015-08-09 17:18:09 +02:00
|
|
|
|
|
|
|
/* Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
|
2015-08-09 19:00:48 +02:00
|
|
|
|
2015-08-08 23:35:51 +02:00
|
|
|
{ .oc = OC_REFRESH_MELT,
|
2015-08-09 17:18:09 +02:00
|
|
|
.label = "refresh-melt-1",
|
2015-08-08 23:35:51 +02:00
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2016-05-16 11:55:47 +02:00
|
|
|
.details.refresh_melt.melted_coin = {
|
|
|
|
.amount = "EUR:4",
|
|
|
|
.coin_ref = "refresh-withdraw-coin-1" },
|
2015-08-09 14:55:38 +02:00
|
|
|
.details.refresh_melt.fresh_amounts = melt_fresh_amounts_1 },
|
2015-08-08 23:35:51 +02:00
|
|
|
|
2015-08-09 21:25:02 +02:00
|
|
|
|
2015-08-08 23:35:51 +02:00
|
|
|
/* Complete (successful) melt operation, and withdraw the coins */
|
|
|
|
{ .oc = OC_REFRESH_REVEAL,
|
2015-08-09 17:18:09 +02:00
|
|
|
.label = "refresh-reveal-1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.refresh_reveal.melt_ref = "refresh-melt-1" },
|
2015-08-08 23:35:51 +02:00
|
|
|
|
2016-11-17 16:37:40 +01:00
|
|
|
/* do it again to check idempotency */
|
|
|
|
{ .oc = OC_REFRESH_REVEAL,
|
|
|
|
.label = "refresh-reveal-1-idempotency",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.refresh_reveal.melt_ref = "refresh-melt-1" },
|
|
|
|
|
2015-08-08 23:35:51 +02:00
|
|
|
/* Test that /refresh/link works */
|
|
|
|
{ .oc = OC_REFRESH_LINK,
|
2015-08-09 17:18:09 +02:00
|
|
|
.label = "refresh-link-1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.refresh_link.reveal_ref = "refresh-reveal-1" },
|
2015-08-08 23:35:51 +02:00
|
|
|
|
2015-08-14 23:09:34 +02:00
|
|
|
|
2015-08-09 17:18:09 +02:00
|
|
|
/* Test successfully spending coins from the refresh operation:
|
|
|
|
first EUR:1 */
|
2015-08-08 23:35:51 +02:00
|
|
|
{ .oc = OC_DEPOSIT,
|
2015-08-17 03:56:49 +02:00
|
|
|
.label = "refresh-deposit-refreshed-1a",
|
2015-08-08 23:35:51 +02:00
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2015-08-09 17:18:09 +02:00
|
|
|
.details.deposit.amount = "EUR:1",
|
2016-11-17 16:37:40 +01:00
|
|
|
.details.deposit.coin_ref = "refresh-reveal-1-idempotency",
|
2015-08-08 23:35:51 +02:00
|
|
|
.details.deposit.coin_idx = 0,
|
2016-04-11 02:37:56 +02:00
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }" },
|
2015-08-17 03:56:49 +02:00
|
|
|
|
2015-08-09 17:18:09 +02:00
|
|
|
/* Test successfully spending coins from the refresh operation:
|
|
|
|
finally EUR:0.1 */
|
|
|
|
{ .oc = OC_DEPOSIT,
|
|
|
|
.label = "refresh-deposit-refreshed-1b",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.deposit.amount = "EUR:0.1",
|
2015-08-17 03:56:49 +02:00
|
|
|
.details.deposit.coin_ref = "refresh-reveal-1",
|
2015-08-09 17:18:09 +02:00
|
|
|
.details.deposit.coin_idx = 4,
|
2016-05-04 05:16:32 +02:00
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":43 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }" },
|
2015-08-08 23:35:51 +02:00
|
|
|
|
2015-08-09 17:18:09 +02:00
|
|
|
/* Test running a failing melt operation (same operation again must fail) */
|
2015-08-08 23:35:51 +02:00
|
|
|
{ .oc = OC_REFRESH_MELT,
|
2015-08-09 17:18:09 +02:00
|
|
|
.label = "refresh-melt-failing",
|
2015-08-08 23:35:51 +02:00
|
|
|
.expected_response_code = MHD_HTTP_FORBIDDEN,
|
2016-05-16 11:55:47 +02:00
|
|
|
.details.refresh_melt.melted_coin = {
|
|
|
|
.amount = "EUR:4",
|
|
|
|
.coin_ref = "refresh-withdraw-coin-1" },
|
2015-08-09 17:18:09 +02:00
|
|
|
.details.refresh_melt.fresh_amounts = melt_fresh_amounts_1 },
|
2015-08-08 23:35:51 +02:00
|
|
|
|
2015-09-15 10:00:21 +02:00
|
|
|
// FIXME: also test with coin that was already melted
|
2015-08-17 03:57:50 +02:00
|
|
|
// (signature differs from coin that was deposited...)
|
2015-08-09 17:18:09 +02:00
|
|
|
/* *************** end of /refresh testing ************** */
|
2016-01-22 15:50:45 +01:00
|
|
|
|
|
|
|
/* ************** Test tracking API ******************** */
|
|
|
|
/* Try resolving a deposit's WTID, as we never triggered
|
|
|
|
execution of transactions, the answer should be that
|
2016-03-01 15:35:04 +01:00
|
|
|
the exchange knows about the deposit, but has no WTID yet. */
|
2016-01-22 15:50:45 +01:00
|
|
|
{ .oc = OC_DEPOSIT_WTID,
|
|
|
|
.label = "deposit-wtid-found",
|
2016-01-22 17:32:46 +01:00
|
|
|
.expected_response_code = MHD_HTTP_ACCEPTED,
|
2016-01-22 15:50:45 +01:00
|
|
|
.details.deposit_wtid.deposit_ref = "deposit-simple" },
|
|
|
|
/* Try resolving a deposit's WTID for a failed deposit.
|
|
|
|
As the deposit failed, the answer should be that
|
2016-03-01 15:35:04 +01:00
|
|
|
the exchange does NOT know about the deposit. */
|
2016-01-22 15:50:45 +01:00
|
|
|
{ .oc = OC_DEPOSIT_WTID,
|
|
|
|
.label = "deposit-wtid-failing",
|
|
|
|
.expected_response_code = MHD_HTTP_NOT_FOUND,
|
|
|
|
.details.deposit_wtid.deposit_ref = "deposit-double-2" },
|
|
|
|
/* Try resolving an undefined (all zeros) WTID; this
|
2016-03-01 15:35:04 +01:00
|
|
|
should fail as obviously the exchange didn't use that
|
2016-01-22 15:50:45 +01:00
|
|
|
WTID value for any transaction. */
|
|
|
|
{ .oc = OC_WIRE_DEPOSITS,
|
|
|
|
.label = "wire-deposit-failing",
|
|
|
|
.expected_response_code = MHD_HTTP_NOT_FOUND },
|
|
|
|
|
2016-05-04 05:16:32 +02:00
|
|
|
/* Run transfers. Note that _actual_ aggregation will NOT
|
|
|
|
happen here, as each deposit operation is run with a
|
|
|
|
fresh merchant public key! */
|
2016-05-03 07:57:49 +02:00
|
|
|
{ .oc = OC_RUN_AGGREGATOR,
|
|
|
|
.label = "run-aggregator" },
|
|
|
|
|
2016-05-04 05:38:29 +02:00
|
|
|
{ .oc = OC_CHECK_BANK_TRANSFER,
|
|
|
|
.label = "check_bank_transfer-499c",
|
2017-03-02 06:26:12 +01:00
|
|
|
.details.check_bank_transfer.exchange_base_url = "https://exchange.com/",
|
2017-03-04 16:49:33 +01:00
|
|
|
.details.check_bank_transfer.amount = "EUR:4.98",
|
2016-05-04 05:38:29 +02:00
|
|
|
.details.check_bank_transfer.account_debit = 2,
|
|
|
|
.details.check_bank_transfer.account_credit = 42
|
2016-05-04 05:16:32 +02:00
|
|
|
},
|
2016-05-04 05:38:29 +02:00
|
|
|
{ .oc = OC_CHECK_BANK_TRANSFER,
|
|
|
|
.label = "check_bank_transfer-99c1",
|
2017-03-02 06:26:12 +01:00
|
|
|
.details.check_bank_transfer.exchange_base_url = "https://exchange.com/",
|
2017-03-04 16:49:33 +01:00
|
|
|
.details.check_bank_transfer.amount = "EUR:0.98",
|
2016-05-04 05:38:29 +02:00
|
|
|
.details.check_bank_transfer.account_debit = 2,
|
|
|
|
.details.check_bank_transfer.account_credit = 42
|
2016-05-04 05:16:32 +02:00
|
|
|
},
|
2016-05-04 05:38:29 +02:00
|
|
|
{ .oc = OC_CHECK_BANK_TRANSFER,
|
|
|
|
.label = "check_bank_transfer-99c2",
|
2017-03-02 06:26:12 +01:00
|
|
|
.details.check_bank_transfer.exchange_base_url = "https://exchange.com/",
|
2017-03-04 16:49:33 +01:00
|
|
|
.details.check_bank_transfer.amount = "EUR:0.98",
|
2016-05-04 05:38:29 +02:00
|
|
|
.details.check_bank_transfer.account_debit = 2,
|
|
|
|
.details.check_bank_transfer.account_credit = 42
|
2016-05-04 05:16:32 +02:00
|
|
|
},
|
2016-05-04 05:38:29 +02:00
|
|
|
{ .oc = OC_CHECK_BANK_TRANSFER,
|
|
|
|
.label = "check_bank_transfer-9c",
|
2017-03-02 06:26:12 +01:00
|
|
|
.details.check_bank_transfer.exchange_base_url = "https://exchange.com/",
|
2017-03-04 16:49:33 +01:00
|
|
|
.details.check_bank_transfer.amount = "EUR:0.08",
|
2016-05-04 05:38:29 +02:00
|
|
|
.details.check_bank_transfer.account_debit = 2,
|
|
|
|
.details.check_bank_transfer.account_credit = 43
|
2016-05-04 05:16:32 +02:00
|
|
|
},
|
|
|
|
|
2016-05-04 05:38:29 +02:00
|
|
|
{ .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
|
2016-05-03 13:55:40 +02:00
|
|
|
.label = "check_bank_empty" },
|
|
|
|
|
2016-05-04 05:19:47 +02:00
|
|
|
{ .oc = OC_DEPOSIT_WTID,
|
|
|
|
.label = "deposit-wtid-ok",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2016-05-04 05:36:23 +02:00
|
|
|
.details.deposit_wtid.deposit_ref = "deposit-simple",
|
2016-05-04 05:38:29 +02:00
|
|
|
.details.deposit_wtid.bank_transfer_ref = "check_bank_transfer-499c" },
|
2016-05-04 05:19:47 +02:00
|
|
|
|
2016-05-04 06:10:41 +02:00
|
|
|
{ .oc = OC_WIRE_DEPOSITS,
|
2017-03-04 16:49:33 +01:00
|
|
|
.label = "wire-deposits-success-bank",
|
2016-05-04 06:10:41 +02:00
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.wire_deposits.wtid_ref = "check_bank_transfer-99c1",
|
2017-03-04 16:49:33 +01:00
|
|
|
.details.wire_deposits.total_amount_expected = "EUR:0.98",
|
|
|
|
.details.wire_deposits.wire_fee_expected = "EUR:0.01" },
|
2016-05-04 06:10:41 +02:00
|
|
|
|
|
|
|
{ .oc = OC_WIRE_DEPOSITS,
|
2017-03-04 16:49:33 +01:00
|
|
|
.label = "wire-deposits-success-wtid",
|
2016-05-04 06:10:41 +02:00
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.wire_deposits.wtid_ref = "deposit-wtid-ok",
|
2017-03-04 16:49:33 +01:00
|
|
|
.details.wire_deposits.total_amount_expected = "EUR:4.98",
|
|
|
|
.details.wire_deposits.wire_fee_expected = "EUR:0.01" },
|
2016-05-04 06:10:41 +02:00
|
|
|
|
2016-05-21 18:36:12 +02:00
|
|
|
/* ************** End of tracking API testing************* */
|
2016-05-04 05:19:47 +02:00
|
|
|
|
2016-05-21 18:36:12 +02:00
|
|
|
/* ************** Test /refund API ************* */
|
2016-01-22 15:50:45 +01:00
|
|
|
|
|
|
|
|
2016-05-21 18:36:12 +02:00
|
|
|
/* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */
|
|
|
|
{ .oc = OC_ADMIN_ADD_INCOMING,
|
|
|
|
.label = "create-reserve-r1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2016-05-26 16:38:59 +02:00
|
|
|
.details.admin_add_incoming.sender_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
|
|
|
.details.admin_add_incoming.transfer_details = "{ \"uuid\":3 }",
|
2016-05-21 18:36:12 +02:00
|
|
|
.details.admin_add_incoming.amount = "EUR:5.01" },
|
|
|
|
/* Withdraw a 5 EUR coin, at fee of 1 ct */
|
|
|
|
{ .oc = OC_WITHDRAW_SIGN,
|
|
|
|
.label = "withdraw-coin-r1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.reserve_withdraw.reserve_reference = "create-reserve-r1",
|
|
|
|
.details.reserve_withdraw.amount = "EUR:5" },
|
|
|
|
/* Spend 5 EUR of the 5 EUR coin (in full)
|
|
|
|
(merchant would receive EUR:4.99 due to 1 ct deposit fee) */
|
|
|
|
{ .oc = OC_DEPOSIT,
|
|
|
|
.label = "deposit-refund-1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.deposit.amount = "EUR:5",
|
|
|
|
.details.deposit.coin_ref = "withdraw-coin-r1",
|
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:5\" } ] }",
|
2016-05-21 18:36:12 +02:00
|
|
|
.details.deposit.refund_deadline = { 60LL * 1000 * 1000 } /* 60 s */,
|
|
|
|
},
|
|
|
|
/* Run transfers. Should do nothing as refund deadline blocks it */
|
|
|
|
{ .oc = OC_RUN_AGGREGATOR,
|
2016-05-21 19:22:03 +02:00
|
|
|
.label = "run-aggregator-refund" },
|
|
|
|
/* check that aggregator didn't do anything, as expected */
|
|
|
|
{ .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
|
|
|
|
.label = "check-refund-not-run" },
|
2016-05-21 18:36:12 +02:00
|
|
|
/* Trigger refund */
|
|
|
|
{ .oc = OC_REFUND,
|
|
|
|
.label = "refund-ok",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.refund.amount = "EUR:5",
|
|
|
|
.details.refund.fee = "EUR:0.01",
|
|
|
|
.details.refund.deposit_ref = "deposit-refund-1",
|
|
|
|
},
|
|
|
|
/* Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone due to refund)
|
|
|
|
(merchant would receive EUR:4.98 due to 1 ct deposit fee) */
|
|
|
|
{ .oc = OC_DEPOSIT,
|
|
|
|
.label = "deposit-refund-2",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.deposit.amount = "EUR:4.99",
|
|
|
|
.details.deposit.coin_ref = "withdraw-coin-r1",
|
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\" : [ { \"name\":\"more ice cream\", \"value\":\"EUR:5\" } ] }",
|
2016-05-21 18:36:12 +02:00
|
|
|
},
|
|
|
|
/* Run transfers. This will do the transfer as refund deadline was 0 */
|
|
|
|
{ .oc = OC_RUN_AGGREGATOR,
|
2016-05-21 19:22:03 +02:00
|
|
|
.label = "run-aggregator-3" },
|
|
|
|
/* Check that deposit did run */
|
|
|
|
{ .oc = OC_CHECK_BANK_TRANSFER,
|
|
|
|
.label = "check_bank_transfer-pre-refund",
|
2017-03-02 06:26:12 +01:00
|
|
|
.details.check_bank_transfer.exchange_base_url = "https://exchange.com/",
|
2017-03-04 16:49:33 +01:00
|
|
|
.details.check_bank_transfer.amount = "EUR:4.97",
|
2016-05-21 19:22:03 +02:00
|
|
|
.details.check_bank_transfer.account_debit = 2,
|
|
|
|
.details.check_bank_transfer.account_credit = 42
|
|
|
|
},
|
2016-05-21 18:36:12 +02:00
|
|
|
/* Run failing refund, as past deadline & aggregation */
|
|
|
|
{ .oc = OC_REFUND,
|
|
|
|
.label = "refund-fail",
|
2016-05-21 19:22:03 +02:00
|
|
|
.expected_response_code = MHD_HTTP_GONE,
|
2016-05-21 18:36:12 +02:00
|
|
|
.details.refund.amount = "EUR:4.99",
|
|
|
|
.details.refund.fee = "EUR:0.01",
|
|
|
|
.details.refund.deposit_ref = "deposit-refund-2",
|
|
|
|
},
|
2016-01-22 15:50:45 +01:00
|
|
|
|
2017-04-10 01:24:05 +02:00
|
|
|
/* ************** End of refund API testing************* */
|
|
|
|
|
|
|
|
/* ************** Test /payback API ************* */
|
|
|
|
|
2017-04-10 16:37:08 +02:00
|
|
|
/* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config,
|
|
|
|
then withdraw a coin and then have it be paid back. */
|
|
|
|
{ .oc = OC_ADMIN_ADD_INCOMING,
|
|
|
|
.label = "payback-create-reserve-1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.admin_add_incoming.sender_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42}",
|
|
|
|
.details.admin_add_incoming.transfer_details = "{ \"uuid\":4 }",
|
|
|
|
.details.admin_add_incoming.amount = "EUR:5.01" },
|
|
|
|
/* Withdraw a 5 EUR coin, at fee of 1 ct */
|
|
|
|
{ .oc = OC_WITHDRAW_SIGN,
|
|
|
|
.label = "payback-withdraw-coin-1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.reserve_withdraw.reserve_reference = "payback-create-reserve-1",
|
|
|
|
.details.reserve_withdraw.amount = "EUR:5" },
|
|
|
|
{ .oc = OC_REVOKE,
|
|
|
|
.label = "revoke-1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.revoke.ref = "payback-withdraw-coin-1" },
|
|
|
|
{ .oc = OC_PAYBACK,
|
|
|
|
.label = "payback-1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.payback.ref = "payback-withdraw-coin-1",
|
|
|
|
.details.payback.amount = "EUR:5" },
|
2017-04-10 17:59:33 +02:00
|
|
|
/* Check the money is back with the reserve */
|
|
|
|
{ .oc = OC_WITHDRAW_STATUS,
|
|
|
|
.label = "payback-reserve-status-1",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.reserve_status.reserve_reference = "payback-create-reserve-1",
|
|
|
|
.details.reserve_status.expected_balance = "EUR:5.00" },
|
2017-04-10 16:37:08 +02:00
|
|
|
|
|
|
|
|
2017-04-10 16:51:09 +02:00
|
|
|
/* Fill reserve with EUR:2.02, as withdraw fee is 1 ct per config,
|
|
|
|
then withdraw two coin, partially spend one, and then have the rest paid back.
|
|
|
|
Check deposit of other coin fails.
|
2017-04-10 16:37:08 +02:00
|
|
|
(Do not use EUR:5 here as the EUR:5 coin was revoked and we did not
|
|
|
|
bother to create a new one...) */
|
|
|
|
{ .oc = OC_ADMIN_ADD_INCOMING,
|
|
|
|
.label = "payback-create-reserve-2",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.admin_add_incoming.sender_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42}",
|
|
|
|
.details.admin_add_incoming.transfer_details = "{ \"uuid\":5 }",
|
2017-04-10 16:51:09 +02:00
|
|
|
.details.admin_add_incoming.amount = "EUR:2.02" },
|
2017-04-10 16:37:08 +02:00
|
|
|
/* Withdraw a 1 EUR coin, at fee of 1 ct */
|
|
|
|
{ .oc = OC_WITHDRAW_SIGN,
|
2017-04-10 16:51:09 +02:00
|
|
|
.label = "payback-withdraw-coin-2a",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.reserve_withdraw.reserve_reference = "payback-create-reserve-2",
|
|
|
|
.details.reserve_withdraw.amount = "EUR:1" },
|
|
|
|
/* Withdraw a 1 EUR coin, at fee of 1 ct */
|
|
|
|
{ .oc = OC_WITHDRAW_SIGN,
|
|
|
|
.label = "payback-withdraw-coin-2b",
|
2017-04-10 16:37:08 +02:00
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.reserve_withdraw.reserve_reference = "payback-create-reserve-2",
|
|
|
|
.details.reserve_withdraw.amount = "EUR:1" },
|
|
|
|
|
|
|
|
{ .oc = OC_DEPOSIT,
|
|
|
|
.label = "payback-deposit-partial",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.deposit.amount = "EUR:0.5",
|
2017-04-10 16:51:09 +02:00
|
|
|
.details.deposit.coin_ref = "payback-withdraw-coin-2a",
|
2017-04-10 16:37:08 +02:00
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"more ice cream\", \"value\":1 } ] }" },
|
2017-04-10 16:37:08 +02:00
|
|
|
{ .oc = OC_REVOKE,
|
|
|
|
.label = "revoke-2",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2017-04-10 16:51:09 +02:00
|
|
|
.details.revoke.ref = "payback-withdraw-coin-2a" },
|
2017-04-10 16:37:08 +02:00
|
|
|
{ .oc = OC_PAYBACK,
|
|
|
|
.label = "payback-2",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
2017-04-10 16:51:09 +02:00
|
|
|
.details.payback.ref = "payback-withdraw-coin-2a",
|
2017-04-10 16:37:08 +02:00
|
|
|
.details.payback.amount = "EUR:0.5" },
|
2017-04-16 02:39:11 +02:00
|
|
|
{ .oc = OC_PAYBACK,
|
|
|
|
.label = "payback-2b",
|
|
|
|
.expected_response_code = MHD_HTTP_FORBIDDEN,
|
|
|
|
.details.payback.ref = "payback-withdraw-coin-2a",
|
|
|
|
.details.payback.amount = "EUR:0.5" },
|
2017-04-10 16:51:09 +02:00
|
|
|
{ .oc = OC_DEPOSIT,
|
|
|
|
.label = "payback-deposit-revoked",
|
|
|
|
.expected_response_code = MHD_HTTP_NOT_FOUND,
|
|
|
|
.details.deposit.amount = "EUR:1",
|
|
|
|
.details.deposit.coin_ref = "payback-withdraw-coin-2b",
|
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"more ice cream\", \"value\":1 } ] }" },
|
2017-04-10 16:51:09 +02:00
|
|
|
|
|
|
|
/* Test deposit fails after payback, with proof in payback */
|
|
|
|
/* FIXME: #3887: right now, the exchange will never return the
|
|
|
|
coin's transaction history with payback data, as we get a 404 on the DK! */
|
|
|
|
{ .oc = OC_DEPOSIT,
|
|
|
|
.label = "payback-deposit-partial-after-payback",
|
|
|
|
.expected_response_code = MHD_HTTP_NOT_FOUND,
|
|
|
|
.details.deposit.amount = "EUR:0.5",
|
|
|
|
.details.deposit.coin_ref = "payback-withdraw-coin-2a",
|
|
|
|
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
2017-05-29 01:15:41 +02:00
|
|
|
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"extra ice cream\", \"value\":1 } ] }" },
|
2017-04-10 16:51:09 +02:00
|
|
|
|
2017-04-10 16:37:08 +02:00
|
|
|
|
|
|
|
/* Test that revoked coins cannot be withdrawn */
|
|
|
|
{ .oc = OC_ADMIN_ADD_INCOMING,
|
|
|
|
.label = "payback-create-reserve-3",
|
|
|
|
.expected_response_code = MHD_HTTP_OK,
|
|
|
|
.details.admin_add_incoming.sender_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42}",
|
|
|
|
.details.admin_add_incoming.transfer_details = "{ \"uuid\":6 }",
|
|
|
|
.details.admin_add_incoming.amount = "EUR:1.01" },
|
|
|
|
{ .oc = OC_WITHDRAW_SIGN,
|
|
|
|
.label = "payback-withdraw-coin-3-revoked",
|
|
|
|
.expected_response_code = MHD_HTTP_NOT_FOUND,
|
|
|
|
.details.reserve_withdraw.reserve_reference = "payback-create-reserve-3",
|
|
|
|
.details.reserve_withdraw.amount = "EUR:1" },
|
|
|
|
|
2017-04-10 01:24:05 +02:00
|
|
|
|
|
|
|
/* ************** End of payback API testing************* */
|
2015-09-15 17:27:02 +02:00
|
|
|
#endif
|
2015-08-08 23:35:51 +02:00
|
|
|
|
2015-07-04 20:47:39 +02:00
|
|
|
{ .oc = OC_END }
|
|
|
|
};
|
|
|
|
|
|
|
|
is = GNUNET_new (struct InterpreterState);
|
|
|
|
is->commands = commands;
|
|
|
|
|
2016-05-02 08:24:21 +02:00
|
|
|
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
|
|
|
|
&rc);
|
2015-06-18 01:17:01 +02:00
|
|
|
GNUNET_assert (NULL != ctx);
|
2016-05-03 13:55:40 +02:00
|
|
|
rc = GNUNET_CURL_gnunet_rc_create (ctx);
|
2016-06-08 11:35:28 +02:00
|
|
|
fakebank = TALER_FAKEBANK_start (8082);
|
2016-03-01 15:35:04 +01:00
|
|
|
exchange = TALER_EXCHANGE_connect (ctx,
|
2016-03-30 22:56:17 +02:00
|
|
|
"http://localhost:8081",
|
|
|
|
&cert_cb, is,
|
|
|
|
TALER_EXCHANGE_OPTION_END);
|
2016-03-01 15:35:04 +01:00
|
|
|
GNUNET_assert (NULL != exchange);
|
2016-05-02 02:33:14 +02:00
|
|
|
timeout_task
|
2015-07-04 20:47:39 +02:00
|
|
|
= GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
|
2017-06-19 00:00:21 +02:00
|
|
|
(GNUNET_TIME_UNIT_SECONDS, 300),
|
2016-05-02 02:33:14 +02:00
|
|
|
&do_timeout, NULL);
|
|
|
|
GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is);
|
2015-01-08 18:37:20 +01:00
|
|
|
}
|
|
|
|
|
2015-06-18 01:17:01 +02:00
|
|
|
|
2017-04-10 16:37:08 +02:00
|
|
|
/**
|
|
|
|
* Remove files from previous runs
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
cleanup_files ()
|
|
|
|
{
|
|
|
|
struct GNUNET_CONFIGURATION_Handle *cfg;
|
|
|
|
char *dir;
|
|
|
|
|
|
|
|
cfg = GNUNET_CONFIGURATION_create ();
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
GNUNET_CONFIGURATION_load (cfg,
|
|
|
|
"test_exchange_api.conf"))
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
GNUNET_CONFIGURATION_destroy (cfg);
|
|
|
|
exit (77);
|
|
|
|
}
|
|
|
|
GNUNET_assert (GNUNET_OK ==
|
|
|
|
GNUNET_CONFIGURATION_get_value_filename (cfg,
|
|
|
|
"exchange",
|
|
|
|
"keydir",
|
|
|
|
&dir));
|
|
|
|
if (GNUNET_YES ==
|
|
|
|
GNUNET_DISK_directory_test (dir,
|
|
|
|
GNUNET_NO))
|
|
|
|
GNUNET_break (GNUNET_OK ==
|
|
|
|
GNUNET_DISK_directory_remove (dir));
|
|
|
|
GNUNET_free (dir);
|
|
|
|
GNUNET_CONFIGURATION_destroy (cfg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-18 01:17:01 +02:00
|
|
|
/**
|
2016-03-01 15:35:04 +01:00
|
|
|
* Main function for the testcase for the exchange API.
|
2015-06-18 01:17:01 +02:00
|
|
|
*
|
|
|
|
* @param argc expected to be 1
|
|
|
|
* @param argv expected to only contain the program name
|
|
|
|
*/
|
2015-01-08 18:37:20 +01:00
|
|
|
int
|
2015-06-18 01:17:01 +02:00
|
|
|
main (int argc,
|
|
|
|
char * const *argv)
|
2015-01-08 18:37:20 +01:00
|
|
|
{
|
2015-06-18 14:25:09 +02:00
|
|
|
struct GNUNET_OS_Process *proc;
|
2016-05-04 05:16:32 +02:00
|
|
|
struct GNUNET_SIGNAL_Context *shc_chld;
|
2016-10-10 16:54:37 +02:00
|
|
|
enum GNUNET_OS_ProcessStatusType type;
|
|
|
|
unsigned long code;
|
2017-02-08 07:58:46 +01:00
|
|
|
unsigned int iter;
|
2015-06-18 13:44:58 +02:00
|
|
|
|
2016-04-10 17:10:20 +02:00
|
|
|
/* These might get in the way... */
|
|
|
|
unsetenv ("XDG_DATA_HOME");
|
|
|
|
unsetenv ("XDG_CONFIG_HOME");
|
2016-11-18 18:29:18 +01:00
|
|
|
GNUNET_log_setup ("test-exchange-api",
|
|
|
|
"INFO",
|
|
|
|
NULL);
|
2017-03-24 13:41:21 +01:00
|
|
|
if (GNUNET_OK !=
|
|
|
|
GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
|
|
|
|
8081))
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"Required port %u not available, skipping.\n",
|
|
|
|
8081);
|
|
|
|
return 77;
|
|
|
|
}
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
|
|
|
|
8082))
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"Required port %u not available, skipping.\n",
|
|
|
|
8082);
|
|
|
|
return 77;
|
|
|
|
}
|
2017-04-10 16:37:08 +02:00
|
|
|
cleanup_files ();
|
|
|
|
|
2015-06-18 14:25:09 +02:00
|
|
|
proc = GNUNET_OS_start_process (GNUNET_NO,
|
|
|
|
GNUNET_OS_INHERIT_STD_ALL,
|
|
|
|
NULL, NULL, NULL,
|
2016-03-01 15:35:04 +01:00
|
|
|
"taler-exchange-keyup",
|
|
|
|
"taler-exchange-keyup",
|
2016-04-10 17:10:20 +02:00
|
|
|
"-c", "test_exchange_api.conf",
|
2017-05-11 10:56:15 +02:00
|
|
|
"-o", "auditor.in",
|
2015-06-18 14:25:09 +02:00
|
|
|
NULL);
|
2017-02-08 06:04:13 +01:00
|
|
|
if (NULL == proc)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Failed to run `taler-exchange-keyup`, is your PATH correct?\n");
|
|
|
|
return 77;
|
|
|
|
}
|
2015-06-18 14:25:09 +02:00
|
|
|
GNUNET_OS_process_wait (proc);
|
|
|
|
GNUNET_OS_process_destroy (proc);
|
2017-05-11 10:56:15 +02:00
|
|
|
|
|
|
|
proc = GNUNET_OS_start_process (GNUNET_NO,
|
|
|
|
GNUNET_OS_INHERIT_STD_ALL,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
"taler-auditor-sign",
|
|
|
|
"taler-auditor-sign",
|
|
|
|
"-c", "test_exchange_api.conf",
|
|
|
|
"-u", "http://auditor/",
|
|
|
|
"-m", "98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG",
|
|
|
|
"-r", "auditor.in",
|
|
|
|
"-o", "test_exchange_api_home/.local/share/taler/auditors/auditor.out",
|
|
|
|
NULL);
|
|
|
|
if (NULL == proc)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Failed to run `taler-exchange-keyup`, is your PATH correct?\n");
|
|
|
|
return 77;
|
|
|
|
}
|
|
|
|
GNUNET_OS_process_wait (proc);
|
|
|
|
GNUNET_OS_process_destroy (proc);
|
|
|
|
|
2016-05-21 19:22:03 +02:00
|
|
|
proc = GNUNET_OS_start_process (GNUNET_NO,
|
|
|
|
GNUNET_OS_INHERIT_STD_ALL,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
"taler-exchange-dbinit",
|
|
|
|
"taler-exchange-dbinit",
|
|
|
|
"-c", "test_exchange_api.conf",
|
|
|
|
"-r",
|
|
|
|
NULL);
|
2017-02-08 06:04:13 +01:00
|
|
|
if (NULL == proc)
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Failed to run `taler-exchange-dbinit`, is your PATH correct?\n");
|
|
|
|
return 77;
|
|
|
|
}
|
2016-10-10 16:54:37 +02:00
|
|
|
if (GNUNET_SYSERR ==
|
|
|
|
GNUNET_OS_process_wait_status (proc,
|
|
|
|
&type,
|
|
|
|
&code))
|
|
|
|
{
|
|
|
|
GNUNET_break (0);
|
|
|
|
GNUNET_OS_process_destroy (proc);
|
|
|
|
return 1;
|
|
|
|
}
|
2016-05-21 19:22:03 +02:00
|
|
|
GNUNET_OS_process_destroy (proc);
|
2016-10-10 16:54:37 +02:00
|
|
|
if ( (type == GNUNET_OS_PROCESS_EXITED) &&
|
|
|
|
(0 != code) )
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"Failed to setup database\n");
|
|
|
|
return 77;
|
|
|
|
}
|
|
|
|
if ( (type != GNUNET_OS_PROCESS_EXITED) ||
|
|
|
|
(0 != code) )
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
2017-02-08 07:58:46 +01:00
|
|
|
"Unexpected error running `taler-exchange-dbinit'!\n");
|
2016-10-10 16:54:37 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2016-03-01 15:35:04 +01:00
|
|
|
exchanged = GNUNET_OS_start_process (GNUNET_NO,
|
2016-03-30 22:56:17 +02:00
|
|
|
GNUNET_OS_INHERIT_STD_ALL,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
"taler-exchange-httpd",
|
|
|
|
"taler-exchange-httpd",
|
2016-04-10 17:10:20 +02:00
|
|
|
"-c", "test_exchange_api.conf",
|
2017-01-13 14:44:51 +01:00
|
|
|
"-i",
|
2016-03-30 22:56:17 +02:00
|
|
|
NULL);
|
2015-06-18 13:47:35 +02:00
|
|
|
/* give child time to start and bind against the socket */
|
2016-10-10 16:54:37 +02:00
|
|
|
fprintf (stderr,
|
2017-02-08 07:58:46 +01:00
|
|
|
"Waiting for `taler-exchange-httpd' to be ready");
|
|
|
|
iter = 0;
|
2015-08-09 18:11:30 +02:00
|
|
|
do
|
|
|
|
{
|
2017-02-08 07:58:46 +01:00
|
|
|
if (10 == iter)
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
2017-02-08 08:02:01 +01:00
|
|
|
"Failed to launch `taler-exchange-httpd' (or `wget')\n");
|
2017-02-08 07:58:46 +01:00
|
|
|
GNUNET_OS_process_kill (exchanged,
|
|
|
|
SIGTERM);
|
|
|
|
GNUNET_OS_process_wait (exchanged);
|
|
|
|
GNUNET_OS_process_destroy (exchanged);
|
|
|
|
return 77;
|
|
|
|
}
|
2015-08-09 18:11:30 +02:00
|
|
|
fprintf (stderr, ".");
|
|
|
|
sleep (1);
|
2017-02-08 07:58:46 +01:00
|
|
|
iter++;
|
2015-08-09 18:11:30 +02:00
|
|
|
}
|
2015-08-18 12:24:51 +02:00
|
|
|
while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/keys -o /dev/null -O /dev/null"));
|
2015-08-09 18:11:30 +02:00
|
|
|
fprintf (stderr, "\n");
|
2017-03-06 17:36:10 +01:00
|
|
|
result = GNUNET_NO;
|
2016-05-04 05:16:32 +02:00
|
|
|
sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
|
|
|
|
GNUNET_assert (NULL != sigpipe);
|
|
|
|
shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
|
|
|
|
&sighandler_child_death);
|
2015-06-18 13:44:58 +02:00
|
|
|
GNUNET_SCHEDULER_run (&run, NULL);
|
2016-05-04 05:16:32 +02:00
|
|
|
GNUNET_SIGNAL_handler_uninstall (shc_chld);
|
|
|
|
shc_chld = NULL;
|
|
|
|
GNUNET_DISK_pipe_close (sigpipe);
|
2017-09-13 14:35:57 +02:00
|
|
|
GNUNET_break (0 ==
|
|
|
|
GNUNET_OS_process_kill (exchanged,
|
|
|
|
SIGTERM));
|
|
|
|
GNUNET_break (GNUNET_OK ==
|
|
|
|
GNUNET_OS_process_wait (exchanged));
|
2016-03-01 15:35:04 +01:00
|
|
|
GNUNET_OS_process_destroy (exchanged);
|
2015-01-08 18:37:20 +01:00
|
|
|
return (GNUNET_OK == result) ? 0 : 1;
|
|
|
|
}
|
2015-06-18 11:39:53 +02:00
|
|
|
|
2016-03-01 15:35:04 +01:00
|
|
|
/* end of test_exchange_api.c */
|