Merge branch 'master' of git.taler.net:/var/git/exchange

This commit is contained in:
Jeff Burdges 2016-05-04 23:30:36 +02:00
commit 48863ce935
31 changed files with 427 additions and 158 deletions

1
.gitignore vendored
View File

@ -51,6 +51,7 @@ src/util/test_amount
src/util/test_crypto
src/util/test_json
src/util/test_wireformats
src/util/taler-arm
doc/paper/llncs.cls
doc/paper/taler.bbl
doc/paper/taler.blg

View File

@ -0,0 +1,2 @@
Wed May 4 10:19:36 CEST 2016
Releasing taler-exchange 0.0. -CG

View File

@ -21,7 +21,7 @@ AC_INIT([taler-exchange], [0.0.0], [taler-bug@gnunet.org])
AC_CONFIG_SRCDIR([src/util/util.c])
AC_CONFIG_HEADERS([taler_config.h])
# support for non-recursive builds
AM_INIT_AUTOMAKE([subdir-objects])
AM_INIT_AUTOMAKE([subdir-objects 1.9 tar-pax])
# pretty build rules
AM_SILENT_RULES([yes])
@ -152,6 +152,35 @@ AS_IF([test $libgnunetcurl != 1],
*** ]])])
# Check for GNUnet's libgnunetpq.
libgnunetpq=0
AC_MSG_CHECKING([for libgnunetpq])
AC_ARG_WITH(gnunet,
[AS_HELP_STRING([--with-gnunet=PFX], [base of GNUnet installation])],
[AC_MSG_RESULT([given as $with_gnunet])],
[AC_MSG_RESULT(not given)
with_gnunet=yes])
AS_CASE([$with_gnunet],
[yes], [],
[no], [AC_MSG_ERROR([--with-gnunet is required])],
[LDFLAGS="-L$with_gnunet/lib $LDFLAGS"
CPPFLAGS="-I$with_gnunet/include $CPPFLAGS"])
AC_CHECK_HEADERS([gnunet/platform.h gnunet/gnunet_pq_lib.h],
[AC_CHECK_LIB([gnunetpq], [GNUNET_PQ_result_spec_string], libgnunetpq=1)],
[], [#ifdef HAVE_GNUNET_PLATFORM_H
#include <gnunet/platform.h>
#endif])
AS_IF([test $libgnunetpq != 1],
[AC_MSG_ERROR([[
***
*** You need libgnunetpq to build this program.
*** Make sure you have Postgres installed while
*** building GNUnet (and that your GNUnet version
*** is recent!)
*** ]])])
# check for libmicrohttpd
microhttpd=0
AC_MSG_CHECKING([for microhttpd])

View File

@ -19,6 +19,9 @@ pkgcfgdir = $(prefix)/share/taler/config.d/
pkgcfg_DATA = \
taler.conf
EXTRA_DIST = \
taler.conf
SUBDIRS = include util json $(PQ_DIR) $(BANK_LIB) wire exchangedb exchange exchange-tools
if HAVE_LIBCURL
SUBDIRS += exchange-lib

View File

@ -28,7 +28,7 @@ libtalerbank_la_LIBADD = \
$(XLIB)
libfakebank_la_SOURCES = \
fakebank.c
fakebank.c fakebank.h
libfakebank_la_LIBADD = \
$(top_builddir)/src/json/libtalerjson.la \

View File

@ -143,7 +143,7 @@ handle_admin_add_incoming_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;

View File

@ -53,15 +53,15 @@ run (void *cls)
.details.admin_add_incoming.credit_account_no = 3,
.details.admin_add_incoming.debit_account_no = 2,
.details.admin_add_incoming.amount = "PUDOS:3.21" },
/* check transactions arrived at fakebank */
{ .oc = TBI_OC_EXPECT_TRANSACTION,
/* check transfers arrived at fakebank */
{ .oc = TBI_OC_EXPECT_TRANSFER,
.label = "expect-2",
.details.expect_transaction.cmd_ref = "deposit-2" },
{ .oc = TBI_OC_EXPECT_TRANSACTION,
.details.expect_transfer.cmd_ref = "deposit-2" },
{ .oc = TBI_OC_EXPECT_TRANSFER,
.label = "expect-1",
.details.expect_transaction.cmd_ref = "deposit-1" },
/* check transaction list is now empty */
{ .oc = TBI_OC_EXPECT_TRANSACTIONS_EMPTY,
.details.expect_transfer.cmd_ref = "deposit-1" },
/* check transfer list is now empty */
{ .oc = TBI_OC_EXPECT_TRANSFERS_EMPTY,
.label = "expect-empty" },
{ .oc = TBI_OC_END }
};

View File

@ -235,9 +235,9 @@ interpreter_run (void *cls)
return;
}
return;
case TBI_OC_EXPECT_TRANSACTION:
case TBI_OC_EXPECT_TRANSFER:
ref = find_command (is,
cmd->details.expect_transaction.cmd_ref);
cmd->details.expect_transfer.cmd_ref);
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (ref->details.admin_add_incoming.amount,
&amount));
@ -264,7 +264,7 @@ interpreter_run (void *cls)
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
is);
return;
case TBI_OC_EXPECT_TRANSACTIONS_EMPTY:
case TBI_OC_EXPECT_TRANSFERS_EMPTY:
if (GNUNET_OK != FAKEBANK_check_empty (is->fakebank))
{
GNUNET_break (0);

View File

@ -45,14 +45,14 @@ enum TBI_OpCode
TBI_OC_ADMIN_ADD_INCOMING,
/**
* Expect that we have received the specified transaction at fakebank.
* Expect that we have received the specified transfer at fakebank.
*/
TBI_OC_EXPECT_TRANSACTION,
TBI_OC_EXPECT_TRANSFER,
/**
* Expect that we have exhaustively gone over all transactions at fakebank.
* Expect that we have exhaustively gone over all transfers at fakebank.
*/
TBI_OC_EXPECT_TRANSACTIONS_EMPTY
TBI_OC_EXPECT_TRANSFERS_EMPTY
};
@ -118,8 +118,8 @@ struct TBI_Command
} admin_add_incoming;
/**
* If @e opcode is #TBI_OC_EXPECT_TRANSACTION, this
* specifies which transaction we expected.
* If @e opcode is #TBI_OC_EXPECT_TRANSFER, this
* specifies which transfer we expected.
*/
struct {
@ -129,7 +129,7 @@ struct TBI_Command
*/
const char *cmd_ref;
} expect_transaction;
} expect_transfer;
} details;

View File

@ -21,6 +21,7 @@ libtalerexchange_la_SOURCES = \
exchange_api_deposit_wtid.c \
exchange_api_refresh.c \
exchange_api_refresh_link.c \
exchange_api_refund.c \
exchange_api_reserve.c \
exchange_api_wire.c \
exchange_api_wire_deposits.c
@ -63,7 +64,7 @@ test_exchange_api_LDADD = \
-ljansson
EXTRA_DIST = \
test_taler_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv \
test_taler_exchange_api_home/.config/taler/test.json \
test_taler_exchange_api_home/.config/taler/sepa.json \
test_taler_exchange_api.conf
test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv \
test_exchange_api_home/.config/taler/test.json \
test_exchange_api_home/.config/taler/sepa.json \
test_exchange_api.conf

View File

@ -122,7 +122,7 @@ handle_admin_add_incoming_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;

View File

@ -246,7 +246,7 @@ handle_deposit_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;
@ -380,20 +380,20 @@ verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki,
*/
struct TALER_EXCHANGE_DepositHandle *
TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_Amount *amount,
struct GNUNET_TIME_Absolute wire_deadline,
json_t *wire_details,
const struct GNUNET_HashCode *h_contract,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_DenominationSignature *denom_sig,
const struct TALER_DenominationPublicKey *denom_pub,
struct GNUNET_TIME_Absolute timestamp,
uint64_t transaction_id,
const struct TALER_MerchantPublicKeyP *merchant_pub,
struct GNUNET_TIME_Absolute refund_deadline,
const struct TALER_CoinSpendSignatureP *coin_sig,
TALER_EXCHANGE_DepositResultCallback cb,
void *cb_cls)
const struct TALER_Amount *amount,
struct GNUNET_TIME_Absolute wire_deadline,
json_t *wire_details,
const struct GNUNET_HashCode *h_contract,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_DenominationSignature *denom_sig,
const struct TALER_DenominationPublicKey *denom_pub,
struct GNUNET_TIME_Absolute timestamp,
uint64_t transaction_id,
const struct TALER_MerchantPublicKeyP *merchant_pub,
struct GNUNET_TIME_Absolute refund_deadline,
const struct TALER_CoinSpendSignatureP *coin_sig,
TALER_EXCHANGE_DepositResultCallback cb,
void *cb_cls)
{
const struct TALER_EXCHANGE_Keys *key_state;
const struct TALER_EXCHANGE_DenomPublicKey *dki;

View File

@ -110,7 +110,7 @@ verify_deposit_wtid_signature_ok (const struct TALER_EXCHANGE_DepositWtidHandle
key_state = TALER_EXCHANGE_get_keys (dwh->exchange);
if (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key (key_state,
&exchange_pub))
&exchange_pub))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
@ -224,7 +224,7 @@ handle_deposit_wtid_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;
@ -308,7 +308,7 @@ TALER_EXCHANGE_deposit_wtid (struct TALER_EXCHANGE_Handle *exchange,
dwh->cb = cb;
dwh->cb_cls = cb_cls;
dwh->url = MAH_path_to_url (exchange, "/deposit/wtid");
dwh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
dwh->depconf.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS));
dwh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE);
dwh->depconf.h_wire = *h_wire;
dwh->depconf.h_contract = *h_contract;

View File

@ -632,7 +632,7 @@ keys_completed_cb (void *cls,
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
break;
}

View File

@ -1325,7 +1325,7 @@ handle_refresh_melt_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;
@ -1860,7 +1860,7 @@ handle_refresh_reveal_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;

View File

@ -364,7 +364,7 @@ handle_refresh_link_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;

View File

@ -17,7 +17,6 @@
/**
* @file exchange-lib/exchange_api_refund.c
* @brief Implementation of the /refund request of the exchange's HTTP API
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
* @author Christian Grothoff
*/
#include "platform.h"
@ -138,8 +137,8 @@ verify_refund_signature_ok (const struct TALER_EXCHANGE_RefundHandle *rh,
*/
static void
handle_refund_finished (void *cls,
long response_code,
const json_t *json)
long response_code,
const json_t *json)
{
struct TALER_EXCHANGE_RefundHandle *rh = cls;
@ -178,7 +177,7 @@ handle_refund_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;
@ -205,7 +204,7 @@ handle_refund_finished (void *cls,
*
* @param exchange the exchange handle; the exchange must be ready to operate
* @param amount the amount to be refunded; must be larger than the refund fee
* (as that fee is still being subtracted), and smaller than the amount
* (as that fee is still being subtracted), and smaller than the amount
* (with deposit fee) of the original deposit contribution of this coin
* @param refund_fee fee applicable to this coin for the refund
* @param h_contract hash of the contact of the merchant with the customer that is being refunded
@ -226,6 +225,7 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_Amount *amount,
const struct TALER_Amount *refund_fee,
const struct GNUNET_HashCode *h_contract,
uint64_t transaction_id,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
uint64_t rtransaction_id,
const struct TALER_MerchantPrivateKeyP *merchant_priv,
@ -234,8 +234,8 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
{
struct TALER_EXCHANGE_RefundHandle *rh;
struct GNUNET_CURL_Context *ctx;
struct TALER_RefundRequestPS rr;
struct TALER_MerchantSignatureP merchant_sig;
struct TALER_MerchantPublicKeyP merchant_pub;
json_t *refund_obj;
CURL *eh;
@ -245,8 +245,22 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_break (0);
return NULL;
}
/* FIXME: create signature! */
rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND);
rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS));
rr.h_contract = *h_contract;
rr.transaction_id = GNUNET_htonll (transaction_id);
rr.coin_pub = *coin_pub;
GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv,
&rr.merchant.eddsa_pub);
rr.rtransaction_id = GNUNET_htonll (rtransaction_id);
TALER_amount_hton (&rr.refund_amount,
amount);
TALER_amount_hton (&rr.refund_fee,
refund_fee);
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv,
&rr.purpose,
&merchant_sig.eddsa_sig));
refund_obj = json_pack ("{s:o, s:o," /* amount/fee */
" s:o, s:o," /* H_contract, coin_pub */
" s:I, s:I," /* transaction id, rtransaction id */
@ -259,8 +273,8 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
sizeof (*coin_pub)),
"transaction_id", (json_int_t) transaction_id,
"rtransaction_id", (json_int_t) rtransaction_id,
"merchant_pub", GNUNET_JSON_from_data (&merchant_pub,
sizeof (merchant_pub)),
"merchant_pub", GNUNET_JSON_from_data (&rr.merchant,
sizeof (struct TALER_MerchantPublicKeyP)),
"merchant_sig", GNUNET_JSON_from_data (&merchant_sig,
sizeof (merchant_sig))
);
@ -274,13 +288,13 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
rh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND);
rh->depconf.h_contract = *h_contract;
rh->depconf.transaction_id = GNUNET_htonll (transaction_id);
rh->depconf.coin_pub = *coin_pub;
rh->depconf.merchant = rr.merchant;
rh->depconf.rtransaction_id = GNUNET_htonll (rtransaction_id);
TALER_amount_hton (&rh->depconf.refund_amount,
amount);
TALER_amount_hton (&rh->depconf.refund_fee,
refund_fee);
rh->depconf.coin_pub = *coin_pub;
rh->depconf.merchant = *merchant_pub;
eh = curl_easy_init ();
GNUNET_assert (NULL != (rh->json_enc =

View File

@ -363,7 +363,7 @@ handle_reserve_status_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;
@ -738,7 +738,7 @@ handle_reserve_withdraw_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;

View File

@ -203,7 +203,7 @@ handle_wire_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;

View File

@ -96,12 +96,12 @@ handle_wire_deposits_finished (void *cls,
struct TALER_ExchangePublicKeyP exchange_pub;
struct TALER_ExchangeSignatureP exchange_sig;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("H_wire", &h_wire),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub),
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
TALER_JSON_spec_amount ("total", &total_amount),
GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
TALER_JSON_spec_amount ("total_amount", &total_amount),
GNUNET_JSON_spec_json ("details", &details_j),
GNUNET_JSON_spec_fixed_auto ("H_wire", &h_wire),
GNUNET_JSON_spec_json ("deposits", &details_j),
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub),
GNUNET_JSON_spec_end()
};
@ -129,10 +129,10 @@ handle_wire_deposits_finished (void *cls,
struct json_t *detail_j = json_array_get (details_j, i);
struct GNUNET_JSON_Specification spec_detail[] = {
GNUNET_JSON_spec_fixed_auto ("H_contract", &detail->h_contract),
TALER_JSON_spec_amount ("deposit_value", &detail->coin_value),
TALER_JSON_spec_amount ("deposit_fee", &detail->coin_fee),
GNUNET_JSON_spec_uint64 ("transaction_id", &detail->transaction_id),
GNUNET_JSON_spec_fixed_auto ("coin_pub", &detail->coin_pub),
TALER_JSON_spec_amount ("deposit_value", &detail->coin_value),
TALER_JSON_spec_amount ("deposit_fee", &detail->coin_fee),
GNUNET_JSON_spec_end()
};
@ -217,7 +217,7 @@ handle_wire_deposits_finished (void *cls,
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
(unsigned int) response_code);
GNUNET_break (0);
response_code = 0;
break;

View File

@ -139,12 +139,12 @@ enum OpCode
/**
* Check that the fakebank has received a certain transaction.
*/
OC_CHECK_BANK_DEPOSIT,
OC_CHECK_BANK_TRANSFER,
/**
* Check that the fakebank has not received any other transactions.
*/
OC_CHECK_BANK_DEPOSITS_EMPTY
OC_CHECK_BANK_TRANSFERS_EMPTY
};
@ -514,8 +514,13 @@ struct Command
struct TALER_EXCHANGE_WireDepositsHandle *wdh;
/**
* Reference to a /deposit/wtid command. If set, we use the
* WTID from that command.
* 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
* by the bank. In the case of a /deposit/wtid, we check
* that the wire details match.
*/
const char *wtid_ref;
@ -524,6 +529,13 @@ struct Command
*/
struct TALER_WireTransferIdentifierRawP wtid;
/**
* What is the expected total amount? Only used if
* @e expected_response_code was #MHD_HTTP_OK.
*/
const char *total_amount_expected;
/* TODO: may want to add list of deposits we expected
to see aggregated here in the future. */
@ -545,10 +557,9 @@ struct Command
const char *deposit_ref;
/**
* What is the expected total amount? Only used if
* @e expected_response_code was #MHD_HTTP_OK.
* Which #OC_CHECK_BANK_TRANSFER wtid should this match? NULL for none.
*/
struct TALER_Amount total_amount_expected;
const char *bank_transfer_ref;
/**
* Wire transfer identifier, set if #MHD_HTTP_OK was the response code.
@ -588,7 +599,7 @@ struct Command
*/
struct TALER_WireTransferIdentifierRawP wtid;
} check_bank_deposit;
} check_bank_transfer;
} details;
@ -624,6 +635,18 @@ struct InterpreterState
};
/**
* Pipe used to communicate child death via signal.
*/
static struct GNUNET_DISK_PipeHandle *sigpipe;
/**
* ID of task called whenever we get a SIGCHILD.
*/
static struct GNUNET_SCHEDULER_Task *child_death_task;
/**
* The testcase failed, return with an error code.
*
@ -1184,6 +1207,30 @@ link_cb (void *cls,
}
/**
* 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];
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;
next_command (is);
}
/**
* Find denomination key matching the given amount.
*
@ -1223,9 +1270,9 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys,
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Have denomination key for `%s', but with wrong expiration range %llu vs [%llu,%llu)\n",
str,
now.abs_value_us,
pk->valid_from.abs_value_us,
pk->withdraw_valid_until.abs_value_us);
(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);
GNUNET_free (str);
return NULL;
}
@ -1321,6 +1368,7 @@ wire_deposits_cb (void *cls,
struct InterpreterState *is = cls;
struct Command *cmd = &is->commands[is->ip];
const struct Command *ref;
struct TALER_Amount expected_amount;
cmd->details.wire_deposits.wdh = NULL;
if (cmd->expected_response_code != http_status)
@ -1336,42 +1384,82 @@ wire_deposits_cb (void *cls,
switch (http_status)
{
case MHD_HTTP_OK:
ref = find_command (is,
cmd->details.wire_deposits.wtid_ref);
GNUNET_assert (NULL != ref);
if (GNUNET_OK !=
TALER_string_to_amount (cmd->details.wire_deposits.total_amount_expected,
&expected_amount))
{
GNUNET_break (0);
fail (is);
return;
}
if (0 != TALER_amount_cmp (total_amount,
&ref->details.deposit_wtid.total_amount_expected))
&expected_amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Total amount missmatch to command %s\n",
http_status,
cmd->label);
json_dumpf (json, stderr, 0);
fail (is);
return;
}
if (NULL != ref->details.deposit_wtid.deposit_ref)
ref = find_command (is,
cmd->details.wire_deposits.wtid_ref);
GNUNET_assert (NULL != ref);
switch (ref->oc)
{
const struct Command *dep;
struct GNUNET_HashCode hw;
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);
GNUNET_CRYPTO_hash (dep->details.deposit.wire_details,
strlen (dep->details.deposit.wire_details),
&hw);
if (0 != memcmp (&hw,
h_wire,
sizeof (struct GNUNET_HashCode)))
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);
TALER_JSON_hash (wire,
&hw);
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))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire hash missmatch to command %s\n",
"Total amount missmatch to command %s\n",
cmd->label);
json_dumpf (json, stderr, 0);
fail (is);
return;
}
break;
default:
GNUNET_break (0);
fail (is);
return;
}
break;
default:
@ -1421,6 +1509,22 @@ deposit_wtid_cb (void *cls,
{
case MHD_HTTP_OK:
cmd->details.deposit_wtid.wtid = *wtid;
if (NULL != cmd->details.deposit_wtid.bank_transfer_ref)
{
const struct Command *ref;
ref = find_command (is,
cmd->details.deposit_wtid.bank_transfer_ref);
GNUNET_assert (NULL != ref);
if (0 != memcmp (wtid,
&ref->details.check_bank_transfer.wtid,
sizeof (struct TALER_WireTransferIdentifierRawP)))
{
GNUNET_break (0);
fail (is);
return;
}
}
break;
default:
break;
@ -1698,7 +1802,7 @@ interpreter_run (void *cls)
GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.deposit.merchant_priv.eddsa_priv,
&merchant_pub.eddsa_pub);
wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS);
wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_ZERO);
timestamp = GNUNET_TIME_absolute_get ();
GNUNET_TIME_round_abs (&timestamp);
{
@ -1919,8 +2023,8 @@ interpreter_run (void *cls)
case OC_DEPOSIT_WTID:
cmd->details.wire_deposits.wtid = ref->details.deposit_wtid.wtid;
break;
case OC_CHECK_BANK_DEPOSIT:
cmd->details.wire_deposits.wtid = ref->details.check_bank_deposit.wtid;
case OC_CHECK_BANK_TRANSFER:
cmd->details.wire_deposits.wtid = ref->details.check_bank_transfer.wtid;
break;
default:
GNUNET_break (0);
@ -1999,6 +2103,8 @@ interpreter_run (void *cls)
return;
case OC_RUN_AGGREGATOR:
{
const struct GNUNET_DISK_FileHandle *pr;
cmd->details.run_aggregator.aggregator_proc
= GNUNET_OS_start_process (GNUNET_NO,
GNUNET_OS_INHERIT_STD_ALL,
@ -2014,16 +2120,16 @@ interpreter_run (void *cls)
fail (is);
return;
}
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;
next_command (is);
pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
child_death_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
pr,
&maint_child_death, is);
return;
}
case OC_CHECK_BANK_DEPOSIT:
case OC_CHECK_BANK_TRANSFER:
{
if (GNUNET_OK !=
TALER_string_to_amount (cmd->details.check_bank_deposit.amount,
TALER_string_to_amount (cmd->details.check_bank_transfer.amount,
&amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -2036,9 +2142,9 @@ interpreter_run (void *cls)
if (GNUNET_OK !=
FAKEBANK_check (fakebank,
&amount,
cmd->details.check_bank_deposit.account_debit,
cmd->details.check_bank_deposit.account_credit,
&cmd->details.check_bank_deposit.wtid))
cmd->details.check_bank_transfer.account_debit,
cmd->details.check_bank_transfer.account_credit,
&cmd->details.check_bank_transfer.wtid))
{
GNUNET_break (0);
fail (is);
@ -2047,7 +2153,7 @@ interpreter_run (void *cls)
next_command (is);
return;
}
case OC_CHECK_BANK_DEPOSITS_EMPTY:
case OC_CHECK_BANK_TRANSFERS_EMPTY:
{
if (GNUNET_OK !=
FAKEBANK_check_empty (fakebank))
@ -2071,6 +2177,24 @@ interpreter_run (void *cls)
}
/**
* 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 */
}
/**
* Function run when the test terminates (good or bad) with timeout.
*
@ -2251,9 +2375,9 @@ do_shutdown (void *cls)
cmd->details.run_aggregator.aggregator_proc = NULL;
}
break;
case OC_CHECK_BANK_DEPOSIT:
case OC_CHECK_BANK_TRANSFER:
break;
case OC_CHECK_BANK_DEPOSITS_EMPTY:
case OC_CHECK_BANK_TRANSFERS_EMPTY:
break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -2526,7 +2650,7 @@ run (void *cls)
.details.deposit.amount = "EUR:0.1",
.details.deposit.coin_ref = "refresh-reveal-1",
.details.deposit.coin_idx = 4,
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":43 }",
.details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }",
.details.deposit.transaction_id = 2 },
@ -2563,12 +2687,59 @@ run (void *cls)
.label = "wire-deposit-failing",
.expected_response_code = MHD_HTTP_NOT_FOUND },
/* Run transfers. Note that _actual_ aggregation will NOT
happen here, as each deposit operation is run with a
fresh merchant public key! */
{ .oc = OC_RUN_AGGREGATOR,
.label = "run-aggregator" },
{ .oc = OC_CHECK_BANK_DEPOSITS_EMPTY,
{ .oc = OC_CHECK_BANK_TRANSFER,
.label = "check_bank_transfer-499c",
.details.check_bank_transfer.amount = "EUR:4.99",
.details.check_bank_transfer.account_debit = 2,
.details.check_bank_transfer.account_credit = 42
},
{ .oc = OC_CHECK_BANK_TRANSFER,
.label = "check_bank_transfer-99c1",
.details.check_bank_transfer.amount = "EUR:0.99",
.details.check_bank_transfer.account_debit = 2,
.details.check_bank_transfer.account_credit = 42
},
{ .oc = OC_CHECK_BANK_TRANSFER,
.label = "check_bank_transfer-99c2",
.details.check_bank_transfer.amount = "EUR:0.99",
.details.check_bank_transfer.account_debit = 2,
.details.check_bank_transfer.account_credit = 42
},
{ .oc = OC_CHECK_BANK_TRANSFER,
.label = "check_bank_transfer-9c",
.details.check_bank_transfer.amount = "EUR:0.09",
.details.check_bank_transfer.account_debit = 2,
.details.check_bank_transfer.account_credit = 43
},
{ .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
.label = "check_bank_empty" },
{ .oc = OC_DEPOSIT_WTID,
.label = "deposit-wtid-ok",
.expected_response_code = MHD_HTTP_OK,
.details.deposit_wtid.deposit_ref = "deposit-simple",
.details.deposit_wtid.bank_transfer_ref = "check_bank_transfer-499c" },
{ .oc = OC_WIRE_DEPOSITS,
.label = "wire-deposits-sucess-bank",
.expected_response_code = MHD_HTTP_OK,
.details.wire_deposits.wtid_ref = "check_bank_transfer-99c1",
.details.wire_deposits.total_amount_expected = "EUR:0.99" },
{ .oc = OC_WIRE_DEPOSITS,
.label = "wire-deposits-sucess-wtid",
.expected_response_code = MHD_HTTP_OK,
.details.wire_deposits.wtid_ref = "deposit-wtid-ok",
.details.wire_deposits.total_amount_expected = "EUR:4.99" },
/* TODO: trigger aggregation logic and then check the
cases where tracking succeeds! */
@ -2613,6 +2784,7 @@ main (int argc,
{
struct GNUNET_OS_Process *proc;
struct GNUNET_OS_Process *exchanged;
struct GNUNET_SIGNAL_Context *shc_chld;
GNUNET_log_setup ("test-exchange-api",
"WARNING",
@ -2646,7 +2818,14 @@ main (int argc,
while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/keys -o /dev/null -O /dev/null"));
fprintf (stderr, "\n");
result = GNUNET_SYSERR;
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);
GNUNET_SCHEDULER_run (&run, NULL);
GNUNET_SIGNAL_handler_uninstall (shc_chld);
shc_chld = NULL;
GNUNET_DISK_pipe_close (sigpipe);
GNUNET_OS_process_kill (exchanged,
SIGTERM);
GNUNET_OS_process_wait (exchanged);

View File

@ -8,7 +8,6 @@ pkgcfg_DATA = \
exchange-signkeys.conf \
coins.conf
if USE_COVERAGE
AM_CFLAGS = --coverage -O0
XLIB = -lgcov
@ -93,4 +92,5 @@ taler_exchange_dbinit_CPPFLAGS = \
EXTRA_DIST = \
auditor.conf
auditor.conf \
$(pkgcfg_DATA)

View File

@ -94,4 +94,5 @@ EXTRA_DIST = \
test-taler-exchange-aggregator-postgres.conf \
test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv \
test_taler_exchange_httpd.conf \
exchange.conf
exchange.conf \
$(check_SCRIPTS)

View File

@ -434,6 +434,7 @@ deposit_cb (void *cls,
au->row_id = row_id;
au->wire = (json_t *) wire;
au->execution_time = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&au->execution_time);
TALER_JSON_hash (au->wire,
&au->h_wire);
json_incref (au->wire);

View File

@ -1131,7 +1131,7 @@ TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection,
&sig);
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:o, s:o, s:o, s:o, s:o, s:o}",
"{s:o, s:o, s:o, s:o, s:o}",
"wtid", GNUNET_JSON_from_data (wtid,
sizeof (*wtid)),
"execution_time", GNUNET_JSON_from_time_abs (exec_time),
@ -1184,14 +1184,14 @@ TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection,
&dd,
sizeof (struct TALER_WireDepositDetailP));
json_array_append (deposits,
json_pack ("{s:o, s:o, s:o, s:I, s:o}",
"deposit_value", TALER_JSON_from_amount (&wdd_pos->deposit_value),
"deposit_fee", TALER_JSON_from_amount (&wdd_pos->deposit_fee),
json_pack ("{s:o, s:I, s:o, s:o, s:o}",
"H_contract", GNUNET_JSON_from_data (&wdd_pos->h_contract,
sizeof (struct GNUNET_HashCode)),
"transaction_id", (json_int_t) wdd_pos->transaction_id,
"coin_pub", GNUNET_JSON_from_data (&wdd_pos->coin_pub,
sizeof (struct TALER_CoinSpendPublicKeyP))));
sizeof (struct TALER_CoinSpendPublicKeyP)),
"deposit_value", TALER_JSON_from_amount (&wdd_pos->deposit_value),
"deposit_fee", TALER_JSON_from_amount (&wdd_pos->deposit_fee)));
}
wdp.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT);
wdp.purpose.size = htonl (sizeof (struct TALER_WireDepositDataPS));
@ -1206,11 +1206,11 @@ TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection,
&sig);
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:o, s:o, s:o, s:o}",
"{s:o, s:o, s:o, s:o, s:o, s:o}",
"total", TALER_JSON_from_amount (total),
"merchant_pub", GNUNET_JSON_from_data (merchant_pub,
sizeof (struct TALER_MerchantPublicKeyP)),
"h_wire", GNUNET_JSON_from_data (h_wire,
"H_wire", GNUNET_JSON_from_data (h_wire,
sizeof (struct GNUNET_HashCode)),
"deposits", deposits,
"exchange_sig", GNUNET_JSON_from_data (&sig,

View File

@ -174,25 +174,6 @@ TMH_json_validate_wireformat (const json_t *wire,
}
/**
* Check if we support the given wire method.
*
* @param type type of wire method to check
* @return #GNUNET_YES if the method is supported
*/
int
TMH_VALIDATION_test_method (const char *type)
{
struct Plugin *p;
for (p=wire_head;NULL != p;p = p->next)
if (0 == strcasecmp (type,
p->type))
return GNUNET_YES;
return GNUNET_NO;
}
/**
* Obtain JSON of the supported wire methods for a given
* account name prefix.

View File

@ -54,15 +54,6 @@ int
TMH_json_validate_wireformat (const json_t *wire,
int ours);
/**
* Check if we support the given wire method.
*
* @param type type of wire method to check
* @return #GNUNET_YES if the method is supported
*/
int
TMH_VALIDATION_test_method (const char *type);
/**
* Obtain JSON of the supported wire methods for a given

View File

@ -70,7 +70,7 @@ signkeys_iterate_dir_iter (void *cls,
"Invalid signkey file `%s': wrong size (%d, expected %u)\n",
filename,
(int) nread,
sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP));
(unsigned int) sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP));
return GNUNET_OK;
}
return skc->it (skc->it_cls,

View File

@ -504,7 +504,7 @@ typedef void
*
* @param exchange the exchange handle; the exchange must be ready to operate
* @param amount the amount to be refunded; must be larger than the refund fee
* (as that fee is still being subtracted), and smaller than the amount
* (as that fee is still being subtracted), and smaller than the amount
* (with deposit fee) of the original deposit contribution of this coin
* @param refund_fee fee applicable to this coin for the refund
* @param h_contract hash of the contact of the merchant with the customer that is being refunded
@ -525,6 +525,7 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_Amount *amount,
const struct TALER_Amount *refund_fee,
const struct GNUNET_HashCode *h_contract,
uint64_t transaction_id,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
uint64_t rtransaction_id,
const struct TALER_MerchantPrivateKeyP *merchant_priv,
@ -534,7 +535,7 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
/**
* Cancel a refund permission request. This function cannot be used
* on a request handle if a response is already served for it. If
* on a request handle if a response is already served for it. If
* this function is called, the refund may or may not have happened.
* However, it is fine to try to refund the coin a second time.
*

View File

@ -117,6 +117,11 @@
*/
#define TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT 1037
/**
* Signature where the Exchange confirms a refund request.
*/
#define TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND 1038
/*********************/
/* Wallet signatures */
@ -453,6 +458,64 @@ struct TALER_RefundRequestPS
};
/**
* @brief Format used to generate the signature on a request to refund
* a coin into the account of the customer.
*/
struct TALER_RefundConfirmationPS
{
/**
* Purpose must be #TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
* Hash over the contract which is being refunded.
*/
struct GNUNET_HashCode h_contract GNUNET_PACKED;
/**
* Merchant-generated transaction ID of the orginal transaction.
*/
uint64_t transaction_id GNUNET_PACKED;
/**
* The coin's public key. This is the value that must have been
* signed (blindly) by the Exchange.
*/
struct TALER_CoinSpendPublicKeyP coin_pub;
/**
* The Merchant's public key. Allows the merchant to later refund
* the transaction or to inquire about the wire transfer identifier.
*/
struct TALER_MerchantPublicKeyP merchant;
/**
* Merchant-generated transaction ID for the refund.
*/
uint64_t rtransaction_id GNUNET_PACKED;
/**
* Amount to be refunded, including refund fee charged by the
* exchange to the customer.
*/
struct TALER_AmountNBO refund_amount;
/**
* Refund fee charged by the exchange. This must match the
* Exchange's denomination key's refund fee. If the client puts in
* an invalid refund fee (too high or too low) that does not match
* the Exchange's denomination key, the refund operation is invalid
* and will be rejected by the exchange. The @e amount_with_fee
* minus the @e refund_fee is the amount that will be credited to
* the original coin.
*/
struct TALER_AmountNBO refund_fee;
};
/**
* @brief Message signed by a coin to indicate that the coin should be
* melted.

View File

@ -14,7 +14,9 @@ pkgcfg_DATA = \
paths.conf
EXTRA_DIST = \
paths.conf
paths.conf \
taler-config.in \
taler-arm.in
templated_scripts = taler-config taler-arm
dist_bin_SCRIPTS = $(templated_scripts)