[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] [taler-merchant] branch stable updated (73d9a89 -> 64929e2)
From: |
gnunet |
Subject: |
[GNUnet-SVN] [taler-merchant] branch stable updated (73d9a89 -> 64929e2) |
Date: |
Wed, 31 May 2017 17:14:16 +0200 |
This is an automated email from the git hooks/post-receive script.
marcello pushed a change to branch stable
in repository merchant.
from 73d9a89 Restoring the macro-based way of passing values to payments
generator.
add eec82c7 README.
add d0ffaaf Calling the function (still a stub) that works out wire
transfers tracks before returning that to the frontend.
add 7307067 Rough logic for summing up all tracked wire transfers gotten
from the exchange, grouping them by proposal's hash.
add 388a27e TODO comments.
add 52eef77 Summing up deposited amounts *and* deposit fees concerning
tracked transfers, building the response; not tested yet.
add a093c87 json_copy-ing a 'const json_t *' in order to call
'json_object_del()' on its copy.
add 561deba Fix track transfer's response + adjusting tests to it.
add 4187846 Elaborating /track/transfer response for cached responses as
well.
add a42bfbd Returining order_id in place of h_proposal_data among tracked
transfers.
add 4db9844 \#4593.
add 5479efa Porting to new getopt API.
add c7d8e10 helper db methods for /history. Prepared statements have
still problems with 'FETCH FIRST'.. To be fixed.
add 1c7e486 Fix compiler warnings.
add 325db61 FETCH FIRST arg ROW ONLY -> LIMIT arg, in prepared statement,
as postgresql doesn't like FETCH FIRST arg when arg is a $-parameter. DB
testcase does not pass yet, logic is likely to be wrong.
add bcde0fa Fix indentation.
add 3ea60fb fix limit binding
add 2e761cd Fix db testcase against newest plugin.
add b8f25a0 Fix lib testcase.
add b6f8454 'start' and 'nrows' not hardcoded anymore in testcase.
add ab7b69e Removing unneeded configs and dirs.
add 5499f44 Passing values to payments generator via config file.
add 67b6b66 Fix getopt memory issue, actually use values from config file.
add 2dc9f49 Adding function that concatenates amount strings. Needed as
payment generator now reads currency dynamically.
add 0deb49a Fixing remaining problems due to the passing of values from
config file, in the payments generator. Namely, the command list was statically
created, so it was necessary to make it dynamic.
add 3a8a5ca Iterating interpreter commands, according to -n option passed
in CLI.
add 5f35f8c Produce random order_id.
add f4f6c3a README on payments generator.
add fef322c date parameter = now when /history doesn't get one.
add 4073fec Fix #4968.
add 62a1f25 Fix signature of db callback.
add 8a5af34 Fix #4970.
add 20a5731 logging, db minor fix
add f88bad9 fix stale index used by /history
add dba1103 renaming GNUNET_GETOPT-symbols to match latest changes in
GNUnet
add 6970f52 indent
add 061fcf3 README
add c6e834b adding option to use a remote exchange in the payments
generator.
add ab7198d renaming variables
add 48de114 stubs for #4781
add e23a4e4 adding chapter about testing the backend
add d021087 warn the reader on having the instance's bank matching the
exchange's when testing.
add a90e2d2 fix command name
add 3e753ff fix segfaults due to use of remote exchange in payment
generator.
add 19b8436 Still on renaming (#4877)
add 8808d12 Still on #4877
add a1ee058 addressing comment 11995 from #4774
add 21b5a19 fix config file for /lib testcase
add b783ce9 adding option to lookup history entries in the future.
add c5cad65 adding db method to query proposal data "in the future"
add 9cfcd98 fix db testcase due to queries in the future
add 7c083aa debug prints
add 6d354ee indent
add 1439a4f launch run() with GNUNET_PROGRAM_run
add 002bae7 fix compilation due to code move
add 70765db fix segfaults caused by the way the payment generator killed
merchants and exchanges.
add c834ea4 add cherry-pick like query used in /history. This API is
used when the backoffice user enters the exact order id into the form.
add 87eef0b Implement #4995
add 06b7294 specify exchange with '-e' at payments generator
add b61e1dc instructions about generating payments against a non-forked
merchant backend
add 0d201c9 add wire_method to proposal terms
add a489a58 mitm proxies request using the same method used by the client.
add 02d53e6 renaming mitm script
add 3f382cb still renaming scripts
add d17145e reverting renamings
add 8a4eebe mitm standalone takes cli args
add 5640684 add mitm wsgi file
add b6690e0 readme
add 93a4088 autoconf
add aa18b6e installing mitm via makefile
add 466dcea add forgotten file
add c423101 NOT using setuptools' "scripts" keyword as it failed to set
execution permissions on deployed files
add b49aadf missing __init__.py
add 6fa1d31 remove comment
add 0217dad returning all the headers that the mitm got from the
exchange. This copies the "server" headers though. Wise?
add ee0fb92 The mitm do NOT copy header Content-Lenght and Server into
the response; it used to return ill-formed JSONs.
add 9b44e57 make_response() called in one place
add 2607c61 remove useless comment
add dfc0e82 Addressing #4877
add e1050dc payments generator takes exchange's admin uri in config
add 0b56f7b skeleton for /keys perturbating mitm function
add 286d238 pacify 'make check' into the mitm subdir
add f7aeef2 cosmetics
add c9caf31 config sections for wire plugins changed, adjusting
add 60fb29c caveats to run the payments generator
add 2af84a1 fix format string issue
add d3f0593 fix make clean target
add 6da3f7f nicely handle error from json_dumps without assert
add 18aa807 fix 'lib' testcase
add a16bc8a undoing last commit
add 59a2609 fix logic to check auditors of denomination keys
add 1ccb472 log properly which auditors are loaded, fix log level
add fc0f287 log properly which auditors are loaded, fix log level -- fix
FTBFS
add 46c5449 fix style issues
add c1ead02 fix style issue
add 61e31b9 fix style issue
add b50bb3a moving all the tools in one place
add 005d790 nicer logging
add 6004b80 fix FIXME on properly terminating MHD, resuming suspended
connections before stopping the HTTPD
add 0390a22 fix #5008
add bf9ba97 fix whitespace
add 777ad72 fix autoconf
add 2f3564b use demo instead of test, as test is sometimes down
add a0536b3 rename proposal_data to contract_terms (see #4879)
add 1d3c450 configuration subsection in manual
add 7a62a58 fix doc compilation error
add 64929e2 fix doc compilartion warning
No new revisions were added by this update.
Summary of changes:
.gitignore | 1 +
configure.ac | 6 +-
doc/Makefile.am | 2 +-
doc/manual.texi | 181 +++++-
doc/version.texi | 4 +-
src/Makefile.am | 2 +-
src/backend/taler-merchant-httpd.c | 19 +-
src/backend/taler-merchant-httpd_auditors.c | 37 +-
src/backend/taler-merchant-httpd_exchanges.c | 14 +-
src/backend/taler-merchant-httpd_history.c | 136 ++--
src/backend/taler-merchant-httpd_pay.c | 261 +++++---
src/backend/taler-merchant-httpd_pay.h | 11 +-
src/backend/taler-merchant-httpd_proposal.c | 16 +-
.../taler-merchant-httpd_track-transaction.c | 45 +-
src/backend/taler-merchant-httpd_track-transfer.c | 225 ++++++-
src/backenddb/plugin_merchantdb_postgres.c | 500 +++++++++++----
src/backenddb/test_merchantdb.c | 120 +++-
src/include/taler_merchant_service.h | 42 +-
src/include/taler_merchantdb_plugin.h | 176 +++--
src/lib/merchant_api_history.c | 5 +-
src/lib/merchant_api_pay.c | 22 +-
src/lib/merchant_api_proposal.c | 29 +-
src/lib/merchant_api_track_transaction.c | 22 +-
src/lib/merchant_api_track_transfer.c | 25 +-
src/lib/test_merchant_api.c | 156 ++---
src/lib/test_merchant_api.conf | 13 +-
src/merchant-tools/Makefile.am | 23 +-
src/merchant-tools/README | 51 ++
src/merchant-tools/mitm/Makefile.in | 21 +
src/merchant-tools/mitm/README | 25 +
src/merchant-tools/mitm/merchant-mitm.wsgi.in | 21 +
src/merchant-tools/mitm/setup.py | 11 +
src/merchant-tools/mitm/taler-merchant-mitm.in | 45 ++
.../mitm/talermerchantmitm/__init__.py | 0
src/merchant-tools/mitm/talermerchantmitm/mitm.py | 78 +++
src/merchant-tools/taler-merchant-dbinit.c | 11 +-
.../taler-merchant-generate-payments.c} | 713 ++++++++++++++-------
src/samples/Makefile.am | 21 -
src/samples/README | 3 -
.../.config/taler/merchant/wire/test.json | 5 -
.../generate_payments_home/.config/taler/test.json | 6 -
.../.config/taler/test.signed.json | 8 -
.../share/taler/exchange/offline-keys/master.priv | 1 -
src/samples/merchant_generate_payments.conf | 132 ----
src/samples/test_merchant.priv | 1 -
45 files changed, 2191 insertions(+), 1055 deletions(-)
create mode 100644 src/merchant-tools/README
create mode 100644 src/merchant-tools/mitm/Makefile.in
create mode 100644 src/merchant-tools/mitm/README
create mode 100644 src/merchant-tools/mitm/merchant-mitm.wsgi.in
create mode 100644 src/merchant-tools/mitm/setup.py
create mode 100644 src/merchant-tools/mitm/taler-merchant-mitm.in
copy NEWS => src/merchant-tools/mitm/talermerchantmitm/__init__.py (100%)
create mode 100644 src/merchant-tools/mitm/talermerchantmitm/mitm.py
rename src/{samples/generate_payments.c =>
merchant-tools/taler-merchant-generate-payments.c} (69%)
delete mode 100644 src/samples/Makefile.am
delete mode 100644 src/samples/README
delete mode 100644
src/samples/generate_payments_home/.config/taler/merchant/wire/test.json
delete mode 100644 src/samples/generate_payments_home/.config/taler/test.json
delete mode 100644
src/samples/generate_payments_home/.config/taler/test.signed.json
delete mode 100644
src/samples/generate_payments_home/.local/share/taler/exchange/offline-keys/master.priv
delete mode 100644 src/samples/merchant_generate_payments.conf
delete mode 100644 src/samples/test_merchant.priv
diff --git a/.gitignore b/.gitignore
index 6982c64..4cab3d0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
*~
*Makefile.in
+!src/mitm/*.in
*Makefile
aclocal.m4
autom4te.cache
diff --git a/configure.ac b/configure.ac
index e728793..b60ae5d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -280,6 +280,8 @@ src/merchant-tools/Makefile
src/include/Makefile
src/backenddb/Makefile
src/backend/Makefile
-src/samples/Makefile
-src/lib/Makefile])
+src/lib/Makefile
+src/merchant-tools/mitm/taler-merchant-mitm
+src/merchant-tools/mitm/merchant-mitm.wsgi
+src/merchant-tools/mitm/Makefile])
AC_OUTPUT
diff --git a/doc/Makefile.am b/doc/Makefile.am
index b233fa5..86e8e65 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -3,7 +3,7 @@ all: manual.pdf manual.html
manual.pdf: arch.pdf manual.texi
texi2pdf manual.texi
manual.html: arch.jpg manual.texi
- texi2html manual.texi
+ makeinfo --html --no-split manual.texi
arch.pdf: arch.dot
dot -Tpdf arch.dot > arch.pdf
arch.jpg: arch.dot
diff --git a/doc/manual.texi b/doc/manual.texi
index af2dc37..9da4582 100644
--- a/doc/manual.texi
+++ b/doc/manual.texi
@@ -55,6 +55,7 @@ Texts. A copy of the license is included in the section
entitled
* Introduction:: Whom this manual is addressed to
* Installation:: Installing the Merchant backend
* Configuration:: How to set up the Merchant backend
+* Testing:: How to test the installed Merchant backend
* Advanced topics:: Detailed solutions to specific issues
@@ -172,10 +173,10 @@ account information is encapsulated within the Taler
backend.
@node Installation
@menu
+* Installing Taler using Docker:: Installing Taler using Docker
* generic-instructions:: Generic installation guidelines
* Installing Taler on Debian GNU/Linux:: Installing Taler on Debian GNU/Linux
@c * Installing Taler with GNU Guix:: Installing Taler with GNU Guix
-* Installing Taler using Docker:: Installing Taler using Docker
@c * Installing Taler on Arch Linux:: Installing Taler on Arch Linux
@c * Installing Taler on Windows:: Installing Taler on Windows
@c * Installing Taler on OS X:: Installing Taler on OS X
@@ -740,23 +741,191 @@ reachable. Production systems should be configured to
bind
to a UNIX domain socket or properly restrict access to the
port.
address@hidden Testing
address@hidden Testing
+
+The tool @code{taler-merchant-generate-payments} can be used to test
+the merchant backend installation. It implements all the payment's steps
+in a programmatically way, relying on the backend you give it as input.
+Note that this tool gets installed along all the merchant backend's binaries.
+
+This tool gets configured by a config file, that must have the following
+layout:
+
address@hidden
+[payments-generator]
+
+# The exchange used during the test: make sure the merchant backend
+# being tested accpets this exchange.
+# If the sysadmin wants, she can also install a local exchange
+# and test against it.
+exchange = https://exchange.demo.taler.net/
+
+# This value must indicate some URL where the backend
+# to be tested is listening; it doesn't have to be the
+# "official" one, though.
+merchant = http://localbackend/
+
+# This value is used when the tool tries to withdraw coins,
+# and must match the bank used by the exchange. If the test is
+# done against the exchange at https://exchange.demo.taler.net/,
+# then this value can be "https://bank.demo.taler.net/".
+bank = https://bank.demo.taler.net/
+
+# The merchant instance in charge of serving the payment.
+# Make sure this instance has a bank account at the same bank
+# indicated by the 'bank' option above.
+instance = default
+
+# The currency used during the test. Must match the one used
+# by merchant backend and exchange.
+currency = KUDOS
address@hidden example
+
+Run the test in the following way:
+
address@hidden
+$ taler-merchant-generate-payments [-c config] [-e EURI] [-m MURI]
address@hidden example
+
+the argument @code{config} given to @code{-c} points to the configuration
+file and is optional -- @code{~/.config/taler.conf} will be checked by default.
+By default, the tool forks two processes: one for the merchant backend, and one
+for the exchange.
+The option @code{-e} (@code{-m}) avoids any exchange (merchant backend) fork,
+and just runs the generator against the exchange (merchant backend) running
+at @code{EURI} (@code{MURI}).
+
+Please NOTE that the generator contains @emph{hardcoded} values, as for deposit
+fees of the coins it uses. In order to work against the used exchange, those
values
+MUST match the ones used by the exchange.
address@hidden Add section describing how to test the backend.
address@hidden For this, we should write some tools that make it
address@hidden EASY to test the backend without going through the
address@hidden full manual frontend setup!
address@hidden NOTE: include explaining wallet installation to sysadmin
+The following example shows how the generator "sets" a deposit fee of EUR:0.01
+for the 5 EURO coin.
address@hidden
+// from <merchant_repository>/src/sample/generate_payments.c
address@hidden .oc = OC_PAY,
+ .label = "deposit-simple",
+ .expected_response_code = MHD_HTTP_OK,
+ .details.pay.contract_ref = "create-proposal-1",
+ .details.pay.coin_ref = "withdraw-coin-1",
+ .details.pay.amount_with_fee = concat_amount (currency, "5"),
+ .details.pay.amount_without_fee = concat_amount (currency, "4.99") @},
address@hidden example
+
+The logic calculates the deposit fee according to the subtraction:
address@hidden - amount_without_fee}.
+
+The following example shows a 5 EURO coin configuration - needed by the
+used exchange - which is compatible with the hardcoded example above.
+
address@hidden
+[coin_eur_5]
+value = EUR:5
+duration_overlap = 5 minutes
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.00
+fee_deposit = EUR:0.01 # important bit
+fee_refresh = EUR:0.00
+fee_refund = EUR:0.00
+rsa_keysize = 1024
address@hidden example
+
+If the command terminates with no errors, then the merchant backend is
correctly
+installed.
+
+After this operation is done, the merchant database will have some dummy
+data in it, so it may be convenient to clean all the tables; to this purpose,
+issue the following command:
+
address@hidden
+$ taler-merchant-dbinit -r
address@hidden example
@node Advanced topics
@chapter Advanced topics
@menu
+* Configuration in Taler:: Configuration patterns
* Using taler-config:: Introduction to the taler-config tool
* Key management:: Managing the merchant's cryptographic keys
* SEPA configuration:: Configuring a SEPA bank account
@end menu
address@hidden Configuration in Taler
address@hidden Configuration in Taler
address@hidden configuration
+
+In Taler realm, any component obeys to the same pattern to get configuration
+values. According to this pattern, once the component has been installed, the
+installation deploys default values in
@address@hidden@}/share/taler/config.d/}, in
address@hidden files. In order to override these defaults, the user can write
a custom
address@hidden file and either pass it to the component at execution time, or
name it
address@hidden and place it under @cite{$HOME/.config/}.
+
+
+A config file is a text file containing @cite{sections}, and each section
contains
+its @cite{values}. The right format follows:
+
address@hidden
+[section1]
+value1 = string
+value2 = 23
+
+[section2]
+value21 = string
+value22 = /path22
address@hidden example
+
+Throughout any configuration file, it is possible to use @code{$}-prefixed
variables,
+like @code{$VAR}, especially when they represent filesystem paths.
+It is also possible to provide defaults values for those variables that are
unset,
+by using the following syntax: @address@hidden:address@hidden
+However, there are two ways a user can set @code{$}-prefixable variables:
+
+by defining them under a @code{[paths]} section, see example below,
+
address@hidden
+[paths]
+TALER_DEPLOYMENT_SHARED = address@hidden@}/shared-data
+..
+[section-x]
+path-x = address@hidden@}/x
address@hidden example
+
+or by setting them in the environment:
+
address@hidden
+$ export VAR=/x
address@hidden example
+
+The configuration loader will give precedence to variables set under
@code{[path]},
+though.
+
+The utility @code{taler-config}, which gets installed along with the exchange,
serves
+to get and set configuration values without directly editing the @cite{.conf}.
+The option @code{-f} is particularly useful to resolve pathnames, when they use
+several levels of @code{$}-expanded variables. See @code{taler-config --help}.
+
+Note that, in this stage of development, the file
@code{$HOME/.config/taler.conf}
+can contain sections for @emph{all} the component. For example, both an
exchange and
+a bank can read values from it.
+
+The repository @code{git://taler.net/deployment} contains examples of
configuration
+file used in our demos. See under @code{deployment/config}.
+
address@hidden
address@hidden Note
+Expectably, some components will not work just by using default values, as
their
+work is often interdependent. For example, a merchant needs to know an exchange
+URL, or a database name.
address@hidden quotation
address@hidden cartouche
+
+
@node Using taler-config
@section Using taler-config
@cindex taler-config
diff --git a/doc/version.texi b/doc/version.texi
index 0b47203..d4370a3 100644
--- a/doc/version.texi
+++ b/doc/version.texi
@@ -1,4 +1,4 @@
address@hidden UPDATED 27 January 2017
address@hidden UPDATED-MONTH January 2017
address@hidden UPDATED 30 May 2017
address@hidden UPDATED-MONTH May 2017
@set EDITION 0.2.0
@set VERSION 0.2.0
diff --git a/src/Makefile.am b/src/Makefile.am
index 16521e0..e58cf01 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,3 +1,3 @@
# This Makefile is in the public domain
AM_CPPFLAGS = -I$(top_srcdir)/src/include
-SUBDIRS = include backenddb backend lib merchant-tools samples
+SUBDIRS = include backenddb backend lib merchant-tools
diff --git a/src/backend/taler-merchant-httpd.c
b/src/backend/taler-merchant-httpd.c
index f3faa30..0efa7eb 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -286,10 +286,7 @@ do_shutdown (void *cls)
GNUNET_SCHEDULER_cancel (mhd_task);
mhd_task = NULL;
}
- /* FIXME: MHD API requires us to resume all suspended
- connections before we do this, but /pay currently
- suspends connections without giving us a way to
- enumerate / resume them... */
+ MH_force_pc_resume ();
if (NULL != mhd)
{
MHD_stop_daemon (mhd);
@@ -1109,7 +1106,8 @@ run (void *cls,
MHD_OPTION_END);
if (NULL == mhd)
{
- GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to launch HTTP service, exiting.\n");
GNUNET_SCHEDULER_shutdown ();
return;
}
@@ -1128,10 +1126,13 @@ run (void *cls,
int
main (int argc, char *const *argv)
{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- { 'C', "connection-close", NULL,
- "force HTTP connections to be closed after each request", 0,
- &GNUNET_GETOPT_set_one, &TMH_merchant_connection_close},
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+ GNUNET_GETOPT_option_flag ('C',
+ "connection-close",
+ "force HTTP connections to be closed after each
request",
+ &TMH_merchant_connection_close),
+
GNUNET_GETOPT_OPTION_END
};
diff --git a/src/backend/taler-merchant-httpd_auditors.c
b/src/backend/taler-merchant-httpd_auditors.c
index 2671e08..81b6422 100644
--- a/src/backend/taler-merchant-httpd_auditors.c
+++ b/src/backend/taler-merchant-httpd_auditors.c
@@ -79,8 +79,6 @@ TMH_AUDITORS_check_dk (struct TALER_EXCHANGE_Handle *mh,
{
const struct TALER_EXCHANGE_Keys *keys;
const struct TALER_EXCHANGE_AuditorInformation *ai;
- unsigned int i;
- unsigned int j;
if (0 == GNUNET_TIME_absolute_get_remaining
(dk->expire_deposit).rel_value_us)
{
@@ -98,15 +96,28 @@ TMH_AUDITORS_check_dk (struct TALER_EXCHANGE_Handle *mh,
GNUNET_break (0);
return GNUNET_SYSERR;
}
- for (i=0;i<keys->num_auditors;i++)
+ for (unsigned int i=0;i<keys->num_auditors;i++)
{
ai = &keys->auditors[i];
- for (j=0;j<ai->num_denom_keys;j++)
- if (ai->denom_keys[j] == dk)
- return GNUNET_OK;
+ for (unsigned int j=0;j<nauditors;j++)
+ {
+ if (0 == memcmp (&ai->auditor_pub,
+ &auditors[j].public_key,
+ sizeof (struct TALER_AuditorPublicKeyP)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Found supported auditor `%s' (%s)\n",
+ auditors[j].name,
+ TALER_B2S (&auditors[j].public_key));
+
+ }
+ for (unsigned int k=0;j<ai->num_denom_keys;k++)
+ if (ai->denom_keys[k] == dk)
+ return GNUNET_OK;
+ }
}
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Denomination key %s offered by client not audited by accepted
auditor\n",
+ "Denomination key %s offered by client not audited by any
accepted auditor\n",
GNUNET_h2s (&dk->h_key));
return GNUNET_NO;
}
@@ -181,6 +192,10 @@ parse_auditors (void *cls,
GNUNET_free (pks);
return;
}
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Loaded key data of auditor `%s' (%s)\n",
+ auditor.name,
+ TALER_B2S (&auditor.public_key));
GNUNET_free (pks);
GNUNET_array_append (auditors,
nauditors,
@@ -198,15 +213,13 @@ parse_auditors (void *cls,
int
TMH_AUDITORS_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
{
- unsigned int cnt;
-
GNUNET_CONFIGURATION_iterate_sections (cfg,
&parse_auditors,
(void *) cfg);
/* Generate preferred exchange(s) array. */
j_auditors = json_array ();
- for (cnt = 0; cnt < nauditors; cnt++)
+ for (unsigned int cnt = 0; cnt < nauditors; cnt++)
GNUNET_assert (0 ==
json_array_append_new (j_auditors,
json_pack ("{s:s, s:o, s:s}",
@@ -223,11 +236,9 @@ TMH_AUDITORS_init (const struct
GNUNET_CONFIGURATION_Handle *cfg)
void
TMH_AUDITORS_done ()
{
- unsigned int i;
-
json_decref (j_auditors);
j_auditors = NULL;
- for (i=0;i<nauditors;i++)
+ for (unsigned int i=0;i<nauditors;i++)
{
GNUNET_free (auditors[i].name);
GNUNET_free (auditors[i].uri);
diff --git a/src/backend/taler-merchant-httpd_exchanges.c
b/src/backend/taler-merchant-httpd_exchanges.c
index daf5550..aab5b27 100644
--- a/src/backend/taler-merchant-httpd_exchanges.c
+++ b/src/backend/taler-merchant-httpd_exchanges.c
@@ -448,6 +448,11 @@ process_find_operations (struct Exchange *exchange)
wire_fee,
exchange->trusted);
GNUNET_free_non_null (fo->wire_method);
+ if (NULL != fo->at)
+ {
+ GNUNET_SCHEDULER_cancel (fo->at);
+ fo->at = NULL;
+ }
GNUNET_free (fo);
}
return need_wire;
@@ -522,6 +527,11 @@ handle_wire_data (void *cls,
NULL,
GNUNET_NO);
GNUNET_free_non_null (fo->wire_method);
+ if (NULL != fo->at)
+ {
+ GNUNET_SCHEDULER_cancel (fo->at);
+ fo->at = NULL;
+ }
GNUNET_free (fo);
}
return;
@@ -648,6 +658,7 @@ return_result (void *cls)
struct TMH_EXCHANGES_FindOperation *fo = cls;
struct Exchange *exchange = fo->my_exchange;
+ fo->at = NULL;
if ( (GNUNET_YES ==
process_find_operations (exchange)) &&
(NULL == exchange->wire_request) &&
@@ -743,6 +754,7 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
{
/* We are not currently waiting for a reply, immediately
return result */
+ GNUNET_assert (NULL == fo->at);
fo->at = GNUNET_SCHEDULER_add_now (&return_result,
fo);
return fo;
@@ -766,8 +778,6 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
exchange->wire_task = GNUNET_SCHEDULER_add_now (&wire_task_cb,
exchange);
}
-
-
return fo;
}
diff --git a/src/backend/taler-merchant-httpd_history.c
b/src/backend/taler-merchant-httpd_history.c
index 2e530e9..a06259c 100644
--- a/src/backend/taler-merchant-httpd_history.c
+++ b/src/backend/taler-merchant-httpd_history.c
@@ -25,38 +25,20 @@
#include "taler-merchant-httpd.h"
#include "taler-merchant-httpd_responses.h"
-/**
- * Index to the first row to return in response to /history.
- */
-unsigned int start;
-
-/**
- * How many rows we are to return in response to /history.
- */
-unsigned int delta;
-
-/**
- * Index to the current row being processed.
- */
-unsigned int current = 0;
-
/**
* Function called with information about a transaction.
*
* @param cls closure
- * @param merchant_pub merchant's public key
- * @param exchange_uri URI of the exchange
- * @param transaction_id proposal's transaction id
- * @param h_wire hash of our wire details
- * @param timestamp time of the confirmation
- * @param refund refund deadline
- * @param total_amount total amount we receive for the contract after fees
+ * @param order_id transaction's order ID.
+ * @param row_id serial numer of the transaction in the table,
+ * used as index by the frontend to skip previous results.
*/
static void
pd_cb (void *cls,
const char *order_id,
- const json_t *proposal_data)
+ uint64_t row_id,
+ const json_t *contract_terms)
{
json_t *response = cls;
json_t *entry;
@@ -64,32 +46,25 @@ pd_cb (void *cls,
json_t *timestamp;
json_t *instance;
- GNUNET_assert (-1 != json_unpack ((json_t *) proposal_data,
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "/history's row_id: %llu\n",
+ (unsigned long long) row_id);
+
+ GNUNET_assert (-1 != json_unpack ((json_t *) contract_terms,
"{s:o, s:o, s:{s:o}}",
"amount", &amount,
"timestamp", ×tamp,
"merchant", "instance", &instance));
- if ( (current >= start) &&
- (current < start + delta) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Adding history element. Current: %u, start: %u, delta: %u\n",
- current,
- start,
- delta);
- GNUNET_break (NULL != (entry = json_pack ("{s:s, s:O, s:O, s:O}",
- "order_id", order_id,
- "amount", amount,
- "timestamp", timestamp,
- "instance", instance)));
-
- GNUNET_break (0 == json_array_append_new (response,
- entry));
- }
+ GNUNET_break (NULL != (entry = json_pack ("{s:I, s:s, s:O, s:O, s:O}",
+ "row_id", row_id,
+ "order_id", order_id,
+ "amount", amount,
+ "timestamp", timestamp,
+ "instance", instance)));
- // FIXME to zero after returned.
- current++;
+ GNUNET_break (0 == json_array_append_new (response,
+ entry));
}
@@ -118,13 +93,16 @@ MH_handler_history (struct TMH_RequestHandler *rh,
unsigned int ret;
unsigned long long seconds;
struct MerchantInstance *mi;
+ int start = -1;
+ unsigned int delta;
response = json_array (); /*FIXME who decrefs this?*/
str = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"date");
- seconds = 0;
+ date = GNUNET_TIME_absolute_get ();
+
if (NULL != str)
{
if (1 != sscanf (str, "%llu", &seconds))
@@ -134,9 +112,9 @@ MH_handler_history (struct TMH_RequestHandler *rh,
TALER_EC_PARAMETER_MALFORMED,
"date");
}
- }
date.abs_value_us = seconds * 1000LL * 1000LL;
+
if (date.abs_value_us / 1000LL / 1000LL != seconds)
{
json_decref (response);
@@ -146,6 +124,8 @@ MH_handler_history (struct TMH_RequestHandler *rh,
}
+ }
+
mi = TMH_lookup_instance ("default");
str = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
@@ -160,7 +140,35 @@ MH_handler_history (struct TMH_RequestHandler *rh,
TALER_EC_HISTORY_INSTANCE_UNKNOWN,
"instance");
}
- start = 0;
+
+ /* Here goes the cherry-picking logic */
+
+ str = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "order_id");
+
+ if (NULL != str)
+ {
+
+ ret = db->find_contract_terms_history (db->cls,
+ str,
+ &mi->pubkey,
+ pd_cb,
+ response);
+ if (GNUNET_SYSERR == ret)
+ {
+ json_decref (response);
+ return TMH_RESPONSE_reply_internal_error (connection,
+
TALER_EC_HISTORY_DB_FETCH_ERROR,
+ "db error to get history");
+ }
+ ret = TMH_RESPONSE_reply_json (connection,
+ response,
+ MHD_HTTP_OK);
+ json_decref (response);
+ return ret;
+ }
+
delta = 20;
str = MHD_lookup_connection_value (connection,
@@ -169,7 +177,7 @@ MH_handler_history (struct TMH_RequestHandler *rh,
if (NULL != str)
{
if ((1 != sscanf (str, "%d", &start)) ||
- start < 0)
+ 0 > start)
{
json_decref (response);
return TMH_RESPONSE_reply_arg_invalid (connection,
@@ -191,15 +199,27 @@ MH_handler_history (struct TMH_RequestHandler *rh,
"delta");
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Querying history back to %s\n",
- GNUNET_STRINGS_absolute_time_to_string (date));
-
- ret = db->find_proposal_data_by_date (db->cls,
- date,
- &mi->pubkey,
- pd_cb,
- response);
- current = 0;
+ "Querying history back to %s, start: %d, delta: %d\n",
+ GNUNET_STRINGS_absolute_time_to_string (date),
+ start,
+ delta);
+
+ if (0 > start)
+ ret = db->find_contract_terms_by_date (db->cls,
+ date,
+ &mi->pubkey,
+ delta,
+ pd_cb,
+ response);
+ else
+ ret = db->find_contract_terms_by_date_and_range (db->cls,
+ date,
+ &mi->pubkey,
+ start,
+ delta,
+ GNUNET_NO,
+ pd_cb,
+ response);
if (GNUNET_SYSERR == ret)
{
json_decref (response);
@@ -207,10 +227,6 @@ MH_handler_history (struct TMH_RequestHandler *rh,
TALER_EC_HISTORY_DB_FETCH_ERROR,
"db error to get history");
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "history data: %s\n",
- json_dumps (response, JSON_INDENT (1)));
-
ret = TMH_RESPONSE_reply_json (connection,
response,
MHD_HTTP_OK);
diff --git a/src/backend/taler-merchant-httpd_pay.c
b/src/backend/taler-merchant-httpd_pay.c
index c3203ef..97b7ac4 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -119,6 +119,16 @@ struct PayContext
struct TM_HandlerContext hc;
/**
+ * Stored in a DLL.
+ */
+ struct PayContext *next;
+
+ /**
+ * Stored in a DLL.
+ */
+ struct PayContext *prev;
+
+ /**
* Array with @e coins_cnt coins we are despositing.
*/
struct DepositConfirmation *dc;
@@ -129,6 +139,29 @@ struct PayContext
struct MHD_Connection *connection;
/**
+ * Instance of the payment's instance (in JSON format)
+ */
+ struct MerchantInstance *mi;
+
+ /**
+ * Proposal data for the proposal that is being
+ * payed for in this context.
+ */
+ json_t *contract_terms;
+
+ /**
+ * Task called when the (suspended) processing for
+ * the /pay request times out.
+ * Happens when we don't get a response from the exchange.
+ */
+ struct GNUNET_SCHEDULER_Task *timeout_task;
+
+ /**
+ * Response to return, NULL if we don't have one yet.
+ */
+ struct MHD_Response *response;
+
+ /**
* Handle to the exchange that we are doing the payment with.
* (initially NULL while @e fo is trying to find a exchange).
*/
@@ -157,6 +190,17 @@ struct PayContext
const char *order_id;
/**
+ * Hashed proposal.
+ */
+ struct GNUNET_HashCode h_contract_terms;
+
+ /**
+ * "H_wire" from @e contract_terms. Used to identify the instance's
+ * wire transfer method.
+ */
+ struct GNUNET_HashCode h_wire;
+
+ /**
* Maximum fee the merchant is willing to pay, from @e root.
* Note that IF the total fee of the exchange is higher, that is
* acceptable to the merchant if the customer is willing to
@@ -184,57 +228,41 @@ struct PayContext
struct TALER_Amount max_wire_fee;
/**
- * Number of transactions that the wire fees are expected to be
- * amortized over. Never zero, defaults (conservateively) to 1.
- * May be higher if merchants expect many small transactions to
- * be aggregated and thus wire fees to be reasonably amortized
- * due to aggregation.
- */
- uint32_t wire_fee_amortization;
-
- /**
* Amount from @e root. This is the amount the merchant expects
* to make, minus @e max_fee.
*/
struct TALER_Amount amount;
/**
- * Timestamp from @e proposal_data.
- */
- struct GNUNET_TIME_Absolute timestamp;
-
- /**
- * Refund deadline from @e proposal_data.
- */
- struct GNUNET_TIME_Absolute refund_deadline;
-
- /**
- * Deadline for the customer to pay for this contract.
+ * Wire transfer deadline. How soon would the merchant like the
+ * wire transfer to be executed? (Can be given by the frontend
+ * or be determined by our configuration via #wire_transfer_delay.)
*/
- struct GNUNET_TIME_Absolute pay_deadline;
+ struct GNUNET_TIME_Absolute wire_transfer_deadline;
/**
- * "H_contract" from @e proposal_data.
+ * Timestamp from @e contract_terms.
*/
- struct GNUNET_HashCode h_proposal_data;
+ struct GNUNET_TIME_Absolute timestamp;
/**
- * "H_wire" from @e proposal_data. Used to identify the instance's
- * wire transfer method.
+ * Refund deadline from @e contract_terms.
*/
- struct GNUNET_HashCode h_wire;
+ struct GNUNET_TIME_Absolute refund_deadline;
/**
- * Wire transfer deadline. How soon would the merchant like the
- * wire transfer to be executed? (Can be given by the frontend
- * or be determined by our configuration via #wire_transfer_delay.)
+ * Deadline for the customer to pay for this proposal.
*/
- struct GNUNET_TIME_Absolute wire_transfer_deadline;
+ struct GNUNET_TIME_Absolute pay_deadline;
/**
- * Response to return, NULL if we don't have one yet.
+ * Number of transactions that the wire fees are expected to be
+ * amortized over. Never zero, defaults (conservateively) to 1.
+ * May be higher if merchants expect many small transactions to
+ * be aggregated and thus wire fees to be reasonably amortized
+ * due to aggregation.
*/
- struct MHD_Response *response;
+ uint32_t wire_fee_amortization;
/**
* Number of coins this payment is made of. Length
@@ -257,32 +285,50 @@ struct PayContext
unsigned int response_code;
/**
- * Task called when the (suspended) processing for
- * the /pay request times out.
- * Happens when we don't get a response from the exchange.
- */
- struct GNUNET_SCHEDULER_Task *timeout_task;
-
- /**
* #GNUNET_NO if the transaction is not in our database,
* #GNUNET_YES if the transaction is known to our database,
* #GNUNET_SYSERR if the transaction ID is used for a different
* transaction in our database.
*/
- int transaction_exits;
+ int transaction_exists;
/**
- * Instance of the payment's instance (in JSON format)
+ * #GNUNET_NO if the @e connection was not suspended,
+ * #GNUNET_YES if the @e connection was suspended,
+ * #GNUNET_SYSERR if @e connection was resumed to as
+ * part of #MH_force_pc_resume during shutdown.
*/
- struct MerchantInstance *mi;
+ int suspended;
+};
- /**
- * Proposal data for the proposal that is being
- * payed for in this context.
- */
- json_t *proposal_data;
-};
+/**
+ * Head of active pay context DLL.
+ */
+static struct PayContext *pc_head;
+
+/**
+ * Tail of active pay context DLL.
+ */
+static struct PayContext *pc_tail;
+
+
+/**
+ * Force all pay contexts to be resumed as we are about
+ * to shut down MHD.
+ */
+void
+MH_force_pc_resume ()
+{
+ for (struct PayContext *pc = pc_head; NULL != pc; pc = pc->next)
+ {
+ if (GNUNET_YES == pc->suspended)
+ {
+ pc->suspended = GNUNET_SYSERR;
+ MHD_resume_connection (pc->connection);
+ }
+ }
+}
/**
@@ -309,6 +355,8 @@ resume_pay_with_response (struct PayContext *pc,
GNUNET_SCHEDULER_cancel (pc->timeout_task);
pc->timeout_task = NULL;
}
+ GNUNET_assert (GNUNET_YES == pc->suspended);
+ pc->suspended = GNUNET_NO;
MHD_resume_connection (pc->connection);
TMH_trigger_daemon (); /* we resumed, kick MHD */
}
@@ -353,19 +401,19 @@ sign_success_response (struct PayContext *pc)
mr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK);
mr.purpose.size = htonl (sizeof (mr));
- mr.h_proposal_data = pc->h_proposal_data;
+ mr.h_contract_terms = pc->h_contract_terms;
GNUNET_CRYPTO_eddsa_sign (&pc->mi->privkey.eddsa_priv,
&mr.purpose,
&sig);
return TMH_RESPONSE_make_json_pack ("{s:O, s:o, s:o}",
- "proposal_data",
- pc->proposal_data,
+ "contract_terms",
+ pc->contract_terms,
"sig",
GNUNET_JSON_from_data_auto (&sig),
- "h_proposal_data",
- GNUNET_JSON_from_data
(&pc->h_proposal_data,
+ "h_contract_terms",
+ GNUNET_JSON_from_data
(&pc->h_contract_terms,
sizeof (struct
GNUNET_HashCode)));
}
@@ -438,12 +486,12 @@ deposit_cb (void *cls,
}
/* store result to DB */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Storing successful payment for h_proposal_data '%s'\n",
- GNUNET_h2s (&pc->h_proposal_data));
+ "Storing successful payment for h_contract_terms '%s'\n",
+ GNUNET_h2s (&pc->h_contract_terms));
if (GNUNET_OK !=
db->store_deposit (db->cls,
- &pc->h_proposal_data,
+ &pc->h_contract_terms,
&pc->mi->pubkey,
&dc->coin_pub,
&dc->amount_with_fee,
@@ -479,16 +527,14 @@ static void
pay_context_cleanup (struct TM_HandlerContext *hc)
{
struct PayContext *pc = (struct PayContext *) hc;
- unsigned int i;
if (NULL != pc->timeout_task)
{
GNUNET_SCHEDULER_cancel (pc->timeout_task);
pc->timeout_task = NULL;
}
-
TMH_PARSE_post_cleanup_callback (pc->json_parse_context);
- for (i=0;i<pc->coins_cnt;i++)
+ for (unsigned int i=0;i<pc->coins_cnt;i++)
{
struct DepositConfirmation *dc = &pc->dc[i];
@@ -524,11 +570,14 @@ pay_context_cleanup (struct TM_HandlerContext *hc)
GNUNET_free (pc->chosen_exchange);
pc->chosen_exchange = NULL;
}
- if (NULL != pc->proposal_data)
+ if (NULL != pc->contract_terms)
{
- json_decref (pc->proposal_data);
- pc->proposal_data = NULL;
+ json_decref (pc->contract_terms);
+ pc->contract_terms = NULL;
}
+ GNUNET_CONTAINER_DLL_remove (pc_head,
+ pc_tail,
+ pc);
GNUNET_free (pc);
}
@@ -553,7 +602,6 @@ process_pay_with_exchange (void *cls,
struct TALER_Amount wire_fee_delta;
struct TALER_Amount wire_fee_customer_contribution;
const struct TALER_EXCHANGE_Keys *keys;
- unsigned int i;
pc->fo = NULL;
if (NULL == mh)
@@ -580,7 +628,7 @@ process_pay_with_exchange (void *cls,
}
/* Total up the fees and the value of the deposited coins! */
- for (i=0;i<pc->coins_cnt;i++)
+ for (unsigned int i=0;i<pc->coins_cnt;i++)
{
struct DepositConfirmation *dc = &pc->dc[i];
const struct TALER_EXCHANGE_DenomPublicKey *denom_details;
@@ -784,7 +832,7 @@ process_pay_with_exchange (void *cls,
"Exchange and fee structure OK. Initiating deposit operation for
coins\n");
/* Initiate /deposit operation for all coins */
- for (i=0;i<pc->coins_cnt;i++)
+ for (unsigned int i=0;i<pc->coins_cnt;i++)
{
struct DepositConfirmation *dc = &pc->dc[i];
@@ -795,11 +843,12 @@ process_pay_with_exchange (void *cls,
"Timing for this payment, wire_deadline: %llu,
refund_deadline: %llu\n",
(unsigned long long) pc->wire_transfer_deadline.abs_value_us,
(unsigned long long) pc->refund_deadline.abs_value_us);
+
dc->dh = TALER_EXCHANGE_deposit (mh,
&dc->amount_with_fee,
pc->wire_transfer_deadline,
pc->mi->j_wire,
- &pc->h_proposal_data,
+ &pc->h_contract_terms,
&dc->coin_pub,
&dc->ub_sig,
&dc->denom,
@@ -856,7 +905,7 @@ handle_pay_timeout (void *cls)
* Function called with information about a coin that was deposited.
*
* @param cls closure
- * @param transaction_id of the contract
+ * @param h_contract_terms hashed proposal data
* @param coin_pub public key of the coin
* @param amount_with_fee amount the exchange will deposit for this coin
* @param deposit_fee fee the exchange will charge for this coin
@@ -864,7 +913,7 @@ handle_pay_timeout (void *cls)
*/
static void
check_coin_paid (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_Amount *amount_with_fee,
const struct TALER_Amount *deposit_fee,
@@ -873,8 +922,8 @@ check_coin_paid (void *cls,
struct PayContext *pc = cls;
unsigned int i;
- if (0 != memcmp (&pc->h_proposal_data,
- h_proposal_data,
+ if (0 != memcmp (&pc->h_contract_terms,
+ h_contract_terms,
sizeof (struct GNUNET_HashCode)))
{
GNUNET_break (0);
@@ -883,14 +932,23 @@ check_coin_paid (void *cls,
for (i=0;i<pc->coins_cnt;i++)
{
struct DepositConfirmation *dc = &pc->dc[i];
-
+ /* Get matching coin from results*/
if ( (0 != memcmp (coin_pub,
&dc->coin_pub,
sizeof (struct TALER_CoinSpendPublicKeyP))) ||
(0 != TALER_amount_cmp (amount_with_fee,
&dc->amount_with_fee)) )
continue;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Coin (%s) already found in our DB.\n",
+ TALER_b2s (coin_pub, sizeof (*coin_pub)));
+
dc->found_in_db = GNUNET_YES;
+ /**
+ * What happens if a (mad) wallet sends new coins on a
+ * contract that it already paid for?
+ */
pc->pending--;
}
}
@@ -898,12 +956,12 @@ check_coin_paid (void *cls,
/**
* Check if the existing transaction matches our transaction.
- * Update `transaction_exits` accordingly.
+ * Update `transaction_exists` accordingly.
*
* @param cls closure with the `struct PayContext`
- * @param transaction_id of the contract
* @param merchant_pub merchant's public key
* @param exchange_uri URI of the exchange
+ * @param h_contract_terms hashed proposal data
* @param h_xwire hash of our wire details
* @param timestamp time of the confirmation
* @param refund refund deadline
@@ -913,7 +971,7 @@ static void
check_transaction_exists (void *cls,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const char *exchange_uri,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct GNUNET_HashCode *h_xwire,
struct GNUNET_TIME_Absolute timestamp,
struct GNUNET_TIME_Absolute refund,
@@ -921,8 +979,8 @@ check_transaction_exists (void *cls,
{
struct PayContext *pc = cls;
- if ( (0 == memcmp (h_proposal_data,
- &pc->h_proposal_data,
+ if ( (0 == memcmp (h_contract_terms,
+ &pc->h_contract_terms,
sizeof (struct GNUNET_HashCode))) &&
(0 == memcmp (h_xwire,
&pc->mi->h_wire,
@@ -932,12 +990,12 @@ check_transaction_exists (void *cls,
(0 == TALER_amount_cmp (total_amount,
&pc->amount) ) )
{
- pc->transaction_exits = GNUNET_YES;
+ pc->transaction_exists = GNUNET_YES;
}
else
{
GNUNET_break_op (0);
- pc->transaction_exits = GNUNET_SYSERR;
+ pc->transaction_exists = GNUNET_SYSERR;
}
}
@@ -949,7 +1007,6 @@ get_instance (struct json_t *json);
/**
* Try to parse the pay request into the given pay context.
- *
* Schedules an error response in the connection on failure.
*
*
@@ -989,8 +1046,8 @@ parse_pay (struct MHD_Connection *connection,
GNUNET_break (0);
return res;
}
- res = db->find_proposal_data (db->cls,
- &pc->proposal_data,
+ res = db->find_contract_terms (db->cls,
+ &pc->contract_terms,
order_id,
&merchant_pub);
if (GNUNET_OK != res)
@@ -1008,8 +1065,8 @@ parse_pay (struct MHD_Connection *connection,
}
if (GNUNET_OK !=
- TALER_JSON_hash (pc->proposal_data,
- &pc->h_proposal_data))
+ TALER_JSON_hash (pc->contract_terms,
+ &pc->h_contract_terms))
{
GNUNET_JSON_parse_free (spec);
if (MHD_YES !=
@@ -1023,7 +1080,7 @@ parse_pay (struct MHD_Connection *connection,
return GNUNET_NO;
}
- merchant = json_object_get (pc->proposal_data,
+ merchant = json_object_get (pc->contract_terms,
"merchant");
if (NULL == merchant)
{
@@ -1033,7 +1090,7 @@ parse_pay (struct MHD_Connection *connection,
if (MHD_YES !=
TMH_RESPONSE_reply_internal_error (connection,
TALER_EC_PAY_MERCHANT_FIELD_MISSING,
- "No merchant field in contract"))
+ "No merchant field in proposal"))
{
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -1081,7 +1138,7 @@ parse_pay (struct MHD_Connection *connection,
};
res = TMH_PARSE_json_data (connection,
- pc->proposal_data,
+ pc->contract_terms,
espec);
if (GNUNET_YES != res)
{
@@ -1118,7 +1175,7 @@ parse_pay (struct MHD_Connection *connection,
}
/* parse optional details */
- if (NULL != json_object_get (pc->proposal_data,
+ if (NULL != json_object_get (pc->contract_terms,
"max_wire_fee"))
{
struct GNUNET_JSON_Specification espec[] = {
@@ -1128,7 +1185,7 @@ parse_pay (struct MHD_Connection *connection,
};
res = TMH_PARSE_json_data (connection,
- pc->proposal_data,
+ pc->contract_terms,
espec);
if (GNUNET_YES != res)
{
@@ -1146,7 +1203,7 @@ parse_pay (struct MHD_Connection *connection,
TALER_amount_get_zero (pc->max_fee.currency,
&pc->max_wire_fee));
}
- if (NULL != json_object_get (pc->proposal_data,
+ if (NULL != json_object_get (pc->contract_terms,
"wire_fee_amortization"))
{
struct GNUNET_JSON_Specification espec[] = {
@@ -1156,7 +1213,7 @@ parse_pay (struct MHD_Connection *connection,
};
res = TMH_PARSE_json_data (connection,
- pc->proposal_data,
+ pc->contract_terms,
espec);
if ( (GNUNET_YES != res) ||
(0 == pc->wire_fee_amortization) )
@@ -1240,7 +1297,7 @@ handler_pay_json (struct MHD_Connection *connection,
/* Check if this payment attempt has already succeeded */
if (GNUNET_SYSERR ==
db->find_payments (db->cls,
- &pc->h_proposal_data,
+ &pc->h_contract_terms,
&pc->mi->pubkey,
&check_coin_paid,
pc))
@@ -1257,6 +1314,8 @@ handler_pay_json (struct MHD_Connection *connection,
/* Payment succeeded in the past; take short cut
and accept immediately */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Payment succeeded in the past; taking short cut");
resp = MHD_create_response_from_buffer (0,
NULL,
MHD_RESPMEM_PERSISTENT);
@@ -1269,7 +1328,7 @@ handler_pay_json (struct MHD_Connection *connection,
/* Check if transaction is already known, if not store it. */
if (GNUNET_SYSERR ==
db->find_transaction (db->cls,
- &pc->h_proposal_data,
+ &pc->h_contract_terms,
&pc->mi->pubkey,
&check_transaction_exists,
pc))
@@ -1279,31 +1338,31 @@ handler_pay_json (struct MHD_Connection *connection,
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
"Merchant database error");
}
- if (GNUNET_SYSERR == pc->transaction_exits)
+ if (GNUNET_SYSERR == pc->transaction_exists)
{
GNUNET_break (0);
return TMH_RESPONSE_reply_external_error (connection,
TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT,
"Transaction ID reused with
different transaction details");
}
- if (GNUNET_NO == pc->transaction_exits)
+ if (GNUNET_NO == pc->transaction_exists)
{
struct GNUNET_TIME_Absolute now;
+
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Dealing with new transaction '%s'\n",
- GNUNET_h2s (&pc->h_proposal_data));
+ GNUNET_h2s (&pc->h_contract_terms));
now = GNUNET_TIME_absolute_get ();
if (now.abs_value_us > pc->pay_deadline.abs_value_us)
{
/* Time expired, we don't accept this payment now! */
const char *pd_str;
- pd_str = GNUNET_STRINGS_absolute_time_to_string (pc->pay_deadline);
+ pd_str = GNUNET_STRINGS_absolute_time_to_string (pc->pay_deadline);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Attempt to get coins for expired contract. Deadline:
'%s'\n",
pd_str);
-
return TMH_RESPONSE_reply_bad_request (connection,
TALER_EC_PAY_OFFER_EXPIRED,
"The time to pay for this
contract has expired.");
@@ -1311,10 +1370,10 @@ handler_pay_json (struct MHD_Connection *connection,
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Storing transaction '%s'\n",
- GNUNET_h2s (&pc->h_proposal_data));
+ GNUNET_h2s (&pc->h_contract_terms));
if (GNUNET_OK !=
db->store_transaction (db->cls,
- &pc->h_proposal_data,
+ &pc->h_contract_terms,
&pc->mi->pubkey,
pc->chosen_exchange,
&pc->mi->h_wire,
@@ -1330,6 +1389,7 @@ handler_pay_json (struct MHD_Connection *connection,
}
MHD_suspend_connection (connection);
+ pc->suspended = GNUNET_YES;
/* Find the responsible exchange, this may take a while... */
pc->fo = TMH_EXCHANGES_find_exchange (pc->chosen_exchange,
@@ -1379,6 +1439,9 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
if (NULL == *connection_cls)
{
pc = GNUNET_new (struct PayContext);
+ GNUNET_CONTAINER_DLL_insert (pc_head,
+ pc_tail,
+ pc);
pc->hc.cc = &pay_context_cleanup;
pc->connection = connection;
*connection_cls = pc;
diff --git a/src/backend/taler-merchant-httpd_pay.h
b/src/backend/taler-merchant-httpd_pay.h
index 124a9d9..d4f4958 100644
--- a/src/backend/taler-merchant-httpd_pay.h
+++ b/src/backend/taler-merchant-httpd_pay.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2014, 2015 GNUnet e.V.
+ (C) 2014-2017 GNUnet e.V.
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
@@ -23,6 +23,15 @@
#include <microhttpd.h>
#include "taler-merchant-httpd.h"
+
+/**
+ * Force all pay contexts to be resumed as we are about
+ * to shut down MHD.
+ */
+void
+MH_force_pc_resume (void);
+
+
/**
* Manage a payment
*
diff --git a/src/backend/taler-merchant-httpd_proposal.c
b/src/backend/taler-merchant-httpd_proposal.c
index 0d96a1f..fa8251c 100644
--- a/src/backend/taler-merchant-httpd_proposal.c
+++ b/src/backend/taler-merchant-httpd_proposal.c
@@ -183,8 +183,7 @@ proposal_put (struct MHD_Connection *connection,
json_string (buf));
}
- if (NULL == json_object_get (order,
- "timestamp"))
+ if (NULL == json_object_get (order, "timestamp"))
{
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
@@ -277,6 +276,9 @@ proposal_put (struct MHD_Connection *connection,
"H_wire",
GNUNET_JSON_from_data_auto (&mi->h_wire));
json_object_set_new (order,
+ "wire_method",
+ json_string (mi->wire_method));
+ json_object_set_new (order,
"merchant_pub",
GNUNET_JSON_from_data_auto (&mi->pubkey));
@@ -294,7 +296,7 @@ proposal_put (struct MHD_Connection *connection,
/* fetch timestamp from order */
if (GNUNET_OK !=
- db->insert_proposal_data (db->cls,
+ db->insert_contract_terms (db->cls,
order_id,
&mi->pubkey,
timestamp,
@@ -403,7 +405,7 @@ MH_handler_proposal_lookup (struct TMH_RequestHandler *rh,
const char *order_id;
const char *instance;
int res;
- json_t *proposal_data;
+ json_t *contract_terms;
struct MerchantInstance *mi;
instance = MHD_lookup_connection_value (connection,
@@ -425,8 +427,8 @@ MH_handler_proposal_lookup (struct TMH_RequestHandler *rh,
TALER_EC_PARAMETER_MISSING,
"order_id");
- res = db->find_proposal_data (db->cls,
- &proposal_data,
+ res = db->find_contract_terms (db->cls,
+ &contract_terms,
order_id,
&mi->pubkey);
if (GNUNET_NO == res)
@@ -441,7 +443,7 @@ MH_handler_proposal_lookup (struct TMH_RequestHandler *rh,
return TMH_RESPONSE_reply_json (connection,
- proposal_data,
+ contract_terms,
MHD_HTTP_OK);
diff --git a/src/backend/taler-merchant-httpd_track-transaction.c
b/src/backend/taler-merchant-httpd_track-transaction.c
index 9f6e6d1..eb1ee16 100644
--- a/src/backend/taler-merchant-httpd_track-transaction.c
+++ b/src/backend/taler-merchant-httpd_track-transaction.c
@@ -207,7 +207,7 @@ struct TrackTransactionContext
/**
* Proposal's hashcode.
*/
- struct GNUNET_HashCode h_proposal_data;
+ struct GNUNET_HashCode h_contract_terms;
/**
* Response code to return upon resume.
@@ -364,6 +364,7 @@ wire_deposits_cb (void *cls,
tctx->wdh = NULL;
if (MHD_HTTP_OK != http_status)
{
+ GNUNET_break_op (0);
resume_track_transaction_with_response
(tctx,
MHD_HTTP_FAILED_DEPENDENCY,
@@ -404,7 +405,7 @@ wire_deposits_cb (void *cls,
if (GNUNET_OK !=
db->store_coin_to_transfer (db->cls,
- &details[i].h_proposal_data,
+ &details[i].h_contract_terms,
&details[i].coin_pub,
&tctx->current_wtid))
{
@@ -560,7 +561,7 @@ trace_coins (struct TrackTransactionContext *tctx)
tcc->dwh = TALER_EXCHANGE_track_transaction (tctx->eh,
&tctx->mi->privkey,
&tctx->h_wire,
- &tctx->h_proposal_data,
+ &tctx->h_contract_terms,
&tcc->coin_pub,
&wtid_cb,
tcc);
@@ -730,7 +731,7 @@ static void
transaction_cb (void *cls,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const char *exchange_uri,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct GNUNET_HashCode *h_wire,
struct GNUNET_TIME_Absolute timestamp,
struct GNUNET_TIME_Absolute refund,
@@ -738,7 +739,7 @@ transaction_cb (void *cls,
{
struct TrackTransactionContext *tctx = cls;
- tctx->h_proposal_data = *h_proposal_data;
+ tctx->h_contract_terms = *h_contract_terms;
tctx->exchange_uri = GNUNET_strdup (exchange_uri);
tctx->h_wire = *h_wire;
tctx->timestamp = timestamp;
@@ -766,7 +767,7 @@ transaction_cb (void *cls,
*/
static void
transfer_cb (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_WireTransferIdentifierRawP *wtid,
struct GNUNET_TIME_Absolute execution_time,
@@ -796,7 +797,7 @@ transfer_cb (void *cls,
*/
static void
coin_cb (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_Amount *amount_with_fee,
const struct TALER_Amount *deposit_fee,
@@ -815,7 +816,7 @@ coin_cb (void *cls,
tcc);
GNUNET_break (GNUNET_SYSERR !=
db->find_transfers_by_hash (db->cls,
- h_proposal_data,
+ h_contract_terms,
&transfer_cb,
tcc));
}
@@ -842,8 +843,8 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh,
const char *instance;
int ret;
struct GNUNET_HashCode h_instance;
- struct GNUNET_HashCode h_proposal_data;
- struct json_t *proposal_data;
+ struct GNUNET_HashCode h_contract_terms;
+ struct json_t *contract_terms;
if (NULL == *connection_cls)
{
@@ -916,37 +917,37 @@ MH_handler_track_transaction (struct TMH_RequestHandler
*rh,
TALER_EC_TRACK_TRANSACTION_INSTANCE_UNKNOWN,
"unknown instance");
- if (GNUNET_YES != db->find_proposal_data (db->cls,
- &proposal_data,
+ if (GNUNET_YES != db->find_contract_terms (db->cls,
+ &contract_terms,
order_id,
&tctx->mi->pubkey))
return TMH_RESPONSE_reply_not_found (connection,
TALER_EC_PROPOSAL_LOOKUP_NOT_FOUND,
"Given order_id doesn't map to any
proposal");
- TALER_JSON_hash (proposal_data,
- &h_proposal_data);
+ TALER_JSON_hash (contract_terms,
+ &h_contract_terms);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Trying to track h_proposal_data '%s'\n",
- GNUNET_h2s (&h_proposal_data));
+ "Trying to track h_contract_terms '%s'\n",
+ GNUNET_h2s (&h_contract_terms));
ret = db->find_transaction (db->cls,
- &h_proposal_data,
+ &h_contract_terms,
&tctx->mi->pubkey,
&transaction_cb,
tctx);
if (GNUNET_NO == ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "h_proposal_data not found\n");
+ "h_contract_terms not found\n");
return TMH_RESPONSE_reply_not_found (connection,
TALER_EC_TRACK_TRANSACTION_TRANSACTION_UNKNOWN,
- "h_proposal_data is unknown");
+ "h_contract_terms is unknown");
}
if ( (GNUNET_SYSERR == ret) ||
- (0 != memcmp (&tctx->h_proposal_data,
- &h_proposal_data,
+ (0 != memcmp (&tctx->h_contract_terms,
+ &h_contract_terms,
sizeof (struct GNUNET_HashCode))) ||
(NULL == tctx->exchange_uri) )
{
@@ -956,7 +957,7 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh,
"Database error");
}
ret = db->find_payments (db->cls,
- &h_proposal_data,
+ &h_contract_terms,
&tctx->mi->pubkey,
&coin_cb,
tctx);
diff --git a/src/backend/taler-merchant-httpd_track-transfer.c
b/src/backend/taler-merchant-httpd_track-transfer.c
index 3635c1d..4ca22af 100644
--- a/src/backend/taler-merchant-httpd_track-transfer.c
+++ b/src/backend/taler-merchant-httpd_track-transfer.c
@@ -125,6 +125,27 @@ struct TrackTransferContext
int check_transfer_result;
};
+/**
+ * Represents an entry in the table used to sum up
+ * individual deposits for each h_contract_terms.
+ */
+struct Entry {
+ /**
+ * Sum accumulator for deposited value.
+ */
+ struct TALER_Amount deposit_value;
+
+ /**
+ * Sum accumulator for deposit fee.
+ */
+ struct TALER_Amount deposit_fee;
+
+ };
+
+/**
+ * Modified response to return to the frontend.
+ */
+static json_t *deposits_response;
/**
* Free the @a rctx.
@@ -157,6 +178,168 @@ free_transfer_track_context (struct TrackTransferContext
*rctx)
GNUNET_free (rctx);
}
+/**
+ * Callback that frees all the elements in the hashmap
+ *
+ * @param cls closure, NULL
+ * @param key current key
+ * @param value a `struct MerchantInstance`
+ * @return GNUNET_YES if the iteration should continue,
+ * GNUNET_NO otherwise.
+ */
+static int
+hashmap_free (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct TALER_Amount *amount = value;
+ GNUNET_free (amount);
+ /*NOTE: how to find out when iteration should stop?*/
+ return GNUNET_YES;
+}
+
+
+/**
+ * Builds JSON response containing the summed-up amounts
+ * from individual deposits.
+ *
+ * @param cls closure
+ * @param key map's current key
+ * @param map's current value
+ * @return GNUNET_YES if iteration is to be continued,
+ * GNUNET_NO otherwise.
+ */
+int
+build_deposits_response (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct TrackTransferContext *rctx = cls;
+ json_t *element;
+ struct Entry *entry = value;
+ json_t *contract_terms;
+ json_t *order_id;
+
+ if (GNUNET_OK != db->find_contract_terms_from_hash (db->cls,
+ &contract_terms,
+ key,
+ &rctx->mi->pubkey))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+
+ order_id = json_object_get (contract_terms, "order_id");
+
+ element = json_pack ("{s:s, s:o, s:o}",
+ "order_id", json_string_value (order_id),
+ "deposit_value", TALER_JSON_from_amount
(&entry->deposit_value),
+ "deposit_fee", TALER_JSON_from_amount
(&entry->deposit_fee));
+
+ if (NULL == order_id || NULL == element)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+
+ json_array_append_new (deposits_response, element);
+
+ return GNUNET_YES;
+}
+
+/**
+ * Transform /track/transfer result as gotten from the exchange
+ * and transforms it in a format liked by the backoffice Web interface.
+ *
+ * @param result response from exchange's /track/transfer
+ * @result pointer to new JSON, or NULL upon errors.
+ */
+json_t *
+transform_response (const json_t *result, struct TrackTransferContext *rctx)
+{
+ json_t *deposits;
+ json_t *value;
+ json_t *result_mod = NULL;
+ size_t index;
+ const char *key;
+ struct GNUNET_HashCode h_key;
+ struct GNUNET_CONTAINER_MultiHashMap *map;
+ struct TALER_Amount iter_value;
+ struct TALER_Amount iter_fee;
+ struct Entry *current_entry;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transforming /track/transfer response.\n");
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount ("deposit_value", &iter_value),
+ TALER_JSON_spec_amount ("deposit_fee", &iter_fee),
+ GNUNET_JSON_spec_string ("h_contract_terms", &key),
+ GNUNET_JSON_spec_end ()
+ };
+
+ map = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
+ deposits = json_object_get (result, "deposits");
+
+ json_array_foreach (deposits, index, value)
+ {
+ if (GNUNET_OK != GNUNET_JSON_parse (value,
+ spec,
+ NULL,
+ NULL))
+ {
+ GNUNET_break_op (0);
+ return NULL;
+ }
+
+ GNUNET_CRYPTO_hash_from_string (key, &h_key);
+
+ if (NULL != (current_entry = GNUNET_CONTAINER_multihashmap_get (map,
(const struct GNUNET_HashCode *) &h_key)))
+ {
+ /*The map already knows this h_contract_terms*/
+ if ((GNUNET_SYSERR == TALER_amount_add (¤t_entry->deposit_value,
+ ¤t_entry->deposit_value,
+ &iter_value)) ||
+ (GNUNET_SYSERR == TALER_amount_add (¤t_entry->deposit_fee,
+ ¤t_entry->deposit_fee,
+ &iter_fee)))
+ goto cleanup;
+ }
+ else
+ {
+ /*First time in the map for this h_contract_terms*/
+ current_entry = GNUNET_malloc (sizeof (struct Entry));
+ memcpy (¤t_entry->deposit_value, &iter_value, sizeof (struct
TALER_Amount));
+ memcpy (¤t_entry->deposit_fee, &iter_fee, sizeof (struct
TALER_Amount));
+
+ if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (map,
+ (const struct
GNUNET_HashCode *) &h_key,
+ current_entry,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ goto cleanup;
+ }
+ }
+ deposits_response = json_array ();
+
+ if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_iterate (map,
+
build_deposits_response,
+ rctx))
+ goto cleanup;
+
+
+ result_mod = json_copy ((struct json_t *) result);
+ json_object_del (result_mod, "deposits");
+ json_object_set (result_mod, "deposits_sums", deposits_response);
+
+ goto cleanup;
+
+ cleanup:
+ GNUNET_CONTAINER_multihashmap_iterate (map,
+ &hashmap_free,
+ NULL);
+ GNUNET_JSON_parse_free (spec);
+ GNUNET_CONTAINER_multihashmap_destroy (map);
+ return result_mod;
+}
/**
* Resume the given /track/transfer operation and send the given response.
@@ -215,7 +398,7 @@ track_transfer_cleanup (struct TM_HandlerContext *hc)
*/
static void
check_transfer (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_Amount *amount_with_fee,
const struct TALER_Amount *deposit_fee,
@@ -244,7 +427,7 @@ check_transfer (void *cls,
"conflict_offset", (json_int_t)
rctx->current_offset,
"exchange_transfer_proof",
rctx->original_response,
"coin_pub", GNUNET_JSON_from_data_auto
(coin_pub),
- "h_proposal_data",
GNUNET_JSON_from_data_auto (&ttd->h_proposal_data),
+ "h_contract_terms",
GNUNET_JSON_from_data_auto (&ttd->h_contract_terms),
"amount_with_fee", TALER_JSON_from_amount
(amount_with_fee),
"deposit_fee", TALER_JSON_from_amount
(deposit_fee));
return;
@@ -287,6 +470,7 @@ wire_transfer_cb (void *cls,
struct TrackTransferContext *rctx = cls;
unsigned int i;
int ret;
+ json_t *jresponse;
rctx->wdh = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -330,7 +514,7 @@ wire_transfer_cb (void *cls,
rctx->current_detail = &details[i];
rctx->check_transfer_result = GNUNET_NO;
ret = db->find_payments_by_hash_and_coin (db->cls,
- &details[i].h_proposal_data,
+ &details[i].h_contract_terms,
&rctx->mi->pubkey,
&details[i].coin_pub,
&check_transfer,
@@ -386,7 +570,7 @@ wire_transfer_cb (void *cls,
/* Response is consistent with the /deposit we made, remember
it for future reference */
ret = db->store_coin_to_transfer (db->cls,
- &details[i].h_proposal_data,
+ &details[i].h_contract_terms,
&details[i].coin_pub,
&rctx->wtid);
if (GNUNET_OK != ret)
@@ -403,10 +587,24 @@ wire_transfer_cb (void *cls,
}
}
rctx->original_response = NULL;
- resume_track_transfer_with_response
- (rctx,
- MHD_HTTP_OK,
- TMH_RESPONSE_make_json (json));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "About to call tracks transformator.\n");
+
+ if (NULL == (jresponse = transform_response (json, rctx)))
+ {
+ resume_track_transfer_with_response
+ (rctx,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TMH_RESPONSE_make_internal_error
(TALER_EC_TRACK_TRANSFER_JSON_RESPONSE_ERROR,
+ "Fail to elaborate the response."));
+ return;
+ }
+
+ resume_track_transfer_with_response (rctx,
+ MHD_HTTP_OK,
+ TMH_RESPONSE_make_json (jresponse));
+ json_decref (jresponse);
}
@@ -485,9 +683,18 @@ proof_cb (void *cls,
const json_t *proof)
{
struct TrackTransferContext *rctx = cls;
+ json_t *transformed_response;
+
+ if (NULL == (transformed_response = transform_response (proof, rctx)))
+ {
+ rctx->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ rctx->response = TMH_RESPONSE_make_internal_error
(TALER_EC_TRACK_TRANSFER_JSON_RESPONSE_ERROR,
+ "Fail to elaborate
response.");
+ return;
+ }
rctx->response_code = MHD_HTTP_OK;
- rctx->response = TMH_RESPONSE_make_json (proof);
+ rctx->response = TMH_RESPONSE_make_json (transformed_response);
}
diff --git a/src/backenddb/plugin_merchantdb_postgres.c
b/src/backenddb/plugin_merchantdb_postgres.c
index 5381888..5299690 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -18,6 +18,7 @@
* @brief database helper functions for postgres used by the merchant
* @author Sree Harsha Totakura <address@hidden>
* @author Christian Grothoff
+ * @author Marcello Stanisci
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
@@ -146,7 +147,7 @@ postgres_drop_tables (void *cls)
PG_EXEC_INDEX (pg, "DROP TABLE merchant_deposits;");
PG_EXEC_INDEX (pg, "DROP TABLE merchant_transactions;");
PG_EXEC_INDEX (pg, "DROP TABLE merchant_proofs;");
- PG_EXEC_INDEX (pg, "DROP TABLE merchant_proposal_data;");
+ PG_EXEC_INDEX (pg, "DROP TABLE merchant_contract_terms;");
return GNUNET_OK;
}
@@ -164,18 +165,19 @@ postgres_initialize (void *cls)
/* Setup tables */
PG_EXEC (pg,
- "CREATE TABLE IF NOT EXISTS merchant_proposal_data ("
+ "CREATE TABLE IF NOT EXISTS merchant_contract_terms ("
"order_id VARCHAR NOT NULL"
",merchant_pub BYTEA NOT NULL"
- ",proposal_data BYTEA NOT NULL"
- ",h_proposal_data BYTEA NOT NULL"
+ ",contract_terms BYTEA NOT NULL"
+ ",h_contract_terms BYTEA NOT NULL"
",timestamp INT8 NOT NULL"
+ ",row_id BIGSERIAL"
",PRIMARY KEY (order_id, merchant_pub)"
");");
PG_EXEC (pg,
"CREATE TABLE IF NOT EXISTS merchant_transactions ("
- " h_proposal_data BYTEA NOT NULL"
+ " h_contract_terms BYTEA NOT NULL"
",exchange_uri VARCHAR NOT NULL"
",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)"
",h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64)"
@@ -184,13 +186,13 @@ postgres_initialize (void *cls)
",total_amount_val INT8 NOT NULL"
",total_amount_frac INT4 NOT NULL"
",total_amount_curr VARCHAR(" TALER_CURRENCY_LEN_STR ") NOT NULL"
- ",PRIMARY KEY (h_proposal_data, merchant_pub)"
+ ",PRIMARY KEY (h_contract_terms, merchant_pub)"
");");
PG_EXEC (pg,
"CREATE TABLE IF NOT EXISTS merchant_deposits ("
- " h_proposal_data BYTEA NOT NULL"
+ " h_contract_terms BYTEA NOT NULL"
",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)"
- ",FOREIGN KEY (h_proposal_data, merchant_pub) REFERENCES
merchant_transactions (h_proposal_data, merchant_pub)"
+ ",FOREIGN KEY (h_contract_terms, merchant_pub) REFERENCES
merchant_transactions (h_contract_terms, merchant_pub)"
",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)"
",amount_with_fee_val INT8 NOT NULL"
",amount_with_fee_frac INT4 NOT NULL"
@@ -200,7 +202,7 @@ postgres_initialize (void *cls)
",deposit_fee_curr VARCHAR(" TALER_CURRENCY_LEN_STR ") NOT NULL"
",signkey_pub BYTEA NOT NULL CHECK (LENGTH(signkey_pub)=32)"
",exchange_proof BYTEA NOT NULL"
- ",PRIMARY KEY (h_proposal_data, coin_pub)"
+ ",PRIMARY KEY (h_contract_terms, coin_pub)"
");");
PG_EXEC (pg,
"CREATE TABLE IF NOT EXISTS merchant_proofs ("
@@ -211,19 +213,19 @@ postgres_initialize (void *cls)
",proof BYTEA NOT NULL"
",PRIMARY KEY (wtid, exchange_uri)"
");");
- /* Note that transaction_id + coin_pub may actually be unknown to
+ /* Note that h_contract_terms + coin_pub may actually be unknown to
us, e.g. someone else deposits something for us at the exchange.
Hence those cannot be foreign keys into deposits/transactions! */
PG_EXEC (pg,
"CREATE TABLE IF NOT EXISTS merchant_transfers ("
- " h_proposal_data BYTEA NOT NULL"
+ " h_contract_terms BYTEA NOT NULL"
",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)"
",wtid BYTEA NOT NULL CHECK (LENGTH(wtid)=32)"
- ",PRIMARY KEY (h_proposal_data, coin_pub)"
+ ",PRIMARY KEY (h_contract_terms, coin_pub)"
");");
PG_EXEC_INDEX (pg,
"CREATE INDEX IF NOT EXISTS merchant_transfers_by_coin"
- " ON merchant_transfers (transaction_id, coin_pub)");
+ " ON merchant_transfers (h_contract_terms, coin_pub)");
PG_EXEC_INDEX (pg,
"CREATE INDEX IF NOT EXISTS merchant_transfers_by_wtid"
" ON merchant_transfers (wtid)");
@@ -232,7 +234,7 @@ postgres_initialize (void *cls)
PG_PREPARE (pg,
"insert_transaction",
"INSERT INTO merchant_transactions"
- "(h_proposal_data"
+ "(h_contract_terms"
",exchange_uri"
",merchant_pub"
",h_wire"
@@ -247,7 +249,7 @@ postgres_initialize (void *cls)
PG_PREPARE (pg,
"insert_deposit",
"INSERT INTO merchant_deposits"
- "(h_proposal_data"
+ "(h_contract_terms"
",merchant_pub"
",coin_pub"
",amount_with_fee_val"
@@ -263,7 +265,7 @@ postgres_initialize (void *cls)
PG_PREPARE (pg,
"insert_transfer",
"INSERT INTO merchant_transfers"
- "(h_proposal_data"
+ "(h_contract_terms"
",coin_pub"
",wtid) VALUES "
"($1, $2, $3)",
@@ -280,48 +282,80 @@ postgres_initialize (void *cls)
5);
PG_PREPARE (pg,
- "insert_proposal_data",
- "INSERT INTO merchant_proposal_data"
+ "insert_contract_terms",
+ "INSERT INTO merchant_contract_terms"
"(order_id"
",merchant_pub"
",timestamp"
- ",proposal_data"
- ",h_proposal_data)"
+ ",contract_terms"
+ ",h_contract_terms)"
" VALUES "
"($1, $2, $3, $4, $5)",
4);
PG_PREPARE (pg,
- "find_proposal_data_from_hash",
+ "find_contract_terms_from_hash",
"SELECT"
- " proposal_data"
- " FROM merchant_proposal_data"
+ " contract_terms"
+ " FROM merchant_contract_terms"
" WHERE"
- " h_proposal_data=$1"
+ " h_contract_terms=$1"
" AND merchant_pub=$2",
2);
PG_PREPARE (pg,
- "find_proposal_data",
+ "find_contract_terms",
"SELECT"
- " proposal_data"
- " FROM merchant_proposal_data"
+ " contract_terms"
+ " FROM merchant_contract_terms"
" WHERE"
" order_id=$1"
" AND merchant_pub=$2",
2);
PG_PREPARE (pg,
- "find_proposal_data_by_date",
+ "find_contract_terms_by_date",
"SELECT"
- " proposal_data"
+ " contract_terms"
",order_id"
- " FROM merchant_proposal_data"
+ ",row_id"
+ " FROM merchant_contract_terms"
" WHERE"
- " timestamp>=$1"
+ " timestamp<$1"
" AND merchant_pub=$2"
- " ORDER BY timestamp DESC",
- 2);
+ " ORDER BY row_id DESC, timestamp DESC"
+ " LIMIT $3",
+ 3);
+
+ PG_PREPARE (pg,
+ "find_contract_terms_by_date_and_range",
+ "SELECT"
+ " contract_terms"
+ ",order_id"
+ ",row_id"
+ " FROM merchant_contract_terms"
+ " WHERE"
+ " timestamp<$1"
+ " AND merchant_pub=$2"
+ " AND row_id<$3"
+ " ORDER BY row_id DESC, timestamp DESC"
+ " LIMIT $4",
+ 4);
+
+ PG_PREPARE (pg,
+ "find_contract_terms_by_date_and_range_future",
+ "SELECT"
+ " contract_terms"
+ ",order_id"
+ ",row_id"
+ " FROM merchant_contract_terms"
+ " WHERE"
+ " timestamp>$1"
+ " AND merchant_pub=$2"
+ " AND row_id>$3"
+ " ORDER BY row_id DESC, timestamp DESC"
+ " LIMIT $4",
+ 4);
/* Setup prepared "SELECT" statements */
PG_PREPARE (pg,
@@ -335,7 +369,7 @@ postgres_initialize (void *cls)
",total_amount_frac"
",total_amount_curr"
" FROM merchant_transactions"
- " WHERE h_proposal_data=$1"
+ " WHERE h_contract_terms=$1"
" AND merchant_pub=$2",
2);
PG_PREPARE (pg,
@@ -350,11 +384,11 @@ postgres_initialize (void *cls)
",deposit_fee_curr"
",exchange_proof"
" FROM merchant_deposits"
- " WHERE h_proposal_data=$1"
+ " WHERE h_contract_terms=$1"
" AND merchant_pub=$2",
2);
PG_PREPARE (pg,
- "find_deposits_by_tid_and_coin",
+ "find_deposits_by_hash_and_coin",
"SELECT"
" amount_with_fee_val"
",amount_with_fee_frac"
@@ -364,7 +398,7 @@ postgres_initialize (void *cls)
",deposit_fee_curr"
",exchange_proof"
" FROM merchant_deposits"
- " WHERE h_proposal_data=$1"
+ " WHERE h_contract_terms=$1"
" AND merchant_pub=$2"
" AND coin_pub=$3",
3);
@@ -377,12 +411,12 @@ postgres_initialize (void *cls)
",merchant_proofs.proof"
" FROM merchant_transfers"
" JOIN merchant_proofs USING (wtid)"
- " WHERE h_proposal_data=$1",
+ " WHERE h_contract_terms=$1",
1);
PG_PREPARE (pg,
"find_deposits_by_wtid",
"SELECT"
- " merchant_transfers.h_proposal_data"
+ " merchant_transfers.h_contract_terms"
",merchant_transfers.coin_pub"
",merchant_deposits.amount_with_fee_val"
",merchant_deposits.amount_with_fee_frac"
@@ -393,7 +427,7 @@ postgres_initialize (void *cls)
",merchant_deposits.exchange_proof"
" FROM merchant_transfers"
" JOIN merchant_deposits"
- " ON (merchant_deposits.h_proposal_data =
merchant_transfers.h_proposal_data"
+ " ON (merchant_deposits.h_contract_terms =
merchant_transfers.h_contract_terms"
" AND"
" merchant_deposits.coin_pub =
merchant_transfers.coin_pub)"
" WHERE wtid=$1",
@@ -410,19 +444,19 @@ postgres_initialize (void *cls)
}
/**
- * Retrieve proposal data given its transaction id's hashcode
+ * Retrieve proposal data given its proposal data's hashcode
*
* @param cls closure
- * @param h_transaction_id hashcode of the transaction id mentioned in this
- * proposal data
- * @param proposal_data where to store the retrieved proposal data
- * @return #GNUNET_OK on success, #GNUNET_NO if no contract is
+ * @param contract_terms where to store the retrieved proposal data
+ * @param h_contract_terms proposal data's hashcode that will be used to
+ * perform the lookup
+ * @return #GNUNET_OK on success, #GNUNET_NO if no proposal is
* found, #GNUNET_SYSERR upon error
*/
static int
-postgres_find_proposal_data_from_hash (void *cls,
- json_t **proposal_data,
- const struct GNUNET_HashCode
*h_proposal_data,
+postgres_find_contract_terms_from_hash (void *cls,
+ json_t **contract_terms,
+ const struct GNUNET_HashCode
*h_contract_terms,
const struct TALER_MerchantPublicKeyP
*merchant_pub)
{
struct PostgresClosure *pg = cls;
@@ -430,13 +464,13 @@ postgres_find_proposal_data_from_hash (void *cls,
unsigned int i;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_proposal_data),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_end
};
result = GNUNET_PQ_exec_prepared (pg->conn,
- "find_proposal_data_from_hash",
+ "find_contract_terms_from_hash",
params);
i = PQntuples (result);
if (1 < i)
@@ -450,8 +484,8 @@ postgres_find_proposal_data_from_hash (void *cls,
return GNUNET_NO;
struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_result_spec_json ("proposal_data",
- proposal_data),
+ TALER_PQ_result_spec_json ("contract_terms",
+ contract_terms),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
@@ -469,18 +503,17 @@ postgres_find_proposal_data_from_hash (void *cls,
/**
- * Retrieve proposal data given its transaction id's hashcode
+ * Retrieve proposal data given its order id.
*
* @param cls closure
- * @param h_transaction_id hashcode of the transaction id mentioned in this
- * proposal data
- * @param proposal_data where to store the retrieved proposal data
- * @return #GNUNET_OK on success, #GNUNET_NO if no contract is
+ * @param contract_terms where to store the retrieved proposal data
+ * @param order id order id used to perform the lookup
+ * @return #GNUNET_OK on success, #GNUNET_NO if no proposal is
* found, #GNUNET_SYSERR upon error
*/
static int
-postgres_find_proposal_data (void *cls,
- json_t **proposal_data,
+postgres_find_contract_terms (void *cls,
+ json_t **contract_terms,
const char *order_id,
const struct TALER_MerchantPublicKeyP
*merchant_pub)
{
@@ -495,7 +528,7 @@ postgres_find_proposal_data (void *cls,
};
result = GNUNET_PQ_exec_prepared (pg->conn,
- "find_proposal_data",
+ "find_contract_terms",
params);
i = PQntuples (result);
if (1 < i)
@@ -509,8 +542,8 @@ postgres_find_proposal_data (void *cls,
return GNUNET_NO;
struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_result_spec_json ("proposal_data",
- proposal_data),
+ TALER_PQ_result_spec_json ("contract_terms",
+ contract_terms),
GNUNET_PQ_result_spec_end
};
if (GNUNET_OK !=
@@ -528,47 +561,46 @@ postgres_find_proposal_data (void *cls,
/**
- * Insert proposal data and its transaction id's hashcode into db
+ * Insert proposal data and its hashcode into db
*
* @param cls closure
- * @param h_transaction_id hashcode of the transaction id mentioned in this
- * proposal data
- * @param proposal_data proposal data to store
+ * @param order_id identificator of the proposal being stored
+ * @param contract_terms proposal data to store
* @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
*/
static int
-postgres_insert_proposal_data (void *cls,
+postgres_insert_contract_terms (void *cls,
const char *order_id,
const struct TALER_MerchantPublicKeyP
*merchant_pub,
struct GNUNET_TIME_Absolute timestamp,
- const json_t *proposal_data)
+ const json_t *contract_terms)
{
struct PostgresClosure *pg = cls;
PGresult *result;
int ret;
- struct GNUNET_HashCode h_proposal_data;
+ struct GNUNET_HashCode h_contract_terms;
- if (GNUNET_OK != TALER_JSON_hash (proposal_data,
- &h_proposal_data))
+ if (GNUNET_OK != TALER_JSON_hash (contract_terms,
+ &h_contract_terms))
return GNUNET_SYSERR;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (order_id),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_absolute_time (×tamp),
- TALER_PQ_query_param_json (proposal_data),
- GNUNET_PQ_query_param_auto_from_type (&h_proposal_data),
+ TALER_PQ_query_param_json (contract_terms),
+ GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
GNUNET_PQ_query_param_end
};
result = GNUNET_PQ_exec_prepared (pg->conn,
- "insert_proposal_data",
+ "insert_contract_terms",
params);
/**
* We don't treat a unique_violation (code '23505') error as
* an actual error, since there is no problem if a frontend tries
- * to store twice the same contract. That is especially needed
+ * to store twice the same proposal. That is especially needed
* when DB-less frontends perform replayed payments.
*/
if (PGRES_COMMAND_OK != PQresultStatus (result)
@@ -591,7 +623,8 @@ postgres_insert_proposal_data (void *cls,
* Insert transaction data into the database.
*
* @param cls closure
- * @param transaction_id of the proposal
+ * @param h_contract_terms hashcode of the proposal data associated with the
+ * transaction being stored
* @param merchant_pub merchant's public key
* @param exchange_uri URI of the exchange
* @param h_wire hash of our wire details
@@ -602,7 +635,7 @@ postgres_insert_proposal_data (void *cls,
*/
static int
postgres_store_transaction (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const char *exchange_uri,
const struct GNUNET_HashCode *h_wire,
@@ -615,7 +648,7 @@ postgres_store_transaction (void *cls,
int ret;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_proposal_data),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_string (exchange_uri),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_auto_from_type (h_wire),
@@ -626,8 +659,8 @@ postgres_store_transaction (void *cls,
};
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Storing transaction with h_proposal_data '%s'\n",
- GNUNET_h2s (h_proposal_data));
+ "Storing transaction with h_contract_terms '%s'\n",
+ GNUNET_h2s (h_contract_terms));
result = GNUNET_PQ_exec_prepared (pg->conn,
"insert_transaction",
@@ -650,7 +683,7 @@ postgres_store_transaction (void *cls,
* Insert payment confirmation from the exchange into the database.
*
* @param cls closure
- * @param transaction_id of the contract
+ * @param order_id identificator of the proposal associated with this revenue
* @param merchant_pub merchant's public key
* @param coin_pub public key of the coin
* @param amount_with_fee amount the exchange will deposit for this coin
@@ -661,7 +694,7 @@ postgres_store_transaction (void *cls,
*/
static int
postgres_store_deposit (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_Amount *amount_with_fee,
@@ -674,7 +707,7 @@ postgres_store_deposit (void *cls,
int ret;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_proposal_data),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_auto_from_type (coin_pub),
TALER_PQ_query_param_amount (amount_with_fee),
@@ -685,8 +718,8 @@ postgres_store_deposit (void *cls,
};
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "storing payment for h_proposal_data '%s'\n",
- GNUNET_h2s (h_proposal_data));
+ "storing payment for h_contract_terms '%s'\n",
+ GNUNET_h2s (h_contract_terms));
result = GNUNET_PQ_exec_prepared (pg->conn,
"insert_deposit",
params);
@@ -705,11 +738,11 @@ postgres_store_deposit (void *cls,
/**
- * Insert mapping of @a coin_pub and @a transaction_id to
+ * Insert mapping of @a coin_pub and @a h_contract_terms to
* corresponding @a wtid.
*
* @param cls closure
- * @param transaction_id ID of the contract
+ * @param h_contract_terms hashcode of the proposal data paid by @a coin_pub
* @param coin_pub public key of the coin
* @param wtid identifier of the wire transfer in which the exchange
* send us the money for the coin deposit
@@ -717,7 +750,7 @@ postgres_store_deposit (void *cls,
*/
static int
postgres_store_coin_to_transfer (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode
*h_contract_terms,
const struct TALER_CoinSpendPublicKeyP
*coin_pub,
const struct TALER_WireTransferIdentifierRawP
*wtid)
{
@@ -726,7 +759,7 @@ postgres_store_coin_to_transfer (void *cls,
int ret;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_proposal_data),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_auto_from_type (coin_pub),
GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_end
@@ -798,22 +831,205 @@ postgres_store_transfer_to_proof (void *cls,
}
/**
- * Return transactions younger than the given date
+ * Lookup for a proposal, respecting the signature used by the
+ * /history's db methods.
*
- * @param cls our plugin handle
- * @param date limit to transactions' age
- * @param cb function to call with transaction data, can be NULL
+ * @param cls db plugin handle
+ * @param order_id order id used to search for the proposal data
+ * @param merchant_pub public key of the merchant using this method
+ * @param cb the callback
+ * @param cb_cls closure to pass to the callback
+ * @return GNUNET_YES, GNUNET_NO, GNUNET_SYSERR according to the
+ * query being successful, unsuccessful, or generated errors.
+ */
+static int
+postgres_find_contract_terms_history (void *cls,
+ const char *order_id,
+ const struct TALER_MerchantPublicKeyP
*merchant_pub,
+ TALER_MERCHANTDB_ProposalDataCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ PGresult *result;
+ unsigned int i;
+ json_t *contract_terms;
+
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_end
+ };
+
+ result = GNUNET_PQ_exec_prepared (pg->conn,
+ "find_contract_terms",
+ params);
+ i = PQntuples (result);
+ if (1 < i)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Mupltiple proposal data share the same hashcode.\n");
+ return GNUNET_SYSERR;
+ }
+
+ if (0 == i)
+ return GNUNET_NO;
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_json ("contract_terms",
+ &contract_terms),
+ GNUNET_PQ_result_spec_end
+ };
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ cb (cb_cls,
+ order_id,
+ 0,
+ contract_terms);
+
+ PQclear (result);
+ return GNUNET_OK;
+
+}
+
+
+/**
+ * Return proposals whose timestamp are older than `date`.
+ * Among those proposals, only those ones being between the
+ * start-th and (start-nrows)-th record are returned. The rows
+ * are sorted having the youngest first.
+ *
+ * @param cls our plugin handle.
+ * @param date only results older than this date are returned.
+ * @param merchant_pub instance's public key; only rows related to this
+ * instance are returned.
+ * @param start only rows with serial id less than start are returned.
+ * In other words, you lower `start` to get older records. The tipical
+ * usage is to firstly call `find_contract_terms_by_date`, so that you get
+ * the `nrows` youngest records. The oldest of those records will tell you
+ * from which timestamp and `start` you can query the DB in order to get
+ * furtherly older records, and so on. Alternatively, you can use always
+ * the same timestamp and just go behind in history by tuning `start`.
+ * @param nrows only nrows rows are returned.
+ * @param future if set to GNUNET_YES, retrieves rows younger than `date`.
+ * This is tipically used to show live updates on the merchant's backoffice
+ * Web interface.
+ * @param cb function to call with transaction data, can be NULL.
* @param cb_cls closure for @a cb
* @return numer of found tuples, #GNUNET_SYSERR upon error
*/
static int
-postgres_find_proposal_data_by_date (void *cls,
+postgres_find_contract_terms_by_date_and_range (void *cls,
+ struct GNUNET_TIME_Absolute
date,
+ const struct
TALER_MerchantPublicKeyP *merchant_pub,
+ unsigned int start,
+ unsigned int nrows,
+ unsigned int future,
+
TALER_MERCHANTDB_ProposalDataCallback cb,
+ void *cb_cls)
+{
+ uint64_t s64 = start;
+ uint64_t r64 = nrows;
+ struct PostgresClosure *pg = cls;
+ PGresult *result;
+ unsigned int n;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_absolute_time (&date),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_uint64 (&s64),
+ GNUNET_PQ_query_param_uint64 (&r64),
+ GNUNET_PQ_query_param_end
+ };
+
+ if (GNUNET_YES == future)
+ result = GNUNET_PQ_exec_prepared (pg->conn,
+
"find_contract_terms_by_date_and_range_future",
+ params);
+ else
+ result = GNUNET_PQ_exec_prepared (pg->conn,
+ "find_contract_terms_by_date_and_range",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if ( (0 == (n = PQntuples (result))) ||
+ (NULL == cb) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "No records found.\n");
+ PQclear (result);
+ return n;
+ }
+ for (unsigned int i = 0; i < n; i++)
+ {
+ char *order_id;
+ json_t *contract_terms;
+ uint64_t row_id;
+
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("order_id",
+ &order_id),
+ TALER_PQ_result_spec_json ("contract_terms",
+ &contract_terms),
+ GNUNET_PQ_result_spec_uint64 ("row_id",
+ &row_id),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ order_id,
+ row_id,
+ contract_terms);
+
+ GNUNET_PQ_cleanup_result (rs);
+ }
+ PQclear (result);
+ return n;
+}
+
+
+/**
+ * Return proposals whose timestamp are older than `date`.
+ * The rows are sorted having the youngest first.
+ *
+ * @param cls our plugin handle.
+ * @param date only results older than this date are returned.
+ * @param merchant_pub instance's public key; only rows related to this
+ * instance are returned.
+ * @param nrows at most nrows rows are returned.
+ * @param cb function to call with transaction data, can be NULL.
+ * @param cb_cls closure for @a cb
+ * @return numer of found tuples, #GNUNET_SYSERR upon error
+ */
+static int
+postgres_find_contract_terms_by_date (void *cls,
struct GNUNET_TIME_Absolute date,
const struct TALER_MerchantPublicKeyP
*merchant_pub,
+ unsigned int nrows,
TALER_MERCHANTDB_ProposalDataCallback cb,
void *cb_cls)
{
+ uint64_t r64 = nrows;
struct PostgresClosure *pg = cls;
PGresult *result;
unsigned int n;
@@ -822,10 +1038,11 @@ postgres_find_proposal_data_by_date (void *cls,
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_absolute_time (&date),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_uint64 (&r64),
GNUNET_PQ_query_param_end
};
result = GNUNET_PQ_exec_prepared (pg->conn,
- "find_proposal_data_by_date",
+ "find_contract_terms_by_date",
params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
@@ -841,13 +1058,16 @@ postgres_find_proposal_data_by_date (void *cls,
for (i = 0; i < n; i++)
{
char *order_id;
- json_t *proposal_data;
+ json_t *contract_terms;
+ uint64_t row_id;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_string ("order_id",
&order_id),
- TALER_PQ_result_spec_json ("proposal_data",
- &proposal_data),
+ TALER_PQ_result_spec_json ("contract_terms",
+ &contract_terms),
+ GNUNET_PQ_result_spec_uint64 ("row_id",
+ &row_id),
GNUNET_PQ_result_spec_end
};
@@ -862,7 +1082,8 @@ postgres_find_proposal_data_by_date (void *cls,
}
cb (cb_cls,
order_id,
- proposal_data);
+ row_id,
+ contract_terms);
GNUNET_PQ_cleanup_result (rs);
}
@@ -874,9 +1095,8 @@ postgres_find_proposal_data_by_date (void *cls,
* Find information about a transaction.
*
* @param cls our plugin handle
- * @param transaction_id the transaction id to search
- * @param merchant_pub merchant's public key. It's AND'd with transaction_id
- * in order to find the result.
+ * @param h_contract_terms value used to perform the lookup
+ * @param merchant_pub merchant's public key
* @param cb function to call with transaction data
* @param cb_cls closure for @a cb
* @return #GNUNET_OK if found, #GNUNET_NO if not, #GNUNET_SYSERR
@@ -884,7 +1104,7 @@ postgres_find_proposal_data_by_date (void *cls,
*/
static int
postgres_find_transaction (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_MerchantPublicKeyP *merchant_pub,
TALER_MERCHANTDB_TransactionCallback cb,
void *cb_cls)
@@ -892,14 +1112,14 @@ postgres_find_transaction (void *cls,
struct PostgresClosure *pg = cls;
PGresult *result;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_proposal_data),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_end
};
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Finding transaction for h_proposal_data '%s'\n",
- GNUNET_h2s (h_proposal_data));
+ "Finding transaction for h_contract_terms '%s'\n",
+ GNUNET_h2s (h_contract_terms));
result = GNUNET_PQ_exec_prepared (pg->conn,
"find_transaction",
@@ -913,8 +1133,8 @@ postgres_find_transaction (void *cls,
if (0 == PQntuples (result))
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Could NOT find transaction for h_proposal_data '%s'\n",
- GNUNET_h2s (h_proposal_data));
+ "Could NOT find transaction for h_contract_terms '%s'\n",
+ GNUNET_h2s (h_contract_terms));
PQclear (result);
return GNUNET_NO;
@@ -958,7 +1178,7 @@ postgres_find_transaction (void *cls,
cb (cb_cls,
merchant_pub,
exchange_uri,
- h_proposal_data,
+ h_contract_terms,
&h_wire,
timestamp,
refund_deadline,
@@ -971,10 +1191,11 @@ postgres_find_transaction (void *cls,
/**
- * Lookup information about coin payments by transaction ID (and @a
merchant_pub)
+ * Lookup information about coin payments by proposal data hash
+ * (and @a merchant_pub)
*
* @param cls closure
- * @param transaction_id key for the search
+ * @param h_contract_terms key for the search
* @param merchant_pub merchant's public key
* @param cb function to call with payment data
* @param cb_cls closure for @a cb
@@ -983,7 +1204,7 @@ postgres_find_transaction (void *cls,
*/
static int
postgres_find_payments (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_MerchantPublicKeyP *merchant_pub,
TALER_MERCHANTDB_CoinDepositCallback cb,
void *cb_cls)
@@ -993,13 +1214,13 @@ postgres_find_payments (void *cls,
unsigned int i;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_proposal_data),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_end
};
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "finding payment for h_proposal_data '%s'\n",
- GNUNET_h2s (h_proposal_data));
+ "finding payment for h_contract_terms '%s'\n",
+ GNUNET_h2s (h_contract_terms));
result = GNUNET_PQ_exec_prepared (pg->conn,
"find_deposits",
params);
@@ -1044,7 +1265,7 @@ postgres_find_payments (void *cls,
return GNUNET_SYSERR;
}
cb (cb_cls,
- h_proposal_data,
+ h_contract_terms,
&coin_pub,
&amount_with_fee,
&deposit_fee,
@@ -1060,13 +1281,12 @@ postgres_find_payments (void *cls,
/**
- * Lookup information about coin payments by transaction ID.
+ * Retrieve information about a deposited coin.
*
* @param cls closure
- * @param transaction_id key for the search
- * @param merchant_pub merchant's public key. It's AND'd with @a transaction_id
- * in order to find the result.
- * @param coin_pub public key to use for the search
+ * @param h_contract_terms hashcode of the proposal data paid by @a coin_pub
+ * @param merchant_pub merchant's public key.
+ * @param coin_pub coin's public key used for the search
* @param cb function to call with payment data
* @param cb_cls closure for @a cb
* @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
@@ -1074,7 +1294,7 @@ postgres_find_payments (void *cls,
*/
static int
postgres_find_payments_by_hash_and_coin (void *cls,
- const struct GNUNET_HashCode
*h_proposal_data,
+ const struct GNUNET_HashCode
*h_contract_terms,
const struct TALER_MerchantPublicKeyP
*merchant_pub,
const struct
TALER_CoinSpendPublicKeyP *coin_pub,
TALER_MERCHANTDB_CoinDepositCallback
cb,
@@ -1085,14 +1305,14 @@ postgres_find_payments_by_hash_and_coin (void *cls,
unsigned int i;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_proposal_data),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_auto_from_type (coin_pub),
GNUNET_PQ_query_param_end
};
result = GNUNET_PQ_exec_prepared (pg->conn,
- "find_deposits_by_tid_and_coin",
+ "find_deposits_by_hash_and_coin",
params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
@@ -1132,7 +1352,7 @@ postgres_find_payments_by_hash_and_coin (void *cls,
return GNUNET_SYSERR;
}
cb (cb_cls,
- h_proposal_data,
+ h_contract_terms,
coin_pub,
&amount_with_fee,
&deposit_fee,
@@ -1148,14 +1368,14 @@ postgres_find_payments_by_hash_and_coin (void *cls,
/**
- * Lookup information about a transfer by @a transaction_id. Note
+ * Lookup information about a transfer by @a h_contract_terms. Note
* that in theory there could be multiple wire transfers for a
- * single @a transaction_id, as the transaction may have involved
+ * single @a h_contract_terms, as the transaction may have involved
* multiple coins and the coins may be spread over different wire
* transfers.
*
* @param cls closure
- * @param transaction_id key for the search
+ * @param h_contract_terms key for the search
* @param cb function to call with transfer data
* @param cb_cls closure for @a cb
* @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
@@ -1163,7 +1383,7 @@ postgres_find_payments_by_hash_and_coin (void *cls,
*/
static int
postgres_find_transfers_by_hash (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode
*h_contract_terms,
TALER_MERCHANTDB_TransferCallback cb,
void *cb_cls)
{
@@ -1172,7 +1392,7 @@ postgres_find_transfers_by_hash (void *cls,
unsigned int i;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_proposal_data),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_end
};
result = GNUNET_PQ_exec_prepared (pg->conn,
@@ -1219,7 +1439,7 @@ postgres_find_transfers_by_hash (void *cls,
return GNUNET_SYSERR;
}
cb (cb_cls,
- h_proposal_data,
+ h_contract_terms,
&coin_pub,
&wtid,
execution_time,
@@ -1272,15 +1492,15 @@ postgres_find_deposits_by_wtid (void *cls,
for (i=0;i<PQntuples (result);i++)
{
- struct GNUNET_HashCode h_proposal_data;
+ struct GNUNET_HashCode h_contract_terms;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_Amount amount_with_fee;
struct TALER_Amount deposit_fee;
json_t *exchange_proof;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("h_proposal_data",
- &h_proposal_data),
+ GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
+ &h_contract_terms),
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
&coin_pub),
TALER_PQ_result_spec_amount ("amount_with_fee",
@@ -1302,7 +1522,7 @@ postgres_find_deposits_by_wtid (void *cls,
return GNUNET_SYSERR;
}
cb (cb_cls,
- &h_proposal_data,
+ &h_contract_terms,
&coin_pub,
&amount_with_fee,
&deposit_fee,
@@ -1445,10 +1665,12 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
plugin->find_transfers_by_hash = &postgres_find_transfers_by_hash;
plugin->find_deposits_by_wtid = &postgres_find_deposits_by_wtid;
plugin->find_proof_by_wtid = &postgres_find_proof_by_wtid;
- plugin->insert_proposal_data = &postgres_insert_proposal_data;
- plugin->find_proposal_data = &postgres_find_proposal_data;
- plugin->find_proposal_data_by_date = &postgres_find_proposal_data_by_date;
- plugin->find_proposal_data_from_hash =
&postgres_find_proposal_data_from_hash;
+ plugin->insert_contract_terms = &postgres_insert_contract_terms;
+ plugin->find_contract_terms = &postgres_find_contract_terms;
+ plugin->find_contract_terms_history = &postgres_find_contract_terms_history;
+ plugin->find_contract_terms_by_date = &postgres_find_contract_terms_by_date;
+ plugin->find_contract_terms_by_date_and_range =
&postgres_find_contract_terms_by_date_and_range;
+ plugin->find_contract_terms_from_hash =
&postgres_find_contract_terms_from_hash;
return plugin;
}
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index fe52039..c512651 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -21,6 +21,7 @@
#include "platform.h"
#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
#include "taler_merchantdb_lib.h"
#include <jansson.h>
@@ -70,14 +71,20 @@ static struct GNUNET_HashCode h_wire;
const char *order_id;
/**
+ * Transaction ID used to test the db query
+ * `find_contract_terms_by_date_and_range_future`
+ */
+const char *order_id_future;
+
+/**
* Proposal's hash
*/
-struct GNUNET_HashCode h_proposal_data;
+struct GNUNET_HashCode h_contract_terms;
/**
* Proposal's hash.
*/
-struct GNUNET_HashCode h_proposal_data2;
+struct GNUNET_HashCode h_contract_terms2;
/**
* Time of the transaction.
@@ -143,7 +150,7 @@ static json_t *contract;
/**
* Mock proposal data, not need to be well-formed
*/
-static json_t *proposal_data;
+static json_t *contract_terms;
@@ -163,7 +170,7 @@ static void
transaction_cb (void *cls,
const struct TALER_MerchantPublicKeyP *amerchant_pub,
const char *aexchange_uri,
- const struct GNUNET_HashCode *ah_proposal_data,
+ const struct GNUNET_HashCode *ah_contract_terms,
const struct GNUNET_HashCode *ah_wire,
struct GNUNET_TIME_Absolute atimestamp,
struct GNUNET_TIME_Absolute arefund_deadline,
@@ -173,8 +180,8 @@ transaction_cb (void *cls,
CHECK (0 == memcmp (amerchant_pub,
&merchant_pub,
sizeof (struct TALER_MerchantPublicKeyP)));
- CHECK (0 == memcmp (ah_proposal_data,
- &h_proposal_data,
+ CHECK (0 == memcmp (ah_contract_terms,
+ &h_contract_terms,
sizeof (struct GNUNET_HashCode)));
CHECK (0 == strcmp (aexchange_uri,
EXCHANGE_URI));
@@ -188,16 +195,18 @@ transaction_cb (void *cls,
}
/**
- * Callback for `find_proposal_data_by_date`.
+ * Callback for `find_contract_terms_by_date`.
*
* @param cls closure
* @param order_id order id
- * @param proposal_data proposal data
+ * @param row_id row id in db
+ * @param contract_terms proposal data
*/
static void
pd_cb (void *cls,
const char *order_id,
- const json_t *proposal_data)
+ uint64_t row_id,
+ const json_t *contract_terms)
{
return;
}
@@ -214,14 +223,14 @@ pd_cb (void *cls,
*/
static void
deposit_cb (void *cls,
- const struct GNUNET_HashCode *ah_proposal_data,
+ const struct GNUNET_HashCode *ah_contract_terms,
const struct TALER_CoinSpendPublicKeyP *acoin_pub,
const struct TALER_Amount *aamount_with_fee,
const struct TALER_Amount *adeposit_fee,
const json_t *aexchange_proof)
{
- CHECK ((0 == memcmp (ah_proposal_data,
- &h_proposal_data,
+ CHECK ((0 == memcmp (ah_contract_terms,
+ &h_contract_terms,
sizeof (struct GNUNET_HashCode))));
CHECK (0 == memcmp (acoin_pub,
&coin_pub,
@@ -254,14 +263,14 @@ deposit_cb (void *cls,
*/
static void
transfer_cb (void *cls,
- const struct GNUNET_HashCode *ah_proposal_data,
+ const struct GNUNET_HashCode *ah_contract_terms,
const struct TALER_CoinSpendPublicKeyP *acoin_pub,
const struct TALER_WireTransferIdentifierRawP *awtid,
struct GNUNET_TIME_Absolute execution_time,
const json_t *exchange_proof)
{
- CHECK (0 == memcmp (ah_proposal_data,
- &h_proposal_data,
+ CHECK (0 == memcmp (ah_contract_terms,
+ &h_contract_terms,
sizeof (struct GNUNET_HashCode)));
CHECK (0 == memcmp (acoin_pub,
@@ -321,15 +330,16 @@ run (void *cls)
/* Prepare data for 'store_payment()' */
RND_BLK (&h_wire);
- RND_BLK (&h_proposal_data);
+ RND_BLK (&h_contract_terms);
order_id = "test_ID";
+ order_id_future = "test_ID_future";
RND_BLK (&signkey_pub);
RND_BLK (&merchant_pub);
RND_BLK (&wtid);
- timestamp = GNUNET_TIME_absolute_get();
+ timestamp = GNUNET_TIME_absolute_get ();
GNUNET_TIME_round_abs (×tamp);
delta = GNUNET_TIME_UNIT_MINUTES;
- fake_now = GNUNET_TIME_absolute_subtract (timestamp, delta);
+ fake_now = GNUNET_TIME_absolute_add (timestamp, delta);
refund_deadline = GNUNET_TIME_absolute_get();
GNUNET_TIME_round_abs (&refund_deadline);
GNUNET_assert (GNUNET_OK ==
@@ -350,40 +360,80 @@ run (void *cls)
"test",
json_string ("backenddb test B")));
contract = json_object ();
- proposal_data = json_object ();
+ contract_terms = json_object ();
- TALER_JSON_hash (proposal_data,
- &h_proposal_data2);
+ TALER_JSON_hash (contract_terms,
+ &h_contract_terms2);
FAILIF (GNUNET_OK !=
- plugin->insert_proposal_data (plugin->cls,
+ plugin->insert_contract_terms (plugin->cls,
order_id,
&merchant_pub,
timestamp,
- proposal_data));
+ contract_terms));
json_t *out;
FAILIF (GNUNET_OK !=
- plugin->find_proposal_data (plugin->cls,
- &out, // plain data
+ plugin->find_contract_terms (plugin->cls,
+ &out,
order_id,
&merchant_pub));
FAILIF (GNUNET_OK !=
- plugin->find_proposal_data_from_hash (plugin->cls,
- &out, // plain data
- &h_proposal_data2,
+ plugin->find_contract_terms_history (plugin->cls,
+ order_id,
+ &merchant_pub,
+ pd_cb,
+ NULL));
+
+ FAILIF (GNUNET_OK !=
+ plugin->find_contract_terms_from_hash (plugin->cls,
+ &out,
+ &h_contract_terms2,
&merchant_pub));
FAILIF (1 !=
- plugin->find_proposal_data_by_date (plugin->cls,
+ plugin->find_contract_terms_by_date_and_range (plugin->cls,
+ fake_now,
+ &merchant_pub,
+ 2,
+ 1,
+ GNUNET_NO,
+ pd_cb,
+ NULL));
+ timestamp = GNUNET_TIME_absolute_get ();
+ GNUNET_TIME_round_abs (×tamp);
+
+ FAILIF (GNUNET_OK !=
+ plugin->insert_contract_terms (plugin->cls,
+ order_id_future,
+ &merchant_pub,
+ timestamp,
+ contract_terms));
+
+ fake_now = GNUNET_TIME_absolute_subtract (timestamp, delta);
+
+ FAILIF (2 !=
+ plugin->find_contract_terms_by_date_and_range (plugin->cls,
+ fake_now,
+ &merchant_pub,
+ 0,
+ 5,
+ GNUNET_YES,
+ pd_cb,
+ NULL));
+
+ FAILIF (0 !=
+ plugin->find_contract_terms_by_date (plugin->cls,
fake_now,
&merchant_pub,
+ 1,
pd_cb,
NULL));
+
FAILIF (GNUNET_OK !=
plugin->store_transaction (plugin->cls,
- &h_proposal_data,
+ &h_contract_terms,
&merchant_pub,
EXCHANGE_URI,
&h_wire,
@@ -392,7 +442,7 @@ run (void *cls)
&amount_with_fee));
FAILIF (GNUNET_OK !=
plugin->store_deposit (plugin->cls,
- &h_proposal_data,
+ &h_contract_terms,
&merchant_pub,
&coin_pub,
&amount_with_fee,
@@ -401,7 +451,7 @@ run (void *cls)
deposit_proof));
FAILIF (GNUNET_OK !=
plugin->store_coin_to_transfer (plugin->cls,
- &h_proposal_data,
+ &h_contract_terms,
&coin_pub,
&wtid));
FAILIF (GNUNET_OK !=
@@ -413,20 +463,20 @@ run (void *cls)
transfer_proof));
FAILIF (GNUNET_OK !=
plugin->find_transaction (plugin->cls,
- &h_proposal_data,
+ &h_contract_terms,
&merchant_pub,
&transaction_cb,
NULL));
FAILIF (GNUNET_OK !=
plugin->find_payments (plugin->cls,
- &h_proposal_data,
+ &h_contract_terms,
&merchant_pub,
&deposit_cb,
NULL));
FAILIF (GNUNET_OK !=
plugin->find_transfers_by_hash (plugin->cls,
- &h_proposal_data,
+ &h_contract_terms,
&transfer_cb,
NULL));
FAILIF (GNUNET_OK !=
diff --git a/src/include/taler_merchant_service.h
b/src/include/taler_merchant_service.h
index 68ffe7f..aee46af 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -50,9 +50,9 @@ struct TALER_MERCHANT_ProposalLookupOperation;
* @param cls closure
* @param http_status HTTP response code, 200 indicates success;
* 0 if the backend's reply is bogus (fails to follow the
protocol)
- * @param ec taler-specific error code
+ * @param ec taler-specific error code
* @param obj raw JSON reply, or error details if the request failed
- * @param proposal_data completed contract, NULL on error
+ * @param contract_terms completed contract, NULL on error
* @param sig merchant's signature over the contract, NULL on error
* @param hash proposal data's hashcode, NULL on error
*/
@@ -61,7 +61,7 @@ typedef void
unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *obj,
- const json_t *proposal_data,
+ const json_t *contract_terms,
const struct TALER_MerchantSignatureP *sig,
const struct GNUNET_HashCode *hash);
@@ -88,7 +88,7 @@ typedef void
* backend
* @param proposal_cb the callback to call when a reply for this request is
available
* @param proposal_cb_cls closure for @a proposal_cb
- * @return a handle for this request
+ * @return a handle for this request, NULL on error
*/
struct TALER_MERCHANT_ProposalOperation *
TALER_MERCHANT_order_put (struct GNUNET_CURL_Context *ctx,
@@ -162,7 +162,7 @@ struct TALER_MERCHANT_Pay;
* can indicate success, depending on whether the
interaction
* was with a merchant frontend or backend;
* 0 if the merchant's reply is bogus (fails to follow the
protocol)
- * @param ec taler-specific error code
+ * @param ec taler-specific error code
* @param obj the received JSON reply, with error details if the request failed
*/
typedef void
@@ -359,11 +359,35 @@ TALER_MERCHANT_pay_cancel (struct TALER_MERCHANT_Pay *ph);
struct TALER_MERCHANT_TrackTransferHandle;
/**
+ * Information about the _total_ amount that was paid back
+ * by the exchange for a given h_contract_terms, by _one_ wire
+ * transfer.
+ */
+struct TALER_MERCHANT_TrackTransferDetails {
+
+ /**
+ * Total amount paid back by the exchange.
+ */
+ struct TALER_Amount deposit_value;
+
+ /**
+ * Total amount of deposit fees.
+ */
+ struct TALER_Amount deposit_fee;
+
+ /**
+ * Order ID associated whit this payment.
+ */
+ const char *order_id;
+
+};
+
+/**
* Callbacks of this type are used to work the result of submitting a
/track/transfer request to a merchant
*
* @param cls closure
* @param http_status HTTP status code we got, 0 on exchange protocol violation
- * @param ec taler-specific error code
+ * @param ec taler-specific error code
* @param sign_key exchange key used to sign @a json, or NULL
* @param json original json reply (may include signatures, those have then
been
* validated already)
@@ -382,7 +406,7 @@ typedef void
const struct GNUNET_HashCode *h_wire,
const struct TALER_Amount
*total_amount,
unsigned int details_length,
- const struct
TALER_TrackTransferDetails *details);
+ const struct
TALER_MERCHANT_TrackTransferDetails *details);
/**
* Request backend to return deposits associated with a given wtid.
@@ -484,7 +508,7 @@ struct TALER_MERCHANT_TransactionWireTransfer
*
* @param cls closure
* @param http_status HTTP status code we got, 0 on exchange protocol violation
- * @param ec taler-specific error code
+ * @param ec taler-specific error code
* @param json original json reply from the backend
* @param num_transfers number of wire transfers the exchange used for the
transaction
* @param transfers details about each transfer and which coins are aggregated
in it
@@ -536,7 +560,7 @@ struct TALER_MERCHANT_HistoryOperation;
*
* @param cls closure
* @param http_status HTTP status returned by the merchant backend
- * @param ec taler-specific error code
+ * @param ec taler-specific error code
* @param json actual body containing history
*/
typedef void
diff --git a/src/include/taler_merchantdb_plugin.h
b/src/include/taler_merchantdb_plugin.h
index 0dfbea8..db27e0e 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -32,16 +32,18 @@ struct TALER_MERCHANTDB_Plugin;
/**
- * Tipically called by `find_proposal_data_by_date`.
+ * Tipically called by `find_contract_terms_by_date`.
*
* @param cls closure
* @param order_id order id
- * @param proposal_data proposal data related to order id
+ * @param row_id serial numer of the transaction in the table,
+ * @param contract_terms proposal data related to order id
*/
typedef void
(*TALER_MERCHANTDB_ProposalDataCallback)(void *cls,
const char *order_id,
- const json_t *proposal_data);
+ uint64_t row_id,
+ const json_t *contract_terms);
/**
* Function called with information about a transaction.
@@ -49,7 +51,7 @@ struct TALER_MERCHANTDB_Plugin;
* @param cls closure
* @param merchant_pub merchant's public key
* @param exchange_uri URI of the exchange
- * @param transaction_id proposal's transaction id
+ * @param h_contract_terms proposal data's hashcode
* @param h_wire hash of our wire details
* @param timestamp time of the confirmation
* @param refund refund deadline
@@ -59,7 +61,7 @@ typedef void
(*TALER_MERCHANTDB_TransactionCallback)(void *cls,
const struct TALER_MerchantPublicKeyP
*merchant_pub,
const char *exchange_uri,
- const struct GNUNET_HashCode
*h_proposal_data,
+ const struct GNUNET_HashCode
*h_contract_terms,
const struct GNUNET_HashCode *h_wire,
struct GNUNET_TIME_Absolute timestamp,
struct GNUNET_TIME_Absolute refund,
@@ -70,7 +72,7 @@ typedef void
* Function called with information about a coin that was deposited.
*
* @param cls closure
- * @param transaction_id of the contract
+ * @param h_contract_terms proposal data's hashcode
* @param coin_pub public key of the coin
* @param amount_with_fee amount the exchange will deposit for this coin
* @param deposit_fee fee the exchange will charge for this coin
@@ -79,7 +81,7 @@ typedef void
*/
typedef void
(*TALER_MERCHANTDB_CoinDepositCallback)(void *cls,
- const struct GNUNET_HashCode
*h_proposal_data,
+ const struct GNUNET_HashCode
*h_contract_terms,
const struct TALER_CoinSpendPublicKeyP
*coin_pub,
const struct TALER_Amount
*amount_with_fee,
const struct TALER_Amount *deposit_fee,
@@ -89,13 +91,13 @@ typedef void
/**
* Information about the wire transfer corresponding to
* a deposit operation. Note that it is in theory possible
- * that we have a @a transaction_id and @a coin_pub in the
+ * that we have a @a h_contract_terms and @a coin_pub in the
* result that do not match a deposit that we know about,
* for example because someone else deposited funds into
* our account.
*
* @param cls closure
- * @param transaction_id ID of the contract
+ * @param h_contract_terms hashcode of the proposal data
* @param coin_pub public key of the coin
* @param wtid identifier of the wire transfer in which the exchange
* send us the money for the coin deposit
@@ -105,7 +107,7 @@ typedef void
*/
typedef void
(*TALER_MERCHANTDB_TransferCallback)(void *cls,
- const struct GNUNET_HashCode
*h_proposal_data,
+ const struct GNUNET_HashCode
*h_contract_terms,
const struct TALER_CoinSpendPublicKeyP
*coin_pub,
const struct
TALER_WireTransferIdentifierRawP *wtid,
struct GNUNET_TIME_Absolute
execution_time,
@@ -160,34 +162,36 @@ struct TALER_MERCHANTDB_Plugin
/**
- * Insert proposal data and its transaction id's hashcode into db
+ * Insert proposal data into db; the routine will internally hash and
+ * insert the proposal data's hashcode into the same row.
*
* @param cls closure
- * @param h_transaction_id hashcode of the transaction id mentioned in this
- * proposal data
- * @param proposal_data proposal data to store
+ * @param order_id alphanumeric string that uniquely identifies the proposal
+ * @param merchant_pub merchant's public key
+ * @param timestamp timestamp of this proposal data
+ * @param contract_terms proposal data to store
* @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
*/
int
- (*insert_proposal_data) (void *cls,
+ (*insert_contract_terms) (void *cls,
const char *order_id,
const struct TALER_MerchantPublicKeyP *merchant_pub,
struct GNUNET_TIME_Absolute timestamp,
- const json_t *proposal_data);
+ const json_t *contract_terms);
/**
* Retrieve proposal data given its order ID.
*
* @param cls closure
- * @param proposal_data where to store the result
+ * @param contract_terms where to store the result
* @param order_id order_id used to lookup.
* @param merchant_pub instance's public key.
* @return #GNUNET_OK on success, #GNUNET_NO if no contract is
* found, #GNUNET_SYSERR upon error
*/
int
- (*find_proposal_data) (void *cls,
- json_t **proposal_data,
+ (*find_contract_terms) (void *cls,
+ json_t **contract_terms,
const char *order_id,
const struct TALER_MerchantPublicKeyP *merchant_pub);
@@ -196,32 +200,86 @@ struct TALER_MERCHANTDB_Plugin
* Retrieve proposal data given its hashcode
*
* @param cls closure
- * @param proposal_data where to store the result
- * @param h_proposal_data hashcode used to lookup.
+ * @param contract_terms where to store the result
+ * @param h_contract_terms hashcode used to lookup.
* @param merchant_pub instance's public key.
* @return #GNUNET_OK on success, #GNUNET_NO if no contract is
* found, #GNUNET_SYSERR upon error
*/
int
- (*find_proposal_data_from_hash) (void *cls,
- json_t **proposal_data,
- const struct GNUNET_HashCode
*h_proposal_data,
+ (*find_contract_terms_from_hash) (void *cls,
+ json_t **contract_terms,
+ const struct GNUNET_HashCode
*h_contract_terms,
const struct TALER_MerchantPublicKeyP
*merchant_pub);
+
/**
- * Return proposal data and order id for all proposals younger than
- * date.
+ * Return proposals whose timestamp are older than `date`.
+ * Among those proposals, only those ones being between the
+ * start-th and (start-nrows)-th record are returned. The rows
+ * are sorted having the youngest first.
*
- * @param cls closure
- * @param date limit to the oldest record
- * @param cb callback called with proposal data and order id
- * @param cb_cls closure for cb
+ * @param cls our plugin handle.
+ * @param date only results older than this date are returned.
+ * @param merchant_pub instance's public key; only rows related to this
+ * instance are returned.
+ * @param start only rows with serial id less than start are returned.
+ * @param nrows only nrows rows are returned.
+ * @param future if set to GNUNET_YES, retrieves rows younger than `date`.
+ * This is tipically used to show live updates on the merchant's backoffice
+ * @param cb function to call with transaction data, can be NULL.
+ * @param cb_cls closure for @a cb
+ * @return numer of found tuples, #GNUNET_SYSERR upon error
+ */
+ int
+ (*find_contract_terms_by_date_and_range) (void *cls,
+ struct GNUNET_TIME_Absolute date,
+ const struct
TALER_MerchantPublicKeyP *merchant_pub,
+ unsigned int start,
+ unsigned int nrows,
+ unsigned int future,
+
TALER_MERCHANTDB_ProposalDataCallback cb,
+ void *cb_cls);
+
+ /**
+ * Lookup for a proposal, respecting the signature used by the
+ * /history's db methods.
+ *
+ * @param cls db plugin handle
+ * @param order_id order id used to search for the proposal data
+ * @param merchant_pub public key of the merchant using this method
+ * @param cb the callback
+ * @param cb_cls closure to pass to the callback
+ * @return GNUNET_YES, GNUNET_NO, GNUNET_SYSERR according to the
+ * query being successful, unsuccessful, or generated errors.
+ */
+ int
+ (*find_contract_terms_history) (void *cls,
+ const char *order_id,
+ const struct TALER_MerchantPublicKeyP
*merchant_pub,
+ TALER_MERCHANTDB_ProposalDataCallback cb,
+ void *cb_cls);
+
+
+ /**
+ * Return proposals whose timestamp are older than `date`.
+ * The rows are sorted having the youngest first.*
+ *
+ * @param cls our plugin handle.
+ * @param date only results older than this date are returned.
+ * @param merchant_pub instance's public key; only rows related to this
+ * instance are returned.
+ * @param nrows only nrows rows are returned.
+ * @param cb function to call with transaction data, can be NULL.
+ * @param cb_cls closure for @a cb
+ * @return numer of found tuples, #GNUNET_SYSERR upon error
*/
int
- (*find_proposal_data_by_date) (void *cls,
+ (*find_contract_terms_by_date) (void *cls,
struct GNUNET_TIME_Absolute date,
const struct TALER_MerchantPublicKeyP
*merchant_pub,
+ unsigned int nrows,
TALER_MERCHANTDB_ProposalDataCallback cb,
void *cb_cls);
@@ -230,10 +288,9 @@ struct TALER_MERCHANTDB_Plugin
* Insert transaction data into the database.
*
* @param cls closure
- * @param transaction_id of the contract
+ * @param h_contract_terms proposal data's hashcode
* @param merchant_pub merchant's public key
* @param exchange_uri URI of the exchange
- * @param h_contract hash of the contract
* @param h_wire hash of our wire details
* @param timestamp time of the confirmation
* @param refund refund deadline
@@ -242,7 +299,7 @@ struct TALER_MERCHANTDB_Plugin
*/
int
(*store_transaction) (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const char *exchange_uri,
const struct GNUNET_HashCode *h_wire,
@@ -255,7 +312,7 @@ struct TALER_MERCHANTDB_Plugin
* Insert payment confirmation from the exchange into the database.
*
* @param cls closure
- * @param transaction_id of the contract
+ * @param h_contract_terms proposal data's hashcode
* @param merchant_pub merchant's public key
* @param coin_pub public key of the coin
* @param amount_with_fee amount the exchange will deposit for this coin
@@ -266,7 +323,7 @@ struct TALER_MERCHANTDB_Plugin
*/
int
(*store_deposit) (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_Amount *amount_with_fee,
@@ -276,11 +333,11 @@ struct TALER_MERCHANTDB_Plugin
/**
- * Insert mapping of @a coin_pub and @a transaction_id to
+ * Insert mapping of @a coin_pub and @a h_contract_terms to
* corresponding @a wtid.
*
* @param cls closure
- * @param transaction_id ID of the contract
+ * @param h_contract_terms proposal data's hashcode
* @param coin_pub public key of the coin
* @param wtid identifier of the wire transfer in which the exchange
* send us the money for the coin deposit
@@ -288,7 +345,7 @@ struct TALER_MERCHANTDB_Plugin
*/
int
(*store_coin_to_transfer) (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_WireTransferIdentifierRawP
*wtid);
@@ -333,56 +390,55 @@ struct TALER_MERCHANTDB_Plugin
* Find information about a transaction.
*
* @param cls our plugin handle
- * @param transaction_id the transaction id to search
- * @param merchant_pub merchant's public key. It's AND'd with @a
transaction_id
- * in order to find the result.
+ * @param h_contract_terms proposal data's hashcode
+ * @param merchant_pub merchant's public key.
* @param cb function to call with transaction data
* @param cb_cls closure for @a cb
* @return number of found tuples, #GNUNET_SYSERR upon error
*/
int
(*find_transaction) (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_MerchantPublicKeyP *merchant_pub,
TALER_MERCHANTDB_TransactionCallback cb,
void *cb_cls);
/**
- * Lookup information about coin payments by transaction ID.
+ * Lookup information about coin payments by proposal data's hashcode.
*
* @param cls closure
- * @param transaction_id key for the search
- * @param merchant_pub merchant's public key. It's AND'd with @a
transaction_id
+ * @param h_contract_terms proposal data's hashcode
+ * @param merchant_pub merchant's public key. It's AND'd with @a
h_contract_terms
* in order to find the result.
* @param cb function to call with payment data
* @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
+ * @return #GNUNET_OK on success, #GNUNET_NO if h_contract_terms is unknown,
* #GNUNET_SYSERR on hard errors
*/
int
(*find_payments) (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_MerchantPublicKeyP *merchant_pub,
TALER_MERCHANTDB_CoinDepositCallback cb,
void *cb_cls);
/**
- * Lookup information about coin payments by transaction ID and coin.
+ * Lookup information about coin payments by h_contract_terms and coin.
*
* @param cls closure
- * @param transaction_id key for the search
- * @param merchant_pub merchant's public key. It's AND'd with @a
transaction_id
+ * @param h_contract_terms proposal data's hashcode
+ * @param merchant_pub merchant's public key. It's AND'd with @a
h_contract_terms
* in order to find the result.
* @param coin_pub public key to use for the search
* @param cb function to call with payment data
* @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
+ * @return #GNUNET_OK on success, #GNUNET_NO if h_contract_terms is unknown,
* #GNUNET_SYSERR on hard errors
*/
int
(*find_payments_by_hash_and_coin) (void *cls,
- const struct GNUNET_HashCode
*h_proposal_data,
+ const struct GNUNET_HashCode
*h_contract_terms,
const struct TALER_MerchantPublicKeyP
*merchant_pub,
const struct TALER_CoinSpendPublicKeyP
*coin_pub,
TALER_MERCHANTDB_CoinDepositCallback cb,
@@ -390,22 +446,22 @@ struct TALER_MERCHANTDB_Plugin
/**
- * Lookup information about a transfer by @a transaction_id. Note
+ * Lookup information about a transfer by @a h_contract_terms. Note
* that in theory there could be multiple wire transfers for a
- * single @a transaction_id, as the transaction may have involved
+ * single @a h_contract_terms, as the transaction may have involved
* multiple coins and the coins may be spread over different wire
* transfers.
*
* @param cls closure
- * @param transaction_id key for the search
+ * @param h_contract_terms proposal data's hashcode
* @param cb function to call with transfer data
* @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
+ * @return #GNUNET_OK on success, #GNUNET_NO if h_contract_terms is unknown,
* #GNUNET_SYSERR on hard errors
*/
int
(*find_transfers_by_hash) (void *cls,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
TALER_MERCHANTDB_TransferCallback cb,
void *cb_cls);
@@ -417,7 +473,7 @@ struct TALER_MERCHANTDB_Plugin
* @param wtid wire transfer identifier to find matching transactions for
* @param cb function to call with payment data
* @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
+ * @return #GNUNET_OK on success, #GNUNET_NO if h_contract_terms is unknown,
* #GNUNET_SYSERR on hard errors
*/
int
@@ -435,7 +491,7 @@ struct TALER_MERCHANTDB_Plugin
* @param wtid wire transfer identifier for the search
* @param cb function to call with proof data
* @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
+ * @return #GNUNET_OK on success, #GNUNET_NO if h_contract_terms is unknown,
* #GNUNET_SYSERR on hard errors
*/
int
diff --git a/src/lib/merchant_api_history.c b/src/lib/merchant_api_history.c
index 69d09b8..a2c2d5f 100644
--- a/src/lib/merchant_api_history.c
+++ b/src/lib/merchant_api_history.c
@@ -137,7 +137,8 @@ history_raw_cb (void *cls,
* @param ctx execution context
* @param backend_uri base URL of the merchant backend
* @param instance which merchant instance is performing this call
- * @param start return `delta` records starting from position `start`
+ * @param start return `delta` records starting from position `start`.
+ * If given as zero, then no initial skip of `start` records is done.
* @param delta return `delta` records starting from position `start`
* @param date only transactions younger than/equals to date will be returned
* @param history_cb callback which will work the response gotten from the
backend
@@ -163,6 +164,7 @@ TALER_MERCHANT_history (struct GNUNET_CURL_Context *ctx,
ho->cb = history_cb;
ho->cb_cls = history_cb_cls;
seconds = date.abs_value_us / 1000LL / 1000LL;
+
GNUNET_asprintf (&ho->url,
"%s/history?date=%llu&instance=%s&start=%d&delta=%d",
backend_uri,
@@ -170,6 +172,7 @@ TALER_MERCHANT_history (struct GNUNET_CURL_Context *ctx,
instance,
start,
delta);
+
eh = curl_easy_init ();
if (CURLE_OK != curl_easy_setopt (eh,
CURLOPT_URL,
diff --git a/src/lib/merchant_api_pay.c b/src/lib/merchant_api_pay.c
index 6910bde..9422e07 100644
--- a/src/lib/merchant_api_pay.c
+++ b/src/lib/merchant_api_pay.c
@@ -252,24 +252,19 @@ handle_pay_finished (void *cls,
* @param ctx the execution loop context
* @param merchant_uri base URI of the merchant's backend
* @param instance which merchant instance will receive this payment
- * @param h_wire hash of the merchant’s account details
- * @param h_contract hash of the contact of the merchant with the customer
- * @param transaction_id transaction id for the transaction between merchant
and customer
+ * @param h_contract_terms hashcode of the proposal being paid
* @param amount total value of the contract to be paid to the merchant
* @param max_fee maximum fee covered by the merchant (according to the
contract)
* @param merchant_pub the public key of the merchant (used to identify the
merchant for refund requests)
* @param merchant_sig signature from the merchant over the original contract
* @param timestamp timestamp when the contract was finalized, must match
approximately the current time of the merchant
- * @param transaction_id transaction id for the transaction between merchant
and customer
- * @param merchant_pub the public key of the merchant (used to identify the
merchant for refund requests)
* @param refund_deadline date until which the merchant can issue a refund to
the customer via the merchant (can be zero if refunds are not allowed)
* @param pay_deadline maximum time limit to pay for this contract
+ * @param h_wire hash of the merchant’s account details
* @param exchange_uri URI of the exchange that the coins belong to
+ * @param order_id order id of the proposal being paid
* @param num_coins number of coins used to pay
* @param coins array of coins we use to pay
- * @param coin_sig the signature made with purpose
#TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s
private key.
- * @param max_fee maximum fee covered by the merchant (according to the
contract)
- * @param amount total value of the contract to be paid to the merchant
* @param pay_cb the callback to call when a reply for this request is
available
* @param pay_cb_cls closure for @a pay_cb
* @return a handle for this request
@@ -278,7 +273,7 @@ struct TALER_MERCHANT_Pay *
TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
const char *merchant_uri,
const char *instance,
- const struct GNUNET_HashCode *h_proposal_data,
+ const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_Amount *amount,
const struct TALER_Amount *max_fee,
const struct TALER_MerchantPublicKeyP *merchant_pub,
@@ -312,7 +307,7 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
- dr.h_proposal_data = *h_proposal_data;
+ dr.h_contract_terms = *h_contract_terms;
dr.h_wire = *h_wire;
dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
@@ -340,6 +335,12 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
}
TALER_amount_hton (&dr.deposit_fee,
&fee);
+ {
+ TALER_LOG_DEBUG ("... amount_with_fee was %s\n",
+ TALER_amount2s (&coin->amount_with_fee));
+ TALER_LOG_DEBUG ("... fee was %s\n",
+ TALER_amount2s (&fee));
+ }
GNUNET_CRYPTO_eddsa_sign (&coin->coin_priv.eddsa_priv,
&dr.purpose,
@@ -371,6 +372,7 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
*
* @param ctx the execution loop context
* @param merchant_uri base URI of the merchant's backend
+ * @param merchant_pub public key of the merchant
* @param exchange_uri URI of the exchange that the coins belong to
* @param num_coins number of coins used to pay
* @param coins array of coins we use to pay
diff --git a/src/lib/merchant_api_proposal.c b/src/lib/merchant_api_proposal.c
index c3e5873..c200ce5 100644
--- a/src/lib/merchant_api_proposal.c
+++ b/src/lib/merchant_api_proposal.c
@@ -115,14 +115,14 @@ handle_proposal_finished (void *cls,
const json_t *json)
{
struct TALER_MERCHANT_ProposalOperation *po = cls;
- json_t *proposal_data;
+ json_t *contract_terms;
const struct TALER_MerchantSignatureP *sigp;
const struct GNUNET_HashCode *hashp;
struct TALER_MerchantSignatureP sig;
struct GNUNET_HashCode hash;
po->job = NULL;
- proposal_data = NULL;
+ contract_terms = NULL;
sigp = NULL;
hashp = NULL;
switch (response_code)
@@ -132,12 +132,12 @@ handle_proposal_finished (void *cls,
case MHD_HTTP_OK:
{
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("data", &proposal_data),
+ GNUNET_JSON_spec_json ("data", &contract_terms),
GNUNET_JSON_spec_fixed_auto ("sig", &sig),
GNUNET_JSON_spec_fixed_auto ("hash", &hash),
GNUNET_JSON_spec_end()
};
-
+
if (GNUNET_OK !=
GNUNET_JSON_parse (json,
spec,
@@ -182,11 +182,11 @@ handle_proposal_finished (void *cls,
response_code,
TALER_JSON_get_error_code (json),
json,
- proposal_data,
+ contract_terms,
sigp,
hashp);
- if (NULL != proposal_data)
- json_decref (proposal_data);
+ if (NULL != contract_terms)
+ json_decref (contract_terms);
}
@@ -200,7 +200,7 @@ handle_proposal_finished (void *cls,
* @param proposal_cb the callback to call when a reply for this request is
* available
* @param proposal_cb_cls closure for @a proposal_cb
- * @return a handle for this request
+ * @return a handle for this request, NULL on error
*/
struct TALER_MERCHANT_ProposalOperation *
TALER_MERCHANT_order_put (struct GNUNET_CURL_Context *ctx,
@@ -225,10 +225,15 @@ TALER_MERCHANT_order_put (struct GNUNET_CURL_Context *ctx,
req = json_pack ("{s:O}",
"order", (json_t *) order);
eh = curl_easy_init ();
- GNUNET_assert (NULL != (po->json_enc =
- json_dumps (req,
- JSON_COMPACT)));
+ po->json_enc = json_dumps (req,
+ JSON_COMPACT);
json_decref (req);
+ if (NULL == po->json_enc)
+ {
+ GNUNET_break (0);
+ GNUNET_free (po);
+ return NULL;
+ }
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_URL,
@@ -310,7 +315,7 @@ TALER_MERCHANT_proposal_lookup (struct GNUNET_CURL_Context
*ctx,
CURLOPT_URL,
plo->url))
{
- GNUNET_break (0);
+ GNUNET_break (0);
return NULL;
}
diff --git a/src/lib/merchant_api_track_transaction.c
b/src/lib/merchant_api_track_transaction.c
index abb1d29..4e11acc 100644
--- a/src/lib/merchant_api_track_transaction.c
+++ b/src/lib/merchant_api_track_transaction.c
@@ -64,24 +64,6 @@ struct TALER_MERCHANT_TrackTransactionHandle
struct GNUNET_CURL_Context *ctx;
};
-
-/**
- * Free data in @a transfers.
- *
- * @param num_transfers length of the @a transfers array
- * @param transfers information about wire transfers to free
- */
-static void
-free_transfers (unsigned int num_transfers,
- struct TALER_MERCHANT_TransactionWireTransfer *transfers)
-{
- unsigned int i;
-
- for (i=0;i<num_transfers;i++)
- GNUNET_free (transfers[i].coins);
-}
-
-
/**
* Handle #MHD_HTTP_OK response to /track/transaction.
* Parse @a json and if successful call the callback in @a tdo.
@@ -167,7 +149,7 @@ handle_track_transaction_finished (void *cls,
* @param ctx execution context
* @param backend_uri base URI of the backend
* @param instance which merchant instance is going to be tracked
- * @param transaction_id which transaction should we trace
+ * @param order_id order id pointing to the transaction being tracked
* @param track_transaction_cb the callback to call when a reply for this
request is available
* @param track_transaction_cb_cls closure for @a track_transaction_cb
* @return a handle for this request
@@ -213,7 +195,7 @@ TALER_MERCHANT_track_transaction (struct
GNUNET_CURL_Context *ctx,
* Cancel a /track/transaction request. This function cannot be used
* on a request handle if a response is already served for it.
*
- * @param co the transaction's tracking handle
+ * @param tdo handle to the tracking operation being cancelled
*/
void
TALER_MERCHANT_track_transaction_cancel (struct
TALER_MERCHANT_TrackTransactionHandle *tdo)
diff --git a/src/lib/merchant_api_track_transfer.c
b/src/lib/merchant_api_track_transfer.c
index 10e6981..0de4ac8 100644
--- a/src/lib/merchant_api_track_transfer.c
+++ b/src/lib/merchant_api_track_transfer.c
@@ -85,7 +85,7 @@ static int
check_track_transfer_response_ok (struct TALER_MERCHANT_TrackTransferHandle
*wdh,
const json_t *json)
{
- json_t *details_j;
+ json_t *deposits;
struct GNUNET_HashCode h_wire;
struct TALER_Amount total_amount;
struct TALER_MerchantPublicKeyP merchant_pub;
@@ -95,7 +95,7 @@ check_track_transfer_response_ok (struct
TALER_MERCHANT_TrackTransferHandle *wdh
TALER_JSON_spec_amount ("total", &total_amount),
GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
GNUNET_JSON_spec_fixed_auto ("H_wire", &h_wire),
- GNUNET_JSON_spec_json ("deposits", &details_j),
+ GNUNET_JSON_spec_json ("deposits_sums", &deposits),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub),
GNUNET_JSON_spec_end()
};
@@ -108,25 +108,24 @@ check_track_transfer_response_ok (struct
TALER_MERCHANT_TrackTransferHandle *wdh
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- num_details = json_array_size (details_j);
+ num_details = json_array_size (deposits);
{
- struct TALER_TrackTransferDetails details[num_details];
+ struct TALER_MERCHANT_TrackTransferDetails details[num_details];
unsigned int i;
for (i=0;i<num_details;i++)
{
- struct TALER_TrackTransferDetails *detail = &details[i];
- struct json_t *detail_j = json_array_get (details_j, i);
+ struct TALER_MERCHANT_TrackTransferDetails *detail = &details[i];
+ json_t *deposit = json_array_get (deposits, i);
struct GNUNET_JSON_Specification spec_detail[] = {
- GNUNET_JSON_spec_fixed_auto ("h_proposal_data",
&detail->h_proposal_data),
- 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_string ("order_id", &detail->order_id),
+ TALER_JSON_spec_amount ("deposit_value", &detail->deposit_value),
+ TALER_JSON_spec_amount ("deposit_fee", &detail->deposit_fee),
GNUNET_JSON_spec_end()
};
if (GNUNET_OK !=
- GNUNET_JSON_parse (detail_j,
+ GNUNET_JSON_parse (deposit,
spec_detail,
NULL, NULL))
{
@@ -214,7 +213,7 @@ handle_track_transfer_finished (void *cls,
* @param backend_uri base URI of the backend
* @param instance which merchant instance is going to be tracked
* @param wtid base32 string indicating a wtid
- * @param exchange base URL of the exchange in charge of returning the wanted
information
+ * @param exchange_uri base URL of the exchange in charge of returning the
wanted information
* @param track_transfer_cb the callback to call when a reply for this request
is available
* @param track_transfer_cb_cls closure for @a contract_cb
* @return a handle for this request
@@ -264,7 +263,7 @@ TALER_MERCHANT_track_transfer (struct GNUNET_CURL_Context
*ctx,
* Cancel a /track/transfer request. This function cannot be used
* on a request handle if a response is already served for it.
*
- * @param co the transfer's tracking handle
+ * @param tdo handle to the tracking operation being cancelled
*/
void
TALER_MERCHANT_track_transfer_cancel (struct
TALER_MERCHANT_TrackTransferHandle *tdo)
diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c
index c2d728c..6d0f613 100644
--- a/src/lib/test_merchant_api.c
+++ b/src/lib/test_merchant_api.c
@@ -421,7 +421,7 @@ struct Command
* FIXME: verify in the code that this bit is actually proposal
* data and not the whole proposal.
*/
- json_t *proposal_data;
+ json_t *contract_terms;
/**
* Proposal's signature.
@@ -481,7 +481,7 @@ struct Command
/**
* Hashcode of the proposal data associated to this payment.
*/
- struct GNUNET_HashCode h_proposal_data;
+ struct GNUNET_HashCode h_contract_terms;
/**
* Merchant's public key
@@ -596,6 +596,17 @@ struct Command
*/
struct TALER_MERCHANT_HistoryOperation *ho;
+ /**
+ * The backend will return records with row_id
+ * less than this value.
+ */
+ unsigned int start;
+
+ /**
+ * The backend will return at most `nrows` records.
+ */
+ unsigned int nrows;
+
} history;
@@ -1032,7 +1043,7 @@ reserve_withdraw_cb (void *cls,
* @param ec taler-specific error code
* @param obj the full received JSON reply, or
* error details if the request failed
- * @param proposal_data the order + additional information provided by the
+ * @param contract_terms the order + additional information provided by the
* backend, NULL on error.
* @param sig merchant's signature over the contract, NULL on error
* @param h_contract hash of the contract, NULL on error
@@ -1042,7 +1053,7 @@ proposal_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *obj,
- const json_t *proposal_data,
+ const json_t *contract_terms,
const struct TALER_MerchantSignatureP *sig,
const struct GNUNET_HashCode *hash)
{
@@ -1053,7 +1064,7 @@ proposal_cb (void *cls,
switch (http_status)
{
case MHD_HTTP_OK:
- cmd->details.proposal.proposal_data = json_incref ((json_t *)
proposal_data);
+ cmd->details.proposal.contract_terms = json_incref ((json_t *)
contract_terms);
cmd->details.proposal.merchant_sig = *sig;
cmd->details.proposal.hash = *hash;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1094,7 +1105,7 @@ pay_cb (void *cls,
struct Command *cmd = &is->commands[is->ip];
struct PaymentResponsePS mr;
struct GNUNET_CRYPTO_EddsaSignature sig;
- struct GNUNET_HashCode h_proposal_data;
+ struct GNUNET_HashCode h_contract_terms;
const char *error_name;
unsigned int error_line;
@@ -1114,7 +1125,7 @@ pay_cb (void *cls,
/* Check signature */
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("sig", &sig),
- GNUNET_JSON_spec_fixed_auto ("h_proposal_data", &h_proposal_data),
+ GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &h_contract_terms),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
@@ -1133,7 +1144,7 @@ pay_cb (void *cls,
}
mr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK);
mr.purpose.size = htonl (sizeof (mr));
- mr.h_proposal_data = h_proposal_data;
+ mr.h_contract_terms = h_contract_terms;
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_PAYMENT_OK,
&mr.purpose,
@@ -1200,11 +1211,15 @@ track_transfer_cb (void *cls,
const struct GNUNET_HashCode *h_wire,
const struct TALER_Amount *total_amount,
unsigned int details_length,
- const struct TALER_TrackTransferDetails *details)
+ const struct TALER_MERCHANT_TrackTransferDetails *details)
{
struct InterpreterState *is = cls;
struct Command *cmd = &is->commands[is->ip];
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Tracked transfers: '%s'.\n",
+ json_dumps (json, JSON_INDENT (1)));
+
cmd->details.track_transfer.tdo = NULL;
if (cmd->expected_response_code != http_status)
{
@@ -1218,90 +1233,12 @@ track_transfer_cb (void *cls,
}
switch (http_status)
{
- case MHD_HTTP_OK:
- {
- const struct Command *ref;
- unsigned int i;
- int found;
-
- /**
- * Retrieve the deposit operation that is supposed
- * to have been paid by the wtid used in this operation.
- * After that, check if that operation is actually mentioned
- * in the returned data.
- */
- ref = find_command (is,
- cmd->details.track_transfer.expected_pay_ref);
- GNUNET_assert (NULL != ref);
- found = GNUNET_NO;
-
- /**
- * Iterating over the details makes little sense now,
- * as each payment involves exatcly one coin.
- */
- for (i=0;i<details_length;i++)
- {
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount amount_without_fee;
- struct TALER_Amount deposit_fee;
- const struct Command *cref;
- const struct Command *proposal_ref;
- struct TALER_CoinSpendPublicKeyP coin_pub;
-
- /* Extract */
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount
(ref->details.pay.amount_without_fee,
- &amount_without_fee));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount
(ref->details.pay.amount_with_fee,
- &amount_with_fee));
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_subtract (&deposit_fee,
- &amount_with_fee,
- &amount_without_fee));
-
- /* Find coin ('s public key) associated with the retrieved
- deposit. Yes, one deposit - one coin. */
- cref = find_command (is,
- ref->details.pay.coin_ref);
- proposal_ref = find_command (is,
- ref->details.pay.contract_ref);
- GNUNET_assert (NULL != cref);
- GNUNET_assert (NULL != proposal_ref);
- switch (cref->oc)
- {
- case OC_WITHDRAW_SIGN:
- GNUNET_CRYPTO_eddsa_key_get_public
- (&cref->details.reserve_withdraw.coin_priv.eddsa_priv,
- &coin_pub.eddsa_pub);
- break;
- default:
- GNUNET_assert (0);
- }
-
- if ( (0 == memcmp (&details[i].h_proposal_data,
- &proposal_ref->details.proposal.hash,
- sizeof (struct GNUNET_HashCode))) &&
- (0 == TALER_amount_cmp (&details[i].coin_value,
- &amount_with_fee)) &&
- (0 == TALER_amount_cmp (&details[i].coin_fee,
- &deposit_fee)) &&
- (0 == memcmp (&details[i].coin_pub,
- &coin_pub,
- sizeof (struct TALER_CoinSpendPublicKeyP))) )
- found = GNUNET_YES;
- }
- if (GNUNET_NO == found)
- {
- GNUNET_break (0);
- json_dumpf (json, stderr, 0);
- fail (is);
- return;
- }
+ case MHD_HTTP_OK:
break;
- }
- default:
- break;
+
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unhandled HTTP status.\n");
}
next_command (is);
}
@@ -1361,9 +1298,6 @@ track_transaction_cb (void *cls,
}
if (MHD_HTTP_OK != http_status)
fail (is);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "/track/order response: %s\n",
- json_dumps (json, JSON_INDENT (1)));
next_command (is);
}
@@ -1484,7 +1418,7 @@ interpreter_run (void *cls)
GNUNET_assert (NULL != ref);
order_id =
- json_string_value (json_object_get
(ref->details.proposal.proposal_data,
+ json_string_value (json_object_get
(ref->details.proposal.contract_terms,
"order_id"));
GNUNET_assert (NULL !=
(cmd->details.proposal_lookup.plo
@@ -1719,7 +1653,7 @@ interpreter_run (void *cls)
cmd->details.pay.contract_ref);
GNUNET_assert (NULL != ref);
merchant_sig = ref->details.proposal.merchant_sig;
- GNUNET_assert (NULL != ref->details.proposal.proposal_data);
+ GNUNET_assert (NULL != ref->details.proposal.contract_terms);
{
/* Get information that need to be replied in the deposit permission */
struct GNUNET_JSON_Specification spec[] = {
@@ -1735,7 +1669,7 @@ interpreter_run (void *cls)
};
if (GNUNET_OK !=
- GNUNET_JSON_parse (ref->details.proposal.proposal_data,
+ GNUNET_JSON_parse (ref->details.proposal.contract_terms,
spec,
&error_name,
&error_line))
@@ -1910,7 +1844,7 @@ interpreter_run (void *cls)
GNUNET_assert (NULL != ref);
proposal_ref = find_command (is,
ref->details.pay.contract_ref);
- order_id = json_string_value (json_object_get
(proposal_ref->details.proposal.proposal_data,
+ order_id = json_string_value (json_object_get
(proposal_ref->details.proposal.contract_terms,
"order_id"));
cmd->details.track_transaction.tth =
TALER_MERCHANT_track_transaction (ctx,
@@ -1927,8 +1861,8 @@ interpreter_run (void *cls)
(cmd->details.history.ho = TALER_MERCHANT_history (ctx,
MERCHANT_URI,
instance,
- 0,
- 20,
+
cmd->details.history.start,
+
cmd->details.history.nrows,
cmd->details.history.date,
history_cb,
is)))
@@ -2049,10 +1983,10 @@ do_shutdown (void *cls)
TALER_MERCHANT_proposal_cancel (cmd->details.proposal.po);
cmd->details.proposal.po = NULL;
}
- if (NULL != cmd->details.proposal.proposal_data)
+ if (NULL != cmd->details.proposal.contract_terms)
{
- json_decref (cmd->details.proposal.proposal_data);
- cmd->details.proposal.proposal_data = NULL;
+ json_decref (cmd->details.proposal.contract_terms);
+ cmd->details.proposal.contract_terms = NULL;
}
break;
case OC_PAY:
@@ -2418,15 +2352,19 @@ run (void *cls)
.label = "history-1",
.expected_response_code = MHD_HTTP_OK,
/*all records to be returned*/
- .details.history.date.abs_value_us = 0,
- .details.history.nresult = 2
+ .details.history.date.abs_value_us = 43 * 1000LL * 1000LL,
+ .details.history.nresult = 2,
+ .details.history.start = 10,
+ .details.history.nrows = 10
},
{ .oc = OC_HISTORY,
.label = "history-2",
.expected_response_code = MHD_HTTP_OK,
- /*no records to be returned, as limit is in the future*/
- .details.history.date.abs_value_us = 43 * 1000LL * 1000LL,
- .details.history.nresult = 0
+ /*no records returned, time limit too ancient*/
+ .details.history.date.abs_value_us = 0,
+ .details.history.nresult = 0,
+ .details.history.start = 10,
+ .details.history.nrows = 10
},
/* end of testcase */
diff --git a/src/lib/test_merchant_api.conf b/src/lib/test_merchant_api.conf
index 8a9b80c..5e72ed0 100644
--- a/src/lib/test_merchant_api.conf
+++ b/src/lib/test_merchant_api.conf
@@ -53,6 +53,16 @@ WIRE-FEE-2023 = EUR:0.01
WIRE-FEE-2024 = EUR:0.01
WIRE-FEE-2025 = EUR:0.01
WIRE-FEE-2026 = EUR:0.01
+CLOSING-FEE-2017 = EUR:0.01
+CLOSING-FEE-2018 = EUR:0.01
+CLOSING-FEE-2019 = EUR:0.01
+CLOSING-FEE-2020 = EUR:0.01
+CLOSING-FEE-2021 = EUR:0.01
+CLOSING-FEE-2022 = EUR:0.01
+CLOSING-FEE-2023 = EUR:0.01
+CLOSING-FEE-2024 = EUR:0.01
+CLOSING-FEE-2025 = EUR:0.01
+CLOSING-FEE-2026 = EUR:0.01
[merchant-exchange-test]
@@ -115,14 +125,13 @@ MASTER_PUBLIC_KEY =
T1VVFQZZARQ1CMF4BN58EE7SKTW5AV2BS18S87ZEGYS4S29J6DNG
[exchangedb-postgres]
DB_CONN_STR = "postgres:///talercheck"
-[exchange-wire-incoming-test]
+[exchange-wire-test]
# This is the response we give out for the /wire request. It provides
# wallets with the bank information for transfers to the exchange.
# Note that the _incoming_ account is #3, while the
# outgoing account of the exchange (see below) is #2.
TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/test.json
-[exchange-wire-outgoing-test]
# What is the main website of the bank?
BANK_URI = "http://localhost:8083/"
# From which account at the 'bank' should outgoing wire transfers be made?
diff --git a/src/merchant-tools/Makefile.am b/src/merchant-tools/Makefile.am
index 97f448d..2adee91 100644
--- a/src/merchant-tools/Makefile.am
+++ b/src/merchant-tools/Makefile.am
@@ -1,10 +1,9 @@
-
-
# This Makefile.am is in the public domain
AM_CPPFLAGS = -I$(top_srcdir)/src/include
bin_PROGRAMS = \
- taler-merchant-dbinit
+ taler-merchant-dbinit \
+ taler-merchant-generate-payments
taler_merchant_dbinit_SOURCES = \
taler-merchant-dbinit.c
@@ -15,3 +14,21 @@ taler_merchant_dbinit_LDADD = \
-lgnunetutil \
-ltalerutil \
-ltalerpq
+
+taler_merchant_generate_payments_SOURCES = \
+ taler-merchant-generate-payments.c
+
+taler_merchant_generate_payments_LDADD = \
+ $(top_srcdir)/src/backenddb/libtalermerchantdb.la \
+ $(top_srcdir)/src/lib/libtalermerchant.la \
+ $(LIBGCRYPT_LIBS) \
+ -ltalerfakebank \
+ -ltalerexchange \
+ -ltalerjson \
+ -ltalerutil \
+ -lgnunetjson \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson
+
+SUBDIRS = mitm
diff --git a/src/merchant-tools/README b/src/merchant-tools/README
new file mode 100644
index 0000000..993a87e
--- /dev/null
+++ b/src/merchant-tools/README
@@ -0,0 +1,51 @@
+
+** Taler Merchant Payments Generator **
+
+=== INTRODUCTION ===
+
+The tool contained in this directory is used to populate the
+merchant's and exchange's database with fake payments.
+It is mainly used for debugging applications that need some
+payments to be in place.
+
+It is mandatory to give it a config file that contains information
+about the setup to target. Note that the merchant and the exchange
+tun by this command will use their own config files, so just few values
+are required for it to run.
+
+
+=== COFIGURATION ===
+
+Any config file must look like the following one.
+
+[payments-generator]
+
+# where on this machine the exchange listens; note that
+# this exchange must be among the ones accepted by the
+# merchant
+exchange = http://localexchange/
+
+# where on this machine the merchant listens
+merchant = http://localshop/
+
+# bank's URI of the customer who withdraws coins.
+# Must be known by the exchange.
+bank = http://localbank/
+
+# must match an instance known by the merchant
+instance = FSF
+
+# must match the currency used by merchant and exchange
+currency = EUR
+
+
+=== INVOCATION ===
+
+taler-merchant-generate-payments -c config/file.conf [-n ITERATIONS]
+
+The -n option instructs the tools about how many iteration of all
+the (internal) commands we want to execute.
+
+** Taler Merchant Dbinit **
+
+TBD
diff --git a/src/merchant-tools/mitm/Makefile.in
b/src/merchant-tools/mitm/Makefile.in
new file mode 100644
index 0000000..4a9f33a
--- /dev/null
+++ b/src/merchant-tools/mitm/Makefile.in
@@ -0,0 +1,21 @@
+
+.PHONY: all
+all:
+ true
+
+.PHONY: install-data
+install-data:
+ install -m 444 -Dt @prefix@/share/taler/ merchant-mitm.wsgi
+
+.PHONY: install
+install: install-data
+ pip3 install . --install-option="address@hidden@" --upgrade --no-deps
+ install -m 544 -Dt @prefix@/bin taler-merchant-mitm
+
+# need a way to make 'make check' happy in this subdir.
+# This component is still too young to be tested.
+.PHONY: check
+check:
+ true
+clean:
+ true
diff --git a/src/merchant-tools/mitm/README b/src/merchant-tools/mitm/README
new file mode 100644
index 0000000..662cbe3
--- /dev/null
+++ b/src/merchant-tools/mitm/README
@@ -0,0 +1,25 @@
+
+=== INTRODUCTION ===
+
+This directory contain a Web server that listens for
+requests addressed to the exchange, relays them to the
+exchange, and returns a modified response to the caller.
+
+The modifications are made to test error management in the
+merchant, and are driven by a HTTP header that instructs the
+proxy about the modifications to be made.
+
+=== INVOCATION ===
+
+After a successful 'make install', a command called 'taler-merchant-mitm'
+is placed under <prefix>/bin - make sure PATH points at it.
+
+To run the mitm, give the following commands:
+
+$ taler-merchant-mitm --exchange URL [--port PORT]
+
+The '--exchange' option is mandatory, telling the mitm where to
+forward the requests addressed to the exchange.
+
+The second option just sets the port number where the mitm
+listens, defaulting to 5000.
diff --git a/src/merchant-tools/mitm/merchant-mitm.wsgi.in
b/src/merchant-tools/mitm/merchant-mitm.wsgi.in
new file mode 100644
index 0000000..3fb4cfb
--- /dev/null
+++ b/src/merchant-tools/mitm/merchant-mitm.wsgi.in
@@ -0,0 +1,21 @@
+
+import sys
+
+if sys.version_info.major < 3:
+ print("The merchant mitm needs to run with Python>=3.4")
+ sys.exit(1)
+
+import os
+import site
+import logging
+
+logging.basicConfig(level=logging.INFO)
+
+site.addsitedir("%s/lib/python%d.%d/site-packages" % (
+ "@prefix@",
+ sys.version_info.major,
+ sys.version_info.minor))
+
+import talermerchantmitm.mitm
+
+application = talermerchantmitm.mitm.app
diff --git a/src/merchant-tools/mitm/setup.py b/src/merchant-tools/mitm/setup.py
new file mode 100644
index 0000000..f5eedea
--- /dev/null
+++ b/src/merchant-tools/mitm/setup.py
@@ -0,0 +1,11 @@
+from setuptools import setup, find_packages
+setup(name='talermerchantmitm',
+ version='0.0',
+ description='Layer generating errors for testing',
+ url='git://taler.net/merchant',
+ author='Marcello Stanisci',
+ author_email='address@hidden',
+ license='GPL',
+ packages=find_packages(),
+ install_requires=["Flask>=0.10"],
+ zip_safe=False)
diff --git a/src/merchant-tools/mitm/taler-merchant-mitm.in
b/src/merchant-tools/mitm/taler-merchant-mitm.in
new file mode 100644
index 0000000..39a7275
--- /dev/null
+++ b/src/merchant-tools/mitm/taler-merchant-mitm.in
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+
+"""
+Stand-alone script to manage the merchant's MITM
+error generator.
+"""
+
+import argparse
+import sys
+import os
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--exchange',
+ '-e',
+ help="Exchange URL",
+ metavar="URL",
+ type=str,
+ dest="exchange_url",
+ default=None)
+
+
+parser.add_argument("--port",
+ "-p",
+ help="Port where the MITM listens",
+ dest="port",
+ type=int,
+ default=5000,
+ metavar="PORT")
+
+args = parser.parse_args()
+
+if getattr(args, 'exchange_url', None) is None:
+ parser.print_help()
+ sys.exit(1)
+
+uwsgi_logfmt = "%(ltime) %(proto) %(method) %(uri) %(proto) => %(status)"
+
+os.environ["TALER_EXCHANGE_URL"] = args.exchange_url
+os.execlp("uwsgi", "uwsgi",
+ "--master",
+ "--die-on-term",
+ "--log-format", uwsgi_logfmt,
+ "--http", ":%d" % args.port,
+ "--wsgi-file", "@prefix@/share/taler/merchant-mitm.wsgi")
diff --git a/NEWS b/src/merchant-tools/mitm/talermerchantmitm/__init__.py
similarity index 100%
copy from NEWS
copy to src/merchant-tools/mitm/talermerchantmitm/__init__.py
diff --git a/src/merchant-tools/mitm/talermerchantmitm/mitm.py
b/src/merchant-tools/mitm/talermerchantmitm/mitm.py
new file mode 100644
index 0000000..c998a1c
--- /dev/null
+++ b/src/merchant-tools/mitm/talermerchantmitm/mitm.py
@@ -0,0 +1,78 @@
+#This file is part of TALER
+#Copyright (C) 2014, 2015, 2016, 2017 GNUnet e.V. and INRIA
+#
+#TALER is free software; you can redistribute it and/or modify it under the
+#terms of the GNU Lesser General Public License as published by the Free
Software
+#Foundation; either version 2.1, 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 Lesser General Public License for more
details.
+#
+#You should have received a copy of the GNU Lesser General Public License
along with
+#TALER; see the file COPYING.LGPL. If not, see <http://www.gnu.org/licenses/>
+
+# @author Marcello Stanisci
+# @brief Error generator for responses coming from the exchange
+
+from flask import (request,
+ Flask,
+ make_response)
+import requests
+from urllib.parse import (urljoin,
+ urlencode,
+ urlparse,
+ urlunparse)
+from pytaler import amount
+import base64
+import os
+import logging
+import json
+from random import randint
+from datetime import datetime
+
+app = Flask(__name__)
+app.secret_key = base64.b64encode(os.urandom(64)).decode('utf-8')
+logger = logging.getLogger(__name__)
+exchange_url = os.environ.get("TALER_EXCHANGE_URL")
+assert(None != exchange_url)
+
+def track_transaction(resp):
+ return resp.text
+
+def track_transfer(resp):
+ return resp.text
+
+def keys(resp):
+ try:
+ keys = resp.json()
+ # Put here data perturbation logic
+ return json.dumps(keys)
+ except Exception:
+ return resp.text
+
address@hidden('/', defaults={'path': ''})
address@hidden('/<path:path>', methods=["GET", "POST"])
+def all(path):
+ body = request.get_json()
+ url = list(urlparse(request.url))
+ xurl = urlparse(exchange_url)
+ url[0] = xurl[0]
+ url[1] = xurl[1]
+ url = urlunparse(url)
+ if "POST" == request.method:
+ r = requests.post(urljoin(url, path), json=body)
+ else:
+ r = requests.get(urljoin(url, path), json=body)
+ dispatcher = {
+ "track_transaction": track_transaction,
+ "track_transfer": track_transfer,
+ "keys": keys
+ }
+ func = dispatcher.get(request.headers.get("X-Taler-Mitm"),
+ lambda x: x.text)
+ response = make_response(func(r))
+ for key, value in r.headers.items():
+ if key not in ("Server", "Content-Length"):
+ response.headers[key] = value
+ return response, r.status_code
diff --git a/src/merchant-tools/taler-merchant-dbinit.c
b/src/merchant-tools/taler-merchant-dbinit.c
index 35b5a1b..e846100 100644
--- a/src/merchant-tools/taler-merchant-dbinit.c
+++ b/src/merchant-tools/taler-merchant-dbinit.c
@@ -87,10 +87,13 @@ int
main (int argc,
char *const *argv)
{
- const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'r', "reset", NULL,
- "reset database (DANGEROUS: all existing data is lost!)", 0,
- &GNUNET_GETOPT_set_one, &reset_db},
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+ GNUNET_GETOPT_option_flag ('r',
+ "reset",
+ "reset database (DANGEROUS: all existing
data is lost!)",
+ &reset_db),
+
GNUNET_GETOPT_OPTION_END
};
diff --git a/src/samples/generate_payments.c
b/src/merchant-tools/taler-merchant-generate-payments.c
similarity index 69%
rename from src/samples/generate_payments.c
rename to src/merchant-tools/taler-merchant-generate-payments.c
index d887eff..9a4c3c0 100644
--- a/src/samples/generate_payments.c
+++ b/src/merchant-tools/taler-merchant-generate-payments.c
@@ -26,13 +26,69 @@
#include <gnunet/gnunet_curl_lib.h>
#include <microhttpd.h>
-#define EXCHANGE_URI "http://localexchange/"
-#define MERCHANT_URI "http://localshop/"
-#define BANK_URI "http://localbank/"
-#define INSTANCE "FSF"
-#define CURRENCY "EUR"
+/**
+ * The exchange process launched by the generator
+ */
+static struct GNUNET_OS_Process *exchanged;
+
+/**
+ * The merchant process launched by the generator
+ */
+static struct GNUNET_OS_Process *merchantd;
+
+/**
+ * How many times the command list should be rerun.
+ */
+static unsigned int times = 1;
+
+/**
+ * Current iteration of commands
+ */
+static unsigned int j = 0;
+
+/**
+ * Indicates whether we use an external exchange.
+ * By default, the generator forks a local exchange.
+ */
+static int remote_exchange = 0;
+
+/**
+ * Indicates whether we use an external merchant.
+ * By default, the generator tries to fork a local
+ * merchant.
+ */
+static int remote_merchant = 0;
+
+/**
+ * Exchange URI to withdraw from and deposit to.
+ */
+static char *exchange_uri;
+
+/**
+ * Base URL of exchange's admin interface.
+ */
+static char *exchange_uri_admin;
+
+/**
+ * Merchant backend to get proposals from and pay.
+ */
+static char *merchant_uri;
-#define ORDER_MAX_SIZE 1000
+/**
+ * Customer's bank URI, communicated at withdrawal time
+ * to the exchange; must be the same as the exchange's bank.
+ */
+static char *bank_uri;
+
+/**
+ * Which merchant instance we use.
+ */
+static char *instance;
+
+/**
+ * Currency used to generate payments.
+ */
+static char *currency;
/**
* Task run on timeout.
@@ -175,9 +231,11 @@ struct Command
/**
* String describing the denomination value we should withdraw.
* A corresponding denomination key must exist in the exchange's
- * offerings. Can be NULL if @e pk is set instead.
+ * offerings. Can be NULL if @e pk is set instead.
+ * The interpreter must free this value after it doesn't need it
+ * anymore.
*/
- const char *amount;
+ char *amount;
/**
* If @e amount is NULL, this specifies the denomination key to
@@ -257,11 +315,16 @@ struct Command
{
/**
- * The order.
- * It's dynamically generated because we need different transaction_id
- * for different merchant instances.
+ * Max deposit fee accepted by the merchant.
+ * Given in the form "CURRENCY:X.Y".
+ */
+ char *max_fee;
+
+ /**
+ * Proposal overall price.
+ * Given in the form "CURRENCY:X.Y".
*/
- char order[ORDER_MAX_SIZE];
+ char *amount;
/**
* Handle to the active PUT /proposal operation, or NULL.
@@ -273,7 +336,7 @@ struct Command
* FIXME: verify in the code that this bit is actually proposal
* data and not the whole proposal.
*/
- json_t *proposal_data;
+ json_t *contract_terms;
/**
* Proposal's signature.
@@ -333,7 +396,7 @@ struct Command
/**
* Hashcode of the proposal data associated to this payment.
*/
- struct GNUNET_HashCode h_proposal_data;
+ struct GNUNET_HashCode h_contract_terms;
/**
* Merchant's public key
@@ -406,7 +469,7 @@ next_command (struct InterpreterState *is)
* @param ec taler-specific error code
* @param obj the full received JSON reply, or
* error details if the request failed
- * @param proposal_data the order + additional information provided by the
+ * @param contract_terms the order + additional information provided by the
* backend, NULL on error.
* @param sig merchant's signature over the contract, NULL on error
* @param h_contract hash of the contract, NULL on error
@@ -416,7 +479,7 @@ proposal_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *obj,
- const json_t *proposal_data,
+ const json_t *contract_terms,
const struct TALER_MerchantSignatureP *sig,
const struct GNUNET_HashCode *hash)
{
@@ -427,7 +490,7 @@ proposal_cb (void *cls,
switch (http_status)
{
case MHD_HTTP_OK:
- cmd->details.proposal.proposal_data = json_incref ((json_t *)
proposal_data);
+ cmd->details.proposal.contract_terms = json_incref ((json_t *)
contract_terms);
cmd->details.proposal.merchant_sig = *sig;
cmd->details.proposal.hash = *hash;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -467,7 +530,7 @@ pay_cb (void *cls,
struct Command *cmd = &is->commands[is->ip];
struct PaymentResponsePS mr;
struct GNUNET_CRYPTO_EddsaSignature sig;
- struct GNUNET_HashCode h_proposal_data;
+ struct GNUNET_HashCode h_contract_terms;
const char *error_name;
unsigned int error_line;
@@ -487,7 +550,7 @@ pay_cb (void *cls,
/* Check signature */
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("sig", &sig),
- GNUNET_JSON_spec_fixed_auto ("h_proposal_data", &h_proposal_data),
+ GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &h_contract_terms),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
@@ -506,7 +569,7 @@ pay_cb (void *cls,
}
mr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK);
mr.purpose.size = htonl (sizeof (mr));
- mr.h_proposal_data = h_proposal_data;
+ mr.h_contract_terms = h_contract_terms;
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_PAYMENT_OK,
&mr.purpose,
@@ -546,6 +609,9 @@ add_incoming_cb (void *cls,
if (MHD_HTTP_OK != http_status)
{
GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%s",
+ json_dumps (full_response, JSON_INDENT (2)));
fail (is);
return;
}
@@ -692,6 +758,47 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys,
}
/**
+ * Allocates and return a string representing a order.
+ * In this process, this function gives the order those
+ * prices specified by the user. Please NOTE that any amount
+ * must be given in the form "XX.YY".
+ *
+ * @param max_fee merchant's allowed max_fee
+ * @param amount total amount for this order
+ */
+json_t *
+make_order (char *maxfee,
+ char *total)
+{
+ struct TALER_Amount tmp_amount;
+ json_t *total_j;
+ json_t *maxfee_j;
+ json_t *ret;
+ unsigned long long id;
+
+ TALER_string_to_amount (maxfee, &tmp_amount);
+ maxfee_j = TALER_JSON_from_amount (&tmp_amount);
+ TALER_string_to_amount (total, &tmp_amount);
+ total_j = TALER_JSON_from_amount (&tmp_amount);
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ &id,
+ sizeof (id));
+ ret = json_pack ("{s:O, s:s, s:s, s:s, s:s, s:O, s:s, s:[{s:s}]}",
+ "max_fee", maxfee_j,
+ "order_id", TALER_b2s (&id, sizeof (id)),
+ "timestamp", "/Date(42)/",
+ "refund_deadline", "/Date(0)/",
+ "pay_deadline", "/Date(9999999999)/",
+ "amount", total_j,
+ "summary", "payments generator..",
+ "products", "description", "ice cream");
+
+ GNUNET_assert (NULL != ret);
+ return ret;
+}
+
+/**
* Run the main interpreter loop that performs exchange operations.
*
* @param cls contains the `struct InterpreterState`
@@ -710,6 +817,12 @@ interpreter_run (void *cls)
json_t *sender_details;
json_t *transfer_details;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Interpreter runs command %u/%s(%u)\n",
+ is->ip,
+ cmd->label,
+ cmd->oc);
+
is->task = NULL;
tc = GNUNET_SCHEDULER_get_task_context ();
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
@@ -719,17 +832,27 @@ interpreter_run (void *cls)
fail (is);
return;
}
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Interpreter runs command %u/%s(%u)\n",
- is->ip,
- cmd->label,
- cmd->oc);
switch (cmd->oc)
{
case OC_END:
+
+ j++;
+
+ if (j < times)
+ {
+ is->ip = 0;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Rewinding the interpreter.\n");
+
+ GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+ return;
+ }
result = GNUNET_OK;
GNUNET_SCHEDULER_shutdown ();
+
return;
case OC_PAY:
@@ -746,13 +869,13 @@ interpreter_run (void *cls)
struct TALER_Amount max_fee;
const char *error_name;
unsigned int error_line;
-
+
/* get proposal */
ref = find_command (is,
cmd->details.pay.contract_ref);
GNUNET_assert (NULL != ref);
merchant_sig = ref->details.proposal.merchant_sig;
- GNUNET_assert (NULL != ref->details.proposal.proposal_data);
+ GNUNET_assert (NULL != ref->details.proposal.contract_terms);
{
/* Get information that need to be replied in the deposit permission
*/
struct GNUNET_JSON_Specification spec[] = {
@@ -766,9 +889,9 @@ interpreter_run (void *cls)
TALER_JSON_spec_amount ("max_fee", &max_fee),
GNUNET_JSON_spec_end()
};
-
+
if (GNUNET_OK !=
- GNUNET_JSON_parse (ref->details.proposal.proposal_data,
+ GNUNET_JSON_parse (ref->details.proposal.contract_terms,
spec,
&error_name,
&error_line))
@@ -783,9 +906,9 @@ interpreter_run (void *cls)
}
cmd->details.pay.merchant_pub = merchant_pub;
}
-
+
{
- const struct Command *coin_ref;
+ const struct Command *coin_ref;
memset (&pc, 0, sizeof (pc));
coin_ref = find_command (is,
cmd->details.pay.coin_ref);
@@ -801,7 +924,7 @@ interpreter_run (void *cls)
default:
GNUNET_assert (0);
}
-
+
if (GNUNET_OK !=
TALER_string_to_amount (cmd->details.pay.amount_without_fee,
&pc.amount_without_fee))
@@ -813,7 +936,7 @@ interpreter_run (void *cls)
fail (is);
return;
}
-
+
if (GNUNET_OK !=
TALER_string_to_amount (cmd->details.pay.amount_with_fee,
&pc.amount_with_fee))
@@ -826,21 +949,21 @@ interpreter_run (void *cls)
return;
}
}
-
+
cmd->details.pay.ph
= TALER_MERCHANT_pay_wallet (ctx,
- MERCHANT_URI,
- INSTANCE,
+ merchant_uri,
+ instance,
&ref->details.proposal.hash,
&total_amount,
&max_fee,
&merchant_pub,
- &merchant_sig,
+ &merchant_sig,
timestamp,
refund_deadline,
pay_deadline,
&h_wire,
- EXCHANGE_URI,
+ exchange_uri,
order_id,
1 /* num_coins */,
&pc /* coins */,
@@ -859,26 +982,32 @@ interpreter_run (void *cls)
case OC_PROPOSAL:
{
json_t *order;
- json_error_t error;
-
- order = json_loads (cmd->details.proposal.order,
- JSON_REJECT_DUPLICATES,
- &error);
+ json_t *merchant_obj;
+
+ order = make_order (cmd->details.proposal.max_fee,
+ cmd->details.proposal.amount);
+
+
if (NULL == order)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse the order `%s' at command #%u: %s at
%u\n",
- cmd->details.proposal.order,
- is->ip,
- error.text,
- (unsigned int) error.column);
+ "Failed to create the order at command #%u\n",
+ is->ip);
fail (is);
return;
}
-
+
+ GNUNET_assert (NULL != (merchant_obj = json_pack ("{s:{s:s}}",
+ "merchant",
+ "instance",
+ instance)));
+
+
+ GNUNET_assert (-1 != json_object_update (order, merchant_obj));
+
cmd->details.proposal.po
= TALER_MERCHANT_order_put (ctx,
- MERCHANT_URI,
+ merchant_uri,
order,
&proposal_cb,
is);
@@ -906,7 +1035,7 @@ interpreter_run (void *cls)
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);
@@ -924,7 +1053,7 @@ interpreter_run (void *cls)
fail (is);
return;
}
-
+
execution_date = GNUNET_TIME_absolute_get ();
GNUNET_TIME_round_abs (&execution_date);
sender_details = json_loads
(cmd->details.admin_add_incoming.sender_details,
@@ -939,10 +1068,12 @@ interpreter_run (void *cls)
fail (is);
return;
}
+ json_object_set (sender_details, "bank_uri", json_string (bank_uri));
+
transfer_details = json_loads
(cmd->details.admin_add_incoming.transfer_details,
JSON_REJECT_DUPLICATES,
NULL);
-
+
if (NULL == transfer_details)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -954,7 +1085,7 @@ interpreter_run (void *cls)
}
cmd->details.admin_add_incoming.aih
= TALER_EXCHANGE_admin_add_incoming (exchange,
- EXCHANGE_URI,
+ exchange_uri_admin,
&reserve_pub,
&amount,
execution_date,
@@ -1003,11 +1134,11 @@ interpreter_run (void *cls)
fail (is);
return;
}
-
+
/* create coin's private key */
{
struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
-
+
priv = GNUNET_CRYPTO_eddsa_key_create ();
cmd->details.reserve_withdraw.coin_priv.eddsa_priv = *priv;
GNUNET_free (priv);
@@ -1017,7 +1148,7 @@ interpreter_run (void *cls)
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&cmd->details.reserve_withdraw.blinding_key,
sizeof
(cmd->details.reserve_withdraw.blinding_key));
-
+
cmd->details.reserve_withdraw.wsh
= TALER_EXCHANGE_reserve_withdraw (exchange,
cmd->details.reserve_withdraw.pk,
@@ -1074,6 +1205,7 @@ cert_cb (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Certificate callback invoked, starting interpreter\n");
is->keys = keys;
+
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
is);
}
@@ -1106,7 +1238,6 @@ do_shutdown (void *cls)
{
struct InterpreterState *is = cls;
struct Command *cmd;
- unsigned int i;
if (NULL != timeout_task)
{
@@ -1114,13 +1245,13 @@ do_shutdown (void *cls)
timeout_task = NULL;
}
- for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
+ for (unsigned int i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
switch (cmd->oc)
{
case OC_END:
GNUNET_assert (0);
break;
-
+
case OC_PAY:
if (NULL != cmd->details.pay.ph)
{
@@ -1132,7 +1263,7 @@ do_shutdown (void *cls)
cmd->details.pay.ph = NULL;
}
break;
-
+
case OC_PROPOSAL:
if (NULL != cmd->details.proposal.po)
{
@@ -1143,13 +1274,13 @@ do_shutdown (void *cls)
TALER_MERCHANT_proposal_cancel (cmd->details.proposal.po);
cmd->details.proposal.po = NULL;
}
- if (NULL != cmd->details.proposal.proposal_data)
+ if (NULL != cmd->details.proposal.contract_terms)
{
- json_decref (cmd->details.proposal.proposal_data);
- cmd->details.proposal.proposal_data = NULL;
+ json_decref (cmd->details.proposal.contract_terms);
+ cmd->details.proposal.contract_terms = NULL;
}
break;
-
+
case OC_WITHDRAW_SIGN:
if (NULL != cmd->details.reserve_withdraw.wsh)
{
@@ -1165,8 +1296,9 @@ do_shutdown (void *cls)
GNUNET_CRYPTO_rsa_signature_free
(cmd->details.reserve_withdraw.sig.rsa_signature);
cmd->details.reserve_withdraw.sig.rsa_signature = NULL;
}
+ GNUNET_free_non_null (cmd->details.reserve_withdraw.amount);
break;
-
+
case OC_ADMIN_ADD_INCOMING:
if (NULL != cmd->details.admin_add_incoming.aih)
{
@@ -1178,7 +1310,7 @@ do_shutdown (void *cls)
cmd->details.admin_add_incoming.aih = NULL;
}
break;
-
+
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Shutdown: unknown instruction %d at %u (%s)\n",
@@ -1212,272 +1344,399 @@ do_shutdown (void *cls)
}
/**
+ * Take currency and the part after ":" in the
+ * "CURRENCY:XX.YY" format, and return a string
+ * in the format "CURRENCY:XX.YY".
+ *
+ * @param currency currency
+ * @param rpart float numbers after the ":", in string form
+ * @return pointer to allocated and concatenated "CURRENCY:XX.YY"
+ * formatted string.
+ *
+ */
+char *
+concat_amount (char *currency, char *rpart)
+{
+ char *str;
+
+ GNUNET_asprintf (&str, "%s:%s",
+ currency, rpart);
+ return str;
+}
+
+
+/**
* Main function that will be run by the scheduler.
*
* @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be
+ * NULL!)
+ * @param config configuration
*/
static void
-run (void *cls)
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
{
struct InterpreterState *is;
- static struct Command commands[] =
+ unsigned int cnt;
+ char *wget_cmd;
+
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (config,
+
"payments-generator",
+ "exchange",
+ &exchange_uri))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "payments-generator",
+ "exchange");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (config,
+
"payments-generator",
+ "exchange_admin",
+
&exchange_uri_admin))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "payments-generator",
+ "exchange_admin");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (config,
+
"payments-generator",
+ "merchant",
+ &merchant_uri))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "payments-generator",
+ "merchant");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (config,
+
"payments-generator",
+ "bank",
+ &bank_uri))
+ {
+
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "payments-generator",
+ "bank");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (config,
+
"payments-generator",
+ "instance",
+ &instance))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "payments-generator",
+ "instance");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (config,
+
"payments-generator",
+ "currency",
+ ¤cy))
+ {
+
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "payments-generator",
+ "currency");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (!remote_exchange)
+ {
+ exchanged = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-httpd",
+ "taler-exchange-httpd",
+ NULL);
+ if (NULL == exchanged)
+ {
+ fprintf (stderr,
+ "Failed to run taler-exchange-httpd. Check your PATH.\n");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ fprintf (stderr,
+ "Waiting for taler-exchange-httpd to be ready\n");
+ cnt = 0;
+
+ GNUNET_asprintf (&wget_cmd, "wget -q -t 1 -T 1 %skeys -o /dev/null -O
/dev/null", exchange_uri);
+
+ do
+ {
+ fprintf (stderr, ".");
+ sleep (1);
+ cnt++;
+ if (cnt > 60)
+ {
+ fprintf (stderr,
+ "\nFailed to start taler-exchange-httpd\n");
+ GNUNET_OS_process_kill (exchanged,
+ SIGKILL);
+ GNUNET_OS_process_wait (exchanged);
+ GNUNET_OS_process_destroy (exchanged);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ }
+ while (0 != system (wget_cmd));
+ GNUNET_free (wget_cmd);
+
+ fprintf (stderr, "\n");
+ }
+
+
+ if (!remote_merchant)
+ {
+ merchantd = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-merchant-httpd",
+ "taler-merchant-httpd",
+ "-L", "DEBUG",
+ NULL);
+ if (NULL == merchantd)
+ {
+ fprintf (stderr,
+ "Failed to run taler-merchant-httpd. Check your PATH.\n");
+ GNUNET_OS_process_kill (exchanged,
+ SIGKILL);
+ GNUNET_OS_process_wait (exchanged);
+ GNUNET_OS_process_destroy (exchanged);
+
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ /* give child time to start and bind against the socket */
+ fprintf (stderr,
+ "Waiting for taler-merchant-httpd to be ready\n");
+ cnt = 0;
+ GNUNET_asprintf (&wget_cmd, "wget -q -t 1 -T 1 %s -o /dev/null -O
/dev/null", merchant_uri);
+
+ do
+ {
+ fprintf (stderr, ".");
+ sleep (1);
+ cnt++;
+ if (cnt > 60)
+ {
+ fprintf (stderr,
+ "\nFailed to start taler-merchant-httpd\n");
+ GNUNET_OS_process_kill (merchantd,
+ SIGKILL);
+ GNUNET_OS_process_wait (merchantd);
+ GNUNET_OS_process_destroy (merchantd);
+ GNUNET_OS_process_kill (exchanged,
+ SIGKILL);
+ GNUNET_OS_process_wait (exchanged);
+ GNUNET_OS_process_destroy (exchanged);
+
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ }
+ while (0 != system (wget_cmd));
+ fprintf (stderr, "\n");
+ GNUNET_free (wget_cmd);
+ }
+
+ struct Command commands[] =
{
/* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */
{ .oc = OC_ADMIN_ADD_INCOMING,
.label = "create-reserve-1",
.expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.sender_details = "{ \"bank_uri\":\""
BANK_URI "\", \"type\":\"test\", \"account_number\":62, \"uuid\":1 }",
+ .details.admin_add_incoming.sender_details = "{ \"type\":\"test\",
\"account_number\":62, \"uuid\":1 }",
.details.admin_add_incoming.transfer_details = "{ \"uuid\": 1}",
- .details.admin_add_incoming.amount = CURRENCY ":5.01" },
+ .details.admin_add_incoming.amount = concat_amount (currency, "5.01") },
+
/* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */
{ .oc = OC_ADMIN_ADD_INCOMING,
.label = "create-reserve-2",
.expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.sender_details = "{ \"bank_uri\":\""
BANK_URI "\", \"type\":\"test\", \"account_number\":62, \"uuid\":1 }",
+ .details.admin_add_incoming.sender_details = "{ \"type\":\"test\",
\"account_number\":62, \"uuid\":1 }",
.details.admin_add_incoming.transfer_details = "{ \"uuid\": 1}",
- .details.admin_add_incoming.amount = CURRENCY ":5.01" },
+ .details.admin_add_incoming.amount = concat_amount (currency, "5.01") },
/* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */
{ .oc = OC_ADMIN_ADD_INCOMING,
.label = "create-reserve-3",
.expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.sender_details = "{ \"bank_uri\":\""
BANK_URI "\", \"type\":\"test\", \"account_number\":62, \"uuid\":1 }",
+ .details.admin_add_incoming.sender_details = "{ \"type\":\"test\",
\"account_number\":62, \"uuid\":1 }",
.details.admin_add_incoming.transfer_details = "{ \"uuid\": 1}",
- .details.admin_add_incoming.amount = CURRENCY ":5.01" },
+ .details.admin_add_incoming.amount = concat_amount (currency, "5.01") },
+
/* Withdraw a 5 EUR coin, at fee of 1 ct */
{ .oc = OC_WITHDRAW_SIGN,
.label = "withdraw-coin-1",
.expected_response_code = MHD_HTTP_OK,
.details.reserve_withdraw.reserve_reference = "create-reserve-1",
- .details.reserve_withdraw.amount = CURRENCY ":5" },
+ .details.reserve_withdraw.amount = concat_amount (currency, "5") },
+
/* Withdraw a 5 EUR coin, at fee of 1 ct */
{ .oc = OC_WITHDRAW_SIGN,
.label = "withdraw-coin-2",
.expected_response_code = MHD_HTTP_OK,
.details.reserve_withdraw.reserve_reference = "create-reserve-2",
- .details.reserve_withdraw.amount = CURRENCY ":5" },
+ .details.reserve_withdraw.amount = concat_amount (currency, "5") },
+
/* Withdraw a 5 EUR coin, at fee of 1 ct */
{ .oc = OC_WITHDRAW_SIGN,
.label = "withdraw-coin-3",
.expected_response_code = MHD_HTTP_OK,
.details.reserve_withdraw.reserve_reference = "create-reserve-3",
- .details.reserve_withdraw.amount = CURRENCY ":5" },
+ .details.reserve_withdraw.amount = concat_amount (currency, "5") },
/* Create proposal */
{ .oc = OC_PROPOSAL,
.label = "create-proposal-1",
.expected_response_code = MHD_HTTP_OK,
- .details.proposal.order = "{\
- \"max_fee\":\
- {\"currency\":\"" CURRENCY "\", \"value\":0,
\"fraction\":50000000},\
- \"order_id\":\"1\",\
- \"timestamp\":\"\\/Date(42)\\/\",\
- \"refund_deadline\":\"\\/Date(0)\\/\",\
- \"pay_deadline\":\"\\/Date(9999999999)\\/\",\
- \"amount\":{\"currency\":\"" CURRENCY "\", \"value\":5,
\"fraction\":0},\
- \"merchant\":{\"instance\":\"" INSTANCE "\"},\
- \"summary\": \"merchant-lib testcase\",\
- \"products\":\
- [ {\"description\":\"ice cream\", \"value\":\"{" CURRENCY
":5}\"} ] }"},
+ .details.proposal.max_fee = concat_amount (currency, "0.5"),
+ .details.proposal.amount = concat_amount (currency, "0.5") },
/* Create proposal */
{ .oc = OC_PROPOSAL,
.label = "create-proposal-2",
.expected_response_code = MHD_HTTP_OK,
- .details.proposal.order = "{\
- \"max_fee\":\
- {\"currency\":\"" CURRENCY "\", \"value\":0,
\"fraction\":50000000},\
- \"order_id\":\"2\",\
- \"timestamp\":\"\\/Date(42)\\/\",\
- \"refund_deadline\":\"\\/Date(0)\\/\",\
- \"pay_deadline\":\"\\/Date(9999999999)\\/\",\
- \"amount\":{\"currency\":\"" CURRENCY "\", \"value\":5,
\"fraction\":0},\
- \"merchant\":{\"instance\":\"" INSTANCE "\"},\
- \"summary\": \"merchant-lib testcase\",\
- \"products\":\
- [ {\"description\":\"ice cream\", \"value\":\"{" CURRENCY
":5}\"} ] }"},
+ .details.proposal.max_fee = concat_amount (currency, "0.5"),
+ .details.proposal.amount = concat_amount (currency, "0.5") },
/* Create proposal */
{ .oc = OC_PROPOSAL,
.label = "create-proposal-3",
.expected_response_code = MHD_HTTP_OK,
- .details.proposal.order = "{\
- \"max_fee\":\
- {\"currency\":\"" CURRENCY "\", \"value\":0,
\"fraction\":50000000},\
- \"order_id\":\"3\",\
- \"timestamp\":\"\\/Date(42)\\/\",\
- \"refund_deadline\":\"\\/Date(0)\\/\",\
- \"pay_deadline\":\"\\/Date(9999999999)\\/\",\
- \"amount\":{\"currency\":\"" CURRENCY "\", \"value\":5,
\"fraction\":0},\
- \"merchant\":{\"instance\":\"" INSTANCE "\"},\
- \"summary\": \"merchant-lib testcase\",\
- \"products\":\
- [ {\"description\":\"ice cream\", \"value\":\"{" CURRENCY
":5}\"} ] }"},
+ .details.proposal.max_fee = concat_amount (currency, "0.5"),
+ .details.proposal.amount = concat_amount (currency, "5.0") },
{ .oc = OC_PAY,
- .label = "deposit-simple",
+ .label = "deposit-simple-1",
.expected_response_code = MHD_HTTP_OK,
.details.pay.contract_ref = "create-proposal-1",
.details.pay.coin_ref = "withdraw-coin-1",
- .details.pay.amount_with_fee = CURRENCY ":5",
- .details.pay.amount_without_fee = CURRENCY ":4.99" },
+ .details.pay.amount_with_fee = concat_amount (currency, "5"),
+ .details.pay.amount_without_fee = concat_amount (currency, "4.99") },
{ .oc = OC_PAY,
- .label = "deposit-simple",
+ .label = "deposit-simple-2",
.expected_response_code = MHD_HTTP_OK,
.details.pay.contract_ref = "create-proposal-2",
.details.pay.coin_ref = "withdraw-coin-2",
- .details.pay.amount_with_fee = CURRENCY ":5",
- .details.pay.amount_without_fee = CURRENCY ":4.99" },
+ .details.pay.amount_with_fee = concat_amount (currency, "5"),
+ .details.pay.amount_without_fee = concat_amount (currency, "4.99") },
{ .oc = OC_PAY,
- .label = "deposit-simple",
+ .label = "deposit-simple-3",
.expected_response_code = MHD_HTTP_OK,
.details.pay.contract_ref = "create-proposal-3",
.details.pay.coin_ref = "withdraw-coin-3",
- .details.pay.amount_with_fee = CURRENCY ":5",
- .details.pay.amount_without_fee = CURRENCY ":4.99" },
+ .details.pay.amount_with_fee = concat_amount (currency, "5"),
+ .details.pay.amount_without_fee = concat_amount (currency, "4.99") },
{ .oc = OC_END,
.label = "end-of-commands"}
};
+
is = GNUNET_new (struct InterpreterState);
- is->commands = commands;
+ is->commands = GNUNET_malloc (sizeof (commands));
+ memcpy (is->commands,
+ commands,
+ sizeof (commands));
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
&rc);
GNUNET_assert (NULL != ctx);
rc = GNUNET_CURL_gnunet_rc_create (ctx);
exchange = TALER_EXCHANGE_connect (ctx,
- EXCHANGE_URI,
- &cert_cb, is,
+ exchange_uri,
+ &cert_cb,
+ is,
TALER_EXCHANGE_OPTION_END);
GNUNET_assert (NULL != exchange);
timeout_task
= GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_SECONDS, 150),
&do_timeout, NULL);
- GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is);
-
-
+ GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
+ is);
}
+
int
main (int argc,
char *argv[])
{
- struct GNUNET_OS_Process *exchanged;
- struct GNUNET_OS_Process *merchantd;
- unsigned int cnt;
struct GNUNET_SIGNAL_Context *shc_chld;
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_option_uint ('n',
+ "times",
+ "TIMES",
+ "How many times the commands should be run.",
+ ×),
+ GNUNET_GETOPT_option_flag ('e',
+ "remote-exchange",
+ "Do not fork any exchange",
+ &remote_exchange),
+ GNUNET_GETOPT_option_flag ('m',
+ "remote-merchant",
+ "Do not fork any merchant",
+ &remote_merchant),
+ GNUNET_GETOPT_OPTION_END
+ };
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
-
- GNUNET_log_setup ("merchant-create-payments",
+ GNUNET_log_setup ("taler-merchant-generate-payments",
"DEBUG",
NULL);
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "About to launch the exchange.\n");
-
- exchanged = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-httpd",
- "taler-exchange-httpd",
- NULL);
- if (NULL == exchanged)
- {
- fprintf (stderr,
- "Failed to run taler-exchange-httpd. Check your PATH.\n");
- return 77;
- }
-
- fprintf (stderr,
- "Waiting for taler-exchange-httpd to be ready\n");
- cnt = 0;
- do
- {
- fprintf (stderr, ".");
- sleep (1);
- cnt++;
- if (cnt > 60)
- {
- fprintf (stderr,
- "\nFailed to start taler-exchange-httpd\n");
- GNUNET_OS_process_kill (exchanged,
- SIGKILL);
- GNUNET_OS_process_wait (exchanged);
- GNUNET_OS_process_destroy (exchanged);
- return 77;
- }
- }
- while (0 != system ("wget -q -t 1 -T 1 " EXCHANGE_URI "keys -o /dev/null -O
/dev/null"));
- fprintf (stderr, "\n");
-
- merchantd = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-merchant-httpd",
- "taler-merchant-httpd",
- "-L", "DEBUG",
- NULL);
- if (NULL == merchantd)
- {
- fprintf (stderr,
- "Failed to run taler-merchant-httpd. Check your PATH.\n");
- GNUNET_OS_process_kill (exchanged,
- SIGKILL);
- GNUNET_OS_process_wait (exchanged);
- GNUNET_OS_process_destroy (exchanged);
- return 77;
- }
- /* give child time to start and bind against the socket */
- fprintf (stderr,
- "Waiting for taler-merchant-httpd to be ready\n");
- cnt = 0;
- do
- {
- fprintf (stderr, ".");
- sleep (1);
- cnt++;
- if (cnt > 60)
- {
- fprintf (stderr,
- "\nFailed to start taler-merchant-httpd\n");
- GNUNET_OS_process_kill (merchantd,
- SIGKILL);
- GNUNET_OS_process_wait (merchantd);
- GNUNET_OS_process_destroy (merchantd);
- GNUNET_OS_process_kill (exchanged,
- SIGKILL);
- GNUNET_OS_process_wait (exchanged);
- GNUNET_OS_process_destroy (exchanged);
- return 77;
- }
- }
- while (0 != system ("wget -q -t 1 -T 1 " MERCHANT_URI " -o /dev/null -O
/dev/null"));
- fprintf (stderr, "\n");
-
result = GNUNET_SYSERR;
- sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
+ 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);
+ if (GNUNET_OK !=
+ GNUNET_PROGRAM_run (argc, argv,
+ "taler-merchant-generate-payments",
+ "Populates DB with fake payments",
+ options,
+ &run, NULL))
+ return 77;
+
GNUNET_SIGNAL_handler_uninstall (shc_chld);
shc_chld = NULL;
GNUNET_DISK_pipe_close (sigpipe);
- GNUNET_OS_process_kill (merchantd,
- SIGTERM);
- GNUNET_OS_process_wait (merchantd);
- GNUNET_OS_process_destroy (merchantd);
- GNUNET_OS_process_kill (exchanged,
- SIGTERM);
- GNUNET_OS_process_wait (exchanged);
- GNUNET_OS_process_destroy (exchanged);
+ if (!remote_merchant && NULL != merchantd)
+ {
+ GNUNET_OS_process_kill (merchantd,
+ SIGTERM);
+ GNUNET_OS_process_wait (merchantd);
+ GNUNET_OS_process_destroy (merchantd);
+ }
+ if (!remote_exchange && NULL != exchanged)
+ {
+ GNUNET_OS_process_kill (exchanged,
+ SIGTERM);
+ GNUNET_OS_process_wait (exchanged);
+ GNUNET_OS_process_destroy (exchanged);
+ }
if (77 == result)
return 77;
return (GNUNET_OK == result) ? 0 : 1;
diff --git a/src/samples/Makefile.am b/src/samples/Makefile.am
deleted file mode 100644
index 54c6d8f..0000000
--- a/src/samples/Makefile.am
+++ /dev/null
@@ -1,21 +0,0 @@
-# This Makefile.am is in the public domain
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
-
-bin_PROGRAMS = \
- taler-merchant-generate-payments
-
-taler_merchant_generate_payments_SOURCES = \
- generate_payments.c
-
-taler_merchant_generate_payments_LDADD = \
- $(top_srcdir)/src/backenddb/libtalermerchantdb.la \
- $(top_srcdir)/src/lib/libtalermerchant.la \
- $(LIBGCRYPT_LIBS) \
- -ltalerfakebank \
- -ltalerexchange \
- -ltalerjson \
- -ltalerutil \
- -lgnunetjson \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
diff --git a/src/samples/README b/src/samples/README
deleted file mode 100644
index 4926db6..0000000
--- a/src/samples/README
+++ /dev/null
@@ -1,3 +0,0 @@
-Here is the logic that creates dummy payments into the
-merchant's DB, mainly used for debugging applications that
-need some real data from the merchant backend.
diff --git
a/src/samples/generate_payments_home/.config/taler/merchant/wire/test.json
b/src/samples/generate_payments_home/.config/taler/merchant/wire/test.json
deleted file mode 100644
index 99c9c66..0000000
--- a/src/samples/generate_payments_home/.config/taler/merchant/wire/test.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "type":"test",
- "bank_uri":"http://localhost:8083/",
- "account_number":62
-}
diff --git a/src/samples/generate_payments_home/.config/taler/test.json
b/src/samples/generate_payments_home/.config/taler/test.json
deleted file mode 100644
index 6c29eab..0000000
--- a/src/samples/generate_payments_home/.config/taler/test.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "type": "test",
- "account_number": 3,
- "bank_uri": "http://localhost:8083/",
- "name": "The exchange"
-}
diff --git a/src/samples/generate_payments_home/.config/taler/test.signed.json
b/src/samples/generate_payments_home/.config/taler/test.signed.json
deleted file mode 100644
index 532640f..0000000
--- a/src/samples/generate_payments_home/.config/taler/test.signed.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "type": "test",
- "salt":
"0STGVVCSNJBKCP92596RSHN54Y4YW46J6D910KMPB6FF5ZYXG1C8MTMRFG32H9HFBA2XNNKRPRTKGD0KKKM805QGZ0AR28W5DB00MDG",
- "account_number": 3,
- "bank_uri": "http://localhost:8083/",
- "name": "The exchange",
- "sig":
"6EZF2DQBJP7WFQK93MHW1B21N12DFPJ5KMB9KS6Y775W1YS1ZZ0CAP9Y2CDK14Q01S0HR51SGHVNGA1WDNV5C07K941BRCRE9MSSP0G"
-}
\ No newline at end of file
diff --git
a/src/samples/generate_payments_home/.local/share/taler/exchange/offline-keys/master.priv
b/src/samples/generate_payments_home/.local/share/taler/exchange/offline-keys/master.priv
deleted file mode 100644
index 0a17bb2..0000000
---
a/src/samples/generate_payments_home/.local/share/taler/exchange/offline-keys/master.priv
+++ /dev/null
@@ -1 +0,0 @@
-�QJ�_�#��O4(�kTr�$N ��8��2
\ No newline at end of file
diff --git a/src/samples/merchant_generate_payments.conf
b/src/samples/merchant_generate_payments.conf
deleted file mode 100644
index 07f7692..0000000
--- a/src/samples/merchant_generate_payments.conf
+++ /dev/null
@@ -1,132 +0,0 @@
-# This file is in the public domain.
-#
-[PATHS]
-# Persistant data storage for the testcase
-TALER_TEST_HOME = generate_payments_home/
-
-[taler]
-# What currency do we use?
-CURRENCY = EUR
-
-[exchange-wire-test]
-# Enable 'test' for testing of the actual coin operations.
-ENABLE = YES
-
-# Fees for the forseeable future...
-# If you see this after 2017, update to match the next 10 years...
-WIRE-FEE-2017 = EUR:0.01
-WIRE-FEE-2018 = EUR:0.01
-WIRE-FEE-2019 = EUR:0.01
-WIRE-FEE-2020 = EUR:0.01
-WIRE-FEE-2021 = EUR:0.01
-WIRE-FEE-2022 = EUR:0.01
-WIRE-FEE-2023 = EUR:0.01
-WIRE-FEE-2024 = EUR:0.01
-WIRE-FEE-2025 = EUR:0.01
-WIRE-FEE-2026 = EUR:0.01
-
-############################
-# Exchange's configuration #
-############################
-
-[exchange]
-# How to access our database
-DB = postgres
-
-# HTTP port the exchange listens to
-PORT = 8081
-
-# Our public key
-MASTER_PUBLIC_KEY = BNFX90SBRFRMFW7E598BKVH6CTM83YD2AAKRZ0ADGH15M1XXJGBG
-
-# This value must match the DB we want payments to persist in.
-[exchangedb-postgres]
-DB_CONN_STR = "postgres:///taler"
-
-
-[exchange-wire-incoming-test]
-TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/test.signed.json
-
-[exchange-wire-outgoing-test]
-BANK_URI = "http://localhost:8083/"
-BANK_ACCOUNT_NUMBER = 2
-
-[coin_eur_ct_1]
-value = EUR:0.01
-duration_overlap = 5 minutes
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.00
-fee_deposit = EUR:0.00
-fee_refresh = EUR:0.01
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_ct_10]
-value = EUR:0.10
-duration_overlap = 5 minutes
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_1]
-value = EUR:1
-duration_overlap = 5 minutes
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_5]
-value = EUR:5
-duration_overlap = 5 minutes
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-
-[merchant]
-
-# Which port do we run the backend on? (HTTP server)
-PORT = 8082
-
-# How quickly do we want the exchange to send us our money?
-# Used only if the frontend does not specify a value.
-# FIXME: EDATE is a bit short, 'execution_delay'?
-EDATE = 3 week
-
-# Which plugin (backend) do we use for the DB.
-DB = postgres
-
-# Wire format supported by the merchant.
-WIREFORMAT = test
-
-INSTANCES = default
-
-[merchant-exchange-test]
-URI = http://localhost:8081/
-MASTER_KEY = BNFX90SBRFRMFW7E598BKVH6CTM83YD2AAKRZ0ADGH15M1XXJGBG
-
-[merchant-instance-default]
-KEYFILE = test_merchant.priv
-
-[merchant-instance-wireformat-default]
-TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/merchant/wire/test.json
-
-[merchantdb-postgres]
-CONFIG = postgres:///taler
diff --git a/src/samples/test_merchant.priv b/src/samples/test_merchant.priv
deleted file mode 100644
index 9c18c35..0000000
--- a/src/samples/test_merchant.priv
+++ /dev/null
@@ -1 +0,0 @@
-`�&-���./��� jx�GݢO:6l,ζXT4�
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
address@hidden
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] [taler-merchant] branch stable updated (73d9a89 -> 64929e2),
gnunet <=